diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 5537a46ef8..295dc54371 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -123,7 +123,7 @@ You can get in touch with [the core contributors team](#the-core-contributors-te In order to build the Umbraco source code locally, first make sure you have the following installed. - * [Visual Studio 2017 v15.9.7+](https://visualstudio.microsoft.com/vs/) + * [Visual Studio 2019 v16.3+ (with .NET Core 3.0)](https://visualstudio.microsoft.com/vs/) * [Node.js v10+](https://nodejs.org/en/download/) * npm v6.4.1+ (installed with Node.js) * [Git command line](https://git-scm.com/download/) diff --git a/.github/ISSUE_TEMPLATE/3_BugNetCore.md b/.github/ISSUE_TEMPLATE/3_BugNetCore.md new file mode 100644 index 0000000000..989904d4d8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_BugNetCore.md @@ -0,0 +1,65 @@ +--- +name: 🌟 .Net Core Bug Report +about: For bugs specifically for the upcoming .NET Core release of Umbraco, don't use this if you're working with Umbraco version 7 or 8 +labels: project/net-core +--- + +ℹ️ If this bug **also** appears on the current version 8 of Umbraco then please [report it as a regular bug](https://github.com/umbraco/Umbraco-CMS/issues/new?template=1_Bug.md), fixes in version 8 will be merged to the .NET Core version. + +A brief description of the issue goes here. + + + + +Reproduction +------------ + +If you're filing a bug, please describe how to reproduce it. Include as much +relevant information as possible, such as: + +### Bug summary + + + +### Specifics + + + +### Steps to reproduce + + + +### Expected result + + + +### Actual result + + diff --git a/.github/ISSUE_TEMPLATE/3_Support_question.md b/.github/ISSUE_TEMPLATE/4_Support_question.md similarity index 100% rename from .github/ISSUE_TEMPLATE/3_Support_question.md rename to .github/ISSUE_TEMPLATE/4_Support_question.md diff --git a/.github/ISSUE_TEMPLATE/4_Documentation_issue.md b/.github/ISSUE_TEMPLATE/5_Documentation_issue.md similarity index 100% rename from .github/ISSUE_TEMPLATE/4_Documentation_issue.md rename to .github/ISSUE_TEMPLATE/5_Documentation_issue.md diff --git a/.github/ISSUE_TEMPLATE/5_Security_issue.md b/.github/ISSUE_TEMPLATE/6_Security_issue.md similarity index 100% rename from .github/ISSUE_TEMPLATE/5_Security_issue.md rename to .github/ISSUE_TEMPLATE/6_Security_issue.md diff --git a/.gitignore b/.gitignore index e35117d8e6..8b8a0782af 100644 --- a/.gitignore +++ b/.gitignore @@ -174,6 +174,7 @@ cypress.env.json # eof /src/Umbraco.Web.UI.Client/TESTS-*.xml /src/ApiDocs/api/* +/src/Umbraco.Web.UI.Client/package-lock.json /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.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index 477bb143f9..eeff783d6f 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -23,41 +23,42 @@ the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do not want this to happen as the alpha of the next major is, really, the next major already. --> - - - + + + - - - - + + + + - - - + + + - - - - + + + + - + - + + - - + + - + @@ -71,7 +72,6 @@ - @@ -79,7 +79,6 @@ - @@ -87,7 +86,6 @@ - diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec index 1aeead52a5..7800d05920 100644 --- a/build/NuSpecs/UmbracoCms.Web.nuspec +++ b/build/NuSpecs/UmbracoCms.Web.nuspec @@ -24,16 +24,16 @@ not want this to happen as the alpha of the next major is, really, the next major already. --> - - - - + + + + + - - + @@ -43,18 +43,18 @@ - + - + - + diff --git a/build/NuSpecs/tools/Web.config.install.xdt b/build/NuSpecs/tools/Web.config.install.xdt index f118fa8c3a..e215bdbf29 100644 --- a/build/NuSpecs/tools/Web.config.install.xdt +++ b/build/NuSpecs/tools/Web.config.install.xdt @@ -1,139 +1,136 @@ - - - - - -
-
-
- - + + + + + + +
+
+
+ + - - - - - - + + + + + + - - - - - + + + + + + - - - - - - - + + + + + + + + - - - - - - + - - - > - - + + + + + + + + + + + + - + + + + + + + + + - - - - - - - - + + + + + - - - - - + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + - - - - - - - - - - - + + + + + + + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -177,20 +174,21 @@ - + - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/build/build.ps1 b/build/build.ps1 index 98f975da4f..ee05710f47 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -125,7 +125,23 @@ $error.Clear() Write-Output "### gulp build for version $($this.Version.Release)" >> $log 2>&1 - npx gulp build --buildversion=$this.Version.Release >> $log 2>&1 + npm run build --buildversion=$this.Version.Release >> $log 2>&1 + + # We can ignore this warning, we need to update to node 12 at some point - https://github.com/jsdom/jsdom/issues/2939 + $indexes = [System.Collections.ArrayList]::new() + $index = 0; + $error | ForEach-Object { + # Find which of the errors is the ExperimentalWarning + if($_.ToString().Contains("ExperimentalWarning: The fs.promises API is experimental")) { + [void]$indexes.Add($index) + } + $index++ + } + $indexes | ForEach-Object { + # Loop through the list of indexes and remove the errors that we expect and feel confident we can ignore + $error.Remove($error[$_]) + } + if (-not $?) { throw "Failed to build" } # that one is expected to work } finally { Pop-Location diff --git a/build/templates/UmbracoSolution/.template.config/template.json b/build/templates/UmbracoSolution/.template.config/template.json index c222161245..ed83414eb6 100644 --- a/build/templates/UmbracoSolution/.template.config/template.json +++ b/build/templates/UmbracoSolution/.template.config/template.json @@ -15,7 +15,7 @@ "version": { "type": "parameter", "datatype": "string", - "defaultValue": "0.5.0-alpha001", + "defaultValue": "0.5.0-alpha002", "description": "The version of Umbraco to load using NuGet", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, diff --git a/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs b/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs deleted file mode 100644 index 0cacab9e1d..0000000000 --- a/src/Umbraco.Configuration/AspNetCoreConfigsFactory.cs +++ /dev/null @@ -1,50 +0,0 @@ -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/ConfigsFactory.cs b/src/Umbraco.Configuration/ConfigsFactory.cs deleted file mode 100644 index be6cee2d0c..0000000000 --- a/src/Umbraco.Configuration/ConfigsFactory.cs +++ /dev/null @@ -1,63 +0,0 @@ -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; - -namespace Umbraco.Core.Configuration -{ - public class ConfigsFactory : IConfigsFactory - { - public IHostingSettings HostingSettings { get; } = new HostingSettings(); - 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 Configs Create() - { - 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); - - return configs; - } - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/DisabledHealthCheckElement.cs b/src/Umbraco.Configuration/HealthChecks/DisabledHealthCheckElement.cs deleted file mode 100644 index 01392da614..0000000000 --- a/src/Umbraco.Configuration/HealthChecks/DisabledHealthCheckElement.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Text; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - public class DisabledHealthCheckElement : ConfigurationElement, IDisabledHealthCheck - { - private const string IdKey = "id"; - private const string DisabledOnKey = "disabledOn"; - private const string DisabledByKey = "disabledBy"; - - [ConfigurationProperty(IdKey, IsKey = true, IsRequired = true)] - public Guid Id - { - get - { - return ((Guid)(base[IdKey])); - } - } - - [ConfigurationProperty(DisabledOnKey, IsKey = false, IsRequired = false)] - public DateTime DisabledOn - { - get - { - return ((DateTime)(base[DisabledOnKey])); - } - } - - [ConfigurationProperty(DisabledByKey, IsKey = false, IsRequired = false)] - public int DisabledBy - { - get - { - return ((int)(base[DisabledByKey])); - } - } - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/DisabledHealthChecksElementCollection.cs b/src/Umbraco.Configuration/HealthChecks/DisabledHealthChecksElementCollection.cs deleted file mode 100644 index 87600b8ae3..0000000000 --- a/src/Umbraco.Configuration/HealthChecks/DisabledHealthChecksElementCollection.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - [ConfigurationCollection(typeof(DisabledHealthCheckElement), AddItemName = "check")] - public class DisabledHealthChecksElementCollection : ConfigurationElementCollection, IEnumerable - { - protected override ConfigurationElement CreateNewElement() - { - return new DisabledHealthCheckElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((DisabledHealthCheckElement)(element)).Id; - } - - public new DisabledHealthCheckElement this[string key] - { - get - { - return (DisabledHealthCheckElement)BaseGet(key); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return BaseGet(i) as DisabledHealthCheckElement; - } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/HealthCheckNotificationSettingsElement.cs b/src/Umbraco.Configuration/HealthChecks/HealthCheckNotificationSettingsElement.cs deleted file mode 100644 index 1ccf3e357b..0000000000 --- a/src/Umbraco.Configuration/HealthChecks/HealthCheckNotificationSettingsElement.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - public class HealthCheckNotificationSettingsElement : ConfigurationElement, IHealthCheckNotificationSettings - { - private const string EnabledKey = "enabled"; - private const string FirstRunTimeKey = "firstRunTime"; - private const string PeriodKey = "periodInHours"; - private const string NotificationMethodsKey = "notificationMethods"; - private const string DisabledChecksKey = "disabledChecks"; - - [ConfigurationProperty(EnabledKey, IsRequired = true)] - public bool Enabled - { - get - { - return (bool)base[EnabledKey]; - } - } - - [ConfigurationProperty(FirstRunTimeKey, IsRequired = false)] - public string FirstRunTime - { - get - { - return (string)base[FirstRunTimeKey]; - } - } - - [ConfigurationProperty(PeriodKey, IsRequired = true)] - public int PeriodInHours - { - get - { - return (int)base[PeriodKey]; - } - } - - [ConfigurationProperty(NotificationMethodsKey, IsDefaultCollection = true, IsRequired = false)] - public NotificationMethodsElementCollection NotificationMethods - { - get - { - return (NotificationMethodsElementCollection)base[NotificationMethodsKey]; - } - } - - [ConfigurationProperty(DisabledChecksKey, IsDefaultCollection = false, IsRequired = false)] - public DisabledHealthChecksElementCollection DisabledChecks - { - get - { - return (DisabledHealthChecksElementCollection)base[DisabledChecksKey]; - } - } - - bool IHealthCheckNotificationSettings.Enabled - { - get { return Enabled; } - } - - string IHealthCheckNotificationSettings.FirstRunTime - { - get { return FirstRunTime; } - } - - int IHealthCheckNotificationSettings.PeriodInHours - { - get { return PeriodInHours; } - } - - IReadOnlyDictionary IHealthCheckNotificationSettings.NotificationMethods - { - get { return NotificationMethods; } - } - - IEnumerable IHealthCheckNotificationSettings.DisabledChecks - { - get { return DisabledChecks; } - } - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs b/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs deleted file mode 100644 index 373d846567..0000000000 --- a/src/Umbraco.Configuration/HealthChecks/HealthChecksSection.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Configuration; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - public class HealthChecksSection : ConfigurationSection - { - private const string DisabledChecksKey = "disabledChecks"; - private const string NotificationSettingsKey = "notificationSettings"; - - [ConfigurationProperty(DisabledChecksKey)] - public DisabledHealthChecksElementCollection DisabledChecks - { - get { return ((DisabledHealthChecksElementCollection)(base[DisabledChecksKey])); } - } - - [ConfigurationProperty(NotificationSettingsKey, IsRequired = true)] - public HealthCheckNotificationSettingsElement NotificationSettings - { - get { return ((HealthCheckNotificationSettingsElement)(base[NotificationSettingsKey])); } - } - - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/NotificationMethodElement.cs b/src/Umbraco.Configuration/HealthChecks/NotificationMethodElement.cs deleted file mode 100644 index cbbe5e8b02..0000000000 --- a/src/Umbraco.Configuration/HealthChecks/NotificationMethodElement.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - public class NotificationMethodElement : ConfigurationElement, INotificationMethod - { - private const string AliasKey = "alias"; - private const string EnabledKey = "enabled"; - private const string VerbosityKey = "verbosity"; - private const string FailureonlyKey = "failureOnly"; - private const string SettingsKey = "settings"; - - [ConfigurationProperty(AliasKey, IsKey = true, IsRequired = true)] - public string Alias - { - get - { - return (string)base[AliasKey]; - } - } - - [ConfigurationProperty(EnabledKey, IsKey = true, IsRequired = true)] - public bool Enabled - { - get - { - return (bool)base[EnabledKey]; - } - } - - [ConfigurationProperty(VerbosityKey, IsRequired = true)] - public HealthCheckNotificationVerbosity Verbosity - { - get - { - return (HealthCheckNotificationVerbosity)base[VerbosityKey]; - } - } - - [ConfigurationProperty(FailureonlyKey, IsRequired = false)] - public bool FailureOnly - { - get - { - return (bool)base[FailureonlyKey]; - } - } - - [ConfigurationProperty(SettingsKey, IsDefaultCollection = true, IsRequired = false)] - public NotificationMethodSettingsElementCollection Settings - { - get - { - return (NotificationMethodSettingsElementCollection)base[SettingsKey]; - } - } - - string INotificationMethod.Alias - { - get { return Alias; } - } - - bool INotificationMethod.Enabled - { - get { return Enabled; } - } - - HealthCheckNotificationVerbosity INotificationMethod.Verbosity - { - get { return Verbosity; } - } - - bool INotificationMethod.FailureOnly - { - get { return FailureOnly; } - } - - IReadOnlyDictionary INotificationMethod.Settings - { - get { return Settings; } - } - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/NotificationMethodSettingsElement.cs b/src/Umbraco.Configuration/HealthChecks/NotificationMethodSettingsElement.cs deleted file mode 100644 index ed42eb7221..0000000000 --- a/src/Umbraco.Configuration/HealthChecks/NotificationMethodSettingsElement.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - public class NotificationMethodSettingsElement : ConfigurationElement, INotificationMethodSettings - { - private const string KeyKey = "key"; - private const string ValueKey = "value"; - - [ConfigurationProperty(KeyKey, IsKey = true, IsRequired = true)] - public string Key - { - get - { - return (string)base[KeyKey]; - } - } - - [ConfigurationProperty(ValueKey, IsRequired = true)] - public string Value - { - get - { - return (string)base[ValueKey]; - } - } - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/NotificationMethodSettingsElementCollection.cs b/src/Umbraco.Configuration/HealthChecks/NotificationMethodSettingsElementCollection.cs deleted file mode 100644 index 226278ab61..0000000000 --- a/src/Umbraco.Configuration/HealthChecks/NotificationMethodSettingsElementCollection.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - [ConfigurationCollection(typeof(NotificationMethodSettingsElement), AddItemName = "add")] - public class NotificationMethodSettingsElementCollection : ConfigurationElementCollection, IEnumerable, IReadOnlyDictionary - { - protected override ConfigurationElement CreateNewElement() - { - return new NotificationMethodSettingsElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((NotificationMethodSettingsElement)(element)).Key; - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - var val = (NotificationMethodSettingsElement)BaseGet(i); - var key = (string)BaseGetKey(i); - yield return new KeyValuePair(key, val); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return (NotificationMethodSettingsElement)BaseGet(i); - } - } - - bool IReadOnlyDictionary.ContainsKey(string key) - { - return ((IReadOnlyDictionary)this).Keys.Any(x => x == key); - } - - bool IReadOnlyDictionary.TryGetValue(string key, out INotificationMethodSettings value) - { - try - { - var val = (NotificationMethodSettingsElement)BaseGet(key); - value = val; - return true; - } - catch (Exception) - { - value = null; - return false; - } - } - - INotificationMethodSettings IReadOnlyDictionary.this[string key] - { - get { return (NotificationMethodSettingsElement)BaseGet(key); } - } - - IEnumerable IReadOnlyDictionary.Keys - { - get { return BaseGetAllKeys().Cast(); } - } - - IEnumerable IReadOnlyDictionary.Values - { - get - { - for (var i = 0; i < Count; i++) - { - yield return (NotificationMethodSettingsElement)BaseGet(i); - } - } - } - } -} diff --git a/src/Umbraco.Configuration/HealthChecks/NotificationMethodsElementCollection.cs b/src/Umbraco.Configuration/HealthChecks/NotificationMethodsElementCollection.cs deleted file mode 100644 index ee7e135961..0000000000 --- a/src/Umbraco.Configuration/HealthChecks/NotificationMethodsElementCollection.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - [ConfigurationCollection(typeof(NotificationMethodElement), AddItemName = "notificationMethod")] - public class NotificationMethodsElementCollection : ConfigurationElementCollection, IEnumerable, IReadOnlyDictionary - { - protected override ConfigurationElement CreateNewElement() - { - return new NotificationMethodElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((NotificationMethodElement)(element)).Alias; - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - var val = (NotificationMethodElement)BaseGet(i); - var key = (string)BaseGetKey(i); - yield return new KeyValuePair(key, val); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return (NotificationMethodElement)BaseGet(i); - } - } - - bool IReadOnlyDictionary.ContainsKey(string key) - { - return ((IReadOnlyDictionary) this).Keys.Any(x => x == key); - } - - bool IReadOnlyDictionary.TryGetValue(string key, out INotificationMethod value) - { - try - { - var val = (NotificationMethodElement)BaseGet(key); - value = val; - return true; - } - catch (Exception) - { - value = null; - return false; - } - } - - INotificationMethod IReadOnlyDictionary.this[string key] - { - get { return (NotificationMethodElement)BaseGet(key); } - } - - IEnumerable IReadOnlyDictionary.Keys - { - get { return BaseGetAllKeys().Cast(); } - } - - IEnumerable IReadOnlyDictionary.Values - { - get - { - for (var i = 0; i < Count; i++) - { - yield return (NotificationMethodElement)BaseGet(i); - } - } - } - } -} diff --git a/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs b/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs deleted file mode 100644 index ef100afed6..0000000000 --- a/src/Umbraco.Configuration/Legacy/ActiveDirectorySettings.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Configuration; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration.Legacy -{ - public class ActiveDirectorySettings : IActiveDirectorySettings - { - public ActiveDirectorySettings() - { - ActiveDirectoryDomain = ConfigurationManager.AppSettings["ActiveDirectoryDomain"]; - } - - public string ActiveDirectoryDomain { get; } - } -} diff --git a/src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs deleted file mode 100644 index 3ced2fab46..0000000000 --- a/src/Umbraco.Configuration/Legacy/CommaDelimitedConfigurationElement.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Configuration; - -namespace Umbraco.Core.Configuration -{ - /// - /// Defines a configuration section that contains inner text that is comma delimited - /// - internal class CommaDelimitedConfigurationElement : InnerTextConfigurationElement, IEnumerable - { - public override CommaDelimitedStringCollection Value - { - get - { - var converter = new CommaDelimitedStringCollectionConverter(); - return (CommaDelimitedStringCollection) converter.ConvertFrom(RawValue); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return new InnerEnumerator(Value.GetEnumerator()); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return new InnerEnumerator(Value.GetEnumerator()); - } - - /// - /// A wrapper for StringEnumerator since it doesn't explicitly implement IEnumerable - /// - private class InnerEnumerator : IEnumerator - { - private readonly StringEnumerator _stringEnumerator; - - public InnerEnumerator(StringEnumerator stringEnumerator) - { - _stringEnumerator = stringEnumerator; - } - - public bool MoveNext() - { - return _stringEnumerator.MoveNext(); - } - - public void Reset() - { - _stringEnumerator.Reset(); - } - - string IEnumerator.Current - { - get { return _stringEnumerator.Current; } - } - - public object Current - { - get { return _stringEnumerator.Current; } - } - - public void Dispose() - { - _stringEnumerator.DisposeIfDisposable(); - } - } - } -} diff --git a/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs b/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs deleted file mode 100644 index 0302a7ea31..0000000000 --- a/src/Umbraco.Configuration/Legacy/ConfigurationManagerConfigBase.cs +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index a02c351118..0000000000 --- a/src/Umbraco.Configuration/Legacy/ConnectionStrings.cs +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index 1c3f543bfe..0000000000 --- a/src/Umbraco.Configuration/Legacy/ContentSettings.cs +++ /dev/null @@ -1,22 +0,0 @@ -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/Legacy/CoreDebugSettings.cs b/src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs deleted file mode 100644 index 4902d4489f..0000000000 --- a/src/Umbraco.Configuration/Legacy/CoreDebugSettings.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Configuration; - -namespace Umbraco.Core.Configuration -{ - public class CoreDebugSettings : ICoreDebugSettings - { - public CoreDebugSettings() - { - var appSettings = ConfigurationManager.AppSettings; - LogUncompletedScopes = string.Equals("true", appSettings[Constants.AppSettings.Debug.LogUncompletedScopes], StringComparison.OrdinalIgnoreCase); - DumpOnTimeoutThreadAbort = string.Equals("true", appSettings[Constants.AppSettings.Debug.DumpOnTimeoutThreadAbort], StringComparison.OrdinalIgnoreCase); - } - - /// - public bool LogUncompletedScopes { get; } - - /// - public bool DumpOnTimeoutThreadAbort { get; } - } -} diff --git a/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs b/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs deleted file mode 100644 index 50e2207485..0000000000 --- a/src/Umbraco.Configuration/Legacy/ExceptionFilterSettings.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Configuration; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration.Legacy -{ - public class ExceptionFilterSettings : IExceptionFilterSettings - { - public ExceptionFilterSettings() - { - if (bool.TryParse(ConfigurationManager.AppSettings["Umbraco.Web.DisableModelBindingExceptionFilter"], - out var disabled)) - { - Disabled = disabled; - } - } - public bool Disabled { get; } - } -} diff --git a/src/Umbraco.Configuration/Legacy/GlobalSettings.cs b/src/Umbraco.Configuration/Legacy/GlobalSettings.cs deleted file mode 100644 index fabe95f5bd..0000000000 --- a/src/Umbraco.Configuration/Legacy/GlobalSettings.cs +++ /dev/null @@ -1,377 +0,0 @@ -using System; -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.Legacy -{ - // 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 - - /// - /// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information from web.config appsettings - /// - public class GlobalSettings : IGlobalSettings - { - - // TODO these should not be static - private static string _reservedPaths; - private static string _reservedUrls; - - //ensure the built on (non-changeable) reserved paths are there at all times - 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! - - /// - /// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config) - /// - private static void ResetInternal() - { - _reservedPaths = null; - _reservedUrls = null; - } - - /// - /// Resets settings that were set programmatically, to their initial values. - /// - /// To be used in unit tests. - internal static void Reset() - { - ResetInternal(); - } - - - public bool IsSmtpServerConfigured - { - get - { - var smtpSettings = SmtpSettings; - - if (smtpSettings is null) return false; - - if (!(smtpSettings.From is null)) return true; - if (!(smtpSettings.Host is null)) return true; - if (!(smtpSettings.PickupDirectoryLocation is null)) return true; - - return false; - } - } - - public ISmtpSettings SmtpSettings - { - get - { - var smtpSection = ConfigurationManager.GetSection("system.net/mailSettings/smtp") as ConfigurationSection; - if (smtpSection is null) return null; - - var result = new SmtpSettings(); - var from = smtpSection.ElementInformation.Properties["from"]; - if (@from != null - && @from.Value is string fromPropValue - && string.IsNullOrEmpty(fromPropValue) == false - && !string.Equals("noreply@example.com", fromPropValue, StringComparison.OrdinalIgnoreCase)) - { - result.From = fromPropValue; - } - - var specifiedPickupDirectorySection = ConfigurationManager.GetSection("system.net/mailSettings/smtp/specifiedPickupDirectory") as ConfigurationSection; - var pickupDirectoryLocation = specifiedPickupDirectorySection?.ElementInformation.Properties["pickupDirectoryLocation"]; - if (pickupDirectoryLocation != null - && pickupDirectoryLocation.Value is string pickupDirectoryLocationPropValue - && string.IsNullOrEmpty(pickupDirectoryLocationPropValue) == false) - { - result.PickupDirectoryLocation = pickupDirectoryLocationPropValue; - } - - // SmtpClient can magically read the section system.net/mailSettings/smtp/network, witch is always - // null if we use ConfigurationManager.GetSection. SmtpSection does not exist in .Net Standard - var smtpClient = new SmtpClient(); - - result.Host = smtpClient.Host; - result.Port = smtpClient.Port; - - return result; - - } - } - - /// - /// Gets the reserved urls from web.config. - /// - /// The reserved urls. - public string ReservedUrls - { - get - { - if (_reservedUrls != null) return _reservedUrls; - - var urls = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ReservedUrls) - ? ConfigurationManager.AppSettings[Constants.AppSettings.ReservedUrls] - : string.Empty; - - //ensure the built on (non-changeable) reserved paths are there at all times - _reservedUrls = StaticReservedUrls + urls; - return _reservedUrls; - } - internal set => _reservedUrls = value; - } - - /// - /// Gets the reserved paths from web.config - /// - /// The reserved paths. - public string ReservedPaths - { - get - { - if (_reservedPaths != null) return _reservedPaths; - - var reservedPaths = StaticReservedPaths; - var umbPath = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.UmbracoPath) && !ConfigurationManager.AppSettings[Constants.AppSettings.UmbracoPath].IsNullOrWhiteSpace() - ? ConfigurationManager.AppSettings[Constants.AppSettings.UmbracoPath] - : "~/umbraco"; - //always add the umbraco path to the list - reservedPaths += umbPath.EnsureEndsWith(','); - - var allPaths = ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ReservedPaths) - ? ConfigurationManager.AppSettings[Constants.AppSettings.ReservedPaths] - : string.Empty; - - _reservedPaths = reservedPaths + allPaths; - return _reservedPaths; - } - } - - - - - /// - /// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance. - /// - /// The configuration status. - public string ConfigurationStatus - { - get - { - return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ConfigurationStatus) - ? ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus] - : string.Empty; - } - set - { - SaveSetting(Constants.AppSettings.ConfigurationStatus, value, Current.IOHelper); //TODO remove - } - } - - /// - /// Saves a setting into the configuration file. - /// - /// Key of the setting to be saved. - /// Value of the setting to be saved. - internal static void SaveSetting(string key, string value, IIOHelper ioHelper) - { - var fileName = ioHelper.MapPath("~/web.config"); - var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); - - var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single(); - - // Update appSetting if it exists, or else create a new appSetting for the given key and value - var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key); - if (setting == null) - appSettings.Add(new XElement("add", new XAttribute("key", key), new XAttribute("value", value))); - else - setting.Attribute("value").Value = value; - - xml.Save(fileName, SaveOptions.DisableFormatting); - ConfigurationManager.RefreshSection("appSettings"); - } - - - /// - /// Gets the time out in minutes. - /// - /// The time out in minutes. - public int TimeOutInMinutes - { - get - { - try - { - return int.Parse(ConfigurationManager.AppSettings[Constants.AppSettings.TimeOutInMinutes]); - } - catch - { - return 20; - } - } - } - - /// - /// Returns the number of days that should take place between version checks. - /// - /// The version check period in days (0 = never). - public int VersionCheckPeriod - { - get - { - try - { - var val = ConfigurationManager.AppSettings[Constants.AppSettings.VersionCheckPeriod]; - if (!(val is null)) - { - return int.Parse(val); - } - } - catch - { - // Ignore - } - return 7; - } - } - - - - - /// - /// Gets the default UI language. - /// - /// The default UI language. - // ReSharper disable once InconsistentNaming - public string DefaultUILanguage - { - get - { - return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.DefaultUILanguage) - ? ConfigurationManager.AppSettings[Constants.AppSettings.DefaultUILanguage] - : string.Empty; - } - } - - /// - /// Gets a value indicating whether umbraco should hide top level nodes from generated urls. - /// - /// - /// true if umbraco hides top level nodes from urls; otherwise, false. - /// - public bool HideTopLevelNodeFromPath - { - get - { - try - { - return bool.Parse(ConfigurationManager.AppSettings[Constants.AppSettings.HideTopLevelNodeFromPath]); - } - catch - { - return false; - } - } - } - - /// - /// Gets a value indicating whether umbraco should force a secure (https) connection to the backoffice. - /// - public bool UseHttps - { - get - { - try - { - return bool.Parse(ConfigurationManager.AppSettings[Constants.AppSettings.UseHttps]); - } - catch - { - return false; - } - } - } - - private string _umbracoMediaPath = null; - public string UmbracoMediaPath => GetterWithDefaultValue(Constants.AppSettings.UmbracoMediaPath, "~/media", ref _umbracoMediaPath); - - private string _umbracoScriptsPath = null; - public string UmbracoScriptsPath => GetterWithDefaultValue(Constants.AppSettings.UmbracoScriptsPath, "~/scripts", ref _umbracoScriptsPath); - - private string _umbracoCssPath = null; - public string UmbracoCssPath => GetterWithDefaultValue(Constants.AppSettings.UmbracoCssPath, "~/css", ref _umbracoCssPath); - - private string _umbracoPath = null; - public string UmbracoPath => GetterWithDefaultValue(Constants.AppSettings.UmbracoPath, "~/umbraco", ref _umbracoPath); - - private bool _installMissingDatabase; - public bool InstallMissingDatabase => GetterWithDefaultValue("Umbraco.Core.RuntimeState.InstallMissingDatabase", false, ref _installMissingDatabase); - - private bool _installEmptyDatabase; - public bool InstallEmptyDatabase => GetterWithDefaultValue("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false, ref _installEmptyDatabase); - - private bool _disableElectionForSingleServer; - public bool DisableElectionForSingleServer => GetterWithDefaultValue(Constants.AppSettings.DisableElectionForSingleServer, false, ref _disableElectionForSingleServer); - - private string _registerType; - public string RegisterType => GetterWithDefaultValue(Constants.AppSettings.RegisterType, string.Empty, ref _registerType); - - private string _databaseFactoryServerVersion; - public string DatabaseFactoryServerVersion => GetterWithDefaultValue(Constants.AppSettings.Debug.DatabaseFactoryServerVersion, string.Empty, ref _databaseFactoryServerVersion); - - - - private string _iconsPath; - /// - /// Gets the path to folder containing the icons used in the umbraco backoffice (/umbraco/assets/icons by default). - /// - /// The icons path. - public string IconsPath => GetterWithDefaultValue(Constants.AppSettings.IconsPath, $"{UmbracoPath}/assets/icons", ref _iconsPath); - - private string _mainDomLock; - - public string MainDomLock => GetterWithDefaultValue(Constants.AppSettings.MainDomLock, string.Empty, ref _mainDomLock); - - private T GetterWithDefaultValue(string appSettingKey, T defaultValue, ref T backingField) - { - if (backingField != null) return backingField; - - if (ConfigurationManager.AppSettings.ContainsKey(appSettingKey)) - { - try - { - var value = ConfigurationManager.AppSettings[appSettingKey]; - - backingField = (T)Convert.ChangeType(value, typeof(T)); - } - catch - { - /* ignore and use default value */ - backingField = defaultValue; - } - } - else - { - backingField = defaultValue; - } - - 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 deleted file mode 100644 index 23385d1378..0000000000 --- a/src/Umbraco.Configuration/Legacy/HealthChecksSettings.cs +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index 1858e8a4a4..0000000000 --- a/src/Umbraco.Configuration/Legacy/HostingSettings.cs +++ /dev/null @@ -1,54 +0,0 @@ -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; - } - } - - public string ApplicationVirtualPath => null; - - /// - /// 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/Legacy/IndexCreatorSettings.cs b/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs deleted file mode 100644 index d023d46246..0000000000 --- a/src/Umbraco.Configuration/Legacy/IndexCreatorSettings.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Configuration; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration.Legacy -{ - public class IndexCreatorSettings : IIndexCreatorSettings - { - public IndexCreatorSettings() - { - LuceneDirectoryFactory = ConfigurationManager.AppSettings["Umbraco.Examine.LuceneDirectoryFactory"]; - } - - public string LuceneDirectoryFactory { get; } - } -} diff --git a/src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs deleted file mode 100644 index 6a125f2c1b..0000000000 --- a/src/Umbraco.Configuration/Legacy/InnerTextConfigurationElement.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Xml; -using System.Xml.Linq; - -namespace Umbraco.Core.Configuration -{ - /// - /// A full config section is required for any full element and we have some elements that are defined like this: - /// {element}MyValue{/element} instead of as attribute values. - /// - /// - internal class InnerTextConfigurationElement : RawXmlConfigurationElement - { - public InnerTextConfigurationElement() - { - } - - public InnerTextConfigurationElement(XElement rawXml) : base(rawXml) - { - } - - protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey) - { - base.DeserializeElement(reader, serializeCollectionKey); - //now validate and set the raw value - if (RawXml.HasElements) - throw new InvalidOperationException("An InnerTextConfigurationElement cannot contain any child elements, only attributes and a value"); - RawValue = RawXml.Value.Trim(); - - //RawValue = reader.ReadElementContentAsString(); - } - - public virtual T Value - { - get - { - var converted = RawValue.TryConvertTo(); - if (converted.Success == false) - throw new InvalidCastException("Could not convert value " + RawValue + " to type " + typeof(T)); - return converted.Result; - } - } - - /// - /// Exposes the raw string value - /// - internal string RawValue { get; set; } - - /// - /// Implicit operator so we don't need to use the 'Value' property explicitly - /// - /// - /// - public static implicit operator T(InnerTextConfigurationElement m) - { - return m.Value; - } - - /// - /// Return the string value of Value - /// - /// - public override string ToString() - { - return string.Format("{0}", Value); - } - - } -} diff --git a/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs b/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs deleted file mode 100644 index 0b8315d447..0000000000 --- a/src/Umbraco.Configuration/Legacy/KeepAliveSettings.cs +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index 020b0c0e64..0000000000 --- a/src/Umbraco.Configuration/Legacy/LoggingSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -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 deleted file mode 100644 index e42b02de73..0000000000 --- a/src/Umbraco.Configuration/Legacy/MemberPasswordConfigurationSettings.cs +++ /dev/null @@ -1,16 +0,0 @@ -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/Legacy/ModelsBuilderConfig.cs b/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs deleted file mode 100644 index f6395b23b4..0000000000 --- a/src/Umbraco.Configuration/Legacy/ModelsBuilderConfig.cs +++ /dev/null @@ -1,200 +0,0 @@ -using System; -using System.Configuration; -using System.IO; -using System.Threading; -using Umbraco.Core.Configuration; -using Umbraco.Core; -using Umbraco.Core.IO; - -namespace Umbraco.Configuration.Legacy -{ - /// - /// Represents the models builder configuration. - /// - public class ModelsBuilderConfig : IModelsBuilderConfig - { - - private const string Prefix = "Umbraco.ModelsBuilder."; - private object _modelsModelLock; - private bool _modelsModelConfigured; - private ModelsMode _modelsMode; - private object _flagOutOfDateModelsLock; - private bool _flagOutOfDateModelsConfigured; - private bool _flagOutOfDateModels; - - - public string DefaultModelsDirectory => "~/App_Data/Models"; - - /// - /// Initializes a new instance of the class. - /// - public ModelsBuilderConfig() - { - // giant kill switch, default: false - // must be explicitely set to true for anything else to happen - Enable = ConfigurationManager.AppSettings[Prefix + "Enable"] == "true"; - - // ensure defaults are initialized for tests - ModelsNamespace = Constants.ModelsBuilder.DefaultModelsNamespace; - ModelsDirectory = DefaultModelsDirectory; - DebugLevel = 0; - - // stop here, everything is false - if (!Enable) return; - - // default: false - AcceptUnsafeModelsDirectory = ConfigurationManager.AppSettings[Prefix + "AcceptUnsafeModelsDirectory"].InvariantEquals("true"); - - // default: true - EnableFactory = !ConfigurationManager.AppSettings[Prefix + "EnableFactory"].InvariantEquals("false"); - - // default: initialized above with DefaultModelsNamespace const - var value = ConfigurationManager.AppSettings[Prefix + "ModelsNamespace"]; - if (!string.IsNullOrWhiteSpace(value)) - ModelsNamespace = value; - - // default: initialized above with DefaultModelsDirectory const - value = ConfigurationManager.AppSettings[Prefix + "ModelsDirectory"]; - if (!string.IsNullOrWhiteSpace(value)) - { - // GetModelsDirectory will ensure that the path is safe - ModelsDirectory = value; - } - - // default: 0 - value = ConfigurationManager.AppSettings[Prefix + "DebugLevel"]; - if (!string.IsNullOrWhiteSpace(value)) - { - if (!int.TryParse(value, out var debugLevel)) - throw new ConfigurationErrorsException($"Invalid debug level \"{value}\"."); - DebugLevel = debugLevel; - } - - } - - /// - /// Initializes a new instance of the class. - /// - public ModelsBuilderConfig( - bool enable = false, - ModelsMode modelsMode = ModelsMode.Nothing, - string modelsNamespace = null, - bool enableFactory = true, - bool flagOutOfDateModels = true, - string modelsDirectory = null, - bool acceptUnsafeModelsDirectory = false, - int debugLevel = 0) - { - Enable = enable; - _modelsMode = modelsMode; - - ModelsNamespace = string.IsNullOrWhiteSpace(modelsNamespace) ? Constants.ModelsBuilder.DefaultModelsNamespace : modelsNamespace; - EnableFactory = enableFactory; - _flagOutOfDateModels = flagOutOfDateModels; - ModelsDirectory = string.IsNullOrWhiteSpace(modelsDirectory) ? DefaultModelsDirectory : modelsDirectory; - AcceptUnsafeModelsDirectory = acceptUnsafeModelsDirectory; - DebugLevel = debugLevel; - } - - - - /// - /// 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 { get; } - - /// - /// Gets the models mode. - /// - public ModelsMode ModelsMode => - LazyInitializer.EnsureInitialized(ref _modelsMode, ref _modelsModelConfigured, ref _modelsModelLock, () => - { - // mode - var modelsMode = ConfigurationManager.AppSettings[Prefix + "ModelsMode"]; - if (string.IsNullOrWhiteSpace(modelsMode)) return ModelsMode.Nothing; //default - switch (modelsMode) - { - case nameof(ModelsMode.Nothing): - return ModelsMode.Nothing; - case nameof(ModelsMode.PureLive): - return ModelsMode.PureLive; - case nameof(ModelsMode.AppData): - return ModelsMode.AppData; - case nameof(ModelsMode.LiveAppData): - return ModelsMode.LiveAppData; - default: - throw new ConfigurationErrorsException($"ModelsMode \"{modelsMode}\" is not a valid mode." + " Note that modes are case-sensitive. Possible values are: " + string.Join(", ", Enum.GetNames(typeof(ModelsMode)))); - } - }); - - /// - /// Gets a value indicating whether system.web/compilation/@debug is true. - /// - public bool IsDebug - { - get - { - if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection section && - bool.TryParse(section.ElementInformation.Properties["debug"].Value.ToString(), out var isDebug)) - { - return isDebug; - } - - return false; - } - } - - /// - /// 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 { get; } - - /// - /// 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 { get; } - - /// - /// 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 - => LazyInitializer.EnsureInitialized(ref _flagOutOfDateModels, ref _flagOutOfDateModelsConfigured, ref _flagOutOfDateModelsLock, () => - { - var flagOutOfDateModels = !ConfigurationManager.AppSettings[Prefix + "FlagOutOfDateModels"].InvariantEquals("false"); - if (ModelsMode == ModelsMode.Nothing || ModelsMode.IsLive()) - { - flagOutOfDateModels = false; - } - - return flagOutOfDateModels; - }); - - /// - /// Gets the models directory. - /// - /// Default is ~/App_Data/Models but that can be changed. - public string ModelsDirectory { get; } - - /// - /// 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 { get; } - - /// - /// 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 { get; } - } -} diff --git a/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs b/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs deleted file mode 100644 index 25f52a5c7d..0000000000 --- a/src/Umbraco.Configuration/Legacy/NuCacheSettings.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Configuration; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration.Legacy -{ - public class NuCacheSettings : INuCacheSettings - { - public NuCacheSettings() - { - BTreeBlockSize = ConfigurationManager.AppSettings["Umbraco.Web.PublishedCache.NuCache.BTree.BlockSize"]; - } - public string BTreeBlockSize { get; } - } -} diff --git a/src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs deleted file mode 100644 index 610067d2db..0000000000 --- a/src/Umbraco.Configuration/Legacy/OptionalCommaDelimitedConfigurationElement.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; - -namespace Umbraco.Core.Configuration -{ - /// - /// Used for specifying default values for comma delimited config - /// - internal class OptionalCommaDelimitedConfigurationElement : CommaDelimitedConfigurationElement - { - private readonly CommaDelimitedConfigurationElement _wrapped; - private readonly string[] _defaultValue; - - public OptionalCommaDelimitedConfigurationElement() - { - } - - public OptionalCommaDelimitedConfigurationElement(CommaDelimitedConfigurationElement wrapped, string[] defaultValue) - { - _wrapped = wrapped; - _defaultValue = defaultValue; - } - - public override CommaDelimitedStringCollection Value - { - get - { - if (_wrapped == null) - { - return base.Value; - } - - if (string.IsNullOrEmpty(_wrapped.RawValue)) - { - var val = new CommaDelimitedStringCollection(); - val.AddRange(_defaultValue); - return val; - } - return _wrapped.Value; - } - } - } -} diff --git a/src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs deleted file mode 100644 index b15e33019d..0000000000 --- a/src/Umbraco.Configuration/Legacy/OptionalInnerTextConfigurationElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - /// - /// This is used to supply optional/default values when using InnerTextConfigurationElement - /// - /// - internal class OptionalInnerTextConfigurationElement : InnerTextConfigurationElement - { - private readonly InnerTextConfigurationElement _wrapped; - private readonly T _defaultValue; - - public OptionalInnerTextConfigurationElement(InnerTextConfigurationElement wrapped, T defaultValue) - { - _wrapped = wrapped; - _defaultValue = defaultValue; - } - - public override T Value - { - get { return string.IsNullOrEmpty(_wrapped.RawValue) ? _defaultValue : _wrapped.Value; } - } - } -} diff --git a/src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs b/src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs deleted file mode 100644 index 5bc6ad3d32..0000000000 --- a/src/Umbraco.Configuration/Legacy/RawXmlConfigurationElement.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Configuration; -using System.Xml; -using System.Xml.Linq; - -namespace Umbraco.Core.Configuration -{ - /// - /// A configuration section that simply exposes the entire raw xml of the section itself which inheritors can use - /// to do with as they please. - /// - internal abstract class RawXmlConfigurationElement : ConfigurationElement - { - protected RawXmlConfigurationElement() - { - - } - - protected RawXmlConfigurationElement(XElement rawXml) - { - RawXml = rawXml; - } - - protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey) - { - RawXml = (XElement)XNode.ReadFrom(reader); - } - - protected XElement RawXml { get; private set; } - } -} diff --git a/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs b/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs deleted file mode 100644 index 1c54f4d475..0000000000 --- a/src/Umbraco.Configuration/Legacy/RequestHandlerSettings.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; - -namespace Umbraco.Configuration.Implementations -{ - internal class RequestHandlerSettings : ConfigurationManagerConfigBase, IRequestHandlerSettings - { - public bool AddTrailingSlash => UmbracoSettingsSection?.RequestHandler?.AddTrailingSlash ?? true; - public bool ConvertUrlsToAscii => UmbracoSettingsSection?.RequestHandler?.UrlReplacing?.ConvertUrlsToAscii.InvariantEquals("true") ?? false; - public bool TryConvertUrlsToAscii => UmbracoSettingsSection?.RequestHandler?.UrlReplacing?.ConvertUrlsToAscii.InvariantEquals("try") ?? false; - public IEnumerable CharCollection => UmbracoSettingsSection?.RequestHandler?.UrlReplacing?.CharCollection ?? Enumerable.Empty(); - } -} diff --git a/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs b/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs deleted file mode 100644 index 200642a819..0000000000 --- a/src/Umbraco.Configuration/Legacy/RuntimeSettings.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Configuration; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration.Legacy -{ - public class RuntimeSettings : IRuntimeSettings - { - public RuntimeSettings() - { - if (ConfigurationManager.GetSection("system.web/httpRuntime") is ConfigurationSection section) - { - var maxRequestLengthProperty = section.ElementInformation.Properties["maxRequestLength"]; - if (maxRequestLengthProperty != null && maxRequestLengthProperty.Value is int requestLength) - { - MaxRequestLength = requestLength; - } - - var maxQueryStringProperty = section.ElementInformation.Properties["maxQueryStringLength"]; - if (maxQueryStringProperty != null && maxQueryStringProperty.Value is int maxQueryStringLength) - { - MaxQueryStringLength = maxQueryStringLength; - } - } - } - public int? MaxQueryStringLength { get; } - public int? MaxRequestLength { get; } - - } -} diff --git a/src/Umbraco.Configuration/Legacy/SecuritySettings.cs b/src/Umbraco.Configuration/Legacy/SecuritySettings.cs deleted file mode 100644 index b7e39b0608..0000000000 --- a/src/Umbraco.Configuration/Legacy/SecuritySettings.cs +++ /dev/null @@ -1,14 +0,0 @@ -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/Legacy/TourSettings.cs b/src/Umbraco.Configuration/Legacy/TourSettings.cs deleted file mode 100644 index 134c3c48d5..0000000000 --- a/src/Umbraco.Configuration/Legacy/TourSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -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/Legacy/TypeFinderSettings.cs b/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs deleted file mode 100644 index b1009f754b..0000000000 --- a/src/Umbraco.Configuration/Legacy/TypeFinderSettings.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Configuration; -using Umbraco.Core; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration.Legacy -{ - public class TypeFinderSettings : ITypeFinderSettings - { - public TypeFinderSettings() - { - AssembliesAcceptingLoadExceptions = ConfigurationManager.AppSettings[ - Constants.AppSettings.AssembliesAcceptingLoadExceptions]; - } - - public string AssembliesAcceptingLoadExceptions { get; } - } -} diff --git a/src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs b/src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs deleted file mode 100644 index 8c0754b91d..0000000000 --- a/src/Umbraco.Configuration/Legacy/UmbracoConfigurationSection.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration -{ - /// - /// Represents an Umbraco section within the configuration file. - /// - /// - /// The requirement for these sections is to be read-only. - /// However for unit tests purposes it is internally possible to override some values, and - /// then calling >ResetSection should cancel these changes and bring the section back to - /// what it was originally. - /// The UmbracoSettings.For{T} method will return a section, either one that - /// is in the configuration file, or a section that was created with default values. - /// - public abstract class UmbracoConfigurationSection : ConfigurationSection, IUmbracoConfigurationSection - { - /// - /// Gets a value indicating whether the section actually is in the configuration file. - /// - protected bool IsPresent { get { return ElementInformation.IsPresent; } } - - } -} diff --git a/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs b/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs deleted file mode 100644 index 51dd645c42..0000000000 --- a/src/Umbraco.Configuration/Legacy/UserPasswordConfigurationSettings.cs +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index cfca66822b..0000000000 --- a/src/Umbraco.Configuration/Legacy/WebRoutingSettings.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Umbraco.Core.Configuration.UmbracoSettings; - -namespace Umbraco.Configuration.Implementations -{ - internal class WebRoutingSettings : ConfigurationManagerConfigBase, IWebRoutingSettings - { - public bool TrySkipIisCustomErrors => UmbracoSettingsSection?.WebRouting?.TrySkipIisCustomErrors ?? false; - public bool InternalRedirectPreservesTemplate => UmbracoSettingsSection?.WebRouting?.InternalRedirectPreservesTemplate ?? false; - public bool DisableAlternativeTemplates => UmbracoSettingsSection?.WebRouting?.DisableAlternativeTemplates ?? false; - public bool ValidateAlternativeTemplates => UmbracoSettingsSection?.WebRouting?.ValidateAlternativeTemplates ?? false; - public bool DisableFindContentByIdPath => UmbracoSettingsSection?.WebRouting?.DisableFindContentByIdPath ?? false; - public bool DisableRedirectUrlTracking => UmbracoSettingsSection?.WebRouting?.DisableRedirectUrlTracking ?? false; - public string UrlProviderMode => UmbracoSettingsSection?.WebRouting?.UrlProviderMode ?? "Auto"; - public string UmbracoApplicationUrl => UmbracoSettingsSection?.WebRouting?.UmbracoApplicationUrl; - } -} diff --git a/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs b/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs deleted file mode 100644 index 015fb17a8e..0000000000 --- a/src/Umbraco.Configuration/Models/ActiveDirectorySettings.cs +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 586765714c..0000000000 --- a/src/Umbraco.Configuration/Models/ConnectionStrings.cs +++ /dev/null @@ -1,69 +0,0 @@ -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 && !string.IsNullOrEmpty(server)) - { - if (builder.TryGetValue("Database", out var db) && db is string database && !string.IsNullOrEmpty(database)) - { - return Constants.DbProviderNames.SqlServer; - } - - if (builder.TryGetValue("AttachDbFileName", out var a) && a is string attachDbFileName && !string.IsNullOrEmpty(attachDbFileName)) - { - return Constants.DbProviderNames.SqlServer; - } - - if (builder.TryGetValue("Initial Catalog", out var i) && i is string initialCatalog && !string.IsNullOrEmpty(initialCatalog)) - { - 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 deleted file mode 100644 index 6c9b986dd1..0000000000 --- a/src/Umbraco.Configuration/Models/ContentSettings.cs +++ /dev/null @@ -1,119 +0,0 @@ -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 = Constants.Conventions.Media.File, - WidthFieldAlias = Constants.Conventions.Media.Width, - HeightFieldAlias =Constants.Conventions.Media.Height, - ExtensionFieldAlias =Constants.Conventions.Media.Extension, - LengthFieldAlias =Constants.Conventions.Media.Bytes, - } - }; - - 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", "assets/img/login.jpg"); - - 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 deleted file mode 100644 index 6d6c0eaf0d..0000000000 --- a/src/Umbraco.Configuration/Models/CoreDebugSettings.cs +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index 581daf9f40..0000000000 --- a/src/Umbraco.Configuration/Models/ExceptionFilterSettings.cs +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 02b73d1196..0000000000 --- a/src/Umbraco.Configuration/Models/GlobalSettings.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Linq; -using System.Net.Mail; -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.ConfigGlobalPrefix; - - 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); - - // 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 + "DefaultUILanguage", "en-US"); - - public bool HideTopLevelNodeFromPath => - _configuration.GetValue(Prefix + "HideTopLevelNodeFromPath", true); - - 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 IconsPath => _configuration.GetValue(Prefix + "IconsPath", $"{UmbracoPath}/assets/icons"); - - 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.ConfigGlobalPrefix + "Smtp")?.GetChildren().Any() ?? false; - - public ISmtpSettings SmtpSettings => - new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigGlobalPrefix + "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"); - public SmtpDeliveryMethod DeliveryMethod => _configurationSection.GetValue("DeliveryMethod"); - - public string Username => _configurationSection.GetValue("Username"); - - public string Password => _configurationSection.GetValue("Password"); - } - } -} diff --git a/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs b/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs deleted file mode 100644 index 1e3751b6aa..0000000000 --- a/src/Umbraco.Configuration/Models/HealthChecksSettingsSettings.cs +++ /dev/null @@ -1,105 +0,0 @@ -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), StringComparer.InvariantCultureIgnoreCase); - - 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), StringComparer.InvariantCultureIgnoreCase); - } - - 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 deleted file mode 100644 index f0fbcf4cab..0000000000 --- a/src/Umbraco.Configuration/Models/HostingSettings.cs +++ /dev/null @@ -1,29 +0,0 @@ -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); - - public string ApplicationVirtualPath => null; - - /// - /// 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 deleted file mode 100644 index 4a9501b2ba..0000000000 --- a/src/Umbraco.Configuration/Models/ImagingSettings.cs +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index b4bb000552..0000000000 --- a/src/Umbraco.Configuration/Models/IndexCreatorSettings.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 04194e1a3c..0000000000 --- a/src/Umbraco.Configuration/Models/KeepAliveSettings.cs +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index b05fe03875..0000000000 --- a/src/Umbraco.Configuration/Models/LoggingSettings.cs +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 5a8313a351..0000000000 --- a/src/Umbraco.Configuration/Models/MemberPasswordConfigurationSettings.cs +++ /dev/null @@ -1,38 +0,0 @@ -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", Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); // TODO: Need to change to current format when we do members - - public int MaxFailedAccessAttemptsBeforeLockout => - _configuration.GetValue(Prefix + "MaxFailedAccessAttemptsBeforeLockout", 5); - } -} diff --git a/src/Umbraco.Configuration/Models/NuCacheSettings.cs b/src/Umbraco.Configuration/Models/NuCacheSettings.cs deleted file mode 100644 index 51b8b1fe08..0000000000 --- a/src/Umbraco.Configuration/Models/NuCacheSettings.cs +++ /dev/null @@ -1,19 +0,0 @@ -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/RuntimeSettings.cs b/src/Umbraco.Configuration/Models/RuntimeSettings.cs deleted file mode 100644 index ef129030b6..0000000000 --- a/src/Umbraco.Configuration/Models/RuntimeSettings.cs +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 297c95b1af..0000000000 --- a/src/Umbraco.Configuration/Models/SecuritySettings.cs +++ /dev/null @@ -1,33 +0,0 @@ -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", false); - - 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 deleted file mode 100644 index 9fe1814ff5..0000000000 --- a/src/Umbraco.Configuration/Models/TourSettings.cs +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 8a1f7ac9e0..0000000000 --- a/src/Umbraco.Configuration/Models/TypeFinderSettings.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 25ce3e3d9a..0000000000 --- a/src/Umbraco.Configuration/Models/UserPasswordConfigurationSettings.cs +++ /dev/null @@ -1,36 +0,0 @@ -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", Constants.Security.AspNetCoreV3PasswordHashAlgorithmName); - - public int MaxFailedAccessAttemptsBeforeLockout => - _configuration.GetValue(Prefix + "MaxFailedAccessAttemptsBeforeLockout", 5); - } -} diff --git a/src/Umbraco.Configuration/Models/WebRoutingSettings.cs b/src/Umbraco.Configuration/Models/WebRoutingSettings.cs deleted file mode 100644 index 9ac856ca9f..0000000000 --- a/src/Umbraco.Configuration/Models/WebRoutingSettings.cs +++ /dev/null @@ -1,42 +0,0 @@ -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/Umbraco.Configuration.csproj b/src/Umbraco.Configuration/Umbraco.Configuration.csproj index a4dac22386..21a6dd83af 100644 --- a/src/Umbraco.Configuration/Umbraco.Configuration.csproj +++ b/src/Umbraco.Configuration/Umbraco.Configuration.csproj @@ -26,9 +26,9 @@ - - - + + + diff --git a/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs b/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs deleted file mode 100644 index 46b9bf32a9..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/BackOfficeElement.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class BackOfficeElement : UmbracoConfigurationElement, IBackOfficeSection - { - [ConfigurationProperty("tours")] - internal TourConfigElement Tours => (TourConfigElement)this["tours"]; - - ITourSettings IBackOfficeSection.Tours => Tours; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/CharCollection.cs b/src/Umbraco.Configuration/UmbracoSettings/CharCollection.cs deleted file mode 100644 index 7b62fcc123..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/CharCollection.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class CharCollection : ConfigurationElementCollection, IEnumerable - { - internal void Add(CharElement c) - { - BaseAdd(c); - } - - protected override ConfigurationElement CreateNewElement() - { - return new CharElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((CharElement)element).Char; - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return BaseGet(i) as IChar; - } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/CharElement.cs b/src/Umbraco.Configuration/UmbracoSettings/CharElement.cs deleted file mode 100644 index 1ff63ac017..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/CharElement.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class CharElement : InnerTextConfigurationElement, IChar - { - private string _char; - private string _replacement; - - internal string Char - { - get => _char ?? (_char = (string)RawXml.Attribute("org")); - set => _char = value; - } - - internal string Replacement - { - get => _replacement ?? (_replacement = Value); - set => _replacement = value; - } - - string IChar.Char => Char; - - string IChar.Replacement => Replacement; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs deleted file mode 100644 index 28b4314c9a..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/ContentElement.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; -using Umbraco.Core.Macros; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class ContentElement : UmbracoConfigurationElement, IContentSettings - { - private const string DefaultPreviewBadge = @"
Preview modeClick to end
"; - - [ConfigurationProperty("imaging")] - internal ContentImagingElement Imaging => (ContentImagingElement) this["imaging"]; - - [ConfigurationProperty("ResolveUrlsFromTextString")] - internal InnerTextConfigurationElement ResolveUrlsFromTextString => GetOptionalTextElement("ResolveUrlsFromTextString", false); - - public IEnumerable Error404Collection => Errors.Error404Collection; - - [ConfigurationProperty("errors", IsRequired = true)] - internal ContentErrorsElement Errors => (ContentErrorsElement) base["errors"]; - - [ConfigurationProperty("notifications", IsRequired = true)] - internal NotificationsElement Notifications => (NotificationsElement) base["notifications"]; - - [ConfigurationProperty("PreviewBadge")] - internal InnerTextConfigurationElement PreviewBadge => GetOptionalTextElement("PreviewBadge", DefaultPreviewBadge); - - [ConfigurationProperty("MacroErrors")] - internal InnerTextConfigurationElement MacroErrors => GetOptionalTextElement("MacroErrors", MacroErrorBehaviour.Inline); - - [ConfigurationProperty("disallowedUploadFiles")] - internal CommaDelimitedConfigurationElement DisallowedUploadFiles => GetOptionalDelimitedElement("disallowedUploadFiles", new[] {"ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd"}); - - [ConfigurationProperty("allowedUploadFiles")] - internal CommaDelimitedConfigurationElement AllowedUploadFiles => GetOptionalDelimitedElement("allowedUploadFiles", new string[0]); - - [ConfigurationProperty("showDeprecatedPropertyEditors")] - internal InnerTextConfigurationElement ShowDeprecatedPropertyEditors => GetOptionalTextElement("showDeprecatedPropertyEditors", false); - - [ConfigurationProperty("loginBackgroundImage")] - internal InnerTextConfigurationElement LoginBackgroundImage => GetOptionalTextElement("loginBackgroundImage", string.Empty); - - string IContentSettings.NotificationEmailAddress => Notifications.NotificationEmailAddress; - - bool IContentSettings.DisableHtmlEmail => Notifications.DisableHtmlEmail; - - IEnumerable IContentSettings.ImageFileTypes => Imaging.ImageFileTypes; - - IEnumerable IContentSettings.ImageAutoFillProperties => Imaging.ImageAutoFillProperties; - - bool IContentSettings.ResolveUrlsFromTextString => ResolveUrlsFromTextString; - - string IContentSettings.PreviewBadge => PreviewBadge; - - MacroErrorBehaviour IContentSettings.MacroErrorBehaviour => MacroErrors; - - IEnumerable IContentSettings.DisallowedUploadFiles => DisallowedUploadFiles; - - IEnumerable IContentSettings.AllowedUploadFiles => AllowedUploadFiles; - - bool IContentSettings.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors; - - string IContentSettings.LoginBackgroundImage => LoginBackgroundImage; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/ContentError404Collection.cs b/src/Umbraco.Configuration/UmbracoSettings/ContentError404Collection.cs deleted file mode 100644 index bdbcb27b4c..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/ContentError404Collection.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class ContentError404Collection : ConfigurationElementCollection, IEnumerable - { - internal void Add(ContentErrorPageElement element) - { - BaseAdd(element); - } - - protected override ConfigurationElement CreateNewElement() - { - return new ContentErrorPageElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((ContentErrorPageElement)element).Culture - + ((ContentErrorPageElement)element).Value; - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return BaseGet(i) as ContentErrorPageElement; - } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/ContentErrorPageElement.cs b/src/Umbraco.Configuration/UmbracoSettings/ContentErrorPageElement.cs deleted file mode 100644 index 96cea71a8e..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/ContentErrorPageElement.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Xml.Linq; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class ContentErrorPageElement : InnerTextConfigurationElement, IContentErrorPage - { - public ContentErrorPageElement(XElement rawXml) - : base(rawXml) - { - } - - public ContentErrorPageElement() - { - - } - - public bool HasContentId => ContentId != int.MinValue; - - public bool HasContentKey => ContentKey != Guid.Empty; - - public int ContentId - { - get - { - int parsed; - if (int.TryParse(Value, out parsed)) - { - return parsed; - } - return int.MinValue; - } - } - - public Guid ContentKey - { - get - { - Guid parsed; - if (Guid.TryParse(Value, out parsed)) - { - return parsed; - } - return Guid.Empty; - } - } - - public string ContentXPath => Value; - - public string Culture - { - get => (string) RawXml.Attribute("culture"); - set => RawXml.Attribute("culture").Value = value; - } - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/ContentErrorsElement.cs b/src/Umbraco.Configuration/UmbracoSettings/ContentErrorsElement.cs deleted file mode 100644 index 5b5b54380d..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/ContentErrorsElement.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class ContentErrorsElement : RawXmlConfigurationElement - { - - public IEnumerable Error404Collection - { - get - { - var result = new ContentError404Collection(); - if (RawXml != null) - { - var e404 = RawXml.Elements("error404").First(); - var ePages = e404.Elements("errorPage").ToArray(); - if (ePages.Any()) - { - //there are multiple - foreach (var e in ePages) - { - result.Add(new ContentErrorPageElement(e) - { - Culture = (string)e.Attribute("culture"), - RawValue = e.Value - }); - } - } - else - { - //there's only one defined - result.Add(new ContentErrorPageElement(e404) - { - RawValue = e404.Value - }); - } - } - return result; - } - } - - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/ContentImagingElement.cs b/src/Umbraco.Configuration/UmbracoSettings/ContentImagingElement.cs deleted file mode 100644 index 9a5a9b2a59..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/ContentImagingElement.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class ContentImagingElement : ConfigurationElement - { - - [ConfigurationProperty("imageFileTypes")] - internal CommaDelimitedConfigurationElement ImageFileTypes => - new OptionalCommaDelimitedConfigurationElement( - (CommaDelimitedConfigurationElement)this["imageFileTypes"], - //set the default - GetDefaultImageFileTypes()); - - public static string[] GetDefaultImageFileTypes() - { - return new[] {"jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif"}; - } - - private ImagingAutoFillPropertiesCollection _defaultImageAutoFill; - - [ConfigurationCollection(typeof(ImagingAutoFillPropertiesCollection), AddItemName = "uploadField")] - [ConfigurationProperty("autoFillImageProperties", IsDefaultCollection = true)] - internal ImagingAutoFillPropertiesCollection ImageAutoFillProperties - { - get - { - if (_defaultImageAutoFill != null) - { - return _defaultImageAutoFill; - } - - //here we need to check if this element is defined, if it is not then we'll setup the defaults - var prop = Properties["autoFillImageProperties"]; - var autoFill = this[prop] as ConfigurationElement; - if (autoFill != null && autoFill.ElementInformation.IsPresent == false) - { - _defaultImageAutoFill = new ImagingAutoFillPropertiesCollection - { - new ImagingAutoFillUploadFieldElement - { - Alias = "umbracoFile" - } - }; - return _defaultImageAutoFill; - } - - return (ImagingAutoFillPropertiesCollection) base["autoFillImageProperties"]; - } - } - - public static ImagingAutoFillPropertiesCollection GetDefaultImageAutoFillProperties() - { - return new ImagingAutoFillPropertiesCollection - { - new ImagingAutoFillUploadFieldElement - { - Alias = "umbracoFile" - } - }; - } - - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/ImagingAutoFillPropertiesCollection.cs b/src/Umbraco.Configuration/UmbracoSettings/ImagingAutoFillPropertiesCollection.cs deleted file mode 100644 index 0bac9721a3..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/ImagingAutoFillPropertiesCollection.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class ImagingAutoFillPropertiesCollection : ConfigurationElementCollection, IEnumerable - { - - protected override ConfigurationElement CreateNewElement() - { - return new ImagingAutoFillUploadFieldElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((ImagingAutoFillUploadFieldElement)element).Alias; - } - - internal void Add(ImagingAutoFillUploadFieldElement item) - { - BaseAdd(item); - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return BaseGet(i) as IImagingAutoFillUploadField; - } - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/ImagingAutoFillUploadFieldElement.cs b/src/Umbraco.Configuration/UmbracoSettings/ImagingAutoFillUploadFieldElement.cs deleted file mode 100644 index 9b4c45b5c6..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/ImagingAutoFillUploadFieldElement.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class ImagingAutoFillUploadFieldElement : UmbracoConfigurationElement, IImagingAutoFillUploadField - { - /// - /// Allow setting internally so we can create a default - /// - [ConfigurationProperty("alias", IsKey = true, IsRequired = true)] - public string Alias - { - get => (string)this["alias"]; - set => this["alias"] = value; - } - - [ConfigurationProperty("widthFieldAlias")] - internal InnerTextConfigurationElement WidthFieldAlias => GetOptionalTextElement("widthFieldAlias", "umbracoWidth"); - - [ConfigurationProperty("heightFieldAlias")] - internal InnerTextConfigurationElement HeightFieldAlias => GetOptionalTextElement("heightFieldAlias", "umbracoHeight"); - - [ConfigurationProperty("lengthFieldAlias")] - internal InnerTextConfigurationElement LengthFieldAlias => GetOptionalTextElement("lengthFieldAlias", "umbracoBytes"); - - [ConfigurationProperty("extensionFieldAlias")] - internal InnerTextConfigurationElement ExtensionFieldAlias => GetOptionalTextElement("extensionFieldAlias", "umbracoExtension"); - - string IImagingAutoFillUploadField.Alias => Alias; - - string IImagingAutoFillUploadField.WidthFieldAlias => WidthFieldAlias; - - string IImagingAutoFillUploadField.HeightFieldAlias => HeightFieldAlias; - - string IImagingAutoFillUploadField.LengthFieldAlias => LengthFieldAlias; - - string IImagingAutoFillUploadField.ExtensionFieldAlias => ExtensionFieldAlias; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs b/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs deleted file mode 100644 index 2297fb4e20..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/KeepAliveElement.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class KeepAliveElement : ConfigurationElement, IKeepAliveSettings - { - [ConfigurationProperty("disableKeepAliveTask", DefaultValue = "false")] - public bool DisableKeepAliveTask => (bool)base["disableKeepAliveTask"]; - - [ConfigurationProperty("keepAlivePingUrl", DefaultValue = "{umbracoApplicationUrl}/api/keepalive/ping")] - public string KeepAlivePingUrl => (string)base["keepAlivePingUrl"]; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs b/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs deleted file mode 100644 index 2fdd61e169..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/LoggingElement.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class LoggingElement : UmbracoConfigurationElement, ILoggingSettings - { - - [ConfigurationProperty("maxLogAge")] - internal InnerTextConfigurationElement MaxLogAge => GetOptionalTextElement("maxLogAge", -1); - - int ILoggingSettings.MaxLogAge => MaxLogAge; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs b/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs deleted file mode 100644 index 92cd112630..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/MemberPasswordConfigurationElement.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfiguration - { - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/NotificationsElement.cs b/src/Umbraco.Configuration/UmbracoSettings/NotificationsElement.cs deleted file mode 100644 index afadff5654..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/NotificationsElement.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class NotificationsElement : UmbracoConfigurationElement - { - [ConfigurationProperty("email")] - internal InnerTextConfigurationElement NotificationEmailAddress => (InnerTextConfigurationElement)this["email"]; - - [ConfigurationProperty("disableHtmlEmail")] - internal InnerTextConfigurationElement DisableHtmlEmail => GetOptionalTextElement("disableHtmlEmail", false); - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/PasswordConfigurationElement.cs b/src/Umbraco.Configuration/UmbracoSettings/PasswordConfigurationElement.cs deleted file mode 100644 index 91b5cae7a4..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/PasswordConfigurationElement.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class PasswordConfigurationElement : UmbracoConfigurationElement - { - [ConfigurationProperty("requiredLength", DefaultValue = "12")] - public int RequiredLength => (int)base["requiredLength"]; - - [ConfigurationProperty("requireNonLetterOrDigit", DefaultValue = "false")] - public bool RequireNonLetterOrDigit => (bool)base["requireNonLetterOrDigit"]; - - [ConfigurationProperty("requireDigit", DefaultValue = "false")] - public bool RequireDigit => (bool)base["requireDigit"]; - - [ConfigurationProperty("requireLowercase", DefaultValue = "false")] - public bool RequireLowercase => (bool)base["requireLowercase"]; - - [ConfigurationProperty("requireUppercase", DefaultValue = "false")] - public bool RequireUppercase => (bool)base["requireUppercase"]; - - [ConfigurationProperty("useLegacyEncoding", DefaultValue = "false")] - public bool UseLegacyEncoding => (bool)base["useLegacyEncoding"]; - - [ConfigurationProperty("hashAlgorithmType", DefaultValue = Constants.Security.AspNetCoreV3PasswordHashAlgorithmName)] - public string HashAlgorithmType => (string)base["hashAlgorithmType"]; - - [ConfigurationProperty("maxFailedAccessAttemptsBeforeLockout", DefaultValue = "5")] - public int MaxFailedAccessAttemptsBeforeLockout => (int)base["maxFailedAccessAttemptsBeforeLockout"]; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs b/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs deleted file mode 100644 index f959a56e71..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/RequestHandlerElement.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Configuration; -using System.Globalization; -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSettings - { - [ConfigurationProperty("addTrailingSlash")] - public InnerTextConfigurationElement AddTrailingSlash => GetOptionalTextElement("addTrailingSlash", true); - - private UrlReplacingElement _defaultUrlReplacing; - [ConfigurationProperty("urlReplacing")] - public UrlReplacingElement UrlReplacing - { - get - { - if (_defaultUrlReplacing != null) - { - return _defaultUrlReplacing; - } - - //here we need to check if this element is defined, if it is not then we'll setup the defaults - var prop = Properties["urlReplacing"]; - var urls = this[prop] as ConfigurationElement; - if (urls != null && urls.ElementInformation.IsPresent == false) - { - _defaultUrlReplacing = new UrlReplacingElement() - { - CharCollection = GetDefaultCharReplacements() - }; - - return _defaultUrlReplacing; - } - - return (UrlReplacingElement)this["urlReplacing"]; - } - } - - public static CharCollection GetDefaultCharReplacements() - { - var dictionary = new Dictionary() - { - {' ',"-"}, - {'\"',""}, - {'\'',""}, - {'%',""}, - {'.',""}, - {';',""}, - {'/',""}, - {'\\',""}, - {':',""}, - {'#',""}, - {'+',"plus"}, - {'*',"star"}, - {'&',""}, - {'?',""}, - {'æ',"ae"}, - {'ø',"oe"}, - {'å',"aa"}, - {'ä',"ae"}, - {'ö',"oe"}, - {'ü',"ue"}, - {'ß',"ss"}, - {'Ä',"ae"}, - {'Ö',"oe"}, - {'|',"-"}, - {'<',""}, - {'>',""} - }; - - //const string chars = @" ,"",',%,.,;,/,\,:,#,+,*,&,?,æ,ø,å,ä,ö,ü,ß,Ä,Ö,|,<,>"; - - var collection = new CharCollection(); - foreach (var c in dictionary) - { - collection.Add(new CharElement - { - Char = c.Key.ToString(CultureInfo.InvariantCulture), - Replacement = c.Value.ToString(CultureInfo.InvariantCulture) - }); - } - - return collection; - } - - bool IRequestHandlerSettings.AddTrailingSlash => AddTrailingSlash; - - bool IRequestHandlerSettings.ConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true"); - - bool IRequestHandlerSettings.TryConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try"); - - IEnumerable IRequestHandlerSettings.CharCollection => UrlReplacing.CharCollection; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs b/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs deleted file mode 100644 index aec6809298..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/SecurityElement.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class SecurityElement : UmbracoConfigurationElement, ISecuritySettings - { - [ConfigurationProperty("keepUserLoggedIn")] - internal InnerTextConfigurationElement KeepUserLoggedIn => GetOptionalTextElement("keepUserLoggedIn", true); - - [ConfigurationProperty("hideDisabledUsersInBackoffice")] - internal InnerTextConfigurationElement HideDisabledUsersInBackoffice => GetOptionalTextElement("hideDisabledUsersInBackoffice", false); - - /// - /// Used to enable/disable the forgot password functionality on the back office login screen - /// - [ConfigurationProperty("allowPasswordReset")] - internal InnerTextConfigurationElement AllowPasswordReset => GetOptionalTextElement("allowPasswordReset", true); - - /// - /// A boolean indicating that by default the email address will be the username - /// - /// - /// 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. - /// - [ConfigurationProperty("usernameIsEmail")] - internal InnerTextConfigurationElement UsernameIsEmail => GetOptionalTextElement("usernameIsEmail", true); - - [ConfigurationProperty("authCookieName")] - internal InnerTextConfigurationElement AuthCookieName => GetOptionalTextElement("authCookieName", "UMB_UCONTEXT"); - - [ConfigurationProperty("authCookieDomain")] - internal InnerTextConfigurationElement AuthCookieDomain => GetOptionalTextElement("authCookieDomain", null); - - [ConfigurationProperty("userPasswordConfiguration")] - public UserPasswordConfigurationElement UserPasswordConfiguration => (UserPasswordConfigurationElement)this["userPasswordConfiguration"]; - - [ConfigurationProperty("memberPasswordConfiguration")] - public MemberPasswordConfigurationElement MemberPasswordConfiguration => (MemberPasswordConfigurationElement)this["memberPasswordConfiguration"]; - - bool ISecuritySettings.KeepUserLoggedIn => KeepUserLoggedIn; - - bool ISecuritySettings.HideDisabledUsersInBackoffice => HideDisabledUsersInBackoffice; - - /// - /// Used to enable/disable the forgot password functionality on the back office login screen - /// - bool ISecuritySettings.AllowPasswordReset => AllowPasswordReset; - - /// - /// A boolean indicating that by default the email address will be the username - /// - /// - /// 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 ISecuritySettings.UsernameIsEmail => UsernameIsEmail; - - string ISecuritySettings.AuthCookieName => AuthCookieName; - - string ISecuritySettings.AuthCookieDomain => AuthCookieDomain; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs b/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs deleted file mode 100644 index f75b71fc57..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/TourConfigElement.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - 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 ? - [ConfigurationProperty("enable", DefaultValue = false)] - public bool EnableTours => (bool)this["enable"]; - - // TODO: We could have additional filters, etc... defined here - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/UmbracoConfigurationElement.cs b/src/Umbraco.Configuration/UmbracoSettings/UmbracoConfigurationElement.cs deleted file mode 100644 index 670f620b15..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/UmbracoConfigurationElement.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Concurrent; -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - /// - /// Base class with shared helper methods - /// - internal class UmbracoConfigurationElement : ConfigurationElement - { - /// - /// Used so the RawElement types are not re-created every time they are accessed - /// - private readonly ConcurrentDictionary _rawElements = new ConcurrentDictionary(); - - protected OptionalInnerTextConfigurationElement GetOptionalTextElement(string name, T defaultVal) - { - return (OptionalInnerTextConfigurationElement) _rawElements.GetOrAdd( - name, - s => new OptionalInnerTextConfigurationElement( - (InnerTextConfigurationElement) this[s], - //set the default - defaultVal)); - } - - protected OptionalCommaDelimitedConfigurationElement GetOptionalDelimitedElement(string name, string[] defaultVal) - { - return (OptionalCommaDelimitedConfigurationElement) _rawElements.GetOrAdd( - name, - s => new OptionalCommaDelimitedConfigurationElement( - (CommaDelimitedConfigurationElement) this[name], - //set the default - defaultVal)); - } - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs b/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs deleted file mode 100644 index 781d00b979..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsSection.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class UmbracoSettingsSection : ConfigurationSection - { - [ConfigurationProperty("backOffice")] - public BackOfficeElement BackOffice => (BackOfficeElement)this["backOffice"]; - - [ConfigurationProperty("content")] - public ContentElement Content => (ContentElement)this["content"]; - - [ConfigurationProperty("security")] - public SecurityElement Security => (SecurityElement)this["security"]; - - [ConfigurationProperty("requestHandler")] - public RequestHandlerElement RequestHandler => (RequestHandlerElement)this["requestHandler"]; - - [ConfigurationProperty("logging")] - public LoggingElement Logging => (LoggingElement)this["logging"]; - - [ConfigurationProperty("web.routing")] - public WebRoutingElement WebRouting => (WebRoutingElement)this["web.routing"]; - - [ConfigurationProperty("keepAlive")] - internal KeepAliveElement KeepAlive => (KeepAliveElement)this["keepAlive"]; - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/UrlReplacingElement.cs b/src/Umbraco.Configuration/UmbracoSettings/UrlReplacingElement.cs deleted file mode 100644 index 3e12d106ff..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/UrlReplacingElement.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class UrlReplacingElement : ConfigurationElement - { - [ConfigurationProperty("removeDoubleDashes", DefaultValue = true)] - internal bool RemoveDoubleDashes => (bool) base["removeDoubleDashes"]; - - [ConfigurationProperty("toAscii", DefaultValue = "false")] - internal string ConvertUrlsToAscii => (string) base["toAscii"]; - - [ConfigurationCollection(typeof(CharCollection), AddItemName = "char")] - [ConfigurationProperty("", IsDefaultCollection = true)] - internal CharCollection CharCollection - { - get => (CharCollection)base[""]; - set => base[""] = value; - } - - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs b/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs deleted file mode 100644 index a1d2aa8842..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/UserPasswordConfigurationElement.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfiguration - { - } -} diff --git a/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs b/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs deleted file mode 100644 index 206fc213d2..0000000000 --- a/src/Umbraco.Configuration/UmbracoSettings/WebRoutingElement.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - internal class WebRoutingElement : ConfigurationElement, IWebRoutingSettings - { - [ConfigurationProperty("trySkipIisCustomErrors", DefaultValue = "false")] - public bool TrySkipIisCustomErrors => (bool) base["trySkipIisCustomErrors"]; - - [ConfigurationProperty("internalRedirectPreservesTemplate", DefaultValue = "false")] - public bool InternalRedirectPreservesTemplate => (bool) base["internalRedirectPreservesTemplate"]; - - [ConfigurationProperty("disableAlternativeTemplates", DefaultValue = "false")] - public bool DisableAlternativeTemplates => (bool) base["disableAlternativeTemplates"]; - - [ConfigurationProperty("validateAlternativeTemplates", DefaultValue = "false")] - public bool ValidateAlternativeTemplates => (bool) base["validateAlternativeTemplates"]; - - [ConfigurationProperty("disableFindContentByIdPath", DefaultValue = "false")] - public bool DisableFindContentByIdPath => (bool) base["disableFindContentByIdPath"]; - - [ConfigurationProperty("disableRedirectUrlTracking", DefaultValue = "false")] - public bool DisableRedirectUrlTracking => (bool) base["disableRedirectUrlTracking"]; - - [ConfigurationProperty("urlProviderMode", DefaultValue = "Auto")] - public string UrlProviderMode => (string) base["urlProviderMode"]; - - [ConfigurationProperty("umbracoApplicationUrl", DefaultValue = null)] - public string UmbracoApplicationUrl => (string)base["umbracoApplicationUrl"]; - } -} diff --git a/src/Umbraco.Core/BackOffice/BackOfficeIdentityUser.cs b/src/Umbraco.Core/BackOffice/BackOfficeIdentityUser.cs index 8df253b296..bd04b44b18 100644 --- a/src/Umbraco.Core/BackOffice/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/BackOffice/BackOfficeIdentityUser.cs @@ -5,6 +5,7 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Linq; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Identity; using Umbraco.Core.Models.Membership; @@ -39,7 +40,7 @@ namespace Umbraco.Core.BackOffice /// This is allowed to be null (but would need to be filled in if trying to persist this instance) /// /// - public static BackOfficeIdentityUser CreateNew(IGlobalSettings globalSettings, string username, string email, string culture) + public static BackOfficeIdentityUser CreateNew(GlobalSettings globalSettings, string username, string email, string culture) { if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(username)); if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(culture)); @@ -57,7 +58,7 @@ namespace Umbraco.Core.BackOffice return user; } - private BackOfficeIdentityUser(IGlobalSettings globalSettings, IReadOnlyUserGroup[] groups) + private BackOfficeIdentityUser(GlobalSettings globalSettings, IReadOnlyUserGroup[] groups) { _startMediaIds = Array.Empty(); _startContentIds = Array.Empty(); @@ -78,7 +79,7 @@ namespace Umbraco.Core.BackOffice /// /// /// - public BackOfficeIdentityUser(IGlobalSettings globalSettings, int userId, IEnumerable groups) + public BackOfficeIdentityUser(GlobalSettings globalSettings, int userId, IEnumerable groups) : this(globalSettings, groups.ToArray()) { // use the property setters - they do more than just setting a field diff --git a/src/Umbraco.Core/BackOffice/IdentityMapDefinition.cs b/src/Umbraco.Core/BackOffice/IdentityMapDefinition.cs index e8d16a7903..61fdf82d19 100644 --- a/src/Umbraco.Core/BackOffice/IdentityMapDefinition.cs +++ b/src/Umbraco.Core/BackOffice/IdentityMapDefinition.cs @@ -1,5 +1,7 @@ using System; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -11,13 +13,13 @@ namespace Umbraco.Core.BackOffice { private readonly ILocalizedTextService _textService; private readonly IEntityService _entityService; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public IdentityMapDefinition(ILocalizedTextService textService, IEntityService entityService, IGlobalSettings globalSettings) + public IdentityMapDefinition(ILocalizedTextService textService, IEntityService entityService, IOptions globalSettings) { _textService = textService; _entityService = entityService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } public void DefineMaps(UmbracoMapper mapper) diff --git a/src/Umbraco.Core/Composing/Composition.cs b/src/Umbraco.Core/Composing/Composition.cs index f6e8655575..998f42a2dc 100644 --- a/src/Umbraco.Core/Composing/Composition.cs +++ b/src/Umbraco.Core/Composing/Composition.cs @@ -21,7 +21,6 @@ namespace Umbraco.Core.Composing private readonly Dictionary> _uniques = new Dictionary>(); private readonly IRegister _register; - /// /// Initializes a new instance of the class. /// @@ -32,13 +31,12 @@ namespace Umbraco.Core.Composing /// Optional configs. /// An IOHelper /// - public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, Configs configs, IIOHelper ioHelper, AppCaches appCaches) + public Composition(IRegister register, TypeLoader typeLoader, IProfilingLogger logger, IRuntimeState runtimeState, IIOHelper 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)); } @@ -63,11 +61,6 @@ namespace Umbraco.Core.Composing /// public IRuntimeState RuntimeState { get; } - /// - /// Gets the configurations. - /// - public Configs Configs { get; } - #endregion #region IRegister @@ -136,8 +129,6 @@ namespace Umbraco.Core.Composing IFactory factory = null; - Configs.RegisterWith(_register); - // ReSharper disable once AccessToModifiedClosure -- on purpose _register.Register(_ => factory, Lifetime.Singleton); factory = _register.CreateFactory(); diff --git a/src/Umbraco.Core/Composing/Current.cs b/src/Umbraco.Core/Composing/Current.cs index 055a29228a..856be9f414 100644 --- a/src/Umbraco.Core/Composing/Current.cs +++ b/src/Umbraco.Core/Composing/Current.cs @@ -1,7 +1,9 @@ using System; using System.Runtime.CompilerServices; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -11,18 +13,21 @@ namespace Umbraco.Composing public static class Current { private static ILogger _logger = new NullLogger(); - private static Configs _configs; private static IIOHelper _ioHelper; private static IHostingEnvironment _hostingEnvironment; private static IBackOfficeInfo _backOfficeInfo; private static IProfiler _profiler; + private static SecuritySettings _securitySettings; + private static GlobalSettings _globalSettings; public static ILogger Logger => EnsureInitialized(_logger); - public static Configs Configs => EnsureInitialized(_configs); + public static IIOHelper IOHelper => EnsureInitialized(_ioHelper); public static IHostingEnvironment HostingEnvironment => EnsureInitialized(_hostingEnvironment); public static IBackOfficeInfo BackOfficeInfo => EnsureInitialized(_backOfficeInfo); public static IProfiler Profiler => EnsureInitialized(_profiler); + public static SecuritySettings SecuritySettings => EnsureInitialized(_securitySettings); + public static GlobalSettings GlobalSettings => EnsureInitialized(_globalSettings); public static bool IsInitialized { get; internal set; } @@ -37,7 +42,8 @@ namespace Umbraco.Composing public static void Initialize( ILogger logger, - Configs configs, + SecuritySettings securitySettings, + GlobalSettings globalSettings, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, @@ -49,13 +55,15 @@ namespace Umbraco.Composing } _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _configs = configs ?? throw new ArgumentNullException(nameof(configs)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); _backOfficeInfo = backOfficeInfo ?? throw new ArgumentNullException(nameof(backOfficeInfo)); _profiler = profiler ?? throw new ArgumentNullException(nameof(profiler)); + _securitySettings = securitySettings ?? throw new ArgumentNullException(nameof(securitySettings)); + _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); IsInitialized = true; } + } } diff --git a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs index c5d87abf91..3e0ea9c971 100644 --- a/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs +++ b/src/Umbraco.Core/Composing/DefaultUmbracoAssemblyProvider.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Composing "Umbraco.Core", "Umbraco.Infrastructure", "Umbraco.PublishedCache.NuCache", - // "Umbraco.ModelsBuilder.Embedded", TODO reintroduce when ModelsBuilder is migrated + "Umbraco.ModelsBuilder.Embedded", "Umbraco.Examine.Lucene", "Umbraco.Web.Common", "Umbraco.Web.BackOffice", diff --git a/src/Umbraco.Core/Composing/TypeFinder.cs b/src/Umbraco.Core/Composing/TypeFinder.cs index 13c5e063be..3427c55731 100644 --- a/src/Umbraco.Core/Composing/TypeFinder.cs +++ b/src/Umbraco.Core/Composing/TypeFinder.cs @@ -156,6 +156,7 @@ namespace Umbraco.Core.Composing "MiniProfiler.", "Owin,", "SQLite", + "ReSharperTestRunner32" // used by resharper testrunner }; /// diff --git a/src/Umbraco.Core/Composing/TypeFinderConfig.cs b/src/Umbraco.Core/Composing/TypeFinderConfig.cs index 9a3cd7072c..302d45b4e8 100644 --- a/src/Umbraco.Core/Composing/TypeFinderConfig.cs +++ b/src/Umbraco.Core/Composing/TypeFinderConfig.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; namespace Umbraco.Core.Composing @@ -11,12 +12,12 @@ namespace Umbraco.Core.Composing /// public class TypeFinderConfig : ITypeFinderConfig { - private readonly ITypeFinderSettings _settings; + private readonly TypeFinderSettings _settings; private IEnumerable _assembliesAcceptingLoadExceptions; - public TypeFinderConfig(ITypeFinderSettings settings) + public TypeFinderConfig(IOptionsMonitor settings) { - _settings = settings; + _settings = settings.CurrentValue; } public IEnumerable AssembliesAcceptingLoadExceptions diff --git a/src/Umbraco.Core/ConfigConnectionStringExtensions.cs b/src/Umbraco.Core/ConfigConnectionStringExtensions.cs index 693b8a433e..8047af88c5 100644 --- a/src/Umbraco.Core/ConfigConnectionStringExtensions.cs +++ b/src/Umbraco.Core/ConfigConnectionStringExtensions.cs @@ -5,7 +5,6 @@ using Umbraco.Core.Configuration; namespace Umbraco.Core { - public static class ConfigConnectionStringExtensions { public static bool IsConnectionStringConfigured(this ConfigConnectionString databaseSettings) diff --git a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs index e9ac944b85..3a540aa3e2 100644 --- a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs +++ b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs @@ -1,16 +1,61 @@ +using System; +using System.Data.Common; + namespace Umbraco.Core.Configuration { public class ConfigConnectionString { - public ConfigConnectionString(string connectionString, string providerName, string name) + public ConfigConnectionString(string name, string connectionString, string providerName = null) { + Name = name ?? throw new ArgumentNullException(nameof(name)); ConnectionString = connectionString; - ProviderName = providerName; - Name = name; + + ProviderName = string.IsNullOrEmpty(providerName) ? ParseProvider(connectionString) : providerName; } public string ConnectionString { get; } public string ProviderName { get; } public string Name { get; } + + private string ParseProvider(string connectionString) + { + if (string.IsNullOrEmpty(connectionString)) + { + return null; + } + + var builder = new DbConnectionStringBuilder + { + 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 && !string.IsNullOrEmpty(server)) + { + if (builder.TryGetValue("Database", out var db) && db is string database && !string.IsNullOrEmpty(database)) + { + return Constants.DbProviderNames.SqlServer; + } + + if (builder.TryGetValue("AttachDbFileName", out var a) && a is string attachDbFileName && !string.IsNullOrEmpty(attachDbFileName)) + { + return Constants.DbProviderNames.SqlServer; + } + + if (builder.TryGetValue("Initial Catalog", out var i) && i is string initialCatalog && !string.IsNullOrEmpty(initialCatalog)) + { + return Constants.DbProviderNames.SqlServer; + } + } + + throw new ArgumentException("Cannot determine provider name from connection string", nameof(connectionString)); + } } } diff --git a/src/Umbraco.Core/Configuration/Configs.cs b/src/Umbraco.Core/Configuration/Configs.cs deleted file mode 100644 index 821ee308f0..0000000000 --- a/src/Umbraco.Core/Configuration/Configs.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Core.Composing; - -namespace Umbraco.Core.Configuration -{ - /// - /// Represents Umbraco configurations. - /// - /// - /// During composition, use composition.Configs. When running, either inject the required configuration, - /// or use Current.Configs. - /// - public class Configs - { - private readonly Dictionary> _configs = new Dictionary>(); - private Dictionary> _registerings = new Dictionary>(); - - /// - /// Gets a configuration. - /// - public TConfig GetConfig() - where TConfig : class - { - if (!_configs.TryGetValue(typeof(TConfig), out var configFactory)) - throw new InvalidOperationException($"No configuration of type {typeof(TConfig)} has been added."); - - return (TConfig) configFactory.Value; - } - - /// - /// 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); - - var lazyConfigFactory = _configs[typeOfConfig] = new Lazy(configFactory); - _registerings[typeOfConfig] = register => register.Register(_ => (TConfig) lazyConfigFactory.Value, Lifetime.Singleton); - } - - /// - /// Registers configurations in a register. - /// - public void RegisterWith(IRegister register) - { - // do it only once - if (_registerings == null) - throw new InvalidOperationException("Configurations have already been registered."); - - register.Register(this); - - foreach (var registering in _registerings.Values) - registering(register); - - // no need to keep them around - _registerings = null; - } - } -} diff --git a/src/Umbraco.Core/Configuration/ConfigsExtensions.cs b/src/Umbraco.Core/Configuration/ConfigsExtensions.cs deleted file mode 100644 index a4bdb5c55f..0000000000 --- a/src/Umbraco.Core/Configuration/ConfigsExtensions.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Grid; -using Umbraco.Core.Configuration.HealthChecks; -using Umbraco.Core.Configuration.UmbracoSettings; - -namespace Umbraco.Core -{ - /// - /// Provides extension methods for the class. - /// - public static class ConfigsExtensions - { - - public static IImagingSettings Imaging(this Configs configs) - => configs.GetConfig(); - public static IGlobalSettings Global(this Configs configs) - => configs.GetConfig(); - - public static IHostingSettings Hosting(this Configs configs) - => configs.GetConfig(); - - public static IConnectionStrings ConnectionStrings(this Configs configs) - => configs.GetConfig(); - - public static IContentSettings Content(this Configs configs) - => configs.GetConfig(); - - public static ISecuritySettings Security(this Configs configs) - => configs.GetConfig(); - - public static ITypeFinderSettings TypeFinder(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 IRequestHandlerSettings RequestHandler(this Configs configs) - => configs.GetConfig(); - - 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(); - - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs b/src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs similarity index 74% rename from src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs rename to src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs index d100eb0a74..21ebe55f2f 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs +++ b/src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs @@ -1,9 +1,11 @@ using System; using System.Linq; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.UmbracoSettings; -namespace Umbraco.Core.Configuration.UmbracoSettings +namespace Umbraco.Core.Configuration { - public static class ContentSectionExtensions + public static class ContentSettingsExtensions { /// /// Gets a value indicating whether the file extension corresponds to an image. @@ -11,12 +13,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings /// The file extension. /// /// A value indicating whether the file extension corresponds to an image. - public static bool IsImageFile(this IContentSettings contentConfig, string extension) + public static bool IsImageFile(this ContentSettings contentConfig, string extension) { if (contentConfig == null) throw new ArgumentNullException(nameof(contentConfig)); if (extension == null) return false; extension = extension.TrimStart('.'); - return contentConfig.ImageFileTypes.InvariantContains(extension); + return contentConfig.Imaging.ImageFileTypes.InvariantContains(extension); } /// @@ -24,7 +26,7 @@ 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 IContentSettings contentSettings, string extension) + public static bool IsFileAllowedForUpload(this ContentSettings contentSettings, string extension) { return contentSettings.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) || (contentSettings.AllowedUploadFiles.Any() == false && @@ -37,9 +39,9 @@ namespace Umbraco.Core.Configuration.UmbracoSettings /// /// The property type alias. /// The auto-fill configuration for the specified property alias, or null. - public static IImagingAutoFillUploadField GetConfig(this IContentSettings contentSettings, string propertyTypeAlias) + public static IImagingAutoFillUploadField GetConfig(this ContentSettings contentSettings, string propertyTypeAlias) { - var autoFillConfigs = contentSettings.ImageAutoFillProperties; + var autoFillConfigs = contentSettings.Imaging.AutoFillImageProperties; return autoFillConfigs?.FirstOrDefault(x => x.Alias == propertyTypeAlias); } } diff --git a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs b/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs index a9a7f578d0..f9b2362e14 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs @@ -1,4 +1,5 @@ using System; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; namespace Umbraco.Core.Configuration @@ -14,7 +15,7 @@ namespace Umbraco.Core.Configuration /// /// /// - public static string GetBackOfficePath(this IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + public static string GetBackOfficePath(this GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { if (_backOfficePath != null) return _backOfficePath; _backOfficePath = hostingEnvironment.ToAbsolute(globalSettings.UmbracoPath); @@ -32,7 +33,7 @@ namespace Umbraco.Core.Configuration /// 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, IHostingEnvironment hostingEnvironment) + public static string GetUmbracoMvcArea(this GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { if (_mvcArea != null) return _mvcArea; @@ -41,7 +42,7 @@ namespace Umbraco.Core.Configuration return _mvcArea; } - internal static string GetUmbracoMvcAreaNoCache(this IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + internal static string GetUmbracoMvcAreaNoCache(this GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { var path = string.IsNullOrEmpty(globalSettings.UmbracoPath) ? string.Empty diff --git a/src/Umbraco.Core/Configuration/HealthChecks/DisabledHealthCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/DisabledHealthCheck.cs new file mode 100644 index 0000000000..c962014bd5 --- /dev/null +++ b/src/Umbraco.Core/Configuration/HealthChecks/DisabledHealthCheck.cs @@ -0,0 +1,11 @@ +using System; + +namespace Umbraco.Core.Configuration.HealthChecks +{ + public class DisabledHealthCheck + { + public Guid Id { get; set; } + public DateTime DisabledOn { get; set; } + public int DisabledBy { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/HealthChecks/IDisabledHealthCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/IDisabledHealthCheck.cs deleted file mode 100644 index 4ea63048f8..0000000000 --- a/src/Umbraco.Core/Configuration/HealthChecks/IDisabledHealthCheck.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - public interface IDisabledHealthCheck - { - Guid Id { get; } - DateTime DisabledOn { get; } - int DisabledBy { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/HealthChecks/IHealthCheckNotificationSettings.cs b/src/Umbraco.Core/Configuration/HealthChecks/IHealthCheckNotificationSettings.cs deleted file mode 100644 index 4564e87ed6..0000000000 --- a/src/Umbraco.Core/Configuration/HealthChecks/IHealthCheckNotificationSettings.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - public interface IHealthCheckNotificationSettings - { - bool Enabled { get; } - string FirstRunTime { get; } - int PeriodInHours { get; } - IReadOnlyDictionary NotificationMethods { get; } - IEnumerable DisabledChecks { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs b/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs deleted file mode 100644 index 785e8d5651..0000000000 --- a/src/Umbraco.Core/Configuration/HealthChecks/IHealthChecksSettings.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.HealthChecks -{ - public interface IHealthChecksSettings - { - IEnumerable DisabledChecks { get; } - IHealthCheckNotificationSettings NotificationSettings { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/IActiveDirectorySettings.cs b/src/Umbraco.Core/Configuration/IActiveDirectorySettings.cs deleted file mode 100644 index e6b9202c06..0000000000 --- a/src/Umbraco.Core/Configuration/IActiveDirectorySettings.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface IActiveDirectorySettings - { - string ActiveDirectoryDomain { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/IConfigManipulator.cs b/src/Umbraco.Core/Configuration/IConfigManipulator.cs index 1d9230be44..bc89b7bd1d 100644 --- a/src/Umbraco.Core/Configuration/IConfigManipulator.cs +++ b/src/Umbraco.Core/Configuration/IConfigManipulator.cs @@ -7,5 +7,6 @@ namespace Umbraco.Core.Configuration void RemoveConnectionString(); void SaveConnectionString(string connectionString, string providerName); void SaveConfigValue(string itemPath, object value); + void SaveDisableRedirectUrlTracking(bool disable); } } diff --git a/src/Umbraco.Core/Configuration/IConfigsFactory.cs b/src/Umbraco.Core/Configuration/IConfigsFactory.cs deleted file mode 100644 index dd2459b88c..0000000000 --- a/src/Umbraco.Core/Configuration/IConfigsFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Umbraco.Core.IO; -using Umbraco.Core.Logging; - -namespace Umbraco.Core.Configuration -{ - public interface IConfigsFactory - { - Configs Create(); - } -} diff --git a/src/Umbraco.Core/Configuration/IConnectionStrings.cs b/src/Umbraco.Core/Configuration/IConnectionStrings.cs deleted file mode 100644 index 0d33378669..0000000000 --- a/src/Umbraco.Core/Configuration/IConnectionStrings.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface IConnectionStrings - { - ConfigConnectionString this[string key] - { - get; - } - } -} diff --git a/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs b/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs deleted file mode 100644 index 586e4bc3e4..0000000000 --- a/src/Umbraco.Core/Configuration/ICoreDebugSettings.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface ICoreDebugSettings - { - /// - /// When set to true, Scope logs the stack trace for any scope that gets disposed without being completed. - /// this helps troubleshooting rogue scopes that we forget to complete - /// - bool LogUncompletedScopes { get; } - - /// - /// When set to true, the Logger creates a mini dump of w3wp in ~/App_Data/MiniDump whenever it logs - /// an error due to a ThreadAbortException that is due to a timeout. - /// - bool DumpOnTimeoutThreadAbort { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/IExceptionFilterSettings.cs b/src/Umbraco.Core/Configuration/IExceptionFilterSettings.cs deleted file mode 100644 index 169c04da5f..0000000000 --- a/src/Umbraco.Core/Configuration/IExceptionFilterSettings.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface IExceptionFilterSettings - { - bool Disabled { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/IGlobalSettings.cs b/src/Umbraco.Core/Configuration/IGlobalSettings.cs deleted file mode 100644 index 26d833613f..0000000000 --- a/src/Umbraco.Core/Configuration/IGlobalSettings.cs +++ /dev/null @@ -1,108 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - /// - /// Contains general settings information for the entire Umbraco instance based on information from web.config appsettings - /// - public interface IGlobalSettings - { - // fixme: Review this class, it is now just a dumping ground for config options (based basically on whatever might be in appSettings), - // our config classes should be named according to what they are configuring. - - /// - /// Gets the reserved urls from web.config. - /// - /// The reserved urls. - string ReservedUrls { get; } - - /// - /// Gets the reserved paths from web.config - /// - /// The reserved paths. - string ReservedPaths { get; } - - /// - /// Gets the path to umbraco's icons directory (/umbraco/assets/icons by default). - /// - string IconsPath { get; } - - /// - /// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance. - /// - string ConfigurationStatus { get; set; } - - /// - /// Gets the time out in minutes. - /// - int TimeOutInMinutes { get; } - - /// - /// Gets the default UI language. - /// - /// The default UI language. - // ReSharper disable once InconsistentNaming - string DefaultUILanguage { get; } - - /// - /// Gets a value indicating whether umbraco should hide top level nodes from generated urls. - /// - /// - /// true if umbraco hides top level nodes from urls; otherwise, false. - /// - bool HideTopLevelNodeFromPath { get; } - - /// - /// Gets a value indicating whether umbraco should force a secure (https) connection to the backoffice. - /// - bool UseHttps { get; } - - /// - /// Returns a string value to determine if umbraco should skip version-checking. - /// - /// The version check period in days (0 = never). - int VersionCheckPeriod { get; } - - /// - /// Gets the path to umbraco's root directory. - /// - string UmbracoPath { get; } - string UmbracoCssPath { get; } - string UmbracoScriptsPath { get; } - string UmbracoMediaPath { get; } - - bool IsSmtpServerConfigured { get; } - ISmtpSettings SmtpSettings { get; } - - /// - /// Gets a value indicating whether the runtime should enter Install level when the database is missing. - /// - /// - /// By default, when a database connection string is configured but it is not possible to - /// connect to the database, the runtime enters the BootFailed level. If this options is set to true, - /// it enters the Install level instead. - /// It is then up to the implementor, that is setting this value, to take over the installation - /// sequence. - /// - bool InstallMissingDatabase { get; } - - /// - /// Gets a value indicating whether the runtime should enter Install level when the database is empty. - /// - /// - /// By default, when a database connection string is configured and it is possible to connect to - /// the database, but the database is empty, the runtime enters the BootFailed level. If this options - /// is set to true, it enters the Install level instead. - /// It is then up to the implementor, that is setting this value, to take over the installation - /// sequence. - /// - bool InstallEmptyDatabase { get; } - bool DisableElectionForSingleServer { get; } - 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/IHostingSettings.cs b/src/Umbraco.Core/Configuration/IHostingSettings.cs deleted file mode 100644 index 48ff4f216e..0000000000 --- a/src/Umbraco.Core/Configuration/IHostingSettings.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Umbraco.Core.Hosting; - -namespace Umbraco.Core.Configuration -{ - public interface IHostingSettings - { - bool DebugMode { get; } - - /// - /// Gets the configuration for the location of temporary files. - /// - LocalTempStorage LocalTempStorageLocation { get; } - - /// - /// Optional property to explicitly configure the application's virtual path - /// - /// - /// By default this is null which will mean that the is automatically configured, - /// otherwise this explicitly sets it. - /// If set, this value must begin with a "/" and cannot end with "/". - /// - string ApplicationVirtualPath { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/IImagingSettings.cs b/src/Umbraco.Core/Configuration/IImagingSettings.cs deleted file mode 100644 index 13e1b30389..0000000000 --- a/src/Umbraco.Core/Configuration/IImagingSettings.cs +++ /dev/null @@ -1,12 +0,0 @@ -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/IIndexCreatorSettings.cs b/src/Umbraco.Core/Configuration/IIndexCreatorSettings.cs deleted file mode 100644 index b3e2854a0d..0000000000 --- a/src/Umbraco.Core/Configuration/IIndexCreatorSettings.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface IIndexCreatorSettings - { - string LuceneDirectoryFactory { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs b/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs deleted file mode 100644 index 990bde9843..0000000000 --- a/src/Umbraco.Core/Configuration/IModelsBuilderConfig.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface IModelsBuilderConfig - { - bool Enable { get; } - bool AcceptUnsafeModelsDirectory { get; } - int DebugLevel { get; } - bool EnableFactory { get; } - bool FlagOutOfDateModels { get; } - string ModelsDirectory { get; } - ModelsMode ModelsMode { get; } - string ModelsNamespace { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/INuCacheSettings.cs b/src/Umbraco.Core/Configuration/INuCacheSettings.cs deleted file mode 100644 index c6524297a6..0000000000 --- a/src/Umbraco.Core/Configuration/INuCacheSettings.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface INuCacheSettings - { - string BTreeBlockSize { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/IRuntimeSettings.cs b/src/Umbraco.Core/Configuration/IRuntimeSettings.cs deleted file mode 100644 index 915e774186..0000000000 --- a/src/Umbraco.Core/Configuration/IRuntimeSettings.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Umbraco.Core.Configuration -{ - public interface IRuntimeSettings - { - int? MaxQueryStringLength { get; } - int? MaxRequestLength { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/ISmtpSettings.cs b/src/Umbraco.Core/Configuration/ISmtpSettings.cs deleted file mode 100644 index ea42ae5567..0000000000 --- a/src/Umbraco.Core/Configuration/ISmtpSettings.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Net.Mail; - -namespace Umbraco.Core.Configuration -{ - public interface ISmtpSettings - { - string From { get; } - string Host { get; } - int Port{ get; } - string PickupDirectoryLocation { get; } - SmtpDeliveryMethod DeliveryMethod { get; } - string Username { get; } - string Password { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/Models/ActiveDirectorySettings.cs b/src/Umbraco.Core/Configuration/Models/ActiveDirectorySettings.cs new file mode 100644 index 0000000000..0fe541416a --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ActiveDirectorySettings.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class ActiveDirectorySettings + { + public string Domain { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs b/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs new file mode 100644 index 0000000000..d21cba4486 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Configuration.Models +{ + public class ConnectionStrings + { + // Backing field for UmbracoConnectionString to load from configuration value with key umbracoDbDSN. + // Attributes cannot be applied to map from keys that don't match, and have chosen to retain the key name + // used in configuration for older Umbraco versions. + // See: https://stackoverflow.com/a/54607296/489433 + private string umbracoDbDSN + { + get => UmbracoConnectionString?.ConnectionString; + set => UmbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, value); + } + + public ConfigConnectionString UmbracoConnectionString { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs b/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs new file mode 100644 index 0000000000..8971dda5cc --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs @@ -0,0 +1,15 @@ +using System; + +namespace Umbraco.Core.Configuration.Models +{ + public class ContentErrorPage + { + //TODO introduce validation, to check only one of key/id/xPath is used. + 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; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs b/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs new file mode 100644 index 0000000000..018936896c --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Core.Configuration.Models +{ + public class ContentImagingSettings + { + private static readonly ImagingAutoFillUploadField[] DefaultImagingAutoFillUploadField = +{ + new ImagingAutoFillUploadField + { + Alias = Constants.Conventions.Media.File, + WidthFieldAlias = Constants.Conventions.Media.Width, + HeightFieldAlias = Constants.Conventions.Media.Height, + ExtensionFieldAlias = Constants.Conventions.Media.Extension, + LengthFieldAlias = Constants.Conventions.Media.Bytes, + } + }; + + public IEnumerable ImageFileTypes { get; set; } = new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" }; + + public IEnumerable AutoFillImageProperties { get; set; } = DefaultImagingAutoFillUploadField; + + 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.Core/Configuration/Models/ContentNotificationSettings.cs b/src/Umbraco.Core/Configuration/Models/ContentNotificationSettings.cs new file mode 100644 index 0000000000..ab1c10ff77 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ContentNotificationSettings.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class ContentNotificationSettings + { + public string Email { get; set; } + + public bool DisableHtmlEmail { get; set; } = false; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ContentSettings.cs b/src/Umbraco.Core/Configuration/Models/ContentSettings.cs new file mode 100644 index 0000000000..5158a5c746 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ContentSettings.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Macros; + +namespace Umbraco.Core.Configuration.Models +{ + public class ContentSettings + { + private const string DefaultPreviewBadge = + @"
Preview modeClick to end
"; + + public ContentNotificationSettings Notifications { get; set; } = new ContentNotificationSettings(); + + public ContentImagingSettings Imaging { get; set; } = new ContentImagingSettings(); + + public bool ResolveUrlsFromTextString { get; set; } = false; + + public IEnumerable Error404Collection { get; set; } = Array.Empty(); + + public string PreviewBadge { get; set; } = DefaultPreviewBadge; + + public MacroErrorBehaviour MacroErrors { get; set; } = MacroErrorBehaviour.Inline; + + public IEnumerable DisallowedUploadFiles { get; set; } = new[] { "ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd" }; + + public IEnumerable AllowedUploadFiles { get; set; } = Array.Empty(); + + public bool ShowDeprecatedPropertyEditors { get; set; } = false; + + public string LoginBackgroundImage { get; set; } = "assets/img/login.jpg"; + + + } +} diff --git a/src/Umbraco.Core/Configuration/Models/CoreDebugSettings.cs b/src/Umbraco.Core/Configuration/Models/CoreDebugSettings.cs new file mode 100644 index 0000000000..2b13609509 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/CoreDebugSettings.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class CoreDebugSettings + { + public bool LogUncompletedScopes { get; set; } = false; + + public bool DumpOnTimeoutThreadAbort { get; set; } = false; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ExceptionFilterSettings.cs b/src/Umbraco.Core/Configuration/Models/ExceptionFilterSettings.cs new file mode 100644 index 0000000000..6b8f74bef0 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ExceptionFilterSettings.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class ExceptionFilterSettings + { + public bool Disabled { get; set; } = false; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs b/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs new file mode 100644 index 0000000000..84956c7636 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs @@ -0,0 +1,61 @@ +namespace Umbraco.Core.Configuration.Models +{ + /// + /// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information + /// from web.config appsettings + /// + public class GlobalSettings + { + internal const string + StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,~/umbraco/,"; //must end with a comma! + + internal const string + StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma! + + public string ReservedUrls { get; set; } = StaticReservedUrls; + + public string ReservedPaths { get; set; } = StaticReservedPaths; + + // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings + // TODO: previously this would throw on set, but presumably we can't do that if we do still want this in config. + public string ConfigurationStatus { get; set; } + + public int TimeOutInMinutes { get; set; } = 20; + + public string DefaultUILanguage { get; set; } = "en-US"; + + public bool HideTopLevelNodeFromPath { get; set; } = false; + + public bool UseHttps { get; set; } = false; + + public int VersionCheckPeriod { get; set; } = 7; + + public string UmbracoPath { get; set; } = "~/umbraco"; + + public string IconsPath { get; set; } = $"~/umbraco/assets/icons"; + + public string UmbracoCssPath { get; set; } = "~/css"; + + public string UmbracoScriptsPath { get; set; } = "~/scripts"; + + public string UmbracoMediaPath { get; set; } = "~/media"; + + public bool InstallMissingDatabase { get; set; } = false; + + public bool InstallEmptyDatabase { get; set; } = false; + + public bool DisableElectionForSingleServer { get; set; } = false; + + public string RegisterType { get; set; } = string.Empty; + + public string DatabaseFactoryServerVersion { get; set; } = string.Empty; + + public string MainDomLock { get; set; } = string.Empty; + + public string NoNodesViewPath { get; set; } = "~/config/splashes/NoNodes.cshtml"; + + public bool IsSmtpServerConfigured => !string.IsNullOrWhiteSpace(Smtp?.Host); + + public SmtpSettings Smtp { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/HealthChecksSettings.cs b/src/Umbraco.Core/Configuration/Models/HealthChecksSettings.cs new file mode 100644 index 0000000000..0903a8f242 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/HealthChecksSettings.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Configuration.HealthChecks; + +namespace Umbraco.Core.Configuration.Models +{ + public class HealthChecksSettings + { + public IEnumerable DisabledChecks { get; set; } = Enumerable.Empty(); + + public HealthCheckNotificationSettings NotificationSettings { get; set; } = new HealthCheckNotificationSettings(); + + public class HealthCheckNotificationSettings + { + public bool Enabled { get; set; } = false; + + public string FirstRunTime { get; set; } + + public int PeriodInHours { get; set; } = 24; + + public IReadOnlyDictionary NotificationMethods { get; set; } = new Dictionary(); + + public IEnumerable DisabledChecks { get; set; } = Enumerable.Empty(); + } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/HostingSettings.cs b/src/Umbraco.Core/Configuration/Models/HostingSettings.cs new file mode 100644 index 0000000000..0863181922 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/HostingSettings.cs @@ -0,0 +1,18 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class HostingSettings + { + public string ApplicationVirtualPath { get; set; } + + /// + /// Gets the configuration for the location of temporary files. + /// + public LocalTempStorage LocalTempStorageLocation { get; set; } = LocalTempStorage.Default; + + /// + /// Gets a value indicating whether umbraco is running in [debug mode]. + /// + /// true if [debug mode]; otherwise, false. + public bool Debug { get; set; } = false; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs b/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs new file mode 100644 index 0000000000..25467b5a46 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs @@ -0,0 +1,15 @@ +using System.IO; + +namespace Umbraco.Core.Configuration.Models +{ + public class ImagingCacheSettings + { + public int MaxBrowserCacheDays { get; set; } = 7; + + public int MaxCacheDays { get; set; } = 365; + + public uint CachedNameLength { get; set; } = 8; + + public string CacheFolder { get; set; } = Path.Combine("..", "Umbraco", "MediaCache"); + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ImagingResizeSettings.cs b/src/Umbraco.Core/Configuration/Models/ImagingResizeSettings.cs new file mode 100644 index 0000000000..f9db53d7dd --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ImagingResizeSettings.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class ImagingResizeSettings + { + public int MaxWidth { get; set; } = 5000; + + public int MaxHeight { get; set; } = 5000; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ImagingSettings.cs b/src/Umbraco.Core/Configuration/Models/ImagingSettings.cs new file mode 100644 index 0000000000..2f253b151b --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ImagingSettings.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class ImagingSettings + { + public ImagingCacheSettings Cache { get; set; } = new ImagingCacheSettings(); + + public ImagingResizeSettings Resize { get; set; } = new ImagingResizeSettings(); + } +} diff --git a/src/Umbraco.Core/Configuration/Models/IndexCreatorSettings.cs b/src/Umbraco.Core/Configuration/Models/IndexCreatorSettings.cs new file mode 100644 index 0000000000..fcc22de9a3 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/IndexCreatorSettings.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class IndexCreatorSettings + { + public string LuceneDirectoryFactory { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/KeepAliveSettings.cs b/src/Umbraco.Core/Configuration/Models/KeepAliveSettings.cs new file mode 100644 index 0000000000..01d3b36a5d --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/KeepAliveSettings.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class KeepAliveSettings + { + public bool DisableKeepAliveTask => false; + + public string KeepAlivePingUrl => "{umbracoApplicationUrl}/api/keepalive/ping"; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/LoggingSettings.cs b/src/Umbraco.Core/Configuration/Models/LoggingSettings.cs new file mode 100644 index 0000000000..414ff06b57 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/LoggingSettings.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class LoggingSettings + { + public int MaxLogAge { get; set; } = -1; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/MemberPasswordConfigurationSettings.cs b/src/Umbraco.Core/Configuration/Models/MemberPasswordConfigurationSettings.cs new file mode 100644 index 0000000000..52bba6f4b8 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/MemberPasswordConfigurationSettings.cs @@ -0,0 +1,19 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class MemberPasswordConfigurationSettings : IPasswordConfiguration + { + public int RequiredLength { get; set; } = 10; + + public bool RequireNonLetterOrDigit { get; set; } = false; + + public bool RequireDigit { get; set; } = false; + + public bool RequireLowercase { get; set; } = false; + + public bool RequireUppercase { get; set; } = false; + + public string HashAlgorithmType { get; set; } = Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName; + + public int MaxFailedAccessAttemptsBeforeLockout { get; set; } = 5; + } +} diff --git a/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs b/src/Umbraco.Core/Configuration/Models/ModelsBuilderConfig.cs similarity index 59% rename from src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs rename to src/Umbraco.Core/Configuration/Models/ModelsBuilderConfig.cs index d111dbba70..e99557755c 100644 --- a/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs +++ b/src/Umbraco.Core/Configuration/Models/ModelsBuilderConfig.cs @@ -1,26 +1,13 @@ -using Microsoft.Extensions.Configuration; -using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Configuration; -namespace Umbraco.Configuration.Models +namespace Umbraco.Core.Configuration.Models { /// /// Represents the models builder configuration. /// - internal class ModelsBuilderConfig : IModelsBuilderConfig + public class ModelsBuilderConfig { - 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"; + public static string DefaultModelsDirectory => "~/App_Data/Models"; /// /// Gets a value indicating whether the whole models experience is enabled. @@ -29,25 +16,26 @@ namespace Umbraco.Configuration.Models /// 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); + public bool Enable { get; set; } = false; /// /// Gets the models mode. /// - public ModelsMode ModelsMode => - _configuration.GetValue(Prefix+"ModelsMode", ModelsMode.Nothing); + public ModelsMode ModelsMode { get; set; } = 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"); + public string ModelsNamespace { get; set; } /// /// 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); + public bool EnableFactory { get; set; } = true; + + private bool _flagOutOfDateModels; /// /// Gets a value indicating whether we should flag out-of-date models. @@ -57,15 +45,26 @@ namespace Umbraco.Configuration.Models /// 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(); + public bool FlagOutOfDateModels + { + get => _flagOutOfDateModels; + + set + { + if (!ModelsMode.IsLive()) + { + _flagOutOfDateModels = false; + } + + _flagOutOfDateModels = value; + } + } /// /// Gets the models directory. /// /// Default is ~/App_Data/Models but that can be changed. - public string ModelsDirectory => - _configuration.GetValue(Prefix+"ModelsDirectory", "~/App_Data/Models"); + public string ModelsDirectory { get; set; } = DefaultModelsDirectory; /// /// Gets a value indicating whether to accept an unsafe value for ModelsDirectory. @@ -74,13 +73,12 @@ namespace Umbraco.Configuration.Models /// 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); + public bool AcceptUnsafeModelsDirectory { get; set; } = 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); + public int DebugLevel { get; set; } = 0; } } diff --git a/src/Umbraco.Core/Configuration/Models/NuCacheSettings.cs b/src/Umbraco.Core/Configuration/Models/NuCacheSettings.cs new file mode 100644 index 0000000000..a2bc7d3561 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/NuCacheSettings.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class NuCacheSettings + { + public string BTreeBlockSize { get; set; } + } +} diff --git a/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs b/src/Umbraco.Core/Configuration/Models/RequestHandlerSettings.cs similarity index 50% rename from src/Umbraco.Configuration/Models/RequestHandlerSettings.cs rename to src/Umbraco.Core/Configuration/Models/RequestHandlerSettings.cs index ce5cd65c20..d7203b4901 100644 --- a/src/Umbraco.Configuration/Models/RequestHandlerSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/RequestHandlerSettings.cs @@ -1,16 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Extensions.Configuration; -using Umbraco.Core; +using System.Collections.Generic; using Umbraco.Core.Configuration.UmbracoSettings; -namespace Umbraco.Configuration.Models +namespace Umbraco.Core.Configuration.Models { - internal class RequestHandlerSettings : IRequestHandlerSettings + public class RequestHandlerSettings { - private const string Prefix = Constants.Configuration.ConfigPrefix + "RequestHandler:"; - private static readonly CharItem[] DefaultCharCollection = + internal static readonly CharItem[] DefaultCharCollection = { new CharItem { Char = " ", Replacement = "-" }, new CharItem { Char = "\"", Replacement = "" }, @@ -38,49 +33,38 @@ namespace Umbraco.Configuration.Models new CharItem { Char = ">", Replacement = "" } }; - private readonly IConfiguration _configuration; + public bool AddTrailingSlash { get; set; } = true; - public RequestHandlerSettings(IConfiguration configuration) - { - _configuration = configuration; - } + public string ConvertUrlsToAscii { get; set; } = "try"; - 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"); + public bool ShouldConvertUrlsToAscii => ConvertUrlsToAscii.InvariantEquals("true"); + public bool ShouldTryConvertUrlsToAscii => 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; - } + // TODO: implement from configuration - return DefaultCharCollection; - } - } + //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 IEnumerable CharCollection { get; set; } = DefaultCharCollection; public class CharItem : IChar { public string Char { get; set; } + public string Replacement { get; set; } } } diff --git a/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs b/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs new file mode 100644 index 0000000000..f93530b490 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class RuntimeSettings + { + public int? MaxQueryStringLength { get; set; } + + public int? MaxRequestLength { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/SecuritySettings.cs b/src/Umbraco.Core/Configuration/Models/SecuritySettings.cs new file mode 100644 index 0000000000..f40160d69b --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/SecuritySettings.cs @@ -0,0 +1,21 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class SecuritySettings + { + public bool KeepUserLoggedIn { get; set; } = false; + + public bool HideDisabledUsersInBackoffice { get; set; } = false; + + public bool AllowPasswordReset { get; set; } = true; + + public string AuthCookieName { get; set; } = "UMB_UCONTEXT"; + + public string AuthCookieDomain { get; set; } + + public bool UsernameIsEmail { get; set; } = true; + + public UserPasswordConfigurationSettings UserPassword { get; set; } + + public MemberPasswordConfigurationSettings MemberPassword { get; set; } + } +} diff --git a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs b/src/Umbraco.Core/Configuration/Models/SmtpSettings.cs similarity index 72% rename from src/Umbraco.Configuration/Legacy/SmtpSettings.cs rename to src/Umbraco.Core/Configuration/Models/SmtpSettings.cs index dce3d85840..a507f8a62f 100644 --- a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/SmtpSettings.cs @@ -1,14 +1,17 @@ -using System.Net.Mail; -using Umbraco.Core.Configuration; +using System.Net.Mail; -namespace Umbraco.Configuration +namespace Umbraco.Core.Configuration.Models { - public class SmtpSettings : ISmtpSettings + public class SmtpSettings { public string From { get; set; } + public string Host { get; set; } + public int Port { get; set; } + public string PickupDirectoryLocation { get; set; } + public SmtpDeliveryMethod DeliveryMethod { get; set; } public string Username { get; set; } diff --git a/src/Umbraco.Core/Configuration/Models/TourSettings.cs b/src/Umbraco.Core/Configuration/Models/TourSettings.cs new file mode 100644 index 0000000000..895eff6dee --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/TourSettings.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class TourSettings + { + public bool EnableTours { get; set; } = true; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/TypeFinderSettings.cs b/src/Umbraco.Core/Configuration/Models/TypeFinderSettings.cs new file mode 100644 index 0000000000..c5210f6c8e --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/TypeFinderSettings.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class TypeFinderSettings + { + public string AssembliesAcceptingLoadExceptions { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/UserPasswordConfigurationSettings.cs b/src/Umbraco.Core/Configuration/Models/UserPasswordConfigurationSettings.cs new file mode 100644 index 0000000000..445a0f545c --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/UserPasswordConfigurationSettings.cs @@ -0,0 +1,19 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class UserPasswordConfigurationSettings : IPasswordConfiguration + { + public int RequiredLength { get; set; } = 10; + + public bool RequireNonLetterOrDigit { get; set; } = false; + + public bool RequireDigit { get; set; } = false; + + public bool RequireLowercase { get; set; } = false; + + public bool RequireUppercase { get; set; } = false; + + public string HashAlgorithmType { get; set; } = Constants.Security.AspNetCoreV3PasswordHashAlgorithmName; + + public int MaxFailedAccessAttemptsBeforeLockout { get; set; } = 5; + } +} diff --git a/src/Umbraco.Core/Configuration/Models/WebRoutingSettings.cs b/src/Umbraco.Core/Configuration/Models/WebRoutingSettings.cs new file mode 100644 index 0000000000..7e0c4d5d8c --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/WebRoutingSettings.cs @@ -0,0 +1,23 @@ +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Core.Configuration.Models +{ + public class WebRoutingSettings + { + public bool TrySkipIisCustomErrors { get; set; } = false; + + public bool InternalRedirectPreservesTemplate { get; set; } = false; + + public bool DisableAlternativeTemplates { get; set; } = false; + + public bool ValidateAlternativeTemplates { get; set; } = false; + + public bool DisableFindContentByIdPath { get; set; } = false; + + public bool DisableRedirectUrlTracking { get; set; } = false; + + public string UrlProviderMode { get; set; } = UrlMode.Auto.ToString(); + + public string UmbracoApplicationUrl { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs index 3e3b116395..edf068e16f 100644 --- a/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs +++ b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs @@ -1,5 +1,7 @@ using System.Configuration; using System.IO; +using Umbraco.Core.Hosting; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; namespace Umbraco.Core.Configuration @@ -8,13 +10,12 @@ namespace Umbraco.Core.Configuration { private static string _modelsDirectoryAbsolute = null; - public static string ModelsDirectoryAbsolute(this IModelsBuilderConfig modelsBuilderConfig, IIOHelper ioHelper) + public static string ModelsDirectoryAbsolute(this ModelsBuilderConfig modelsBuilderConfig, IHostingEnvironment hostingEnvironment) { - if (_modelsDirectoryAbsolute is null) { var modelsDirectory = modelsBuilderConfig.ModelsDirectory; - var root = ioHelper.MapPath("~/"); + var root = hostingEnvironment.MapPathContentRoot("~/"); _modelsDirectoryAbsolute = GetModelsDirectory(root, modelsDirectory, modelsBuilderConfig.AcceptUnsafeModelsDirectory); diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs deleted file mode 100644 index 85df4540c0..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IBackOfficeSection - { - ITourSettings Tours { get; } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentErrorPage.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentErrorPage.cs deleted file mode 100644 index 3ea00d7c74..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentErrorPage.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IContentErrorPage - { - int ContentId { get; } - Guid ContentKey { get; } - string ContentXPath { get; } - bool HasContentId { get; } - bool HasContentKey { get; } - string Culture { get; set; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs deleted file mode 100644 index 08f6231309..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSettings.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using Umbraco.Core.Macros; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IContentSettings : IUmbracoConfigurationSection - { - string NotificationEmailAddress { get; } - - bool DisableHtmlEmail { get; } - - IEnumerable ImageFileTypes { get; } - - IEnumerable ImageAutoFillProperties { get; } - - bool ResolveUrlsFromTextString { get; } - - IEnumerable Error404Collection { get; } - - string PreviewBadge { get; } - - MacroErrorBehaviour MacroErrorBehaviour { get; } - - IEnumerable DisallowedUploadFiles { get; } - - IEnumerable AllowedUploadFiles { get; } - - /// - /// Gets a value indicating whether to show deprecated property editors in - /// a datatype list of available editors. - /// - bool ShowDeprecatedPropertyEditors { get; } - - string LoginBackgroundImage { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs deleted file mode 100644 index 58a8151474..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IKeepAliveSettings.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IKeepAliveSettings : IUmbracoConfigurationSection - { - bool DisableKeepAliveTask { get; } - string KeepAlivePingUrl { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs deleted file mode 100644 index ee5647ee27..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ILoggingSettings.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface ILoggingSettings : IUmbracoConfigurationSection - { - int MaxLogAge { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs deleted file mode 100644 index 11fdaa8310..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IRequestHandlerSettings.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IRequestHandlerSettings : IUmbracoConfigurationSection - { - bool AddTrailingSlash { get; } - - bool ConvertUrlsToAscii { get; } - - bool TryConvertUrlsToAscii { get; } - - IEnumerable CharCollection { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs deleted file mode 100644 index 6ab520fefd..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ISecuritySettings.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface ISecuritySettings : IUmbracoConfigurationSection - { - bool KeepUserLoggedIn { get; } - - bool HideDisabledUsersInBackoffice { get; } - - /// - /// Used to enable/disable the forgot password functionality on the back office login screen - /// - bool AllowPasswordReset { get; } - - string AuthCookieName { get; } - - string AuthCookieDomain { get; } - - /// - /// A boolean indicating that by default the email address will be the username - /// - /// - /// 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 UsernameIsEmail { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs deleted file mode 100644 index d3d8293140..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ITourSettings.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface ITourSettings - { - bool EnableTours { get; } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs deleted file mode 100644 index f7f6a94d30..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IWebRoutingSettings.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public interface IWebRoutingSettings : IUmbracoConfigurationSection - { - bool TrySkipIisCustomErrors { get; } - - bool InternalRedirectPreservesTemplate { get; } - - bool DisableAlternativeTemplates { get; } - - bool ValidateAlternativeTemplates { get; } - - bool DisableFindContentByIdPath { get; } - - bool DisableRedirectUrlTracking { get; } - - string UrlProviderMode { get; } - - string UmbracoApplicationUrl { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index 0ddac4a8bd..2e45be6cc6 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -1,5 +1,4 @@ using System; -using System.Configuration; using System.Reflection; using Semver; @@ -10,14 +9,6 @@ namespace Umbraco.Core.Configuration /// public class UmbracoVersion : IUmbracoVersion { - private readonly IGlobalSettings _globalSettings; - - public UmbracoVersion(IGlobalSettings globalSettings) - : this() - { - _globalSettings = globalSettings; - } - public UmbracoVersion() { var umbracoCoreAssembly = typeof(SemVersion).Assembly; diff --git a/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs index 80d795bb48..dd7e4baa94 100644 --- a/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs +++ b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs @@ -2,8 +2,8 @@ using System.Configuration; using System.IO; using System.Linq; +using System.Xml; using System.Xml.Linq; -using Umbraco.Composing; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -111,6 +111,26 @@ namespace Umbraco.Core.Configuration throw new NotImplementedException(); } + public void SaveDisableRedirectUrlTracking(bool disable) + { + var fileName = _ioHelper.MapPath("~/config/umbracoSettings.config"); + + var umbracoConfig = new XmlDocument { PreserveWhitespace = true }; + umbracoConfig.Load(fileName); + + var action = disable ? "disable" : "enable"; + + if (File.Exists(fileName) == false) + throw new Exception($"Couldn't {action} URL Tracker, the umbracoSettings.config file does not exist."); + + if (!(umbracoConfig.SelectSingleNode("//web.routing") is XmlElement webRoutingElement)) + throw new Exception($"Couldn't {action} URL Tracker, the web.routing element was not found in umbracoSettings.config."); + + // note: this adds the attribute if it does not exist + webRoutingElement.SetAttribute("disableRedirectUrlTracking", disable.ToString().ToLowerInvariant()); + umbracoConfig.Save(fileName); + } + private static void AddOrUpdateAttribute(XElement element, string name, string value) { var attribute = element.Attribute(name); diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 3e70bcda53..51221086ec 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -7,7 +7,65 @@ namespace Umbraco.Core public static class ContentExtensions { - #region XML methods + internal static bool IsMoving(this IContentBase entity) + { + // Check if this entity is being moved as a descendant as part of a bulk moving operations. + // When this occurs, only Path + Level + UpdateDate are being changed. In this case we can bypass a lot of the below + // operations which will make this whole operation go much faster. When moving we don't need to create + // new versions, etc... because we cannot roll this operation back anyways. + var isMoving = entity.IsPropertyDirty(nameof(entity.Path)) + && entity.IsPropertyDirty(nameof(entity.Level)) + && entity.IsPropertyDirty(nameof(entity.UpdateDate)); + + return isMoving; + } + + + /// + /// Removes characters that are not valid XML characters from all entity properties + /// of type string. See: http://stackoverflow.com/a/961504/5018 + /// + /// + /// + /// If this is not done then the xml cache can get corrupt and it will throw YSODs upon reading it. + /// + /// + public static void SanitizeEntityPropertiesForXmlStorage(this IContentBase entity) + { + entity.Name = entity.Name.ToValidXmlString(); + foreach (var property in entity.Properties) + { + foreach (var propertyValue in property.Values) + { + if (propertyValue.EditedValue is string editString) + propertyValue.EditedValue = editString.ToValidXmlString(); + if (propertyValue.PublishedValue is string publishedString) + propertyValue.PublishedValue = publishedString.ToValidXmlString(); + } + } + } + + /// + /// Checks if the IContentBase has children + /// + /// + /// + /// + /// + /// This is a bit of a hack because we need to type check! + /// + internal static bool HasChildren(IContentBase content, ServiceContext services) + { + if (content is IContent) + { + return services.ContentService.HasChildren(content.Id); + } + if (content is IMedia) + { + return services.MediaService.HasChildren(content.Id); + } + return false; + } /// /// Creates the full xml representation for the object and all of it's descendants @@ -53,6 +111,5 @@ namespace Umbraco.Core { return serializer.Serialize(member); } - #endregion } } diff --git a/src/Umbraco.Core/Dashboards/DashboardCollectionBuilder.cs b/src/Umbraco.Core/Dashboards/DashboardCollectionBuilder.cs index d790b04d46..a903d15abb 100644 --- a/src/Umbraco.Core/Dashboards/DashboardCollectionBuilder.cs +++ b/src/Umbraco.Core/Dashboards/DashboardCollectionBuilder.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Umbraco.Core; using Umbraco.Core.Composing; @@ -9,8 +10,22 @@ namespace Umbraco.Web.Dashboards { public class DashboardCollectionBuilder : WeightedCollectionBuilderBase { + private Dictionary _customWeights = new Dictionary(); + protected override DashboardCollectionBuilder This => this; + /// + /// Changes the default weight of a dashboard + /// + /// The type of dashboard + /// The new dashboard weight + /// + public DashboardCollectionBuilder SetWeight(int weight) where T : IDashboard + { + _customWeights[typeof(T)] = weight; + return this; + } + protected override IEnumerable CreateItems(IFactory factory) { // get the manifest parser just-in-time - injecting it in the ctor would mean that @@ -32,6 +47,12 @@ namespace Umbraco.Web.Dashboards private int GetWeight(IDashboard dashboard) { + var typeOfDashboard = dashboard.GetType(); + if(_customWeights.ContainsKey(typeOfDashboard)) + { + return _customWeights[typeOfDashboard]; + } + switch (dashboard) { case ManifestDashboard manifestDashboardDefinition: diff --git a/src/Umbraco.Core/Editors/BackOfficeModel.cs b/src/Umbraco.Core/Editors/BackOfficeModel.cs deleted file mode 100644 index be91654d9e..0000000000 --- a/src/Umbraco.Core/Editors/BackOfficeModel.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using Umbraco.Web.Features; -using Umbraco.Web.Trees; - -namespace Umbraco.Web.Editors -{ - // TODO: Almost nothing here needs to exist since we can inject these into the view - public class BackOfficeModel - { - public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, - IContentSettings contentSettings, - IHostingEnvironment hostingEnvironment, - IRuntimeSettings runtimeSettings, ISecuritySettings securitySettings) - { - Features = features; - GlobalSettings = globalSettings; - UmbracoVersion = umbracoVersion; - ContentSettings = contentSettings; - HostingEnvironment = hostingEnvironment; - RuntimeSettings = runtimeSettings; - SecuritySettings = securitySettings; - BackOfficePath = GlobalSettings.GetBackOfficePath(HostingEnvironment); - } - - public UmbracoFeatures Features { get; } - public IGlobalSettings GlobalSettings { get; } - public IUmbracoVersion UmbracoVersion { get; } - public IContentSettings ContentSettings { get; } - public IHostingEnvironment HostingEnvironment { get; } - public IRuntimeSettings RuntimeSettings { get; set; } - public ISecuritySettings SecuritySettings { get; set; } - - public string BackOfficePath { get; } - } -} diff --git a/src/Umbraco.Core/Editors/BackOfficePreviewModel.cs b/src/Umbraco.Core/Editors/BackOfficePreviewModel.cs index 10d12f30f8..40d145afb0 100644 --- a/src/Umbraco.Core/Editors/BackOfficePreviewModel.cs +++ b/src/Umbraco.Core/Editors/BackOfficePreviewModel.cs @@ -1,7 +1,4 @@ using System.Collections.Generic; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Hosting; using Umbraco.Core.Models; using Umbraco.Web.Features; @@ -10,7 +7,7 @@ namespace Umbraco.Web.Editors public class BackOfficePreviewModel { private readonly UmbracoFeatures _features; - + public BackOfficePreviewModel(UmbracoFeatures features, IEnumerable languages) { _features = features; diff --git a/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs index 6aeb83d61c..d6fbfae813 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Install; using Umbraco.Core.IO; using Umbraco.Core.Services; @@ -29,14 +31,14 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions public class FolderAndFilePermissionsCheck : HealthCheck { private readonly ILocalizedTextService _textService; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IFilePermissionHelper _filePermissionHelper; private readonly IIOHelper _ioHelper; - public FolderAndFilePermissionsCheck(ILocalizedTextService textService, IGlobalSettings globalSettings, IFilePermissionHelper filePermissionHelper, IIOHelper ioHelper) + public FolderAndFilePermissionsCheck(ILocalizedTextService textService, IOptions globalSettings, IFilePermissionHelper filePermissionHelper, IIOHelper ioHelper) { _textService = textService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _filePermissionHelper = filePermissionHelper; _ioHelper = ioHelper; } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs index 43776ad827..7f85d326df 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs @@ -8,6 +8,8 @@ using Umbraco.Core.IO; using Umbraco.Core.Services; using Umbraco.Core.Logging; using Umbraco.Web.HealthCheck.Checks.Config; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.HealthCheck.Checks.Security { @@ -19,17 +21,17 @@ namespace Umbraco.Web.HealthCheck.Checks.Security public class HttpsCheck : HealthCheck { private readonly ILocalizedTextService _textService; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IIOHelper _ioHelper; private readonly ILogger _logger; private readonly IRequestAccessor _requestAccessor; private const string FixHttpsSettingAction = "fixHttpsSetting"; - public HttpsCheck(ILocalizedTextService textService, IGlobalSettings globalSettings, IIOHelper ioHelper, ILogger logger, IRequestAccessor requestAccessor) + public HttpsCheck(ILocalizedTextService textService, IOptions globalSettings, IIOHelper ioHelper, ILogger logger, IRequestAccessor requestAccessor) { _textService = textService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _ioHelper = ioHelper; _logger = logger; _requestAccessor = requestAccessor; diff --git a/src/Umbraco.Core/HealthCheck/Checks/Services/SmtpCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Services/SmtpCheck.cs index 7b57c01223..77b1201ef6 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Services/SmtpCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Services/SmtpCheck.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using System.IO; using System.Net.Sockets; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Services @@ -16,14 +18,12 @@ namespace Umbraco.Web.HealthCheck.Checks.Services public class SmtpCheck : HealthCheck { private readonly ILocalizedTextService _textService; - private readonly IRuntimeState _runtime; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public SmtpCheck(ILocalizedTextService textService, IRuntimeState runtime, IGlobalSettings globalSettings) + public SmtpCheck(ILocalizedTextService textService, IOptions globalSettings) { _textService = textService; - _runtime = runtime; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } /// @@ -48,11 +48,11 @@ namespace Umbraco.Web.HealthCheck.Checks.Services private HealthCheckStatus CheckSmtpSettings() { - var message = string.Empty; var success = false; - var smtpSettings = _globalSettings.SmtpSettings; + var smtpSettings = _globalSettings.Smtp; + string message; if (smtpSettings == null) { message = _textService.Localize("healthcheck/smtpMailSettingsNotFound"); diff --git a/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs b/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs new file mode 100644 index 0000000000..a953ed8b82 --- /dev/null +++ b/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs @@ -0,0 +1,30 @@ +using Umbraco.Core.Cache; +using Umbraco.Core.Security; +using Umbraco.Web; +using Umbraco.Web.Security; + +namespace Umbraco.Core +{ + + public class HybridBackofficeSecurityAccessor : HybridAccessorBase, IBackofficeSecurityAccessor + { + /// + /// Initializes a new instance of the class. + /// + public HybridBackofficeSecurityAccessor(IRequestCache requestCache) + : base(requestCache) + { } + + /// + protected override string ItemKey => "Umbraco.Web.HybridBackofficeSecurityAccessor"; + + /// + /// Gets or sets the object. + /// + public IBackofficeSecurity BackofficeSecurity + { + get => Value; + set => Value = value; + } + } +} diff --git a/src/Umbraco.Core/IBackofficeSecurityFactory.cs b/src/Umbraco.Core/IBackofficeSecurityFactory.cs new file mode 100644 index 0000000000..9f8f791e4c --- /dev/null +++ b/src/Umbraco.Core/IBackofficeSecurityFactory.cs @@ -0,0 +1,15 @@ +using Umbraco.Web.Security; + +namespace Umbraco.Core +{ + /// + /// Creates and manages instances. + /// + public interface IBackofficeSecurityFactory + { + /// + /// Ensures that a current exists. + /// + void EnsureBackofficeSecurity(); + } +} diff --git a/src/Umbraco.Core/IO/FileSystems.cs b/src/Umbraco.Core/IO/FileSystems.cs index ba5fcb91f3..505f714620 100644 --- a/src/Umbraco.Core/IO/FileSystems.cs +++ b/src/Umbraco.Core/IO/FileSystems.cs @@ -6,6 +6,8 @@ using Umbraco.Core.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Core.IO { @@ -36,12 +38,12 @@ namespace Umbraco.Core.IO #region Constructor // DI wants a public ctor - public FileSystems(IFactory container, ILogger logger, IIOHelper ioHelper, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + public FileSystems(IFactory container, ILogger logger, IIOHelper ioHelper, IOptions globalSettings, IHostingEnvironment hostingEnvironment) { _container = container; _logger = logger; _ioHelper = ioHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; } @@ -156,7 +158,7 @@ namespace Umbraco.Core.IO // internal for tests internal IReadOnlyDictionary Paths => _paths; - private IGlobalSettings _globalSettings; + private GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; /// diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index a8a34e2e93..118b528869 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Reflection; using System.IO; using System.Linq; -using Umbraco.Core.Configuration; +using System.Reflection; using Umbraco.Core.Hosting; using Umbraco.Core.Strings; @@ -14,7 +13,7 @@ namespace Umbraco.Core.IO { private readonly IHostingEnvironment _hostingEnvironment; - public IOHelper(IHostingEnvironment hostingEnvironment, IGlobalSettings globalSettings) + public IOHelper(IHostingEnvironment hostingEnvironment) { _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); } diff --git a/src/Umbraco.Core/IO/ViewHelper.cs b/src/Umbraco.Core/IO/ViewHelper.cs index 77b2d6cc99..569d8cdfc9 100644 --- a/src/Umbraco.Core/IO/ViewHelper.cs +++ b/src/Umbraco.Core/IO/ViewHelper.cs @@ -69,6 +69,7 @@ namespace Umbraco.Core.IO // either // @inherits Umbraco.Web.Mvc.UmbracoViewPage // @inherits Umbraco.Web.Mvc.UmbracoViewPage + content.AppendLine("@using Umbraco.Web.PublishedModels;"); content.Append("@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage"); if (modelClassName.IsNullOrWhiteSpace() == false) { diff --git a/src/Umbraco.Core/IUmbracoContext.cs b/src/Umbraco.Core/IUmbracoContext.cs index 66b3dc3965..03fb305fb6 100644 --- a/src/Umbraco.Core/IUmbracoContext.cs +++ b/src/Umbraco.Core/IUmbracoContext.cs @@ -16,9 +16,9 @@ namespace Umbraco.Web DateTime ObjectCreated { get; } /// - /// Gets the WebSecurity class + /// Gets the BackofficeSecurity class /// - IWebSecurity Security { get; } + IBackofficeSecurity Security { get; } /// /// Gets the uri that is handled by ASP.NET after server-side rewriting took place. diff --git a/src/Umbraco.Core/Models/Blocks/BlockListItem.cs b/src/Umbraco.Core/Models/Blocks/BlockListItem.cs index f4b5c489e7..620c3d9fe0 100644 --- a/src/Umbraco.Core/Models/Blocks/BlockListItem.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockListItem.cs @@ -5,41 +5,126 @@ using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core.Models.Blocks { /// - /// Represents a layout item for the Block List editor + /// Represents a layout item for the Block List editor. /// + /// [DataContract(Name = "block", Namespace = "")] public class BlockListItem : IBlockReference { + /// + /// Initializes a new instance of the class. + /// + /// The content UDI. + /// The content. + /// The settings UDI. + /// The settings. + /// contentUdi + /// or + /// content public BlockListItem(Udi contentUdi, IPublishedElement content, Udi settingsUdi, IPublishedElement settings) { - ContentUdi = contentUdi ?? throw new ArgumentNullException(nameof(contentUdi)); + ContentUdi = contentUdi ?? throw new ArgumentNullException(nameof(contentUdi)); Content = content ?? throw new ArgumentNullException(nameof(content)); - Settings = settings; // can be null - SettingsUdi = settingsUdi; // can be null + SettingsUdi = settingsUdi; + Settings = settings; } /// - /// The Id of the content data item + /// Gets the content UDI. /// + /// + /// The content UDI. + /// [DataMember(Name = "contentUdi")] public Udi ContentUdi { get; } /// - /// The Id of the settings data item - /// - [DataMember(Name = "settingsUdi")] - public Udi SettingsUdi { get; } - - /// - /// The content data item referenced + /// Gets the content. /// + /// + /// The content. + /// [DataMember(Name = "content")] public IPublishedElement Content { get; } /// - /// The settings data item referenced + /// Gets the settings UDI. /// + /// + /// The settings UDI. + /// + [DataMember(Name = "settingsUdi")] + public Udi SettingsUdi { get; } + + /// + /// Gets the settings. + /// + /// + /// The settings. + /// [DataMember(Name = "settings")] public IPublishedElement Settings { get; } } + + /// + /// Represents a layout item with a generic content type for the Block List editor. + /// + /// The type of the content. + /// + public class BlockListItem : BlockListItem + where T : IPublishedElement + { + /// + /// Initializes a new instance of the class. + /// + /// The content UDI. + /// The content. + /// The settings UDI. + /// The settings. + public BlockListItem(Udi contentUdi, T content, Udi settingsUdi, IPublishedElement settings) + : base(contentUdi, content, settingsUdi, settings) + { + Content = content; + } + + /// + /// Gets the content. + /// + /// + /// The content. + /// + public new T Content { get; } + } + + /// + /// Represents a layout item with generic content and settings types for the Block List editor. + /// + /// The type of the content. + /// The type of the settings. + /// + public class BlockListItem : BlockListItem + where TContent : IPublishedElement + where TSettings : IPublishedElement + { + /// + /// Initializes a new instance of the class. + /// + /// The content udi. + /// The content. + /// The settings udi. + /// The settings. + public BlockListItem(Udi contentUdi, TContent content, Udi settingsUdi, TSettings settings) + : base(contentUdi, content, settingsUdi, settings) + { + Settings = settings; + } + + /// + /// Gets the settings. + /// + /// + /// The settings. + /// + public new TSettings Settings { get; } + } } diff --git a/src/Umbraco.Core/Models/Blocks/IBlockReference.cs b/src/Umbraco.Core/Models/Blocks/IBlockReference.cs index 8d8ddd47f0..7f5c835b3c 100644 --- a/src/Umbraco.Core/Models/Blocks/IBlockReference.cs +++ b/src/Umbraco.Core/Models/Blocks/IBlockReference.cs @@ -1,26 +1,37 @@ namespace Umbraco.Core.Models.Blocks { - /// - /// Represents a data item reference for a Block editor implementation - /// - /// - /// - /// see: https://github.com/umbraco/rfcs/blob/907f3758cf59a7b6781296a60d57d537b3b60b8c/cms/0011-block-data-structure.md#strongly-typed - /// - public interface IBlockReference : IBlockReference - { - TSettings Settings { get; } - } - - /// - /// Represents a data item reference for a Block Editor implementation + /// Represents a data item reference for a Block Editor implementation. /// /// - /// see: https://github.com/umbraco/rfcs/blob/907f3758cf59a7b6781296a60d57d537b3b60b8c/cms/0011-block-data-structure.md#strongly-typed + /// See: https://github.com/umbraco/rfcs/blob/907f3758cf59a7b6781296a60d57d537b3b60b8c/cms/0011-block-data-structure.md#strongly-typed /// public interface IBlockReference { + /// + /// Gets the content UDI. + /// + /// + /// The content UDI. + /// Udi ContentUdi { get; } } + + /// + /// Represents a data item reference with settings for a Block editor implementation. + /// + /// The type of the settings. + /// + /// See: https://github.com/umbraco/rfcs/blob/907f3758cf59a7b6781296a60d57d537b3b60b8c/cms/0011-block-data-structure.md#strongly-typed + /// + public interface IBlockReference : IBlockReference + { + /// + /// Gets the settings. + /// + /// + /// The settings. + /// + TSettings Settings { get; } + } } diff --git a/src/Umbraco.Core/Models/IconModel.cs b/src/Umbraco.Core/Models/IconModel.cs index 5c79ad6219..12fa8884ae 100644 --- a/src/Umbraco.Core/Models/IconModel.cs +++ b/src/Umbraco.Core/Models/IconModel.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models { public class IconModel { diff --git a/src/Umbraco.Core/Models/Language.cs b/src/Umbraco.Core/Models/Language.cs index e83c59443d..0ac8526181 100644 --- a/src/Umbraco.Core/Models/Language.cs +++ b/src/Umbraco.Core/Models/Language.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Runtime.Serialization; using System.Threading; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models @@ -14,7 +15,7 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class Language : EntityBase, ILanguage { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private string _isoCode; private string _cultureName; @@ -22,7 +23,7 @@ namespace Umbraco.Core.Models private bool _mandatory; private int? _fallbackLanguageId; - public Language(IGlobalSettings globalSettings, string isoCode) + public Language(GlobalSettings globalSettings, string isoCode) { IsoCode = isoCode; _globalSettings = globalSettings; diff --git a/src/Umbraco.Core/Models/MediaExtensions.cs b/src/Umbraco.Core/Models/MediaExtensions.cs index ffcc2c2a92..9615969c07 100644 --- a/src/Umbraco.Core/Models/MediaExtensions.cs +++ b/src/Umbraco.Core/Models/MediaExtensions.cs @@ -1,5 +1,5 @@ using System.Linq; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.PropertyEditors; namespace Umbraco.Core.Models @@ -27,9 +27,9 @@ namespace Umbraco.Core.Models /// /// Gets the urls of a media item. /// - public static string[] GetUrls(this IMedia media, IContentSettings contentSettings, MediaUrlGeneratorCollection mediaUrlGenerators) + public static string[] GetUrls(this IMedia media, ContentSettings contentSettings, MediaUrlGeneratorCollection mediaUrlGenerators) { - return contentSettings.ImageAutoFillProperties + return contentSettings.Imaging.AutoFillImageProperties .Select(field => media.GetUrl(field.Alias, mediaUrlGenerators)) .Where(link => string.IsNullOrWhiteSpace(link) == false) .ToArray(); diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 43cedec951..7599997750 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Runtime.Serialization; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Entities; namespace Umbraco.Core.Models.Membership @@ -18,7 +19,7 @@ namespace Umbraco.Core.Models.Membership /// /// Constructor for creating a new/empty user /// - public User(IGlobalSettings globalSettings) + public User(GlobalSettings globalSettings) { SessionTimeout = 60; _userGroups = new HashSet(); @@ -38,7 +39,7 @@ namespace Umbraco.Core.Models.Membership /// /// /// - public User(IGlobalSettings globalSettings, string name, string email, string username, string rawPasswordValue) + public User(GlobalSettings globalSettings, string name, string email, string username, string rawPasswordValue) : this(globalSettings) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(name)); @@ -69,7 +70,7 @@ namespace Umbraco.Core.Models.Membership /// /// /// - public User(IGlobalSettings globalSettings, int id, string name, string email, string username, + public User(GlobalSettings globalSettings, int id, string name, string email, string username, string rawPasswordValue, string passwordConfig, IEnumerable userGroups, int[] startContentIds, int[] startMediaIds) : this(globalSettings) diff --git a/src/Umbraco.Core/Models/PropertyCollection.cs b/src/Umbraco.Core/Models/PropertyCollection.cs index dd62ba83cb..e206a3b38c 100644 --- a/src/Umbraco.Core/Models/PropertyCollection.cs +++ b/src/Umbraco.Core/Models/PropertyCollection.cs @@ -7,6 +7,7 @@ using System.Runtime.Serialization; namespace Umbraco.Core.Models { + /// /// Represents a collection of property values. /// diff --git a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs index dd60eb9beb..94e7958780 100644 --- a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs @@ -390,7 +390,6 @@ namespace Umbraco.Core.Models.PublishedContent protected override bool IsCOMObjectImpl() => false; - public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) { throw new NotSupportedException(); diff --git a/src/Umbraco.Core/Models/UmbracoUserExtensions.cs b/src/Umbraco.Core/Models/UmbracoUserExtensions.cs index 6ed3e6279b..18684f7946 100644 --- a/src/Umbraco.Core/Models/UmbracoUserExtensions.cs +++ b/src/Umbraco.Core/Models/UmbracoUserExtensions.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Text; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; @@ -48,14 +49,14 @@ namespace Umbraco.Core.Models /// /// /// - public static CultureInfo GetUserCulture(this IUser user, ILocalizedTextService textService, IGlobalSettings globalSettings) + public static CultureInfo GetUserCulture(this IUser user, ILocalizedTextService textService, GlobalSettings globalSettings) { if (user == null) throw new ArgumentNullException(nameof(user)); if (textService == null) throw new ArgumentNullException(nameof(textService)); return GetUserCulture(user.Language, textService, globalSettings); } - public static CultureInfo GetUserCulture(string userLanguage, ILocalizedTextService textService, IGlobalSettings globalSettings) + public static CultureInfo GetUserCulture(string userLanguage, ILocalizedTextService textService, GlobalSettings globalSettings) { try { diff --git a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs index 510a4122e9..b4cd2bd03f 100644 --- a/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs +++ b/src/Umbraco.Core/Packaging/CompiledPackageXmlParser.cs @@ -3,7 +3,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Packaging; using File = System.IO.File; @@ -15,12 +16,12 @@ namespace Umbraco.Core.Packaging public class CompiledPackageXmlParser { private readonly ConflictingPackageData _conflictingPackageData; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public CompiledPackageXmlParser(ConflictingPackageData conflictingPackageData, IGlobalSettings globalSettings) + public CompiledPackageXmlParser(ConflictingPackageData conflictingPackageData, IOptions globalSettings) { _conflictingPackageData = conflictingPackageData; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } public CompiledPackage ToCompiledPackage(XDocument xml, FileInfo packageFile, string applicationRootFolder) diff --git a/src/Umbraco.Core/Packaging/PackageFileInstallation.cs b/src/Umbraco.Core/Packaging/PackageFileInstallation.cs index 4ae20cd951..4f6c622bb3 100644 --- a/src/Umbraco.Core/Packaging/PackageFileInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageFileInstallation.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Xml.Linq; -using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.Logging; -using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; -using Umbraco.Core.Services; using File = System.IO.File; namespace Umbraco.Core.Packaging diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index 0764378b06..7e57fe25f4 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -5,9 +5,10 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; @@ -61,7 +62,7 @@ namespace Umbraco.Core.Packaging IHostingEnvironment hostingEnvironment, IEntityXmlSerializer serializer, ILogger logger, IUmbracoVersion umbracoVersion, - IGlobalSettings globalSettings, + IOptions globalSettings, string packageRepositoryFileName, string tempFolderPath = null, string packagesFolderPath = null, string mediaFolderPath = null) { @@ -79,7 +80,7 @@ namespace Umbraco.Core.Packaging _tempFolderPath = tempFolderPath ?? Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "PackageFiles"; _packagesFolderPath = packagesFolderPath ?? Constants.SystemDirectories.Packages; - _mediaFolderPath = mediaFolderPath ?? globalSettings.UmbracoMediaPath + "/created-packages"; + _mediaFolderPath = mediaFolderPath ?? globalSettings.Value.UmbracoMediaPath + "/created-packages"; _parser = new PackageDefinitionXmlParser(logger, umbracoVersion); _umbracoVersion = umbracoVersion; diff --git a/src/Umbraco.Core/PropertyEditors/TextboxConfiguration.cs b/src/Umbraco.Core/PropertyEditors/TextboxConfiguration.cs index c9f15e2e2f..641cc8e42a 100644 --- a/src/Umbraco.Core/PropertyEditors/TextboxConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/TextboxConfiguration.cs @@ -7,7 +7,7 @@ namespace Umbraco.Web.PropertyEditors /// public class TextboxConfiguration { - [ConfigurationField("maxChars", "Maximum allowed characters", "textstringlimited", Description = "If empty, 500 character limit")] + [ConfigurationField("maxChars", "Maximum allowed characters", "textstringlimited", Description = "If empty, 512 character limit")] public int? MaxChars { get; set; } } } diff --git a/src/Umbraco.Core/PublishedContentExtensions.cs b/src/Umbraco.Core/PublishedContentExtensions.cs index 03ce0c066a..62f48917c3 100644 --- a/src/Umbraco.Core/PublishedContentExtensions.cs +++ b/src/Umbraco.Core/PublishedContentExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -149,7 +150,7 @@ namespace Umbraco.Core } public static bool IsAllowedTemplate(this IPublishedContent content, IContentTypeService contentTypeService, - IWebRoutingSettings webRoutingSettings, int templateId) + WebRoutingSettings webRoutingSettings, int templateId) { return content.IsAllowedTemplate(contentTypeService, webRoutingSettings.DisableAlternativeTemplates, diff --git a/src/Umbraco.Core/Routing/AliasUrlProvider.cs b/src/Umbraco.Core/Routing/AliasUrlProvider.cs index e71de2f6c6..0d919614f3 100644 --- a/src/Umbraco.Core/Routing/AliasUrlProvider.cs +++ b/src/Umbraco.Core/Routing/AliasUrlProvider.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; @@ -13,17 +15,15 @@ namespace Umbraco.Web.Routing /// public class AliasUrlProvider : IUrlProvider { - private readonly IGlobalSettings _globalSettings; - private readonly IRequestHandlerSettings _requestConfig; + private readonly RequestHandlerSettings _requestConfig; private readonly ISiteDomainHelper _siteDomainHelper; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly UriUtility _uriUtility; private readonly IPublishedValueFallback _publishedValueFallback; - public AliasUrlProvider(IGlobalSettings globalSettings, IRequestHandlerSettings requestConfig, ISiteDomainHelper siteDomainHelper, UriUtility uriUtility, IPublishedValueFallback publishedValueFallback, IUmbracoContextAccessor umbracoContextAccessor) + public AliasUrlProvider(IOptions requestConfig, ISiteDomainHelper siteDomainHelper, UriUtility uriUtility, IPublishedValueFallback publishedValueFallback, IUmbracoContextAccessor umbracoContextAccessor) { - _globalSettings = globalSettings; - _requestConfig = requestConfig; + _requestConfig = requestConfig.Value; _siteDomainHelper = siteDomainHelper; _uriUtility = uriUtility; _publishedValueFallback = publishedValueFallback; @@ -100,7 +100,7 @@ namespace Umbraco.Web.Routing { var path = "/" + alias; var uri = new Uri(path, UriKind.Relative); - yield return UrlInfo.Url(_uriUtility.UriFromUmbraco(uri, _globalSettings, _requestConfig).ToString()); + yield return UrlInfo.Url(_uriUtility.UriFromUmbraco(uri, _requestConfig).ToString()); } } else @@ -127,7 +127,7 @@ namespace Umbraco.Web.Routing { var path = "/" + alias; var uri = new Uri(CombinePaths(domainUri.Uri.GetLeftPart(UriPartial.Path), path)); - yield return UrlInfo.Url(_uriUtility.UriFromUmbraco(uri, _globalSettings, _requestConfig).ToString(), domainUri.Culture.Name); + yield return UrlInfo.Url(_uriUtility.UriFromUmbraco(uri, _requestConfig).ToString(), domainUri.Culture.Name); } } } diff --git a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs index 4b58832e8e..a9d67c24fb 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs @@ -4,6 +4,8 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; using System.Globalization; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Routing { @@ -17,11 +19,11 @@ namespace Umbraco.Web.Routing { private readonly ILogger _logger; private readonly IRequestAccessor _requestAccessor; - private readonly IWebRoutingSettings _webRoutingSettings; + private readonly WebRoutingSettings _webRoutingSettings; - public ContentFinderByIdPath(IWebRoutingSettings webRoutingSettings, ILogger logger, IRequestAccessor requestAccessor) + public ContentFinderByIdPath(IOptions webRoutingSettings, ILogger logger, IRequestAccessor requestAccessor) { - _webRoutingSettings = webRoutingSettings ?? throw new System.ArgumentNullException(nameof(webRoutingSettings)); + _webRoutingSettings = webRoutingSettings.Value ?? throw new System.ArgumentNullException(nameof(webRoutingSettings)); _logger = logger ?? throw new System.ArgumentNullException(nameof(logger)); _requestAccessor = requestAccessor; } diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs index 7bcea4681e..b6a01c0c51 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs @@ -3,6 +3,8 @@ using Umbraco.Core; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Routing { @@ -19,14 +21,14 @@ namespace Umbraco.Web.Routing private readonly IFileService _fileService; private readonly IContentTypeService _contentTypeService; - private readonly IWebRoutingSettings _webRoutingSettings; + private readonly WebRoutingSettings _webRoutingSettings; - public ContentFinderByUrlAndTemplate(ILogger logger, IFileService fileService, IContentTypeService contentTypeService, IWebRoutingSettings webRoutingSettings) + public ContentFinderByUrlAndTemplate(ILogger logger, IFileService fileService, IContentTypeService contentTypeService, IOptions webRoutingSettings) : base(logger) { _fileService = fileService; _contentTypeService = contentTypeService; - _webRoutingSettings = webRoutingSettings; + _webRoutingSettings = webRoutingSettings.Value; } /// diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs index f56d96b6b3..2af36465dd 100644 --- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; @@ -12,18 +14,18 @@ namespace Umbraco.Web.Routing /// public class DefaultUrlProvider : IUrlProvider { - private readonly IRequestHandlerSettings _requestSettings; + private readonly RequestHandlerSettings _requestSettings; private readonly ILogger _logger; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly ISiteDomainHelper _siteDomainHelper; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly UriUtility _uriUtility; - public DefaultUrlProvider(IRequestHandlerSettings requestSettings, ILogger logger, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IUmbracoContextAccessor umbracoContextAccessor, UriUtility uriUtility) + public DefaultUrlProvider(IOptions requestSettings, ILogger logger, IOptions globalSettings, ISiteDomainHelper siteDomainHelper, IUmbracoContextAccessor umbracoContextAccessor, UriUtility uriUtility) { - _requestSettings = requestSettings; + _requestSettings = requestSettings.Value; _logger = logger; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _siteDomainHelper = siteDomainHelper; _uriUtility = uriUtility; _umbracoContextAccessor = umbracoContextAccessor; @@ -113,7 +115,7 @@ namespace Umbraco.Web.Routing var path = pos == 0 ? route : route.Substring(pos); var uri = new Uri(CombinePaths(d.Uri.GetLeftPart(UriPartial.Path), path)); - uri = _uriUtility.UriFromUmbraco(uri, _globalSettings, _requestSettings); + uri = _uriUtility.UriFromUmbraco(uri, _requestSettings); yield return UrlInfo.Url(uri.ToString(), culture); } } @@ -172,7 +174,7 @@ namespace Umbraco.Web.Routing // UriFromUmbraco will handle vdir // meaning it will add vdir into domain urls too! - return _uriUtility.UriFromUmbraco(uri, _globalSettings, _requestSettings); + return _uriUtility.UriFromUmbraco(uri, _requestSettings); } string CombinePaths(string path1, string path2) diff --git a/src/Umbraco.Core/Routing/PublishedRequest.cs b/src/Umbraco.Core/Routing/PublishedRequest.cs index a46eb26e7e..3e13270fa0 100644 --- a/src/Umbraco.Core/Routing/PublishedRequest.cs +++ b/src/Umbraco.Core/Routing/PublishedRequest.cs @@ -5,6 +5,8 @@ using System.Threading; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Routing { @@ -16,7 +18,7 @@ namespace Umbraco.Web.Routing public class PublishedRequest : IPublishedRequest { private readonly IPublishedRouter _publishedRouter; - private readonly IWebRoutingSettings _webRoutingSettings; + private readonly WebRoutingSettings _webRoutingSettings; private bool _readonly; // after prepared private bool _readonlyUri; // after preparing @@ -33,11 +35,11 @@ namespace Umbraco.Web.Routing /// The published router. /// The Umbraco context. /// The request Uri. - public PublishedRequest(IPublishedRouter publishedRouter, IUmbracoContext umbracoContext, IWebRoutingSettings webRoutingSettings, Uri uri = null) + public PublishedRequest(IPublishedRouter publishedRouter, IUmbracoContext umbracoContext, IOptions webRoutingSettings, Uri uri = null) { UmbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); _publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter)); - _webRoutingSettings = webRoutingSettings; + _webRoutingSettings = webRoutingSettings.Value; Uri = uri ?? umbracoContext.CleanedUmbracoUrl; } diff --git a/src/Umbraco.Core/Routing/PublishedRouter.cs b/src/Umbraco.Core/Routing/PublishedRouter.cs index 1a422dea92..6de64800c3 100644 --- a/src/Umbraco.Core/Routing/PublishedRouter.cs +++ b/src/Umbraco.Core/Routing/PublishedRouter.cs @@ -10,6 +10,8 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Web.Security; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Routing { @@ -18,7 +20,7 @@ namespace Umbraco.Web.Routing /// public class PublishedRouter : IPublishedRouter { - private readonly IWebRoutingSettings _webRoutingSettings; + private readonly WebRoutingSettings _webRoutingSettings; private readonly ContentFinderCollection _contentFinders; private readonly IContentLastChanceFinder _contentLastChanceFinder; private readonly IProfilingLogger _profilingLogger; @@ -36,7 +38,7 @@ namespace Umbraco.Web.Routing /// Initializes a new instance of the class. /// public PublishedRouter( - IWebRoutingSettings webRoutingSettings, + IOptions webRoutingSettings, ContentFinderCollection contentFinders, IContentLastChanceFinder contentLastChanceFinder, IVariationContextAccessor variationContextAccessor, @@ -49,7 +51,7 @@ namespace Umbraco.Web.Routing IContentTypeService contentTypeService, IPublicAccessService publicAccessService) { - _webRoutingSettings = webRoutingSettings ?? throw new ArgumentNullException(nameof(webRoutingSettings)); + _webRoutingSettings = webRoutingSettings.Value ?? 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)); @@ -67,7 +69,7 @@ namespace Umbraco.Web.Routing /// public IPublishedRequest CreateRequest(IUmbracoContext umbracoContext, Uri uri = null) { - return new PublishedRequest(this, umbracoContext, _webRoutingSettings, uri ?? umbracoContext.CleanedUmbracoUrl); + return new PublishedRequest(this, umbracoContext, Options.Create(_webRoutingSettings), uri ?? umbracoContext.CleanedUmbracoUrl); } #region Request diff --git a/src/Umbraco.Core/Routing/UriUtility.cs b/src/Umbraco.Core/Routing/UriUtility.cs index 1ff6ba7436..1bcfab6490 100644 --- a/src/Umbraco.Core/Routing/UriUtility.cs +++ b/src/Umbraco.Core/Routing/UriUtility.cs @@ -2,6 +2,7 @@ using System.Text; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Hosting; @@ -62,7 +63,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, IRequestHandlerSettings requestConfig) + public Uri UriFromUmbraco(Uri uri, RequestHandlerSettings requestConfig) { var path = uri.GetSafeAbsolutePath(); diff --git a/src/Umbraco.Core/Routing/UrlProvider.cs b/src/Umbraco.Core/Routing/UrlProvider.cs index fa764cf7ff..69d2e00276 100644 --- a/src/Umbraco.Core/Routing/UrlProvider.cs +++ b/src/Umbraco.Core/Routing/UrlProvider.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Configuration.UmbracoSettings; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Routing @@ -24,10 +25,8 @@ namespace Umbraco.Web.Routing /// The list of media url providers. /// The current variation accessor. /// - public UrlProvider(IUmbracoContextAccessor umbracoContextAccessor, IWebRoutingSettings routingSettings, UrlProviderCollection urlProviders, MediaUrlProviderCollection mediaUrlProviders, IVariationContextAccessor variationContextAccessor) + public UrlProvider(IUmbracoContextAccessor umbracoContextAccessor, IOptions routingSettings, UrlProviderCollection urlProviders, MediaUrlProviderCollection mediaUrlProviders, IVariationContextAccessor variationContextAccessor) { - if (routingSettings == null) throw new ArgumentNullException(nameof(routingSettings)); - _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _urlProviders = urlProviders; _mediaUrlProviders = mediaUrlProviders; @@ -35,7 +34,7 @@ namespace Umbraco.Web.Routing var provider = UrlMode.Auto; Mode = provider; - if (Enum.TryParse(routingSettings.UrlProviderMode, out provider)) + if (Enum.TryParse(routingSettings.Value.UrlProviderMode, out provider)) { Mode = provider; } diff --git a/src/Umbraco.Core/Scheduling/KeepAlive.cs b/src/Umbraco.Core/Scheduling/KeepAlive.cs index a47080912c..98c6268e69 100644 --- a/src/Umbraco.Core/Scheduling/KeepAlive.cs +++ b/src/Umbraco.Core/Scheduling/KeepAlive.cs @@ -2,8 +2,9 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Sync; @@ -13,22 +14,24 @@ namespace Umbraco.Web.Scheduling { private readonly IRequestAccessor _requestAccessor; private readonly IMainDom _mainDom; - private readonly IKeepAliveSettings _keepAliveSettings; + private readonly KeepAliveSettings _keepAliveSettings; private readonly IProfilingLogger _logger; private readonly IServerRegistrar _serverRegistrar; private static HttpClient _httpClient; public KeepAlive(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, - IRequestAccessor requestAccessor, IMainDom mainDom, IKeepAliveSettings keepAliveSettings, IProfilingLogger logger, IServerRegistrar serverRegistrar) + IRequestAccessor requestAccessor, IMainDom mainDom, IOptions keepAliveSettings, IProfilingLogger logger, IServerRegistrar serverRegistrar) : base(runner, delayMilliseconds, periodMilliseconds) { _requestAccessor = requestAccessor; _mainDom = mainDom; - _keepAliveSettings = keepAliveSettings; + _keepAliveSettings = keepAliveSettings.Value; _logger = logger; _serverRegistrar = serverRegistrar; if (_httpClient == null) + { _httpClient = new HttpClient(); + } } public override async Task PerformRunAsync(CancellationToken token) diff --git a/src/Umbraco.Core/Security/IWebSecurity.cs b/src/Umbraco.Core/Security/IBackofficeSecurity.cs similarity index 97% rename from src/Umbraco.Core/Security/IWebSecurity.cs rename to src/Umbraco.Core/Security/IBackofficeSecurity.cs index 594f6d96ea..3a0e0baa1d 100644 --- a/src/Umbraco.Core/Security/IWebSecurity.cs +++ b/src/Umbraco.Core/Security/IBackofficeSecurity.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Models.Membership; namespace Umbraco.Web.Security { - public interface IWebSecurity + public interface IBackofficeSecurity { /// /// Gets the current user. diff --git a/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs b/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs new file mode 100644 index 0000000000..d3cea99f9f --- /dev/null +++ b/src/Umbraco.Core/Security/IBackofficeSecurityAccessor.cs @@ -0,0 +1,9 @@ +using Umbraco.Web.Security; + +namespace Umbraco.Core.Security +{ + public interface IBackofficeSecurityAccessor + { + IBackofficeSecurity BackofficeSecurity { get; set; } + } +} diff --git a/src/Umbraco.Core/Services/IIconService.cs b/src/Umbraco.Core/Services/IIconService.cs new file mode 100644 index 0000000000..9ae9164c72 --- /dev/null +++ b/src/Umbraco.Core/Services/IIconService.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Web.Models; + +namespace Umbraco.Core.Services +{ + public interface IIconService + { + /// + /// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path + /// + /// + /// + IconModel GetIcon(string iconName); + + /// + /// Gets a list of all svg icons found at at the global icons path. + /// + /// + IList GetAllIcons(); + } +} diff --git a/src/Umbraco.Core/Services/IRuntimeState.cs b/src/Umbraco.Core/Services/IRuntimeState.cs index 4b57908ea7..fd817f1986 100644 --- a/src/Umbraco.Core/Services/IRuntimeState.cs +++ b/src/Umbraco.Core/Services/IRuntimeState.cs @@ -50,5 +50,10 @@ namespace Umbraco.Core /// BootFailedException BootFailedException { get; } + /// + /// Determines the runtime level. + /// + void DetermineRuntimeLevel(); + } } diff --git a/src/Umbraco.Core/SimpleMainDom.cs b/src/Umbraco.Core/SimpleMainDom.cs index e6bdda67d7..a2ef0b8d78 100644 --- a/src/Umbraco.Core/SimpleMainDom.cs +++ b/src/Umbraco.Core/SimpleMainDom.cs @@ -8,11 +8,12 @@ namespace Umbraco.Core /// /// Provides a simple implementation of . /// - public class SimpleMainDom : IMainDom + public class SimpleMainDom : IMainDom, IDisposable { private readonly object _locko = new object(); private readonly List> _callbacks = new List>(); private bool _isStopping; + private bool _disposedValue; /// public bool IsMainDom { get; private set; } = true; @@ -59,5 +60,24 @@ namespace Umbraco.Core IsMainDom = false; } } + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + Stop(); + } + _disposedValue = true; + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } } } diff --git a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs index c3e7fa85c3..3894525d2d 100644 --- a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs +++ b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs @@ -4,6 +4,8 @@ using System.IO; using System.Linq; using System.Globalization; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Core.Strings { @@ -19,9 +21,9 @@ namespace Umbraco.Core.Strings { #region Ctor, consts and vars - public DefaultShortStringHelper(IRequestHandlerSettings settings) + public DefaultShortStringHelper(IOptions settings) { - _config = new DefaultShortStringHelperConfig().WithDefault(settings); + _config = new DefaultShortStringHelperConfig().WithDefault(settings.Value); } // clones the config so it cannot be changed at runtime diff --git a/src/Umbraco.Core/Strings/DefaultShortStringHelperConfig.cs b/src/Umbraco.Core/Strings/DefaultShortStringHelperConfig.cs index 25ee781ae9..d6adf5b221 100644 --- a/src/Umbraco.Core/Strings/DefaultShortStringHelperConfig.cs +++ b/src/Umbraco.Core/Strings/DefaultShortStringHelperConfig.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; namespace Umbraco.Core.Strings @@ -57,16 +58,16 @@ namespace Umbraco.Core.Strings /// Sets the default configuration. /// /// The short string helper. - public DefaultShortStringHelperConfig WithDefault(IRequestHandlerSettings requestHandlerSettings) + public DefaultShortStringHelperConfig WithDefault(RequestHandlerSettings requestHandlerSettings) { UrlReplaceCharacters = requestHandlerSettings.CharCollection .Where(x => string.IsNullOrEmpty(x.Char) == false) .ToDictionary(x => x.Char, x => x.Replacement); var urlSegmentConvertTo = CleanStringType.Utf8; - if (requestHandlerSettings.ConvertUrlsToAscii) + if (requestHandlerSettings.ShouldConvertUrlsToAscii) urlSegmentConvertTo = CleanStringType.Ascii; - if (requestHandlerSettings.TryConvertUrlsToAscii) + if (requestHandlerSettings.ShouldTryConvertUrlsToAscii) 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 566fce8b87..60b6f829b0 100644 --- a/src/Umbraco.Core/Templates/HtmlUrlParser.cs +++ b/src/Umbraco.Core/Templates/HtmlUrlParser.cs @@ -1,5 +1,6 @@ using System.Text.RegularExpressions; -using Umbraco.Core.Configuration.UmbracoSettings; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -7,16 +8,16 @@ namespace Umbraco.Web.Templates { public sealed class HtmlUrlParser { - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _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(IContentSettings contentSettings, IProfilingLogger logger, IIOHelper ioHelper) + public HtmlUrlParser(IOptions contentSettings, IProfilingLogger logger, IIOHelper ioHelper) { - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _ioHelper = ioHelper; _logger = logger; } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b5e553a78e..43e3d208f0 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -15,16 +15,20 @@ + - - + + <_Parameter1>Umbraco.Tests + + <_Parameter1>Umbraco.Tests.Common + <_Parameter1>Umbraco.Tests.UnitTests diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 13aa6bde46..9a49df7d95 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -3,8 +3,8 @@ using System.IO; using System.Linq; using Umbraco.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; namespace Umbraco.Core { @@ -38,7 +38,7 @@ namespace Umbraco.Core /// But if we've got this far we'll just have to assume it's front-end anyways. /// /// - public static bool IsBackOfficeRequest(this Uri url, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + public static bool IsBackOfficeRequest(this Uri url, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { var applicationPath = hostingEnvironment.ApplicationVirtualPath; @@ -128,7 +128,7 @@ namespace Umbraco.Core /// /// /// - internal static bool IsDefaultBackOfficeRequest(this Uri url, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + internal static bool IsDefaultBackOfficeRequest(this Uri url, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { var backOfficePath = globalSettings.GetBackOfficePath(hostingEnvironment); if (url.AbsolutePath.InvariantEquals(backOfficePath.TrimEnd("/")) diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs index b7d9cde9d1..b1254a4beb 100644 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs @@ -20,6 +20,7 @@ namespace Umbraco.Examine composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Examine.Lucene/ILuceneDirectoryFactory.cs b/src/Umbraco.Examine.Lucene/ILuceneDirectoryFactory.cs new file mode 100644 index 0000000000..f4946d491e --- /dev/null +++ b/src/Umbraco.Examine.Lucene/ILuceneDirectoryFactory.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Examine +{ + public interface ILuceneDirectoryFactory + { + Lucene.Net.Store.Directory CreateDirectory(string indexName); + } +} diff --git a/src/Umbraco.Examine.Lucene/LuceneFileSystemDirectoryFactory.cs b/src/Umbraco.Examine.Lucene/LuceneFileSystemDirectoryFactory.cs new file mode 100644 index 0000000000..32c441ab28 --- /dev/null +++ b/src/Umbraco.Examine.Lucene/LuceneFileSystemDirectoryFactory.cs @@ -0,0 +1,71 @@ +using Umbraco.Core.Configuration; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Hosting; +using Lucene.Net.Store; +using System.IO; +using System; +using Examine.LuceneEngine.Directories; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; + +namespace Umbraco.Examine +{ + + public class LuceneFileSystemDirectoryFactory : ILuceneDirectoryFactory + { + private readonly ITypeFinder _typeFinder; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IndexCreatorSettings _settings; + + public LuceneFileSystemDirectoryFactory(ITypeFinder typeFinder, IHostingEnvironment hostingEnvironment, IOptions settings) + { + _typeFinder = typeFinder; + _hostingEnvironment = hostingEnvironment; + _settings = settings.Value; + } + + public Lucene.Net.Store.Directory CreateDirectory(string indexName) => CreateFileSystemLuceneDirectory(indexName); + + /// + /// Creates a file system based Lucene with the correct locking guidelines for Umbraco + /// + /// + /// The folder name to store the index (single word, not a fully qualified folder) (i.e. Internal) + /// + /// + public virtual Lucene.Net.Store.Directory CreateFileSystemLuceneDirectory(string folderName) + { + + var dirInfo = new DirectoryInfo(Path.Combine(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempData), "ExamineIndexes", folderName)); + if (!dirInfo.Exists) + System.IO.Directory.CreateDirectory(dirInfo.FullName); + + //check if there's a configured directory factory, if so create it and use that to create the lucene dir + var configuredDirectoryFactory = _settings.LuceneDirectoryFactory; + + if (!configuredDirectoryFactory.IsNullOrWhiteSpace()) + { + //this should be a fully qualified type + var factoryType = _typeFinder.GetTypeByName(configuredDirectoryFactory); + if (factoryType == null) throw new NullReferenceException("No directory type found for value: " + configuredDirectoryFactory); + var directoryFactory = (IDirectoryFactory)Activator.CreateInstance(factoryType); + return directoryFactory.CreateDirectory(dirInfo); + } + + //no dir factory, just create a normal fs directory + + var luceneDir = new SimpleFSDirectory(dirInfo); + + //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain + //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock + //which simply checks the existence of the lock file + // The full syntax of this is: new NoPrefixSimpleFsLockFactory(dirInfo) + // however, we are setting the DefaultLockFactory in startup so we'll use that instead since it can be managed globally. + luceneDir.SetLockFactory(DirectoryFactory.DefaultLockFactory(dirInfo)); + return luceneDir; + + + } + } +} diff --git a/src/Umbraco.Examine.Lucene/LuceneIndexCreator.cs b/src/Umbraco.Examine.Lucene/LuceneIndexCreator.cs index 9efcdc4891..8ecb1b4421 100644 --- a/src/Umbraco.Examine.Lucene/LuceneIndexCreator.cs +++ b/src/Umbraco.Examine.Lucene/LuceneIndexCreator.cs @@ -4,11 +4,11 @@ using System.IO; using Examine; using Examine.LuceneEngine.Directories; using Lucene.Net.Store; -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; namespace Umbraco.Examine { @@ -20,56 +20,15 @@ namespace Umbraco.Examine { private readonly ITypeFinder _typeFinder; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IIndexCreatorSettings _settings; + private readonly IndexCreatorSettings _settings; - protected LuceneIndexCreator(ITypeFinder typeFinder, IHostingEnvironment hostingEnvironment, IIndexCreatorSettings settings) + protected LuceneIndexCreator(ITypeFinder typeFinder, IHostingEnvironment hostingEnvironment, IOptions settings) { _typeFinder = typeFinder; _hostingEnvironment = hostingEnvironment; - _settings = settings; + _settings = settings.Value; } - public abstract IEnumerable Create(); - - /// - /// Creates a file system based Lucene with the correct locking guidelines for Umbraco - /// - /// - /// The folder name to store the index (single word, not a fully qualified folder) (i.e. Internal) - /// - /// - public virtual Lucene.Net.Store.Directory CreateFileSystemLuceneDirectory(string folderName) - { - - var dirInfo = new DirectoryInfo(Path.Combine(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempData), "ExamineIndexes", folderName)); - if (!dirInfo.Exists) - System.IO.Directory.CreateDirectory(dirInfo.FullName); - - //check if there's a configured directory factory, if so create it and use that to create the lucene dir - var configuredDirectoryFactory = _settings.LuceneDirectoryFactory; - - if (!configuredDirectoryFactory.IsNullOrWhiteSpace()) - { - //this should be a fully qualified type - var factoryType = _typeFinder.GetTypeByName(configuredDirectoryFactory); - if (factoryType == null) throw new NullReferenceException("No directory type found for value: " + configuredDirectoryFactory); - var directoryFactory = (IDirectoryFactory)Activator.CreateInstance(factoryType); - return directoryFactory.CreateDirectory(dirInfo); - } - - //no dir factory, just create a normal fs directory - - var luceneDir = new SimpleFSDirectory(dirInfo); - - //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain - //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock - //which simply checks the existence of the lock file - // The full syntax of this is: new NoPrefixSimpleFsLockFactory(dirInfo) - // however, we are setting the DefaultLockFactory in startup so we'll use that instead since it can be managed globally. - luceneDir.SetLockFactory(DirectoryFactory.DefaultLockFactory(dirInfo)); - return luceneDir; - - - } + public abstract IEnumerable Create(); } } diff --git a/src/Umbraco.Examine.Lucene/LuceneRAMDirectoryFactory.cs b/src/Umbraco.Examine.Lucene/LuceneRAMDirectoryFactory.cs new file mode 100644 index 0000000000..327328390b --- /dev/null +++ b/src/Umbraco.Examine.Lucene/LuceneRAMDirectoryFactory.cs @@ -0,0 +1,24 @@ +using Lucene.Net.Store; +using System; + +namespace Umbraco.Examine +{ + public class LuceneRAMDirectoryFactory : ILuceneDirectoryFactory + { + public LuceneRAMDirectoryFactory() + { + + } + + public Lucene.Net.Store.Directory CreateDirectory(string indexName) => new RandomIdRAMDirectory(); + + private class RandomIdRAMDirectory : RAMDirectory + { + private readonly string _lockId = Guid.NewGuid().ToString(); + public override string GetLockId() + { + return _lockId; + } + } + } +} diff --git a/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs b/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs index dc2a5570a6..4cb26d5ae5 100644 --- a/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs +++ b/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs @@ -19,9 +19,8 @@ namespace Umbraco.Examine /// /// An indexer for Umbraco content and media /// - public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex + public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex, IDisposable { - protected ILocalizationService LanguageService { get; } #region Constructors diff --git a/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs b/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs index 3cf7d6d386..39113b4f50 100644 --- a/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs +++ b/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs @@ -9,9 +9,12 @@ using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Hosting; using Umbraco.Core.IO; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Examine { + /// /// Creates the indexes used by Umbraco /// @@ -28,7 +31,8 @@ namespace Umbraco.Examine IUmbracoIndexConfig umbracoIndexConfig, IHostingEnvironment hostingEnvironment, IRuntimeState runtimeState, - IIndexCreatorSettings settings) : base(typeFinder, hostingEnvironment, settings) + IOptions settings, + ILuceneDirectoryFactory directoryFactory) : base(typeFinder, hostingEnvironment, settings) { ProfilingLogger = profilingLogger ?? throw new System.ArgumentNullException(nameof(profilingLogger)); LanguageService = languageService ?? throw new System.ArgumentNullException(nameof(languageService)); @@ -37,11 +41,13 @@ namespace Umbraco.Examine UmbracoIndexConfig = umbracoIndexConfig; HostingEnvironment = hostingEnvironment ?? throw new System.ArgumentNullException(nameof(hostingEnvironment)); RuntimeState = runtimeState ?? throw new System.ArgumentNullException(nameof(runtimeState)); + DirectoryFactory = directoryFactory; } protected IProfilingLogger ProfilingLogger { get; } protected IHostingEnvironment HostingEnvironment { get; } protected IRuntimeState RuntimeState { get; } + protected ILuceneDirectoryFactory DirectoryFactory { get; } protected ILocalizationService LanguageService { get; } protected IPublicAccessService PublicAccessService { get; } protected IMemberService MemberService { get; } @@ -65,7 +71,7 @@ namespace Umbraco.Examine { var index = new UmbracoContentIndex( Constants.UmbracoIndexes.InternalIndexName, - CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.InternalIndexPath), + DirectoryFactory.CreateDirectory(Constants.UmbracoIndexes.InternalIndexPath), new UmbracoFieldDefinitionCollection(), new CultureInvariantWhitespaceAnalyzer(), ProfilingLogger, @@ -81,7 +87,7 @@ namespace Umbraco.Examine { var index = new UmbracoContentIndex( Constants.UmbracoIndexes.ExternalIndexName, - CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.ExternalIndexPath), + DirectoryFactory.CreateDirectory(Constants.UmbracoIndexes.ExternalIndexPath), new UmbracoFieldDefinitionCollection(), new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30), ProfilingLogger, @@ -97,7 +103,7 @@ namespace Umbraco.Examine var index = new UmbracoMemberIndex( Constants.UmbracoIndexes.MembersIndexName, new UmbracoFieldDefinitionCollection(), - CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.MembersIndexPath), + DirectoryFactory.CreateDirectory(Constants.UmbracoIndexes.MembersIndexPath), new CultureInvariantWhitespaceAnalyzer(), ProfilingLogger, HostingEnvironment, diff --git a/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs b/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs index c901c14ee1..8a7186da77 100644 --- a/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs +++ b/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs @@ -7,13 +7,14 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Security; using Umbraco.Extensions; using Umbraco.Net; namespace Umbraco.Core.BackOffice { - public class BackOfficeUserManager : BackOfficeUserManager + public class BackOfficeUserManager : BackOfficeUserManager, IBackOfficeUserManager { public BackOfficeUserManager( IIpResolver ipResolver, @@ -26,7 +27,7 @@ namespace Umbraco.Core.BackOffice BackOfficeIdentityErrorDescriber errors, IServiceProvider services, ILogger> logger, - IUserPasswordConfiguration passwordConfiguration) + IOptions passwordConfiguration) : base(ipResolver, store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger, passwordConfiguration) { } @@ -48,11 +49,11 @@ namespace Umbraco.Core.BackOffice BackOfficeIdentityErrorDescriber errors, IServiceProvider services, ILogger> logger, - IUserPasswordConfiguration passwordConfiguration) + IOptions passwordConfiguration) : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger) { IpResolver = ipResolver ?? throw new ArgumentNullException(nameof(ipResolver)); - PasswordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration)); + PasswordConfiguration = passwordConfiguration.Value ?? throw new ArgumentNullException(nameof(passwordConfiguration)); } #region What we do not currently support diff --git a/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserStore.cs b/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserStore.cs index 96b3d8559a..d14a951877 100644 --- a/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserStore.cs +++ b/src/Umbraco.Infrastructure/BackOffice/BackOfficeUserStore.cs @@ -5,7 +5,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Identity; @@ -32,16 +34,16 @@ namespace Umbraco.Core.BackOffice private readonly IUserService _userService; private readonly IEntityService _entityService; private readonly IExternalLoginService _externalLoginService; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly UmbracoMapper _mapper; private bool _disposed = false; - public BackOfficeUserStore(IUserService userService, IEntityService entityService, IExternalLoginService externalLoginService, IGlobalSettings globalSettings, UmbracoMapper mapper) + public BackOfficeUserStore(IUserService userService, IEntityService entityService, IExternalLoginService externalLoginService, IOptions globalSettings, UmbracoMapper mapper) { _userService = userService; _entityService = entityService; _externalLoginService = externalLoginService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; if (userService == null) throw new ArgumentNullException("userService"); if (externalLoginService == null) throw new ArgumentNullException("externalLoginService"); _mapper = mapper; diff --git a/src/Umbraco.Infrastructure/BackOffice/IBackOfficeUserManager.cs b/src/Umbraco.Infrastructure/BackOffice/IBackOfficeUserManager.cs new file mode 100644 index 0000000000..e4cff3e042 --- /dev/null +++ b/src/Umbraco.Infrastructure/BackOffice/IBackOfficeUserManager.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.Security.Principal; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; + + +namespace Umbraco.Core.BackOffice +{ + public interface IBackOfficeUserManager : IBackOfficeUserManager + { + + } + public interface IBackOfficeUserManager: IDisposable + where TUser : BackOfficeIdentityUser + { + + /// + /// Finds and returns a user, if any, who has the specified . + /// + /// The user ID to search for. + /// + /// The that represents the asynchronous operation, containing the user matching the specified if it exists. + /// + Task FindByIdAsync(string userId); + + /// + /// Generates a password reset token for the specified , using + /// the configured password reset token provider. + /// + /// The user to generate a password reset token for. + /// The that represents the asynchronous operation, + /// containing a password reset token for the specified . + Task GeneratePasswordResetTokenAsync(TUser user); + + /// + /// This is a special method that will reset the password but will raise the Password Changed event instead of the reset event + /// + /// + /// + /// + /// + /// + /// We use this because in the back office the only way an admin can change another user's password without first knowing their password + /// is to generate a token and reset it, however, when we do this we want to track a password change, not a password reset + /// + Task ChangePasswordWithResetAsync(int userId, string token, string newPassword); + + /// + /// Validates that an email confirmation token matches the specified . + /// + /// The user to validate the token against. + /// The email confirmation token to validate. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task ConfirmEmailAsync(TUser user, string token); + + /// + /// Gets the user, if any, associated with the normalized value of the specified email address. + /// Note: Its recommended that identityOptions.User.RequireUniqueEmail be set to true when using this method, otherwise + /// the store may throw if there are users with duplicate emails. + /// + /// The email address to return the user for. + /// + /// The task object containing the results of the asynchronous lookup operation, the user, if any, associated with a normalized value of the specified email address. + /// + Task FindByEmailAsync(string email); + + /// + /// Resets the 's password to the specified after + /// validating the given password reset . + /// + /// The user whose password should be reset. + /// The password reset token to verify. + /// The new password to set if reset token verification succeeds. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task ResetPasswordAsync(TUser user, string token, string newPassword); + + /// + /// Override to check the user approval value as well as the user lock out date, by default this only checks the user's locked out date + /// + /// + /// + /// + /// In the ASP.NET Identity world, there is only one value for being locked out, in Umbraco we have 2 so when checking this for Umbraco we need to check both values + /// + Task IsLockedOutAsync(TUser user); + + /// + /// Locks out a user until the specified end date has passed. Setting a end date in the past immediately unlocks a user. + /// + /// The user whose lockout date should be set. + /// The after which the 's lockout should end. + /// The that represents the asynchronous operation, containing the of the operation. + Task SetLockoutEndDateAsync(TUser user, DateTimeOffset? lockoutEnd); + + /// + /// Gets a flag indicating whether the email address for the specified has been verified, true if the email address is verified otherwise + /// false. + /// + /// The user whose email confirmation status should be returned. + /// + /// The task object containing the results of the asynchronous operation, a flag indicating whether the email address for the specified + /// has been confirmed or not. + /// + Task IsEmailConfirmedAsync(TUser user); + + /// + /// Updates the specified in the backing store. + /// + /// The user to update. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task UpdateAsync(TUser user); + + /// + /// Returns a flag indicating whether the specified is valid for + /// the given and . + /// + /// The user to validate the token against. + /// The token provider used to generate the token. + /// The purpose the token should be generated for. + /// The token to validate + /// + /// The that represents the asynchronous operation, returning true if the + /// is valid, otherwise false. + /// + Task VerifyUserTokenAsync(TUser user, string tokenProvider, string purpose, + string token); + + /// + /// Adds the to the specified only if the user + /// does not already have a password. + /// + /// The user whose password should be set. + /// The password to set. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task AddPasswordAsync(TUser user, string password); + + + /// + /// Returns a flag indicating whether the given is valid for the + /// specified . + /// + /// The user whose password should be validated. + /// The password to validate + /// The that represents the asynchronous operation, containing true if + /// the specified matches the one store for the , + /// otherwise false. + Task CheckPasswordAsync(TUser user, string password); + + /// + /// Changes a user's password after confirming the specified is correct, + /// as an asynchronous operation. + /// + /// The user whose password should be set. + /// The current password to validate before changing. + /// The new password to set for the specified . + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task ChangePasswordAsync(TUser user, string currentPassword, + string newPassword); + + /// + /// Used to validate a user's session + /// + /// + /// + /// + Task ValidateSessionIdAsync(string userId, string sessionId); + + /// + /// Creates the specified in the backing store with no password, + /// as an asynchronous operation. + /// + /// The user to create. + /// + /// The that represents the asynchronous operation, containing the + /// of the operation. + /// + Task CreateAsync(TUser user); + + /// + /// Helper method to generate a password for a user based on the current password validator + /// + /// + string GeneratePassword(); + + + /// + /// Generates an email confirmation token for the specified user. + /// + /// The user to generate an email confirmation token for. + /// + /// The that represents the asynchronous operation, an email confirmation token. + /// + Task GenerateEmailConfirmationTokenAsync(TUser user); + + /// + /// Finds and returns a user, if any, who has the specified user name. + /// + /// The user name to search for. + /// + /// The that represents the asynchronous operation, containing the user matching the specified if it exists. + /// + Task FindByNameAsync(string userName); + + /// + /// Increments the access failed count for the user as an asynchronous operation. + /// If the failed access account is greater than or equal to the configured maximum number of attempts, + /// the user will be locked out for the configured lockout time span. + /// + /// The user whose failed access count to increment. + /// The that represents the asynchronous operation, containing the of the operation. + Task AccessFailedAsync(TUser user); + + /// + /// Returns a flag indicating whether the specified has two factor authentication enabled or not, + /// as an asynchronous operation. + /// + /// The user whose two factor authentication enabled status should be retrieved. + /// + /// The that represents the asynchronous operation, true if the specified + /// has two factor authentication enabled, otherwise false. + /// + Task GetTwoFactorEnabledAsync(TUser user); + + /// + /// Gets a list of valid two factor token providers for the specified , + /// as an asynchronous operation. + /// + /// The user the whose two factor authentication providers will be returned. + /// + /// The that represents result of the asynchronous operation, a list of two + /// factor authentication providers for the specified user. + /// + Task> GetValidTwoFactorProvidersAsync(TUser user); + + /// + /// Verifies the specified two factor authentication against the . + /// + /// The user the token is supposed to be for. + /// The provider which will verify the token. + /// The token to verify. + /// + /// The that represents result of the asynchronous operation, true if the token is valid, + /// otherwise false. + /// + Task VerifyTwoFactorTokenAsync(TUser user, string tokenProvider, string token); + + Task ResetAccessFailedCountAsync(TUser user); + + void RaiseForgotPasswordRequestedEvent(IPrincipal currentUser, int userId); + void RaiseForgotPasswordChangedSuccessEvent(IPrincipal currentUser, int userId); + void RaiseLogoutSuccessEvent(IPrincipal currentUser, int userId); + + void RaiseLoginSuccessEvent(TUser currentUser, int userId); + } +} diff --git a/src/Umbraco.Infrastructure/Compose/BlockEditorComponent.cs b/src/Umbraco.Infrastructure/Compose/BlockEditorComponent.cs new file mode 100644 index 0000000000..a8b4cfb8ca --- /dev/null +++ b/src/Umbraco.Infrastructure/Compose/BlockEditorComponent.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Models.Blocks; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.Compose +{ + /// + /// A component for Block editors used to bind to events + /// + public class BlockEditorComponent : IComponent + { + private ComplexPropertyEditorContentEventHandler _handler; + private readonly BlockListEditorDataConverter _converter = new BlockListEditorDataConverter(); + + public void Initialize() + { + _handler = new ComplexPropertyEditorContentEventHandler( + Constants.PropertyEditors.Aliases.BlockList, + ReplaceBlockListUdis); + } + + public void Terminate() => _handler?.Dispose(); + + private string ReplaceBlockListUdis(string rawJson, bool onlyMissingUdis) + { + // the block editor doesn't ever have missing UDIs so when this is true there's nothing to process + if (onlyMissingUdis) return rawJson; + + return ReplaceBlockListUdis(rawJson, null); + } + + // internal for tests + internal string ReplaceBlockListUdis(string rawJson, Func createGuid = null) + { + // used so we can test nicely + if (createGuid == null) + createGuid = () => Guid.NewGuid(); + + if (string.IsNullOrWhiteSpace(rawJson) || !rawJson.DetectIsJson()) + return rawJson; + + // Parse JSON + // This will throw a FormatException if there are null UDIs (expected) + var blockListValue = _converter.Deserialize(rawJson); + + UpdateBlockListRecursively(blockListValue, createGuid); + + return JsonConvert.SerializeObject(blockListValue.BlockValue); + } + + private void UpdateBlockListRecursively(BlockEditorData blockListData, Func createGuid) + { + var oldToNew = new Dictionary(); + MapOldToNewUdis(oldToNew, blockListData.BlockValue.ContentData, createGuid); + MapOldToNewUdis(oldToNew, blockListData.BlockValue.SettingsData, createGuid); + + for (var i = 0; i < blockListData.References.Count; i++) + { + var reference = blockListData.References[i]; + var hasContentMap = oldToNew.TryGetValue(reference.ContentUdi, out var contentMap); + Udi settingsMap = null; + var hasSettingsMap = reference.SettingsUdi != null && oldToNew.TryGetValue(reference.SettingsUdi, out settingsMap); + + if (hasContentMap) + { + // replace the reference + blockListData.References.RemoveAt(i); + blockListData.References.Insert(i, new ContentAndSettingsReference(contentMap, hasSettingsMap ? settingsMap : null)); + } + } + + // build the layout with the new UDIs + var layout = (JArray)blockListData.Layout; + layout.Clear(); + foreach (var reference in blockListData.References) + { + layout.Add(JObject.FromObject(new BlockListLayoutItem + { + ContentUdi = reference.ContentUdi, + SettingsUdi = reference.SettingsUdi + })); + } + + + RecursePropertyValues(blockListData.BlockValue.ContentData, createGuid); + RecursePropertyValues(blockListData.BlockValue.SettingsData, createGuid); + } + + private void RecursePropertyValues(IEnumerable blockData, Func createGuid) + { + foreach (var data in blockData) + { + // check if we need to recurse (make a copy of the dictionary since it will be modified) + foreach (var propertyAliasToBlockItemData in new Dictionary(data.RawPropertyValues)) + { + if (propertyAliasToBlockItemData.Value is JToken jtoken) + { + if (ProcessJToken(jtoken, createGuid, out var result)) + { + // need to re-save this back to the RawPropertyValues + data.RawPropertyValues[propertyAliasToBlockItemData.Key] = result; + } + } + else + { + var asString = propertyAliasToBlockItemData.Value?.ToString(); + + if (asString != null && asString.DetectIsJson()) + { + // this gets a little ugly because there could be some other complex editor that contains another block editor + // and since we would have no idea how to parse that, all we can do is try JSON Path to find another block editor + // of our type + var json = JToken.Parse(asString); + if (ProcessJToken(json, createGuid, out var result)) + { + // need to re-save this back to the RawPropertyValues + data.RawPropertyValues[propertyAliasToBlockItemData.Key] = result; + } + } + } + } + } + } + + private bool ProcessJToken(JToken json, Func createGuid, out JToken result) + { + var updated = false; + result = json; + + // select all tokens (flatten) + var allProperties = json.SelectTokens("$..*").Select(x => x.Parent as JProperty).WhereNotNull().ToList(); + foreach (var prop in allProperties) + { + if (prop.Name == Constants.PropertyEditors.Aliases.BlockList) + { + // get it's parent 'layout' and it's parent's container + var layout = prop.Parent?.Parent as JProperty; + if (layout != null && layout.Parent is JObject layoutJson) + { + // recurse + var blockListValue = _converter.ConvertFrom(layoutJson); + UpdateBlockListRecursively(blockListValue, createGuid); + + // set new value + if (layoutJson.Parent != null) + { + // we can replace the object + layoutJson.Replace(JObject.FromObject(blockListValue.BlockValue)); + updated = true; + } + else + { + // if there is no parent it means that this json property was the root, in which case we just return + result = JObject.FromObject(blockListValue.BlockValue); + return true; + } + } + } + else if (prop.Name != "layout" && prop.Name != "contentData" && prop.Name != "settingsData" && prop.Name != "contentTypeKey") + { + // this is an arbitrary property that could contain a nested complex editor + var propVal = prop.Value?.ToString(); + // check if this might contain a nested Block Editor + if (!propVal.IsNullOrWhiteSpace() && propVal.DetectIsJson() && propVal.InvariantContains(Constants.PropertyEditors.Aliases.BlockList)) + { + if (_converter.TryDeserialize(propVal, out var nestedBlockData)) + { + // recurse + UpdateBlockListRecursively(nestedBlockData, createGuid); + // set the value to the updated one + prop.Value = JObject.FromObject(nestedBlockData.BlockValue); + updated = true; + } + } + } + } + + return updated; + } + + private void MapOldToNewUdis(Dictionary oldToNew, IEnumerable blockData, Func createGuid) + { + foreach (var data in blockData) + { + // This should never happen since a FormatException will be thrown if one is empty but we'll keep this here + if (data.Udi == null) + throw new InvalidOperationException("Block data cannot contain a null UDI"); + + // replace the UDIs + var newUdi = GuidUdi.Create(Constants.UdiEntityType.Element, createGuid()); + oldToNew[data.Udi] = newUdi; + data.Udi = newUdi; + } + } + } +} diff --git a/src/Umbraco.Infrastructure/Compose/BlockEditorComposer.cs b/src/Umbraco.Infrastructure/Compose/BlockEditorComposer.cs new file mode 100644 index 0000000000..e281bcb19f --- /dev/null +++ b/src/Umbraco.Infrastructure/Compose/BlockEditorComposer.cs @@ -0,0 +1,12 @@ +using Umbraco.Core; +using Umbraco.Core.Composing; + +namespace Umbraco.Web.Compose +{ + /// + /// A composer for Block editors to run a component + /// + [RuntimeLevel(MinLevel = RuntimeLevel.Run)] + public class BlockEditorComposer : ComponentComposer, ICoreComposer + { } +} diff --git a/src/Umbraco.Web/Compose/NestedContentPropertyComponent.cs b/src/Umbraco.Infrastructure/Compose/NestedContentPropertyComponent.cs similarity index 51% rename from src/Umbraco.Web/Compose/NestedContentPropertyComponent.cs rename to src/Umbraco.Infrastructure/Compose/NestedContentPropertyComponent.cs index 5d1aa8cb85..7116b3eb86 100644 --- a/src/Umbraco.Web/Compose/NestedContentPropertyComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/NestedContentPropertyComponent.cs @@ -1,71 +1,31 @@ using System; -using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Events; -using Umbraco.Core.Models; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; +using Umbraco.Core.PropertyEditors; using Umbraco.Web.PropertyEditors; namespace Umbraco.Web.Compose { + + /// + /// A component for NestedContent used to bind to events + /// public class NestedContentPropertyComponent : IComponent { + private ComplexPropertyEditorContentEventHandler _handler; + public void Initialize() { - ContentService.Copying += ContentService_Copying; - ContentService.Saving += ContentService_Saving; + _handler = new ComplexPropertyEditorContentEventHandler( + Constants.PropertyEditors.Aliases.NestedContent, + CreateNestedContentKeys); } - private void ContentService_Copying(IContentService sender, CopyEventArgs e) - { - // When a content node contains nested content property - // Check if the copied node contains a nested content - var nestedContentProps = e.Copy.Properties.Where(x => x.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.NestedContent); - UpdateNestedContentProperties(nestedContentProps, false); - } - - private void ContentService_Saving(IContentService sender, ContentSavingEventArgs e) - { - // One or more content nodes could be saved in a bulk publish - foreach (var entity in e.SavedEntities) - { - // When a content node contains nested content property - // Check if the copied node contains a nested content - var nestedContentProps = entity.Properties.Where(x => x.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.NestedContent); - UpdateNestedContentProperties(nestedContentProps, true); - } - } - - public void Terminate() - { - ContentService.Copying -= ContentService_Copying; - ContentService.Saving -= ContentService_Saving; - } - - private void UpdateNestedContentProperties(IEnumerable nestedContentProps, bool onlyMissingKeys) - { - // Each NC Property on a doctype - foreach (var nestedContentProp in nestedContentProps) - { - // A NC Prop may have one or more values due to cultures - var propVals = nestedContentProp.Values; - foreach (var cultureVal in propVals) - { - // Remove keys from published value & any nested NC's - var updatedPublishedVal = CreateNestedContentKeys(cultureVal.PublishedValue?.ToString(), onlyMissingKeys); - cultureVal.PublishedValue = updatedPublishedVal; - - // Remove keys from edited/draft value & any nested NC's - var updatedEditedVal = CreateNestedContentKeys(cultureVal.EditedValue?.ToString(), onlyMissingKeys); - cultureVal.EditedValue = updatedEditedVal; - } - } - } + public void Terminate() => _handler?.Dispose(); + private string CreateNestedContentKeys(string rawJson, bool onlyMissingKeys) => CreateNestedContentKeys(rawJson, onlyMissingKeys, null); // internal for tests internal string CreateNestedContentKeys(string rawJson, bool onlyMissingKeys, Func createGuid = null) @@ -98,7 +58,6 @@ namespace Umbraco.Web.Compose { // get it's sibling 'key' property var ncKeyVal = prop.Parent["key"] as JValue; - // TODO: This bool seems odd, if the key is null, shouldn't we fill it in regardless of onlyMissingKeys? if ((onlyMissingKeys && ncKeyVal == null) || (!onlyMissingKeys && ncKeyVal != null)) { // create or replace diff --git a/src/Umbraco.Web/Compose/NestedContentPropertyComposer.cs b/src/Umbraco.Infrastructure/Compose/NestedContentPropertyComposer.cs similarity index 73% rename from src/Umbraco.Web/Compose/NestedContentPropertyComposer.cs rename to src/Umbraco.Infrastructure/Compose/NestedContentPropertyComposer.cs index 4c9d9dee1c..8e4cfbfffc 100644 --- a/src/Umbraco.Web/Compose/NestedContentPropertyComposer.cs +++ b/src/Umbraco.Infrastructure/Compose/NestedContentPropertyComposer.cs @@ -3,6 +3,9 @@ using Umbraco.Core.Composing; namespace Umbraco.Web.Compose { + /// + /// A composer for nested content to run a component + /// [RuntimeLevel(MinLevel = RuntimeLevel.Run)] public class NestedContentPropertyComposer : ComponentComposer, ICoreComposer { } diff --git a/src/Umbraco.Infrastructure/Compose/NotificationsComponent.cs b/src/Umbraco.Infrastructure/Compose/NotificationsComponent.cs index 3a4b8a5fac..790cab0913 100644 --- a/src/Umbraco.Infrastructure/Compose/NotificationsComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/NotificationsComponent.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; -using Umbraco.Core.Models.Identity; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; @@ -33,42 +32,78 @@ namespace Umbraco.Web.Compose public void Initialize() { //Send notifications for the send to publish action - ContentService.SentToPublish += (sender, args) => _notifier.Notify(_actions.GetAction(), args.Entity); - + ContentService.SentToPublish += ContentService_SentToPublish; //Send notifications for the published action - ContentService.Published += (sender, args) => _notifier.Notify(_actions.GetAction(), args.PublishedEntities.ToArray()); - + ContentService.Published += ContentService_Published; //Send notifications for the saved action - ContentService.Sorted += (sender, args) => ContentServiceSorted(_notifier, sender, args, _actions); - + ContentService.Sorted += ContentService_Sorted; //Send notifications for the update and created actions - ContentService.Saved += (sender, args) => ContentServiceSaved(_notifier, sender, args, _actions); - + ContentService.Saved += ContentService_Saved; //Send notifications for the unpublish action - ContentService.Unpublished += (sender, args) => _notifier.Notify(_actions.GetAction(), args.PublishedEntities.ToArray()); - + ContentService.Unpublished += ContentService_Unpublished; //Send notifications for the move/move to recycle bin and restore actions - ContentService.Moved += (sender, args) => ContentServiceMoved(_notifier, sender, args, _actions); - + ContentService.Moved += ContentService_Moved; //Send notifications for the delete action when content is moved to the recycle bin - ContentService.Trashed += (sender, args) => _notifier.Notify(_actions.GetAction(), args.MoveInfoCollection.Select(m => m.Entity).ToArray()); - + ContentService.Trashed += ContentService_Trashed; //Send notifications for the copy action - ContentService.Copied += (sender, args) => _notifier.Notify(_actions.GetAction(), args.Original); - + ContentService.Copied += ContentService_Copied; //Send notifications for the rollback action - ContentService.RolledBack += (sender, args) => _notifier.Notify(_actions.GetAction(), args.Entity); - + ContentService.RolledBack += ContentService_RolledBack; //Send notifications for the public access changed action - PublicAccessService.Saved += (sender, args) => PublicAccessServiceSaved(_notifier, sender, args, _contentService, _actions); + PublicAccessService.Saved += PublicAccessService_Saved; - UserService.UserGroupPermissionsAssigned += (sender, args) => UserServiceUserGroupPermissionsAssigned(_notifier, sender, args, _contentService, _actions); + UserService.UserGroupPermissionsAssigned += UserService_UserGroupPermissionsAssigned; } public void Terminate() - { } + { + ContentService.SentToPublish -= ContentService_SentToPublish; + ContentService.Published -= ContentService_Published; + ContentService.Sorted -= ContentService_Sorted; + ContentService.Saved -= ContentService_Saved; + ContentService.Unpublished -= ContentService_Unpublished; + ContentService.Moved -= ContentService_Moved; + ContentService.Trashed -= ContentService_Trashed; + ContentService.Copied -= ContentService_Copied; + ContentService.RolledBack -= ContentService_RolledBack; + PublicAccessService.Saved -= PublicAccessService_Saved; + UserService.UserGroupPermissionsAssigned -= UserService_UserGroupPermissionsAssigned; + } - private void ContentServiceSorted(Notifier notifier, IContentService sender, Core.Events.SaveEventArgs args, ActionCollection actions) + private void UserService_UserGroupPermissionsAssigned(IUserService sender, Core.Events.SaveEventArgs args) + => UserServiceUserGroupPermissionsAssigned(args, _contentService); + + private void PublicAccessService_Saved(IPublicAccessService sender, Core.Events.SaveEventArgs args) + => PublicAccessServiceSaved(args, _contentService); + + private void ContentService_RolledBack(IContentService sender, Core.Events.RollbackEventArgs args) + => _notifier.Notify(_actions.GetAction(), args.Entity); + + private void ContentService_Copied(IContentService sender, Core.Events.CopyEventArgs args) + => _notifier.Notify(_actions.GetAction(), args.Original); + + private void ContentService_Trashed(IContentService sender, Core.Events.MoveEventArgs args) + => _notifier.Notify(_actions.GetAction(), args.MoveInfoCollection.Select(m => m.Entity).ToArray()); + + private void ContentService_Moved(IContentService sender, Core.Events.MoveEventArgs args) + => ContentServiceMoved(args); + + private void ContentService_Unpublished(IContentService sender, Core.Events.PublishEventArgs args) + => _notifier.Notify(_actions.GetAction(), args.PublishedEntities.ToArray()); + + private void ContentService_Saved(IContentService sender, Core.Events.ContentSavedEventArgs args) + => ContentServiceSaved(args); + + private void ContentService_Sorted(IContentService sender, Core.Events.SaveEventArgs args) + => ContentServiceSorted(sender, args); + + private void ContentService_Published(IContentService sender, Core.Events.ContentPublishedEventArgs args) + => _notifier.Notify(_actions.GetAction(), args.PublishedEntities.ToArray()); + + private void ContentService_SentToPublish(IContentService sender, Core.Events.SendToPublishEventArgs args) + => _notifier.Notify(_actions.GetAction(), args.Entity); + + private void ContentServiceSorted(IContentService sender, Core.Events.SaveEventArgs args) { var parentId = args.SavedEntities.Select(x => x.ParentId).Distinct().ToList(); if (parentId.Count != 1) return; // this shouldn't happen, for sorting all entities will have the same parent id @@ -80,10 +115,10 @@ namespace Umbraco.Web.Compose var parent = sender.GetById(parentId[0]); if (parent == null) return; // this shouldn't happen - notifier.Notify(actions.GetAction(), new[] { parent }); + _notifier.Notify(_actions.GetAction(), new[] { parent }); } - private void ContentServiceSaved(Notifier notifier, IContentService sender, Core.Events.SaveEventArgs args, ActionCollection actions) + private void ContentServiceSaved(Core.Events.SaveEventArgs args) { var newEntities = new List(); var updatedEntities = new List(); @@ -103,21 +138,21 @@ namespace Umbraco.Web.Compose updatedEntities.Add(entity); } } - notifier.Notify(actions.GetAction(), newEntities.ToArray()); - notifier.Notify(actions.GetAction(), updatedEntities.ToArray()); + _notifier.Notify(_actions.GetAction(), newEntities.ToArray()); + _notifier.Notify(_actions.GetAction(), updatedEntities.ToArray()); } - private void UserServiceUserGroupPermissionsAssigned(Notifier notifier, IUserService sender, Core.Events.SaveEventArgs args, IContentService contentService, ActionCollection actions) + private void UserServiceUserGroupPermissionsAssigned(Core.Events.SaveEventArgs args, IContentService contentService) { var entities = contentService.GetByIds(args.SavedEntities.Select(e => e.EntityId)).ToArray(); if(entities.Any() == false) { return; } - notifier.Notify(actions.GetAction(), entities); + _notifier.Notify(_actions.GetAction(), entities); } - private void ContentServiceMoved(Notifier notifier, IContentService sender, Core.Events.MoveEventArgs args, ActionCollection actions) + private void ContentServiceMoved(Core.Events.MoveEventArgs args) { // notify about the move for all moved items _notifier.Notify(_actions.GetAction(), args.MoveInfoCollection.Select(m => m.Entity).ToArray()); @@ -133,14 +168,14 @@ namespace Umbraco.Web.Compose } } - private void PublicAccessServiceSaved(Notifier notifier, IPublicAccessService sender, Core.Events.SaveEventArgs args, IContentService contentService, ActionCollection actions) + private void PublicAccessServiceSaved(Core.Events.SaveEventArgs args, IContentService contentService) { var entities = contentService.GetByIds(args.SavedEntities.Select(e => e.ProtectedNodeId)).ToArray(); if(entities.Any() == false) { return; } - notifier.Notify(actions.GetAction(), entities); + _notifier.Notify(_actions.GetAction(), entities); } /// @@ -153,7 +188,7 @@ namespace Umbraco.Web.Compose private readonly INotificationService _notificationService; private readonly IUserService _userService; private readonly ILocalizedTextService _textService; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly ILogger _logger; /// @@ -166,14 +201,21 @@ namespace Umbraco.Web.Compose /// /// /// - public Notifier(IUmbracoContextAccessor umbracoContextAccessor, IRequestAccessor requestAccessor, INotificationService notificationService, IUserService userService, ILocalizedTextService textService, IGlobalSettings globalSettings, ILogger logger) + public Notifier( + IUmbracoContextAccessor umbracoContextAccessor, + IRequestAccessor requestAccessor, + INotificationService notificationService, + IUserService userService, + ILocalizedTextService textService, + IOptions globalSettings, + ILogger logger) { _umbracoContextAccessor = umbracoContextAccessor; _requestAccessor = requestAccessor; _notificationService = notificationService; _userService = userService; _textService = textService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _logger = logger; } diff --git a/src/Umbraco.Infrastructure/Compose/PublicAccessComponent.cs b/src/Umbraco.Infrastructure/Compose/PublicAccessComponent.cs index 37bcfb1ceb..a917cfe0ef 100644 --- a/src/Umbraco.Infrastructure/Compose/PublicAccessComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/PublicAccessComponent.cs @@ -16,13 +16,15 @@ namespace Umbraco.Web.Compose public void Initialize() { - MemberGroupService.Saved += (s, e) => MemberGroupService_Saved(s, e, _publicAccessService); + MemberGroupService.Saved += MemberGroupService_Saved; } public void Terminate() - { } + { + MemberGroupService.Saved -= MemberGroupService_Saved; + } - static void MemberGroupService_Saved(IMemberGroupService sender, Core.Events.SaveEventArgs e, IPublicAccessService publicAccessService) + private void MemberGroupService_Saved(IMemberGroupService sender, Core.Events.SaveEventArgs e) { foreach (var grp in e.SavedEntities) { @@ -32,7 +34,7 @@ namespace Umbraco.Web.Compose && grp.AdditionalData["previousName"].ToString().IsNullOrWhiteSpace() == false && grp.AdditionalData["previousName"].ToString() != grp.Name) { - publicAccessService.RenameMemberGroupRoleRules(grp.AdditionalData["previousName"].ToString(), grp.Name); + _publicAccessService.RenameMemberGroupRoleRules(grp.AdditionalData["previousName"].ToString(), grp.Name); } } } diff --git a/src/Umbraco.Infrastructure/Compose/RelateOnCopyComponent.cs b/src/Umbraco.Infrastructure/Compose/RelateOnCopyComponent.cs index 56a97e4cba..3418dfcfc0 100644 --- a/src/Umbraco.Infrastructure/Compose/RelateOnCopyComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/RelateOnCopyComponent.cs @@ -23,7 +23,9 @@ namespace Umbraco.Core.Compose } public void Terminate() - { } + { + ContentService.Copied -= ContentServiceCopied; + } private void ContentServiceCopied(IContentService sender, Events.CopyEventArgs e) { diff --git a/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs b/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs index c81aa2fd7d..aa92972e9c 100644 --- a/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs @@ -24,47 +24,52 @@ namespace Umbraco.Core.Compose public void Initialize() { - ContentService.Moved += (sender, args) => ContentService_Moved(sender, args, _relationService); - ContentService.Trashed += (sender, args) => ContentService_Trashed(sender, args, _relationService, _entityService, _textService, _auditService); - MediaService.Moved += (sender, args) => MediaService_Moved(sender, args, _relationService); - MediaService.Trashed += (sender, args) => MediaService_Trashed(sender, args, _relationService, _entityService, _textService, _auditService); + ContentService.Moved += ContentService_Moved; + ContentService.Trashed += ContentService_Trashed; + MediaService.Moved += MediaService_Moved; + MediaService.Trashed += MediaService_Trashed; } public void Terminate() - { } + { + ContentService.Moved -= ContentService_Moved; + ContentService.Trashed -= ContentService_Trashed; + MediaService.Moved -= MediaService_Moved; + MediaService.Trashed -= MediaService_Trashed; + } - private static void ContentService_Moved(IContentService sender, MoveEventArgs e, IRelationService relationService) + private void ContentService_Moved(IContentService sender, MoveEventArgs e) { foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContentString))) { const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias; - var relations = relationService.GetByChildId(item.Entity.Id); + var relations = _relationService.GetByChildId(item.Entity.Id); foreach (var relation in relations.Where(x => x.RelationType.Alias.InvariantEquals(relationTypeAlias))) { - relationService.Delete(relation); + _relationService.Delete(relation); } } } - private static void MediaService_Moved(IMediaService sender, MoveEventArgs e, IRelationService relationService) + private void MediaService_Moved(IMediaService sender, MoveEventArgs e) { foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinMediaString))) { const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias; - var relations = relationService.GetByChildId(item.Entity.Id); + var relations = _relationService.GetByChildId(item.Entity.Id); foreach (var relation in relations.Where(x => x.RelationType.Alias.InvariantEquals(relationTypeAlias))) { - relationService.Delete(relation); + _relationService.Delete(relation); } } } - private static void ContentService_Trashed(IContentService sender, MoveEventArgs e, IRelationService relationService, IEntityService entityService, ILocalizedTextService textService, IAuditService auditService) + private void ContentService_Trashed(IContentService sender, MoveEventArgs e) { const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias; - var relationType = relationService.GetRelationTypeByAlias(relationTypeAlias); + var relationType = _relationService.GetRelationTypeByAlias(relationTypeAlias); // check that the relation-type exists, if not, then recreate it if (relationType == null) @@ -73,7 +78,7 @@ namespace Umbraco.Core.Compose const string relationTypeName = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteName; relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, documentObjectType); - relationService.Save(relationType); + _relationService.Save(relationType); } foreach (var item in e.MoveInfoCollection) @@ -86,34 +91,34 @@ namespace Umbraco.Core.Compose //before we can create this relation, we need to ensure that the original parent still exists which //may not be the case if the encompassing transaction also deleted it when this item was moved to the bin - if (entityService.Exists(originalParentId)) + if (_entityService.Exists(originalParentId)) { // Add a relation for the item being deleted, so that we can know the original parent for if we need to restore later var relation = new Relation(originalParentId, item.Entity.Id, relationType); - relationService.Save(relation); + _relationService.Save(relation); - auditService.Add(AuditType.Delete, + _auditService.Add(AuditType.Delete, item.Entity.WriterId, item.Entity.Id, ObjectTypes.GetName(UmbracoObjectTypes.Document), - string.Format(textService.Localize( + string.Format(_textService.Localize( "recycleBin/contentTrashed"), item.Entity.Id, originalParentId)); } } } - private static void MediaService_Trashed(IMediaService sender, MoveEventArgs e, IRelationService relationService, IEntityService entityService, ILocalizedTextService textService, IAuditService auditService) + private void MediaService_Trashed(IMediaService sender, MoveEventArgs e) { const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias; - var relationType = relationService.GetRelationTypeByAlias(relationTypeAlias); + var relationType = _relationService.GetRelationTypeByAlias(relationTypeAlias); // check that the relation-type exists, if not, then recreate it if (relationType == null) { var documentObjectType = Constants.ObjectTypes.Document; const string relationTypeName = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName; relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, documentObjectType); - relationService.Save(relationType); + _relationService.Save(relationType); } foreach (var item in e.MoveInfoCollection) { @@ -123,16 +128,16 @@ namespace Umbraco.Core.Compose : Constants.System.Root; //before we can create this relation, we need to ensure that the original parent still exists which //may not be the case if the encompassing transaction also deleted it when this item was moved to the bin - if (entityService.Exists(originalParentId)) + if (_entityService.Exists(originalParentId)) { // Add a relation for the item being deleted, so that we can know the original parent for if we need to restore later var relation = new Relation(originalParentId, item.Entity.Id, relationType); - relationService.Save(relation); - auditService.Add(AuditType.Delete, + _relationService.Save(relation); + _auditService.Add(AuditType.Delete, item.Entity.CreatorId, item.Entity.Id, ObjectTypes.GetName(UmbracoObjectTypes.Media), - string.Format(textService.Localize( + string.Format(_textService.Localize( "recycleBin/mediaTrashed"), item.Entity.Id, originalParentId)); } diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs index 9dc130fcba..4b941727ca 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs @@ -1,4 +1,6 @@ -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; @@ -97,7 +99,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions var ioHelper = factory.GetInstance(); var hostingEnvironment = factory.GetInstance(); var logger = factory.GetInstance(); - var globalSettings = factory.GetInstance(); + var globalSettings = factory.GetInstance>().Value; var rootPath = hostingEnvironment.MapPathWebRoot(globalSettings.UmbracoMediaPath); var rootUrl = hostingEnvironment.ToAbsolute(globalSettings.UmbracoMediaPath); diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs index 980dd1c11e..ffd8b880f2 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs @@ -1,8 +1,10 @@ using System; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.IO; @@ -94,13 +96,13 @@ namespace Umbraco.Core.Composing.CompositionExtensions factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), - factory.GetInstance(), + factory.GetInstance>(), packageRepoFileName); private static LocalizedTextServiceFileSources SourcesFactory(IFactory container) { var hostingEnvironment = container.GetInstance(); - var globalSettings = container.GetInstance(); + var globalSettings = container.GetInstance>().Value; var mainLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(globalSettings.UmbracoPath , "config","lang"))); var appPlugins = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins)); var configLangFolder = new DirectoryInfo(hostingEnvironment.MapPathContentRoot(WebPath.Combine(Constants.SystemDirectories.Config ,"lang"))); diff --git a/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs b/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs index 835bd0b9a8..d6c0e74d75 100644 --- a/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs +++ b/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs @@ -6,6 +6,7 @@ using System; using System.Reflection; using Umbraco.Core.Composing.LightInject; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Core.Composing { @@ -29,7 +30,7 @@ namespace Umbraco.Core.Composing /// To override the default LightInjectContainer, add an appSetting named 'Umbraco.Core.RegisterType' with /// a fully qualified type name to a class with a static method "Create" returning an IRegister. /// - public static IRegister Create(IGlobalSettings globalSettings) + public static IRegister Create(GlobalSettings globalSettings) { Type type; diff --git a/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs b/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs index 56a972a64b..6bd0d796ec 100644 --- a/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs +++ b/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs @@ -2,9 +2,11 @@ using LightInject.Microsoft.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using System; +using Microsoft.Extensions.Options; using Umbraco.Composing; using Umbraco.Core.Composing.LightInject; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; namespace Umbraco.Core.Composing @@ -86,7 +88,8 @@ namespace Umbraco.Core.Composing // after cross wiring, configure "Current" Current.Initialize( _container.GetInstance(), - _container.GetInstance(), + _container.GetInstance>().Value, + _container.GetInstance>().Value, _container.GetInstance(), _container.GetInstance(), _container.GetInstance(), diff --git a/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs b/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs index 88ae80bf8b..b2ded07034 100644 --- a/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs +++ b/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs @@ -31,6 +31,7 @@ namespace Umbraco.Core TypeLoader typeLoader, IRuntimeState state, ITypeFinder typeFinder, + IIOHelper ioHelper, IUmbracoVersion umbracoVersion, IDbProviderFactoryCreator dbProviderFactoryCreator, diff --git a/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs index 646df5124d..a3a43d2b93 100644 --- a/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs +++ b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Configuration.Json; using Microsoft.Extensions.FileProviders; using Newtonsoft.Json; using Newtonsoft.Json.Linq; + namespace Umbraco.Core.Configuration { public class JsonConfigManipulator : IConfigManipulator @@ -65,6 +66,40 @@ namespace Umbraco.Core.Configuration } + public void SaveDisableRedirectUrlTracking(bool disable) + { + var provider = GetJsonConfigurationProvider(); + + var json = GetJson(provider); + + var item = GetDisableRedirectUrlItem(disable.ToString().ToLowerInvariant()); + + json.Merge(item, new JsonMergeSettings()); + + SaveJson(provider, json); + } + + private JToken GetDisableRedirectUrlItem(string value) + { + JTokenWriter writer = new JTokenWriter(); + + writer.WriteStartObject(); + writer.WritePropertyName("Umbraco"); + writer.WriteStartObject(); + writer.WritePropertyName("CMS"); + writer.WriteStartObject(); + writer.WritePropertyName("WebRouting"); + writer.WriteStartObject(); + writer.WritePropertyName("DisableRedirectUrlTracking"); + writer.WriteValue(value); + writer.WriteEndObject(); + writer.WriteEndObject(); + writer.WriteEndObject(); + writer.WriteEndObject(); + + return writer.Token; + } + private JToken GetConnectionItem(string connectionString, string providerName) { JTokenWriter writer = new JTokenWriter(); @@ -135,7 +170,7 @@ namespace Umbraco.Core.Configuration { foreach (var provider in configurationRoot.Providers) { - if(provider is JsonConfigurationProvider jsonConfigurationProvider) + if (provider is JsonConfigurationProvider jsonConfigurationProvider) { if (requiredKey is null || provider.TryGet(requiredKey, out _)) { diff --git a/src/Umbraco.Infrastructure/ContentExtensions.cs b/src/Umbraco.Infrastructure/ContentExtensions.cs index d8d39cc984..e71815f911 100644 --- a/src/Umbraco.Infrastructure/ContentExtensions.cs +++ b/src/Umbraco.Infrastructure/ContentExtensions.cs @@ -14,6 +14,14 @@ namespace Umbraco.Core { public static class ContentExtensions { + /// + /// Returns all properties based on the editorAlias + /// + /// + /// + /// + public static IEnumerable GetPropertiesByEditor(this IContentBase content, string editorAlias) + => content.Properties.Where(x => x.PropertyType.PropertyEditorAlias == editorAlias); internal static bool IsMoving(this IContentBase entity) { @@ -28,29 +36,6 @@ namespace Umbraco.Core return isMoving; } - /// - /// Removes characters that are not valid XML characters from all entity properties - /// of type string. See: http://stackoverflow.com/a/961504/5018 - /// - /// - /// - /// If this is not done then the xml cache can get corrupt and it will throw YSODs upon reading it. - /// - /// - public static void SanitizeEntityPropertiesForXmlStorage(this IContentBase entity) - { - entity.Name = entity.Name.ToValidXmlString(); - foreach (var property in entity.Properties) - { - foreach (var propertyValue in property.Values) - { - if (propertyValue.EditedValue is string editString) - propertyValue.EditedValue = editString.ToValidXmlString(); - if (propertyValue.PublishedValue is string publishedString) - propertyValue.PublishedValue = publishedString.ToValidXmlString(); - } - } - } #region IContent diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs index 0240d60f29..49981b0b9a 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs @@ -2,11 +2,11 @@ using System.Net.Mail; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.HealthChecks; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.NotificationMethods @@ -17,10 +17,16 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods private readonly ILocalizedTextService _textService; private readonly IRequestAccessor _requestAccessor; - private readonly IGlobalSettings _globalSettings; - private readonly IContentSettings _contentSettings; + private readonly GlobalSettings _globalSettings; + private readonly ContentSettings _contentSettings; - public EmailNotificationMethod(ILocalizedTextService textService, IRequestAccessor requestAccessor, IGlobalSettings globalSettings, IHealthChecksSettings healthChecksSettings, IContentSettings contentSettings) : base(healthChecksSettings) + public EmailNotificationMethod( + ILocalizedTextService textService, + IRequestAccessor requestAccessor, + IOptions globalSettings, + IOptions healthChecksSettings, + IOptions contentSettings) + : base(healthChecksSettings) { var recipientEmail = Settings?["recipientEmail"]?.Value; if (string.IsNullOrWhiteSpace(recipientEmail)) @@ -33,8 +39,8 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _requestAccessor = requestAccessor; - _globalSettings = globalSettings; - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _globalSettings = globalSettings.Value; + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); } public string RecipientEmail { get; } @@ -64,7 +70,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods var subject = _textService.Localize("healthcheck/scheduledHealthCheckEmailSubject", new[] { host.ToString() }); - var mailSender = new EmailSender(_globalSettings); + var mailSender = new EmailSender(Options.Create(_globalSettings)); using (var mailMessage = CreateMailMessage(subject, message)) { await mailSender.SendAsync(mailMessage); @@ -73,7 +79,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods private MailMessage CreateMailMessage(string subject, string message) { - var to = _contentSettings.NotificationEmailAddress; + var to = _contentSettings.Notifications.Email; 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 3e6606e965..2c0c5bcc1f 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs @@ -2,13 +2,15 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration.HealthChecks; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.HealthCheck.NotificationMethods { public abstract class NotificationMethodBase : IHealthCheckNotificationMethod { - protected NotificationMethodBase(IHealthChecksSettings healthCheckSettingsConfig) + protected NotificationMethodBase(IOptions healthCheckSettings) { var type = GetType(); var attribute = type.GetCustomAttribute(); @@ -18,7 +20,7 @@ namespace Umbraco.Web.HealthCheck.NotificationMethods return; } - var notificationMethods = healthCheckSettingsConfig.NotificationSettings.NotificationMethods; + var notificationMethods = healthCheckSettings.Value.NotificationSettings.NotificationMethods; if(!notificationMethods.TryGetValue(attribute.Alias, out var notificationMethod)) { Enabled = false; diff --git a/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs b/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs index 4c3edf0a1b..7a20a1189e 100644 --- a/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs +++ b/src/Umbraco.Infrastructure/Install/FilePermissionHelper.cs @@ -8,6 +8,8 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Install; using Umbraco.Core.IO; using Umbraco.Web.PublishedCache; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Install { @@ -19,13 +21,13 @@ namespace Umbraco.Web.Install // ensure Umbraco can write to these files (the directories must exist) private readonly string[] _permissionFiles = { }; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IIOHelper _ioHelper; private readonly IPublishedSnapshotService _publishedSnapshotService; - public FilePermissionHelper(IGlobalSettings globalSettings, IIOHelper ioHelper, IPublishedSnapshotService publishedSnapshotService) + public FilePermissionHelper(IOptions globalSettings, IIOHelper ioHelper, IPublishedSnapshotService publishedSnapshotService) { - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _ioHelper = ioHelper; _publishedSnapshotService = publishedSnapshotService; _permissionDirs = new[] { _globalSettings.UmbracoCssPath, Constants.SystemDirectories.Config, Constants.SystemDirectories.Data, _globalSettings.UmbracoMediaPath, Constants.SystemDirectories.Preview }; diff --git a/src/Umbraco.Infrastructure/Install/InstallHelper.cs b/src/Umbraco.Infrastructure/Install/InstallHelper.cs index 1333363355..967e8cc087 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -13,6 +13,8 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Web.Install.Models; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.Install { @@ -22,7 +24,7 @@ namespace Umbraco.Web.Install private readonly DatabaseBuilder _databaseBuilder; private readonly ILogger _logger; private readonly IUmbracoVersion _umbracoVersion; - private readonly IConnectionStrings _connectionStrings; + private readonly ConnectionStrings _connectionStrings; private readonly IInstallationService _installationService; private readonly ICookieManager _cookieManager; private readonly IUserAgentProvider _userAgentProvider; @@ -33,7 +35,7 @@ namespace Umbraco.Web.Install public InstallHelper(DatabaseBuilder databaseBuilder, ILogger logger, IUmbracoVersion umbracoVersion, - IConnectionStrings connectionStrings, + IOptions connectionStrings, IInstallationService installationService, ICookieManager cookieManager, IUserAgentProvider userAgentProvider, @@ -43,7 +45,7 @@ namespace Umbraco.Web.Install _logger = logger; _umbracoVersion = umbracoVersion; _databaseBuilder = databaseBuilder; - _connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings)); + _connectionStrings = connectionStrings.Value ?? throw new ArgumentNullException(nameof(connectionStrings)); _installationService = installationService; _cookieManager = cookieManager; _userAgentProvider = userAgentProvider; @@ -114,7 +116,7 @@ namespace Umbraco.Web.Install { get { - var databaseSettings = _connectionStrings[Constants.System.UmbracoConnectionName]; + var databaseSettings = _connectionStrings.UmbracoConnectionString; if (databaseSettings.IsConnectionStringConfigured() == false) { //no version or conn string configured, must be a brand new install diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs index 0c88c7a096..74b5b68bfd 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs @@ -5,7 +5,8 @@ using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Web.Install.Models; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Install.InstallSteps { @@ -16,12 +17,12 @@ namespace Umbraco.Web.Install.InstallSteps { private readonly DatabaseBuilder _databaseBuilder; private readonly ILogger _logger; - private readonly IConnectionStrings _connectionStrings; + private readonly ConnectionStrings _connectionStrings; - public DatabaseConfigureStep(DatabaseBuilder databaseBuilder, IConnectionStrings connectionStrings) + public DatabaseConfigureStep(DatabaseBuilder databaseBuilder, IOptions connectionStrings) { _databaseBuilder = databaseBuilder; - _connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings)); + _connectionStrings = connectionStrings.Value ?? throw new ArgumentNullException(nameof(connectionStrings)); } public override Task ExecuteAsync(DatabaseModel database) @@ -107,7 +108,7 @@ namespace Umbraco.Web.Install.InstallSteps private bool ShouldDisplayView() { //If the connection string is already present in web.config we don't need to show the settings page and we jump to installing/upgrading. - var databaseSettings = _connectionStrings[Constants.System.UmbracoConnectionName]; + var databaseSettings = _connectionStrings.UmbracoConnectionString; if (databaseSettings.IsConnectionStringConfigured()) { diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs index b3086672d8..e5f783caba 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs @@ -16,19 +16,11 @@ namespace Umbraco.Web.Install.InstallSteps { private readonly DatabaseBuilder _databaseBuilder; private readonly IRuntimeState _runtime; - 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, IConfigManipulator configManipulator) + public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime) { _databaseBuilder = databaseBuilder; _runtime = runtime; - _logger = logger; - _ioHelper = ioHelper; - _connectionStrings = connectionStrings; - _configManipulator = configManipulator; } public override Task ExecuteAsync(object model) diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs index dccf320787..476feba119 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -1,8 +1,10 @@ using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; @@ -20,29 +22,20 @@ namespace Umbraco.Web.Install.InstallSteps private readonly IRuntimeState _runtime; private readonly ILogger _logger; private readonly IUmbracoVersion _umbracoVersion; - private readonly IGlobalSettings _globalSettings; - private readonly IConnectionStrings _connectionStrings; - private readonly IIOHelper _ioHelper; - private readonly IConfigManipulator _configManipulator; + private readonly ConnectionStrings _connectionStrings; public DatabaseUpgradeStep( DatabaseBuilder databaseBuilder, IRuntimeState runtime, ILogger logger, IUmbracoVersion umbracoVersion, - IGlobalSettings globalSettings, - IConnectionStrings connectionStrings, - IIOHelper ioHelper, - IConfigManipulator configManipulator) + IOptions connectionStrings) { _databaseBuilder = databaseBuilder; _runtime = runtime; _logger = logger; _umbracoVersion = umbracoVersion; - _globalSettings = globalSettings; - _connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings)); - _ioHelper = ioHelper; - _configManipulator = configManipulator; + _connectionStrings = connectionStrings.Value ?? throw new ArgumentNullException(nameof(connectionStrings)); } public override Task ExecuteAsync(object model) @@ -55,7 +48,7 @@ namespace Umbraco.Web.Install.InstallSteps { _logger.Info("Running 'Upgrade' service"); - var plan = new UmbracoPlan(_umbracoVersion, _globalSettings); + var plan = new UmbracoPlan(_umbracoVersion); plan.AddPostMigration(); // needed when running installer (back-office) var result = _databaseBuilder.UpgradeSchemaAndData(plan); @@ -82,7 +75,7 @@ namespace Umbraco.Web.Install.InstallSteps return false; } - var databaseSettings = _connectionStrings[Constants.System.UmbracoConnectionName]; + var databaseSettings = _connectionStrings.UmbracoConnectionString; if (databaseSettings.IsConnectionStringConfigured()) { diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs index a240eaf104..96e4a9ae34 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs @@ -3,15 +3,16 @@ using System.Collections.Specialized; using System.Net.Http; using System.Text; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using Umbraco.Core; +using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Services; -using Umbraco.Web.Install.Models; -using Umbraco.Core.BackOffice; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Extensions; +using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { @@ -29,21 +30,26 @@ namespace Umbraco.Web.Install.InstallSteps private readonly IUserService _userService; private readonly DatabaseBuilder _databaseBuilder; private static HttpClient _httpClient; - private readonly IGlobalSettings _globalSettings; - private readonly IUserPasswordConfiguration _passwordConfiguration; - private readonly ISecuritySettings _securitySettings; - private readonly IConnectionStrings _connectionStrings; + private readonly UserPasswordConfigurationSettings _passwordConfiguration; + private readonly SecuritySettings _securitySettings; + private readonly ConnectionStrings _connectionStrings; private readonly ICookieManager _cookieManager; - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; - public NewInstallStep(IUserService userService, DatabaseBuilder databaseBuilder, IGlobalSettings globalSettings, IUserPasswordConfiguration passwordConfiguration, ISecuritySettings securitySettings, IConnectionStrings connectionStrings, ICookieManager cookieManager, BackOfficeUserManager userManager) + public NewInstallStep( + IUserService userService, + DatabaseBuilder databaseBuilder, + IOptions passwordConfiguration, + IOptions securitySettings, + IOptions connectionStrings, + ICookieManager cookieManager, + IBackOfficeUserManager userManager) { _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _databaseBuilder = databaseBuilder ?? throw new ArgumentNullException(nameof(databaseBuilder)); - _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); - _passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration)); - _securitySettings = securitySettings ?? throw new ArgumentNullException(nameof(securitySettings)); - _connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings)); + _passwordConfiguration = passwordConfiguration.Value ?? throw new ArgumentNullException(nameof(passwordConfiguration)); + _securitySettings = securitySettings.Value ?? throw new ArgumentNullException(nameof(securitySettings)); + _connectionStrings = connectionStrings.Value ?? throw new ArgumentNullException(nameof(connectionStrings)); _cookieManager = cookieManager; _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); } @@ -126,7 +132,7 @@ namespace Umbraco.Web.Install.InstallSteps public override bool RequiresExecution(UserModel model) { //now we have to check if this is really a new install, the db might be configured and might contain data - var databaseSettings = _connectionStrings[Constants.System.UmbracoConnectionName]; + var databaseSettings = _connectionStrings.UmbracoConnectionString; if (databaseSettings.IsConnectionStringConfigured() && _databaseBuilder.IsDatabaseConfigured) return _databaseBuilder.HasSomeNonDefaultUser() == false; diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs index 24133d3be1..d060db2c43 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitDownloadStep.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Umbraco.Core.Services; using Umbraco.Core.Configuration; using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Security; using Umbraco.Net; using Umbraco.Web.Install.Models; using Umbraco.Web.Security; @@ -17,16 +18,16 @@ namespace Umbraco.Web.Install.InstallSteps internal class StarterKitDownloadStep : InstallSetupStep { private readonly InstallHelper _installHelper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IUmbracoVersion _umbracoVersion; private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; private readonly IContentService _contentService; private readonly IPackagingService _packageService; - public StarterKitDownloadStep(IContentService contentService, IPackagingService packageService, InstallHelper installHelper, IWebSecurity webSecurity, IUmbracoVersion umbracoVersion, IUmbracoApplicationLifetime umbracoApplicationLifetime) + public StarterKitDownloadStep(IContentService contentService, IPackagingService packageService, InstallHelper installHelper, IBackofficeSecurityAccessor backofficeSecurityAccessor, IUmbracoVersion umbracoVersion, IUmbracoApplicationLifetime umbracoApplicationLifetime) { _installHelper = installHelper; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _umbracoVersion = umbracoVersion; _umbracoApplicationLifetime = umbracoApplicationLifetime; _contentService = contentService; @@ -67,7 +68,7 @@ namespace Umbraco.Web.Install.InstallSteps private async Task<(string packageFile, int packageId)> DownloadPackageFilesAsync(Guid kitGuid) { //Go get the package file from the package repo - var packageFile = await _packageService.FetchPackageFileAsync(kitGuid, _umbracoVersion.Current, _webSecurity.GetUserId().ResultOr(0)); + var packageFile = await _packageService.FetchPackageFileAsync(kitGuid, _umbracoVersion.Current, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (packageFile == null) throw new InvalidOperationException("Could not fetch package file " + kitGuid); //add an entry to the installedPackages.config @@ -77,7 +78,7 @@ namespace Umbraco.Web.Install.InstallSteps _packageService.SaveInstalledPackage(packageDefinition); - _packageService.InstallCompiledPackageFiles(packageDefinition, packageFile, _webSecurity.GetUserId().ResultOr(-1)); + _packageService.InstallCompiledPackageFiles(packageDefinition, packageFile, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(-1)); return (compiledPackage.PackageFile.Name, packageDefinition.Id); } diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs index daf8255132..0f2394dcf4 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/StarterKitInstallStep.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Umbraco.Core.Security; using Umbraco.Net; using Umbraco.Core.Services; using Umbraco.Web.Install.Models; @@ -15,13 +16,13 @@ namespace Umbraco.Web.Install.InstallSteps internal class StarterKitInstallStep : InstallSetupStep { private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IPackagingService _packagingService; - public StarterKitInstallStep(IUmbracoApplicationLifetime umbracoApplicationLifetime, IWebSecurity webSecurity, IPackagingService packagingService) + public StarterKitInstallStep(IUmbracoApplicationLifetime umbracoApplicationLifetime, IBackofficeSecurityAccessor backofficeSecurityAccessor, IPackagingService packagingService) { _umbracoApplicationLifetime = umbracoApplicationLifetime; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _packagingService = packagingService; } @@ -48,7 +49,7 @@ namespace Umbraco.Web.Install.InstallSteps var packageFile = new FileInfo(definition.PackagePath); - _packagingService.InstallCompiledPackageData(definition, packageFile, _webSecurity.GetUserId().ResultOr(-1)); + _packagingService.InstallCompiledPackageData(definition, packageFile, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(-1)); } public override bool RequiresExecution(object model) diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs b/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs index 1f495d3a50..8428b60fde 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/ThreadAbortExceptionEnricher.cs @@ -1,11 +1,12 @@ using System; using System.Reflection; using System.Threading; +using Microsoft.Extensions.Options; using Serilog.Core; using Serilog.Events; -using Umbraco.Core.Configuration; using Umbraco.Core.Diagnostics; using Umbraco.Core.Hosting; +using CoreDebugSettings = Umbraco.Core.Configuration.Models.CoreDebugSettings; namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers { @@ -14,13 +15,13 @@ namespace Umbraco.Infrastructure.Logging.Serilog.Enrichers /// public class ThreadAbortExceptionEnricher : ILogEventEnricher { - private readonly ICoreDebugSettings _coreDebugSettings; + private readonly CoreDebugSettings _coreDebugSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IMarchal _marchal; - public ThreadAbortExceptionEnricher(ICoreDebugSettings coreDebugSettings, IHostingEnvironment hostingEnvironment, IMarchal marchal) + public ThreadAbortExceptionEnricher(IOptions coreDebugSettings, IHostingEnvironment hostingEnvironment, IMarchal marchal) { - _coreDebugSettings = coreDebugSettings; + _coreDebugSettings = coreDebugSettings.Value; _hostingEnvironment = hostingEnvironment; _marchal = marchal; } diff --git a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs b/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs index 05d4744526..762e418441 100644 --- a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs @@ -1,8 +1,10 @@ using System; using System.Drawing; using System.IO; -using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -17,13 +19,16 @@ namespace Umbraco.Web.Media { private readonly IMediaFileSystem _mediaFileSystem; private readonly ILogger _logger; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; - public UploadAutoFillProperties(IMediaFileSystem mediaFileSystem, ILogger logger, IContentSettings contentSettings) + public UploadAutoFillProperties( + IMediaFileSystem mediaFileSystem, + ILogger logger, + IOptions contentSettings) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); } /// diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index 98d50d61b1..678860809a 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -2,7 +2,9 @@ using System.IO; using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -21,7 +23,6 @@ namespace Umbraco.Core.Migrations.Install { private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IScopeProvider _scopeProvider; - private readonly IGlobalSettings _globalSettings; private readonly IRuntimeState _runtime; private readonly IMigrationBuilder _migrationBuilder; private readonly IKeyValueService _keyValueService; @@ -38,7 +39,6 @@ namespace Umbraco.Core.Migrations.Install /// public DatabaseBuilder( IScopeProvider scopeProvider, - IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, @@ -50,7 +50,6 @@ namespace Umbraco.Core.Migrations.Install IConfigManipulator configManipulator) { _scopeProvider = scopeProvider; - _globalSettings = globalSettings; _databaseFactory = databaseFactory; _runtime = runtime; _logger = logger; @@ -319,7 +318,7 @@ namespace Umbraco.Core.Migrations.Install return _databaseSchemaValidationResult; var database = scope.Database; - var dbSchema = new DatabaseSchemaCreator(database, _logger, _umbracoVersion, _globalSettings); + var dbSchema = new DatabaseSchemaCreator(database, _logger, _umbracoVersion); _databaseSchemaValidationResult = dbSchema.ValidateSchema(); return _databaseSchemaValidationResult; } @@ -367,7 +366,7 @@ namespace Umbraco.Core.Migrations.Install if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); - var creator = new DatabaseSchemaCreator(database, _logger, _umbracoVersion, _globalSettings); + var creator = new DatabaseSchemaCreator(database, _logger, _umbracoVersion); creator.InitializeDatabaseSchema(); message = message + "

Installation completed!

"; diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index 36f1a30b20..866f5230b0 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -1,6 +1,7 @@ using System; using NPoco; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Models; @@ -16,14 +17,12 @@ namespace Umbraco.Core.Migrations.Install private readonly IDatabase _database; private readonly ILogger _logger; private readonly IUmbracoVersion _umbracoVersion; - private readonly IGlobalSettings _globalSettings; - public DatabaseDataCreator(IDatabase database, ILogger logger, IUmbracoVersion umbracoVersion, IGlobalSettings globalSettings) + public DatabaseDataCreator(IDatabase database, ILogger logger, IUmbracoVersion umbracoVersion) { _database = database; _logger = logger; _umbracoVersion = umbracoVersion; - _globalSettings = globalSettings; } /// @@ -340,7 +339,7 @@ namespace Umbraco.Core.Migrations.Install { // on install, initialize the umbraco migration plan with the final state - var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion, _globalSettings)); + var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion)); var stateValueKey = upgrader.StateValueKey; var finalState = upgrader.Plan.FinalState; diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs index 921ba0b3d5..bf30a520ca 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using NPoco; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; @@ -20,14 +21,12 @@ namespace Umbraco.Core.Migrations.Install private readonly IUmbracoDatabase _database; private readonly ILogger _logger; private readonly IUmbracoVersion _umbracoVersion; - private readonly IGlobalSettings _globalSettings; - public DatabaseSchemaCreator(IUmbracoDatabase database, ILogger logger, IUmbracoVersion umbracoVersion, IGlobalSettings globalSettings) + public DatabaseSchemaCreator(IUmbracoDatabase database, ILogger logger, IUmbracoVersion umbracoVersion) { _database = database; _logger = logger; _umbracoVersion = umbracoVersion; - _globalSettings = globalSettings; } private ISqlSyntaxProvider SqlSyntax => _database.SqlContext.SqlSyntax; @@ -130,7 +129,7 @@ namespace Umbraco.Core.Migrations.Install if (e.Cancel == false) { - var dataCreation = new DatabaseDataCreator(_database, _logger, _umbracoVersion, _globalSettings); + var dataCreation = new DatabaseDataCreator(_database, _logger, _umbracoVersion); foreach (var table in OrderedTables) CreateTable(false, table, dataCreation); } @@ -400,7 +399,7 @@ namespace Umbraco.Core.Migrations.Install where T : new() { var tableType = typeof(T); - CreateTable(overwrite, tableType, new DatabaseDataCreator(_database, _logger, _umbracoVersion, _globalSettings)); + CreateTable(overwrite, tableType, new DatabaseDataCreator(_database, _logger, _umbracoVersion)); } /// diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index c671b0d236..7f8c47f92f 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -2,6 +2,7 @@ using Semver; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Migrations.Upgrade.Common; using Umbraco.Core.Migrations.Upgrade.V_8_0_0; using Umbraco.Core.Migrations.Upgrade.V_8_0_1; @@ -16,17 +17,15 @@ namespace Umbraco.Core.Migrations.Upgrade public class UmbracoPlan : MigrationPlan { private readonly IUmbracoVersion _umbracoVersion; - private readonly IGlobalSettings _globalSettings; private const string InitPrefix = "{init-"; private const string InitSuffix = "}"; /// /// Initializes a new instance of the class. /// - public UmbracoPlan(IUmbracoVersion umbracoVersion, IGlobalSettings globalSettings) + public UmbracoPlan(IUmbracoVersion umbracoVersion) : base(Constants.System.UmbracoUpgradePlanName) { _umbracoVersion = umbracoVersion; - _globalSettings = globalSettings; DefinePlan(); } @@ -191,7 +190,7 @@ namespace Umbraco.Core.Migrations.Upgrade // to 8.7.0... To("{a78e3369-8ea3-40ec-ad3f-5f76929d2b20}"); - + //FINAL } } diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockEditorDataConverter.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockEditorDataConverter.cs index 22e364c0f8..802e8c2ee3 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockEditorDataConverter.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockEditorDataConverter.cs @@ -18,10 +18,35 @@ namespace Umbraco.Core.Models.Blocks _propertyEditorAlias = propertyEditorAlias; } + public BlockEditorData ConvertFrom(JToken json) + { + var value = json.ToObject(); + return Convert(value); + } + + public bool TryDeserialize(string json, out BlockEditorData blockEditorData) + { + try + { + var value = JsonConvert.DeserializeObject(json); + blockEditorData = Convert(value); + return true; + } + catch (System.Exception) + { + blockEditorData = null; + return false; + } + } + public BlockEditorData Deserialize(string json) { var value = JsonConvert.DeserializeObject(json); + return Convert(value); + } + private BlockEditorData Convert(BlockValue value) + { if (value.Layout == null) return BlockEditorData.Empty; diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockListLayoutItem.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockListLayoutItem.cs index 3453ff2a78..5de44e16c1 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockListLayoutItem.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockListLayoutItem.cs @@ -12,7 +12,7 @@ namespace Umbraco.Core.Models.Blocks [JsonConverter(typeof(UdiJsonConverter))] public Udi ContentUdi { get; set; } - [JsonProperty("settingsUdi")] + [JsonProperty("settingsUdi", NullValueHandling = NullValueHandling.Ignore)] [JsonConverter(typeof(UdiJsonConverter))] public Udi SettingsUdi { get; set; } } diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockListModel.cs b/src/Umbraco.Infrastructure/Models/Blocks/BlockListModel.cs index 9a5a3af22a..9a3a26ab30 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockListModel.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/BlockListModel.cs @@ -1,64 +1,63 @@ using System; -using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Runtime.Serialization; -using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core.Models.Blocks { /// - /// The strongly typed model for the Block List editor + /// The strongly typed model for the Block List editor. /// + /// [DataContract(Name = "blockList", Namespace = "")] - public class BlockListModel : IReadOnlyList + public class BlockListModel : ReadOnlyCollection { - private readonly IReadOnlyList _layout = new List(); - + /// + /// Gets the empty . + /// + /// + /// The empty . + /// public static BlockListModel Empty { get; } = new BlockListModel(); + /// + /// Prevents a default instance of the class from being created. + /// private BlockListModel() - { - } - - public BlockListModel(IEnumerable layout) - { - _layout = layout.ToList(); - } - - public int Count => _layout.Count; + : this(new List()) + { } /// - /// Get the block by index + /// Initializes a new instance of the class. /// - /// - /// - public BlockListItem this[int index] => _layout[index]; + /// The list to wrap. + public BlockListModel(IList list) + : base(list) + { } /// - /// Get the block by content Guid + /// Gets the with the specified content key. /// - /// - /// - public BlockListItem this[Guid contentKey] => _layout.FirstOrDefault(x => x.Content.Key == contentKey); + /// + /// The . + /// + /// The content key. + /// + /// The with the specified content key. + /// + public BlockListItem this[Guid contentKey] => this.FirstOrDefault(x => x.Content.Key == contentKey); /// - /// Get the block by content element Udi + /// Gets the with the specified content UDI. /// - /// - /// - public BlockListItem this[Udi contentUdi] - { - get - { - if (!(contentUdi is GuidUdi guidUdi)) return null; - return _layout.FirstOrDefault(x => x.Content.Key == guidUdi.Guid); - } - } - - public IEnumerator GetEnumerator() => _layout.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - + /// + /// The . + /// + /// The content UDI. + /// + /// The with the specified content UDI. + /// + public BlockListItem this[Udi contentUdi] => contentUdi is GuidUdi guidUdi ? this.FirstOrDefault(x => x.Content.Key == guidUdi.Guid) : null; } } diff --git a/src/Umbraco.Infrastructure/Models/Blocks/ContentAndSettingsReference.cs b/src/Umbraco.Infrastructure/Models/Blocks/ContentAndSettingsReference.cs index 523a964c7b..f7222fe140 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/ContentAndSettingsReference.cs +++ b/src/Umbraco.Infrastructure/Models/Blocks/ContentAndSettingsReference.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using System; +using System; +using System.Collections.Generic; namespace Umbraco.Core.Models.Blocks { @@ -12,26 +12,16 @@ namespace Umbraco.Core.Models.Blocks } public Udi ContentUdi { get; } + public Udi SettingsUdi { get; } - public override bool Equals(object obj) - { - return obj is ContentAndSettingsReference reference && Equals(reference); - } + public override bool Equals(object obj) => obj is ContentAndSettingsReference reference && Equals(reference); - public bool Equals(ContentAndSettingsReference other) - { - return EqualityComparer.Default.Equals(ContentUdi, other.ContentUdi) && - EqualityComparer.Default.Equals(SettingsUdi, other.SettingsUdi); - } + public bool Equals(ContentAndSettingsReference other) => other != null + && EqualityComparer.Default.Equals(ContentUdi, other.ContentUdi) + && EqualityComparer.Default.Equals(SettingsUdi, other.SettingsUdi); - public override int GetHashCode() - { - var hashCode = 272556606; - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(ContentUdi); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(SettingsUdi); - return hashCode; - } + public override int GetHashCode() => (ContentUdi, SettingsUdi).GetHashCode(); public static bool operator ==(ContentAndSettingsReference left, ContentAndSettingsReference right) { diff --git a/src/Umbraco.Infrastructure/Models/ContentEditing/UserInvite.cs b/src/Umbraco.Infrastructure/Models/ContentEditing/UserInvite.cs index 06e4d0748c..68a7a9bd3f 100644 --- a/src/Umbraco.Infrastructure/Models/ContentEditing/UserInvite.cs +++ b/src/Umbraco.Infrastructure/Models/ContentEditing/UserInvite.cs @@ -33,7 +33,8 @@ 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.Security().UsernameIsEmail == false && Username.IsNullOrWhiteSpace()) + // TODO: this will need another way of retrieving this setting if and when Configs are removed from Current. + if (Current.SecuritySettings.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 75a64c7b1e..eb130ae13a 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs @@ -13,6 +13,8 @@ using Umbraco.Core.Exceptions; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Strings; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Models.Mapping { @@ -30,13 +32,12 @@ namespace Umbraco.Web.Models.Mapping private readonly IMemberTypeService _memberTypeService; private readonly ILogger _logger; private readonly IShortStringHelper _shortStringHelper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - public ContentTypeMapDefinition(CommonMapper commonMapper, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IFileService fileService, IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, - ILogger logger, IShortStringHelper shortStringHelper, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + ILogger logger, IShortStringHelper shortStringHelper, IOptions globalSettings, IHostingEnvironment hostingEnvironment) { _commonMapper = commonMapper; _propertyEditors = propertyEditors; @@ -47,7 +48,7 @@ namespace Umbraco.Web.Models.Mapping _memberTypeService = memberTypeService; _logger = logger; _shortStringHelper = shortStringHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; } diff --git a/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs index 0bd6d54c08..b55b18db46 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; @@ -15,13 +16,13 @@ namespace Umbraco.Web.Models.Mapping { private readonly PropertyEditorCollection _propertyEditors; private readonly ILogger _logger; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; - public DataTypeMapDefinition(PropertyEditorCollection propertyEditors, ILogger logger, IContentSettings contentSettings) + public DataTypeMapDefinition(PropertyEditorCollection propertyEditors, ILogger logger, IOptions contentSettings) { _propertyEditors = propertyEditors; _logger = logger; - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); } private static readonly int[] SystemIds = diff --git a/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs b/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs index 9045be20aa..abc32fc008 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs @@ -1,14 +1,19 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Dictionary; using Umbraco.Core.Mapping; using Umbraco.Core.Models; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using Umbraco.Core.Dictionary; using Umbraco.Core.Configuration; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; using Umbraco.Web.Security; namespace Umbraco.Web.Models.Mapping @@ -23,31 +28,31 @@ namespace Umbraco.Web.Models.Mapping /// public class MemberTabsAndPropertiesMapper : TabsAndPropertiesMapper { - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILocalizedTextService _localizedTextService; private readonly IMemberTypeService _memberTypeService; private readonly IMemberService _memberService; private readonly IMemberGroupService _memberGroupService; - private readonly IMemberPasswordConfiguration _memberPasswordConfiguration; + private readonly MemberPasswordConfigurationSettings _memberPasswordConfiguration; private readonly PropertyEditorCollection _propertyEditorCollection; public MemberTabsAndPropertiesMapper(ICultureDictionary cultureDictionary, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService localizedTextService, IMemberTypeService memberTypeService, IMemberService memberService, IMemberGroupService memberGroupService, - IMemberPasswordConfiguration memberPasswordConfiguration, + IOptions memberPasswordConfiguration, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, PropertyEditorCollection propertyEditorCollection) : base(cultureDictionary, localizedTextService, contentTypeBaseServiceProvider) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); _memberService = memberService ?? throw new ArgumentNullException(nameof(memberService)); _memberGroupService = memberGroupService ?? throw new ArgumentNullException(nameof(memberGroupService)); - _memberPasswordConfiguration = memberPasswordConfiguration; + _memberPasswordConfiguration = memberPasswordConfiguration.Value; _propertyEditorCollection = propertyEditorCollection; } @@ -75,8 +80,8 @@ namespace Umbraco.Web.Models.Mapping isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); } - if (_webSecurity.CurrentUser != null - && _webSecurity.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser != null + && _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) { var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", source.ContentTypeId); @@ -190,7 +195,7 @@ namespace Umbraco.Web.Models.Mapping // check if this property is flagged as sensitive var isSensitiveProperty = memberType.IsSensitiveProperty(prop.Alias); // check permissions for viewing sensitive data - if (isSensitiveProperty && (_webSecurity.CurrentUser.HasAccessToSensitiveData() == false)) + if (isSensitiveProperty && (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasAccessToSensitiveData() == false)) { // mark this property as sensitive prop.IsSensitive = true; diff --git a/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs index 043b37a654..58a0d98be1 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs @@ -18,6 +18,8 @@ using Umbraco.Web.Actions; using Umbraco.Web.Services; using Umbraco.Core.Media; using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Models.Mapping { @@ -29,13 +31,13 @@ namespace Umbraco.Web.Models.Mapping private readonly ILocalizedTextService _textService; private readonly ActionCollection _actions; private readonly AppCaches _appCaches; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IMediaFileSystem _mediaFileSystem; private readonly IShortStringHelper _shortStringHelper; private readonly IImageUrlGenerator _imageUrlGenerator; public UserMapDefinition(ILocalizedTextService textService, IUserService userService, IEntityService entityService, ISectionService sectionService, - AppCaches appCaches, ActionCollection actions, IGlobalSettings globalSettings, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, + AppCaches appCaches, ActionCollection actions, IOptions globalSettings, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IImageUrlGenerator imageUrlGenerator) { _sectionService = sectionService; @@ -44,7 +46,7 @@ namespace Umbraco.Web.Models.Mapping _textService = textService; _actions = actions; _appCaches = appCaches; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _mediaFileSystem = mediaFileSystem; _shortStringHelper = shortStringHelper; _imageUrlGenerator = imageUrlGenerator; diff --git a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedModelFactory.cs b/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedModelFactory.cs index 8be56850d1..e065ac17b7 100644 --- a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedModelFactory.cs +++ b/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedModelFactory.cs @@ -12,11 +12,12 @@ namespace Umbraco.Core.Models.PublishedContent { private readonly Dictionary _modelInfos; private readonly Dictionary _modelTypeMap; + private readonly IPublishedValueFallback _publishedValueFallback; private class ModelInfo { public Type ParameterType { get; set; } - public Func Ctor { get; set; } + public Func Ctor { get; set; } public Type ModelType { get; set; } public Func ListCtor { get; set; } } @@ -35,7 +36,8 @@ namespace Umbraco.Core.Models.PublishedContent /// PublishedContentModelFactoryResolver.Current.SetFactory(factory); /// /// - public PublishedModelFactory(IEnumerable types) + public PublishedModelFactory(IEnumerable types, + IPublishedValueFallback publishedValueFallback) { var modelInfos = new Dictionary(StringComparer.InvariantCultureIgnoreCase); var modelTypeMap = new Dictionary(StringComparer.InvariantCultureIgnoreCase); @@ -52,7 +54,7 @@ namespace Umbraco.Core.Models.PublishedContent foreach (var ctor in type.GetConstructors()) { var parms = ctor.GetParameters(); - if (parms.Length == 1 && typeof(IPublishedElement).IsAssignableFrom(parms[0].ParameterType)) + if (parms.Length == 2 && typeof(IPublishedElement).IsAssignableFrom(parms[0].ParameterType) && typeof(IPublishedValueFallback).IsAssignableFrom(parms[1].ParameterType)) { if (constructor != null) throw new InvalidOperationException($"Type {type.FullName} has more than one public constructor with one argument of type, or implementing, IPublishedElement."); @@ -71,13 +73,14 @@ namespace Umbraco.Core.Models.PublishedContent throw new InvalidOperationException($"Both types '{type.AssemblyQualifiedName}' and '{modelInfo.ModelType.AssemblyQualifiedName}' want to be a model type for content type with alias \"{typeName}\"."); // have to use an unsafe ctor because we don't know the types, really - var modelCtor = ReflectionUtilities.EmitConstructorUnsafe>(constructor); + var modelCtor = ReflectionUtilities.EmitConstructorUnsafe>(constructor); modelInfos[typeName] = new ModelInfo { ParameterType = parameterType, ModelType = type, Ctor = modelCtor }; modelTypeMap[typeName] = type; } _modelInfos = modelInfos.Count > 0 ? modelInfos : null; _modelTypeMap = modelTypeMap; + _publishedValueFallback = publishedValueFallback; } /// @@ -95,7 +98,7 @@ namespace Umbraco.Core.Models.PublishedContent throw new InvalidOperationException($"Model {modelInfo.ModelType} expects argument of type {modelInfo.ParameterType.FullName}, but got {element.GetType().FullName}."); // can cast, because we checked when creating the ctor - return (IPublishedElement) modelInfo.Ctor(element); + return (IPublishedElement) modelInfo.Ctor(element, _publishedValueFallback); } /// diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 6b1aa96e69..79f830bc51 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -5,8 +5,10 @@ using System.Linq; using System.Net; using System.Xml.Linq; using System.Xml.XPath; +using Microsoft.Extensions.Options; using Umbraco.Core.Collections; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -29,7 +31,7 @@ namespace Umbraco.Core.Packaging private readonly PropertyEditorCollection _propertyEditors; private readonly IScopeProvider _scopeProvider; private readonly IShortStringHelper _shortStringHelper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly ILocalizedTextService _localizedTextService; private readonly IEntityService _entityService; private readonly IContentTypeService _contentTypeService; @@ -37,7 +39,7 @@ namespace Umbraco.Core.Packaging public PackageDataInstallation(ILogger logger, IFileService fileService, IMacroService macroService, ILocalizationService localizationService, IDataTypeService dataTypeService, IEntityService entityService, IContentTypeService contentTypeService, - IContentService contentService, PropertyEditorCollection propertyEditors, IScopeProvider scopeProvider, IShortStringHelper shortStringHelper, IGlobalSettings globalSettings, + IContentService contentService, PropertyEditorCollection propertyEditors, IScopeProvider scopeProvider, IShortStringHelper shortStringHelper, IOptions globalSettings, ILocalizedTextService localizedTextService) { _logger = logger; @@ -48,7 +50,7 @@ namespace Umbraco.Core.Packaging _propertyEditors = propertyEditors; _scopeProvider = scopeProvider; _shortStringHelper = shortStringHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _localizedTextService = localizedTextService; _entityService = entityService; _contentTypeService = contentTypeService; diff --git a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs index cf31b3ea52..4970fc302e 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs @@ -28,7 +28,6 @@ namespace Umbraco.Core.Packaging public PackageInstallation(PackageDataInstallation packageDataInstallation, PackageFileInstallation packageFileInstallation, CompiledPackageXmlParser parser, IPackageActionRunner packageActionRunner, IHostingEnvironment hostingEnvironment) { - _packageExtraction = new PackageExtraction(); _packageFileInstallation = packageFileInstallation ?? throw new ArgumentNullException(nameof(packageFileInstallation)); _packageDataInstallation = packageDataInstallation ?? throw new ArgumentNullException(nameof(packageDataInstallation)); diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/SpecialDbTypes.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/SpecialDbTypes.cs index 4b606bc0f5..6d211ebbd9 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/SpecialDbTypes.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/SpecialDbTypes.cs @@ -7,6 +7,7 @@ public enum SpecialDbTypes { NTEXT, - NCHAR + NCHAR, + NVARCHARMAX } } diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/LanguageFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/LanguageFactory.cs index 1da4a8dfac..0b5937a328 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/LanguageFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/LanguageFactory.cs @@ -1,5 +1,6 @@ using System.Globalization; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; @@ -7,7 +8,7 @@ namespace Umbraco.Core.Persistence.Factories { internal static class LanguageFactory { - public static ILanguage BuildEntity(IGlobalSettings globalSettings, LanguageDto dto) + public static ILanguage BuildEntity(GlobalSettings globalSettings, LanguageDto dto) { var lang = new Language(globalSettings, dto.IsoCode) { diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/UserFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/UserFactory.cs index b56e822e92..839f7b5ad7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/UserFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/UserFactory.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Dtos; @@ -8,7 +9,7 @@ namespace Umbraco.Core.Persistence.Factories { internal static class UserFactory { - public static IUser BuildEntity(IGlobalSettings globalSettings, UserDto dto) + public static IUser BuildEntity(GlobalSettings globalSettings, UserDto dto) { var guidId = dto.Id.ToGuid(); diff --git a/src/Umbraco.Infrastructure/Persistence/PocoDataDataReader.cs b/src/Umbraco.Infrastructure/Persistence/PocoDataDataReader.cs index 1d7d301b87..460a4d3d90 100644 --- a/src/Umbraco.Infrastructure/Persistence/PocoDataDataReader.cs +++ b/src/Umbraco.Infrastructure/Persistence/PocoDataDataReader.cs @@ -79,6 +79,9 @@ namespace Umbraco.Core.Persistence case SpecialDbTypes.NCHAR: sqlDbType = SqlDbType.NChar; break; + case SpecialDbTypes.NVARCHARMAX: + sqlDbType = SqlDbType.NVarChar; + break; default: throw new ArgumentOutOfRangeException(); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs index 61aabdc1b5..af0f58eb0e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs @@ -54,11 +54,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override bool PerformExists(Guid id) => GetMany().FirstOrDefault(x => x.Key == id) != null; - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable GetAllWithFullCachePolicy() { - // the cache policy will always want everything - // even GetMany(ids) gets everything and filters afterwards - if (ids.Any()) throw new PanicException("There can be no ids specified"); return CommonRepository.GetAllTypes().OfType(); } @@ -135,7 +132,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (objectTypes.Any()) { - sql = sql.Where("umbracoNode.nodeObjectType IN (@objectTypes)", objectTypes); + sql = sql.Where("umbracoNode.nodeObjectType IN (@objectTypes)", new { objectTypes = objectTypes }); } return Database.Fetch(sql); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index b2a83e83fd..5bfbd86486 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -90,6 +90,24 @@ namespace Umbraco.Core.Persistence.Repositories.Implement return moveInfo; } + protected override IEnumerable PerformGetAll(params int[] ids) + { + var result = GetAllWithFullCachePolicy(); + + // By default the cache policy will always want everything + // even GetMany(ids) gets everything and filters afterwards, + // however if we are using No Cache, we must still be able to support + // collections of Ids, so this is to work around that: + if (ids.Any()) + { + return result.Where(x => ids.Contains(x.Id)); + } + + return result; + } + + protected abstract IEnumerable GetAllWithFullCachePolicy(); + protected virtual PropertyType CreatePropertyType(string propertyEditorAlias, ValueStorageType storageType, string propertyTypeAlias) { return new PropertyType(_shortStringHelper, propertyEditorAlias, storageType, propertyTypeAlias); @@ -1185,7 +1203,7 @@ AND umbracoNode.id <> @id", { // first clear dependencies Database.Delete("WHERE propertyTypeId = @Id", new { Id = propertyTypeId }); - Database.Delete("WHERE propertytypeid = @Id", new { Id = propertyTypeId }); + Database.Delete("WHERE propertyTypeId = @Id", new { Id = propertyTypeId }); // then delete the property type Database.Delete("WHERE contentTypeId = @Id AND id = @PropertyTypeId", diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs index 245ff10f7f..80a83ce909 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -19,14 +21,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class LanguageRepository : NPocoRepositoryBase, ILanguageRepository { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly Dictionary _codeIdMap = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _idCodeMap = new Dictionary(); - public LanguageRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IGlobalSettings globalSettings) + public LanguageRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IOptions globalSettings) : base(scopeAccessor, cache, logger) { - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } protected override IRepositoryCachePolicy CreateCachePolicy() @@ -40,7 +42,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override ILanguage PerformGet(int id) { - throw new NotSupportedException(); // not required since policy is full dataset + return PerformGetAll(id).FirstOrDefault(); } protected override IEnumerable PerformGetAll(params int[] ids) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs index c6caa40750..818b5c9f21 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs @@ -48,11 +48,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override IMediaType PerformGet(string alias) => GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias)); - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable GetAllWithFullCachePolicy() { - // the cache policy will always want everything - // even GetMany(ids) gets everything and filters afterwards - if (ids.Any()) throw new PanicException("There can be no ids specified"); return CommonRepository.GetAllTypes().OfType(); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs index b9c40eebc9..059035a9bc 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs @@ -59,11 +59,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override IMemberType PerformGet(string alias) => GetMany().FirstOrDefault(x => x.Alias.InvariantEquals(alias)); - protected override IEnumerable PerformGetAll(params int[] ids) + protected override IEnumerable GetAllWithFullCachePolicy() { - // the cache policy will always want everything - // even GetMany(ids) gets everything and filters afterwards - if (ids.Any()) throw new PanicException("There can be no ids specified"); return CommonRepository.GetAllTypes().OfType(); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs index 498cf51432..aae888e0c5 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Models; @@ -14,13 +16,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class ScriptRepository : FileRepository, IScriptRepository { private readonly IIOHelper _ioHelper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public ScriptRepository(IFileSystems fileSystems, IIOHelper ioHelper, IGlobalSettings globalSettings) + public ScriptRepository(IFileSystems fileSystems, IIOHelper ioHelper, IOptions globalSettings) : base(fileSystems.ScriptsFileSystem) { _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } #region Implementation of IRepository diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs index f432d6959e..4243d534aa 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Models; @@ -13,13 +15,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class StylesheetRepository : FileRepository, IStylesheetRepository { private readonly IIOHelper _ioHelper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public StylesheetRepository(IFileSystems fileSystems, IIOHelper ioHelper, IGlobalSettings globalSettings) + public StylesheetRepository(IFileSystems fileSystems, IIOHelper ioHelper, IOptions globalSettings) : base(fileSystems.StylesheetsFileSystem) { _ioHelper = ioHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } #region Overrides of FileRepository diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs index 5ba32a4d2f..23da951efe 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs @@ -3,9 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; +using Microsoft.Extensions.Options; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -24,8 +26,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class UserRepository : NPocoRepositoryBase, IUserRepository { private readonly IMapperCollection _mapperCollection; - private readonly IGlobalSettings _globalSettings; - private readonly IUserPasswordConfiguration _passwordConfiguration; + private readonly GlobalSettings _globalSettings; + private readonly UserPasswordConfigurationSettings _passwordConfiguration; private readonly IJsonSerializer _jsonSerializer; private string _passwordConfigJson; private bool _passwordConfigInitialized; @@ -40,12 +42,19 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// A dictionary specifying the configuration for user passwords. If this is null then no password configuration will be persisted or read. /// /// - public UserRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IMapperCollection mapperCollection, IGlobalSettings globalSettings, IUserPasswordConfiguration passwordConfiguration, IJsonSerializer jsonSerializer) + public UserRepository( + IScopeAccessor scopeAccessor, + AppCaches appCaches, + ILogger logger, + IMapperCollection mapperCollection, + IOptions globalSettings, + IOptions passwordConfiguration, + IJsonSerializer jsonSerializer) : base(scopeAccessor, appCaches, logger) { _mapperCollection = mapperCollection ?? throw new ArgumentNullException(nameof(mapperCollection)); - _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); - _passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration)); + _globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings)); + _passwordConfiguration = passwordConfiguration.Value ?? throw new ArgumentNullException(nameof(passwordConfiguration)); _jsonSerializer = jsonSerializer; } diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index 6095630161..a9377d696b 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -198,7 +198,13 @@ namespace Umbraco.Core.Persistence.SqlSyntax return "NCHAR"; } else if (dbTypes == SpecialDbTypes.NTEXT) + { return "NTEXT"; + } + else if (dbTypes == SpecialDbTypes.NVARCHARMAX) + { + return "NVARCHAR(MAX)"; + } return "NVARCHAR"; } diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index e243ea45ef..c092cc8b0e 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -1,11 +1,10 @@ using System; using System.Data.Common; -using System.Data.SqlClient; using System.Threading; +using Microsoft.Extensions.Options; using NPoco; using NPoco.FluentMappings; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Persistence.FaultHandling; using Umbraco.Core.Persistence.Mappers; @@ -28,7 +27,7 @@ namespace Umbraco.Core.Persistence internal class UmbracoDatabaseFactory : DisposableObjectSlim, IUmbracoDatabaseFactory { private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly Lazy _mappers; private readonly ILogger _logger; @@ -70,8 +69,8 @@ namespace Umbraco.Core.Persistence /// Initializes a new instance of the . /// /// Used by core runtime. - public UmbracoDatabaseFactory(ILogger logger, IGlobalSettings globalSettings, IConnectionStrings connectionStrings, Lazy mappers,IDbProviderFactoryCreator dbProviderFactoryCreator) - : this(logger, globalSettings, connectionStrings, Constants.System.UmbracoConnectionName, mappers, dbProviderFactoryCreator) + public UmbracoDatabaseFactory(ILogger logger, IOptions globalSettings, IOptions connectionStrings, Lazy mappers,IDbProviderFactoryCreator dbProviderFactoryCreator) + : this(logger, globalSettings.Value, connectionStrings.Value, mappers, dbProviderFactoryCreator) { } @@ -80,17 +79,15 @@ namespace Umbraco.Core.Persistence /// Initializes a new instance of the . /// /// Used by the other ctor and in tests. - public UmbracoDatabaseFactory(ILogger logger, IGlobalSettings globalSettings, IConnectionStrings connectionStrings, string connectionStringName, Lazy mappers, IDbProviderFactoryCreator dbProviderFactoryCreator) + public UmbracoDatabaseFactory(ILogger logger, GlobalSettings globalSettings, ConnectionStrings connectionStrings, 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; _mappers = mappers ?? throw new ArgumentNullException(nameof(mappers)); _dbProviderFactoryCreator = dbProviderFactoryCreator ?? throw new ArgumentNullException(nameof(dbProviderFactoryCreator)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - var settings = connectionStrings[connectionStringName]; + var settings = connectionStrings.UmbracoConnectionString; if (settings == null) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfiguration.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfiguration.cs index e461da40dc..1af3aa1303 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfiguration.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfiguration.cs @@ -4,14 +4,11 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - /// /// The configuration object for the Block List editor /// public class BlockListConfiguration { - - [ConfigurationField("blocks", "Available Blocks", "views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.html", Description = "Define the available blocks.")] public BlockConfiguration[] Blocks { get; set; } @@ -61,7 +58,7 @@ namespace Umbraco.Web.PropertyEditors public int? Max { get; set; } } - [ConfigurationField("useLiveEditing", "Live editing mode", "boolean", Description = "Live editing in editor overlays for live updated custom views.")] + [ConfigurationField("useLiveEditing", "Live editing mode", "boolean", Description = "Live editing in editor overlays for live updated custom views or labels using custom expression.")] public bool UseLiveEditing { get; set; } [ConfigurationField("useInlineEditingAsDefault", "Inline editing mode", "boolean", Description = "Use the inline editor as the default block view.")] @@ -69,7 +66,5 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("maxPropertyWidth", "Property editor width", "textstring", Description = "optional css overwrite, example: 800px or 100%")] public string MaxPropertyWidth { get; set; } - - } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfigurationEditor.cs index 328e545ded..050bcfbfd2 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfigurationEditor.cs @@ -1,11 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text.RegularExpressions; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Umbraco.Core; -using Umbraco.Core.IO; +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors @@ -14,6 +7,8 @@ namespace Umbraco.Web.PropertyEditors { public BlockListConfigurationEditor(IIOHelper ioHelper) : base(ioHelper) { + } + } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ComplexPropertyEditorContentEventHandler.cs b/src/Umbraco.Infrastructure/PropertyEditors/ComplexPropertyEditorContentEventHandler.cs new file mode 100644 index 0000000000..d7fd184329 --- /dev/null +++ b/src/Umbraco.Infrastructure/PropertyEditors/ComplexPropertyEditorContentEventHandler.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Events; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; + +namespace Umbraco.Core.PropertyEditors +{ + /// + /// Utility class for dealing with Copying/Saving events for complex editors + /// + public class ComplexPropertyEditorContentEventHandler : IDisposable + { + private readonly string _editorAlias; + private readonly Func _formatPropertyValue; + private bool _disposedValue; + + public ComplexPropertyEditorContentEventHandler(string editorAlias, + Func formatPropertyValue) + { + _editorAlias = editorAlias; + _formatPropertyValue = formatPropertyValue; + ContentService.Copying += ContentService_Copying; + ContentService.Saving += ContentService_Saving; + } + + /// + /// Copying event handler + /// + /// + /// + private void ContentService_Copying(IContentService sender, CopyEventArgs e) + { + var props = e.Copy.GetPropertiesByEditor(_editorAlias); + UpdatePropertyValues(props, false); + } + + /// + /// Saving event handler + /// + /// + /// + private void ContentService_Saving(IContentService sender, ContentSavingEventArgs e) + { + foreach (var entity in e.SavedEntities) + { + var props = entity.GetPropertiesByEditor(_editorAlias); + UpdatePropertyValues(props, true); + } + } + + private void UpdatePropertyValues(IEnumerable props, bool onlyMissingKeys) + { + foreach (var prop in props) + { + // A Property may have one or more values due to cultures + var propVals = prop.Values; + foreach (var cultureVal in propVals) + { + // Remove keys from published value & any nested properties + var updatedPublishedVal = _formatPropertyValue(cultureVal.PublishedValue?.ToString(), onlyMissingKeys); + cultureVal.PublishedValue = updatedPublishedVal; + + // Remove keys from edited/draft value & any nested properties + var updatedEditedVal = _formatPropertyValue(cultureVal.EditedValue?.ToString(), onlyMissingKeys); + cultureVal.EditedValue = updatedEditedVal; + } + } + } + + /// + /// Unbinds from events + /// + /// + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + ContentService.Copying -= ContentService_Copying; + ContentService.Saving -= ContentService_Saving; + } + _disposedValue = true; + } + } + + /// + /// Unbinds from events + /// + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs index 698fcb10b3..d4c5130b21 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -22,17 +24,24 @@ namespace Umbraco.Web.PropertyEditors public class FileUploadPropertyEditor : DataEditor, IMediaUrlGenerator { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly UploadAutoFillProperties _uploadAutoFillProperties; private readonly IDataTypeService _dataTypeService; private readonly ILocalizationService _localizationService; private readonly ILocalizedTextService _localizedTextService; - public FileUploadPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) + public FileUploadPropertyEditor( + ILogger logger, + IMediaFileSystem mediaFileSystem, + IOptions contentSettings, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper) : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _dataTypeService = dataTypeService; _localizationService = localizationService; _localizedTextService = localizedTextService; @@ -45,8 +54,8 @@ namespace Umbraco.Web.PropertyEditors /// The corresponding property value editor. protected override IDataValueEditor CreateValueEditor() { - var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, _contentSettings); - editor.Validators.Add(new UploadFileTypeValidator(_localizedTextService, _contentSettings)); + var editor = new FileUploadPropertyValueEditor(Attribute, _mediaFileSystem, _dataTypeService, _localizationService, _localizedTextService, ShortStringHelper, Options.Create(_contentSettings)); + editor.Validators.Add(new UploadFileTypeValidator(_localizedTextService, Options.Create(_contentSettings))); return editor; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs index e45896551c..db675e2e42 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs @@ -1,7 +1,8 @@ using System; using System.IO; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; @@ -16,13 +17,20 @@ namespace Umbraco.Web.PropertyEditors internal class FileUploadPropertyValueEditor : DataValueEditor { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; - public FileUploadPropertyValueEditor(DataEditorAttribute attribute, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IContentSettings contentSettings) + public FileUploadPropertyValueEditor( + DataEditorAttribute attribute, + IMediaFileSystem mediaFileSystem, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IOptions contentSettings) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index 586a120609..0fea46f2d3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -29,7 +31,7 @@ namespace Umbraco.Web.PropertyEditors public class ImageCropperPropertyEditor : DataEditor, IMediaUrlGenerator { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly IDataTypeService _dataTypeService; private readonly ILocalizationService _localizationService; private readonly IIOHelper _ioHelper; @@ -38,17 +40,25 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public ImageCropperPropertyEditor(ILogger logger, IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(logger, dataTypeService, localizationService, localizedTextService,shortStringHelper) + public ImageCropperPropertyEditor( + ILogger logger, + IMediaFileSystem mediaFileSystem, + IOptions contentSettings, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + IIOHelper ioHelper, + IShortStringHelper shortStringHelper, + ILocalizedTextService localizedTextService) + : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _dataTypeService = dataTypeService; _localizationService = localizationService; _ioHelper = ioHelper; // TODO: inject? - _autoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, _contentSettings); + _autoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, contentSettings); } public bool TryGetMediaPath(string alias, object value, out string mediaPath) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index 1c7c8b922a..8f88c301d1 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -2,7 +2,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -22,9 +22,17 @@ namespace Umbraco.Web.PropertyEditors { private readonly ILogger _logger; private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; - public ImageCropperPropertyValueEditor(DataEditorAttribute attribute, ILogger logger, IMediaFileSystem mediaFileSystem, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, IContentSettings contentSettings) + public ImageCropperPropertyValueEditor( + DataEditorAttribute attribute, + ILogger logger, + IMediaFileSystem mediaFileSystem, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + ContentSettings contentSettings) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs index 6ad465ecd5..01a03d36e3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs @@ -95,7 +95,6 @@ namespace Umbraco.Web.PropertyEditors _contentTypes = new Lazy>(() => _contentTypeService.GetAll().ToDictionary(c => c.Alias) ); - } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/PropertyEditorsComponent.cs b/src/Umbraco.Infrastructure/PropertyEditors/PropertyEditorsComponent.cs index de071d1a1e..cd7b7a1f39 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/PropertyEditorsComponent.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/PropertyEditorsComponent.cs @@ -1,7 +1,11 @@ -using System.Linq; +using System; +using System.Collections.Generic; +using System.Linq; using Umbraco.Core.Composing; +using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; namespace Umbraco.Web.PropertyEditors @@ -9,6 +13,7 @@ namespace Umbraco.Web.PropertyEditors public sealed class PropertyEditorsComponent : IComponent { private readonly PropertyEditorCollection _propertyEditors; + private readonly List _terminate = new List(); public PropertyEditorsComponent(PropertyEditorCollection propertyEditors) { @@ -27,32 +32,48 @@ namespace Umbraco.Web.PropertyEditors } public void Terminate() - { } - - private static void Initialize(FileUploadPropertyEditor fileUpload) { - MediaService.Saving += fileUpload.MediaServiceSaving; - ContentService.Copied += fileUpload.ContentServiceCopied; - - MediaService.Deleted += (sender, args) - => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast())); - ContentService.Deleted += (sender, args) - => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast())); - MemberService.Deleted += (sender, args) - => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast())); + foreach (var t in _terminate) t(); } - private static void Initialize(ImageCropperPropertyEditor imageCropper) + private void Initialize(FileUploadPropertyEditor fileUpload) + { + MediaService.Saving += fileUpload.MediaServiceSaving; + _terminate.Add(() => MediaService.Saving -= fileUpload.MediaServiceSaving); + ContentService.Copied += fileUpload.ContentServiceCopied; + _terminate.Add(() => ContentService.Copied -= fileUpload.ContentServiceCopied); + + void mediaServiceDeleted(IMediaService sender, DeleteEventArgs args) => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast())); + MediaService.Deleted += mediaServiceDeleted; + _terminate.Add(() => MediaService.Deleted -= mediaServiceDeleted); + + void contentServiceDeleted(IContentService sender, DeleteEventArgs args) => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast())); + ContentService.Deleted += contentServiceDeleted; + _terminate.Add(() => ContentService.Deleted -= contentServiceDeleted); + + void memberServiceDeleted(IMemberService sender, DeleteEventArgs args) => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast())); + MemberService.Deleted += memberServiceDeleted; + _terminate.Add(() => MemberService.Deleted -= memberServiceDeleted); + } + + private void Initialize(ImageCropperPropertyEditor imageCropper) { MediaService.Saving += imageCropper.MediaServiceSaving; + _terminate.Add(() => MediaService.Saving -= imageCropper.MediaServiceSaving); ContentService.Copied += imageCropper.ContentServiceCopied; + _terminate.Add(() => ContentService.Copied -= imageCropper.ContentServiceCopied); - MediaService.Deleted += (sender, args) - => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast())); - ContentService.Deleted += (sender, args) - => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast())); - MemberService.Deleted += (sender, args) - => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast())); + void mediaServiceDeleted(IMediaService sender, DeleteEventArgs args) => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast())); + MediaService.Deleted += mediaServiceDeleted; + _terminate.Add(() => MediaService.Deleted -= mediaServiceDeleted); + + void contentServiceDeleted(IContentService sender, DeleteEventArgs args) => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast())); + ContentService.Deleted += contentServiceDeleted; + _terminate.Add(() => ContentService.Deleted -= contentServiceDeleted); + + void memberServiceDeleted(IMemberService sender, DeleteEventArgs args) => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast())); + MemberService.Deleted += memberServiceDeleted; + _terminate.Add(() => MemberService.Deleted -= memberServiceDeleted); } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs index b64c52648a..d3e1e7aabe 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/UploadFileTypeValidator.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.IO; using System.Linq; +using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; -using Umbraco.Composing; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -16,12 +15,12 @@ namespace Umbraco.Web.PropertyEditors internal class UploadFileTypeValidator : IValueValidator { private readonly ILocalizedTextService _localizedTextService; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; - public UploadFileTypeValidator(ILocalizedTextService localizedTextService, IContentSettings contentSettings) + public UploadFileTypeValidator(ILocalizedTextService localizedTextService, IOptions contentSettings) { _localizedTextService = localizedTextService; - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; } public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration) @@ -55,7 +54,7 @@ namespace Umbraco.Web.PropertyEditors } } - internal static bool IsValidFileExtension(string fileName, IContentSettings contentSettings) + internal static bool IsValidFileExtension(string fileName, ContentSettings contentSettings) { if (fileName.IndexOf('.') <= 0) return false; var extension = fileName.GetFileExtension().TrimStart("."); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs index 0c90a41fbd..f46c118174 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs @@ -120,7 +120,9 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters settingsData = null; } - var layoutRef = new BlockListItem(contentGuidUdi, contentData, settingGuidUdi, settingsData); + var layoutType = typeof(BlockListItem<,>).MakeGenericType(contentData.GetType(), settingsData?.GetType() ?? typeof(IPublishedElement)); + var layoutRef = (BlockListItem)Activator.CreateInstance(layoutType, contentGuidUdi, contentData, settingGuidUdi, settingsData); + layout.Add(layoutRef); } diff --git a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs index ac8d0980c4..5b7a720a40 100644 --- a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs +++ b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs @@ -1,8 +1,9 @@ -using Examine; using System.Globalization; using System.Linq; +using Examine; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -16,14 +17,18 @@ namespace Umbraco.Web.Routing { private readonly ILogger _logger; private readonly IEntityService _entityService; - private readonly IContentSettings _contentConfigSettings; + private readonly ContentSettings _contentSettings; private readonly IExamineManager _examineManager; - public ContentFinderByConfigured404(ILogger logger, IEntityService entityService, IContentSettings contentConfigSettings, IExamineManager examineManager) + public ContentFinderByConfigured404( + ILogger logger, + IEntityService entityService, + IOptions contentConfigSettings, + IExamineManager examineManager) { _logger = logger; _entityService = entityService; - _contentConfigSettings = contentConfigSettings; + _contentSettings = contentConfigSettings.Value; _examineManager = examineManager; } @@ -63,7 +68,7 @@ namespace Umbraco.Web.Routing } var error404 = NotFoundHandlerHelper.GetCurrentNotFoundPageId( - _contentConfigSettings.Error404Collection.ToArray(), + _contentSettings.Error404Collection.ToArray(), _entityService, new PublishedContentQuery(frequest.UmbracoContext.PublishedSnapshot, frequest.UmbracoContext.VariationContextAccessor, _examineManager), errorCulture); diff --git a/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs index 335e1f868a..20fbe9a1ef 100644 --- a/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs +++ b/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Linq; using Umbraco.Composing; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -28,7 +29,7 @@ namespace Umbraco.Web.Routing /// /// internal static int? GetCurrentNotFoundPageId( - IContentErrorPage[] error404Collection, + ContentErrorPage[] error404Collection, string requestServerName, IEntityService entityService, IPublishedContentQuery publishedContentQuery, @@ -38,7 +39,7 @@ namespace Umbraco.Web.Routing } internal static int? GetCurrentNotFoundPageId( - IContentErrorPage[] error404Collection, + ContentErrorPage[] error404Collection, IEntityService entityService, IPublishedContentQuery publishedContentQuery, CultureInfo errorCulture) @@ -67,7 +68,7 @@ namespace Umbraco.Web.Routing /// /// /// - internal static int? GetContentIdFromErrorPageConfig(IContentErrorPage errorPage, IEntityService entityService, IPublishedContentQuery publishedContentQuery) + internal static int? GetContentIdFromErrorPageConfig(ContentErrorPage errorPage, IEntityService entityService, IPublishedContentQuery publishedContentQuery) { if (errorPage.HasContentId) return errorPage.ContentId; diff --git a/src/Umbraco.Infrastructure/Routing/RedirectTrackingComponent.cs b/src/Umbraco.Infrastructure/Routing/RedirectTrackingComponent.cs index f9256b3692..107e224486 100644 --- a/src/Umbraco.Infrastructure/Routing/RedirectTrackingComponent.cs +++ b/src/Umbraco.Infrastructure/Routing/RedirectTrackingComponent.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.Models; @@ -24,15 +26,14 @@ namespace Umbraco.Web.Routing { private const string _eventStateKey = "Umbraco.Web.Redirects.RedirectTrackingEventHandler"; - - private readonly IWebRoutingSettings _webRoutingSettings; + private readonly WebRoutingSettings _webRoutingSettings; private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; private readonly IRedirectUrlService _redirectUrlService; private readonly IVariationContextAccessor _variationContextAccessor; - public RedirectTrackingComponent(IWebRoutingSettings webRoutingSettings, IPublishedSnapshotAccessor publishedSnapshotAccessor, IRedirectUrlService redirectUrlService, IVariationContextAccessor variationContextAccessor) + public RedirectTrackingComponent(IOptions webRoutingSettings, IPublishedSnapshotAccessor publishedSnapshotAccessor, IRedirectUrlService redirectUrlService, IVariationContextAccessor variationContextAccessor) { - _webRoutingSettings = webRoutingSettings; + _webRoutingSettings = webRoutingSettings.Value; _publishedSnapshotAccessor = publishedSnapshotAccessor; _redirectUrlService = redirectUrlService; _variationContextAccessor = variationContextAccessor; @@ -40,9 +41,6 @@ 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 (_webRoutingSettings.DisableRedirectUrlTracking) return; - ContentService.Publishing += ContentService_Publishing; ContentService.Published += ContentService_Published; ContentService.Moving += ContentService_Moving; @@ -57,10 +55,18 @@ namespace Umbraco.Web.Routing } public void Terminate() - { } + { + ContentService.Publishing -= ContentService_Publishing; + ContentService.Published -= ContentService_Published; + ContentService.Moving -= ContentService_Moving; + ContentService.Moved -= ContentService_Moved; + } private void ContentService_Publishing(IContentService sender, PublishEventArgs args) { + // don't let the event handlers kick in if Redirect Tracking is turned off in the config + if (_webRoutingSettings.DisableRedirectUrlTracking) return; + var oldRoutes = GetOldRoutes(args.EventState); foreach (var entity in args.PublishedEntities) { @@ -70,12 +76,18 @@ namespace Umbraco.Web.Routing private void ContentService_Published(IContentService sender, ContentPublishedEventArgs args) { + // don't let the event handlers kick in if Redirect Tracking is turned off in the config + if (_webRoutingSettings.DisableRedirectUrlTracking) return; + var oldRoutes = GetOldRoutes(args.EventState); CreateRedirects(oldRoutes); } private void ContentService_Moving(IContentService sender, MoveEventArgs args) { + // don't let the event handlers kick in if Redirect Tracking is turned off in the config + if (_webRoutingSettings.DisableRedirectUrlTracking) return; + var oldRoutes = GetOldRoutes(args.EventState); foreach (var info in args.MoveInfoCollection) { @@ -85,6 +97,9 @@ namespace Umbraco.Web.Routing private void ContentService_Moved(IContentService sender, MoveEventArgs args) { + // don't let the event handlers kick in if Redirect Tracking is turned off in the config + if (_webRoutingSettings.DisableRedirectUrlTracking) return; + var oldRoutes = GetOldRoutes(args.EventState); CreateRedirects(oldRoutes); } diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComponent.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComponent.cs index 1432e6b7f2..a473511e56 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComponent.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComponent.cs @@ -1,5 +1,6 @@ -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; namespace Umbraco.Core.Runtime @@ -7,12 +8,12 @@ namespace Umbraco.Core.Runtime public class CoreInitialComponent : IComponent { private readonly IIOHelper _ioHelper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public CoreInitialComponent(IIOHelper ioHelper, IGlobalSettings globalSettings) + public CoreInitialComponent(IIOHelper ioHelper, IOptions globalSettings) { _ioHelper = ioHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } public void Initialize() diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs index 852c617750..3422252842 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs @@ -55,6 +55,8 @@ using Umbraco.Web.Templates; using Umbraco.Web.Trees; using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator; using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Core.Runtime { @@ -124,7 +126,7 @@ namespace Umbraco.Core.Runtime // register a server registrar, by default it's the db registrar composition.RegisterUnique(f => { - var globalSettings = f.GetInstance(); + var globalSettings = f.GetInstance>().Value; // TODO: we still register the full IServerMessenger because // even on 1 single server we can have 2 concurrent app domains @@ -163,7 +165,7 @@ namespace Umbraco.Core.Runtime composition.RegisterUnique(); composition.RegisterUnique(factory - => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetInstance()))); + => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(factory.GetInstance>().Value))); composition.UrlSegmentProviders() .Append(); diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 2f9766e5c2..e4b724089c 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -2,9 +2,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using Microsoft.Extensions.Options; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Events; using Umbraco.Core.Exceptions; using Umbraco.Core.Hosting; using Umbraco.Core.IO; @@ -23,14 +26,15 @@ namespace Umbraco.Core.Runtime { private ComponentCollection _components; private IFactory _factory; - private readonly RuntimeState _state; + // runtime state, this instance will get replaced again once the essential services are available to run the check + private RuntimeState _state = RuntimeState.Booting(); private readonly IUmbracoBootPermissionChecker _umbracoBootPermissionChecker; - private readonly IRequestCache _requestCache; - private readonly IGlobalSettings _globalSettings; - private readonly IConnectionStrings _connectionStrings; + private readonly GlobalSettings _globalSettings; + private readonly ConnectionStrings _connectionStrings; public CoreRuntime( - Configs configs, + GlobalSettings globalSettings, + ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, @@ -41,34 +45,28 @@ namespace Umbraco.Core.Runtime IDbProviderFactoryCreator dbProviderFactoryCreator, IMainDom mainDom, ITypeFinder typeFinder, - IRequestCache requestCache) + AppCaches appCaches) { + _globalSettings = globalSettings; + _connectionStrings = connectionStrings; + IOHelper = ioHelper; - Configs = configs; - UmbracoVersion = umbracoVersion ; + AppCaches = appCaches; + UmbracoVersion = umbracoVersion; Profiler = profiler; HostingEnvironment = hostingEnvironment; BackOfficeInfo = backOfficeInfo; DbProviderFactoryCreator = dbProviderFactoryCreator; _umbracoBootPermissionChecker = umbracoBootPermissionChecker; - _requestCache = requestCache; Logger = logger; MainDom = mainDom; TypeFinder = typeFinder; - _globalSettings = Configs.Global(); - _connectionStrings = configs.ConnectionStrings(); + _globalSettings = globalSettings; + _connectionStrings = 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(Configs.Global(), UmbracoVersion) - { - Level = RuntimeLevel.Boot - }; } /// @@ -88,7 +86,7 @@ namespace Umbraco.Core.Runtime /// /// Gets the profiling logger. /// - protected IProfilingLogger ProfilingLogger { get; private set; } + public IProfilingLogger ProfilingLogger { get; private set; } /// /// Gets the @@ -99,9 +97,10 @@ namespace Umbraco.Core.Runtime /// Gets the /// protected IIOHelper IOHelper { get; } + protected IHostingEnvironment HostingEnvironment { get; } - protected Configs Configs { get; } - protected IUmbracoVersion UmbracoVersion { get; } + public AppCaches AppCaches { get; } + public IUmbracoVersion UmbracoVersion { get; } /// public IRuntimeState State => _state; @@ -164,31 +163,33 @@ namespace Umbraco.Core.Runtime try { - - // run handlers - RuntimeOptions.DoRuntimeBoot(ProfilingLogger); - - // application caches - var appCaches = GetAppCaches(); + OnRuntimeBoot(); // database factory - var databaseFactory = GetDatabaseFactory(); + var databaseFactory = CreateDatabaseFactory(); // type finder/loader - var typeLoader = new TypeLoader(TypeFinder, appCaches.RuntimeCache, new DirectoryInfo(HostingEnvironment.LocalTempPath), ProfilingLogger); + var typeLoader = new TypeLoader(TypeFinder, AppCaches.RuntimeCache, new DirectoryInfo(HostingEnvironment.LocalTempPath), ProfilingLogger); + + // re-create the state object with the essential services + _state = new RuntimeState(_globalSettings, UmbracoVersion, databaseFactory, Logger); // 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, HostingEnvironment, BackOfficeInfo); + composition = new Composition(register, typeLoader, ProfilingLogger, _state, IOHelper, AppCaches); + + composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, MainDom, AppCaches, databaseFactory, typeLoader, _state, TypeFinder, IOHelper, UmbracoVersion, DbProviderFactoryCreator, HostingEnvironment, BackOfficeInfo); // register ourselves (TODO: Should we put this in RegisterEssentials?) composition.Register(_ => this, Lifetime.Singleton); + // run handlers + OnRuntimeEssentials(composition, AppCaches, typeLoader, databaseFactory); + try { // determine our runtime level - DetermineRuntimeLevel(databaseFactory, ProfilingLogger); + DetermineRuntimeLevel(databaseFactory); } finally { @@ -243,9 +244,6 @@ namespace Umbraco.Core.Runtime // throws if not full-trust _umbracoBootPermissionChecker.ThrowIfNotPermissions(); - // 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)}"); @@ -257,7 +255,6 @@ namespace Umbraco.Core.Runtime _components = _factory.GetInstance(); _components.Initialize(); - // 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 // fail to resolve - but we run Initialize within a factory scope - and then, @@ -313,31 +310,29 @@ namespace Umbraco.Core.Runtime } } - // internal for tests - internal void DetermineRuntimeLevel(IUmbracoDatabaseFactory databaseFactory, IProfilingLogger profilingLogger) + private void DetermineRuntimeLevel(IUmbracoDatabaseFactory databaseFactory) { - using (var timer = profilingLogger.DebugDuration("Determining runtime level.", "Determined.")) + using var timer = ProfilingLogger.DebugDuration("Determining runtime level.", "Determined."); + + try { - try - { - _state.DetermineRuntimeLevel(databaseFactory, profilingLogger); + _state.DetermineRuntimeLevel(); - profilingLogger.Debug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", _state.Level, _state.Reason); + ProfilingLogger.Debug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", _state.Level, _state.Reason); - if (_state.Level == RuntimeLevel.Upgrade) - { - profilingLogger.Debug("Configure database factory for upgrades."); - databaseFactory.ConfigureForUpgrade(); - } - } - catch + if (_state.Level == RuntimeLevel.Upgrade) { - _state.Level = RuntimeLevel.BootFailed; - _state.Reason = RuntimeLevelReason.BootFailedOnException; - timer?.Fail(); - throw; + ProfilingLogger.Debug("Configure database factory for upgrades."); + databaseFactory.ConfigureForUpgrade(); } } + catch + { + _state.Level = RuntimeLevel.BootFailed; + _state.Reason = RuntimeLevelReason.BootFailedOnException; + timer?.Fail(); + throw; + } } private IEnumerable ResolveComposerTypes(TypeLoader typeLoader) @@ -373,21 +368,6 @@ namespace Umbraco.Core.Runtime protected virtual IEnumerable GetComposerTypes(TypeLoader typeLoader) => typeLoader.GetTypes(); - /// - /// Gets the application caches. - /// - protected virtual AppCaches GetAppCaches() - { - // need the deep clone runtime cache provider to ensure entities are cached properly, ie - // are cloned in and cloned out - no request-based cache here since no web-based context, - // is overridden by the web runtime - - return new AppCaches( - new DeepCloneAppCache(new ObjectCacheAppCache()), - _requestCache, - new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); - } - /// /// Returns the application path of the site/solution /// @@ -400,14 +380,33 @@ namespace Umbraco.Core.Runtime => null; /// - /// Gets the database factory. + /// Creates the database factory. /// /// This is strictly internal, for tests only. - protected internal virtual IUmbracoDatabaseFactory GetDatabaseFactory() - => new UmbracoDatabaseFactory(Logger, _globalSettings, _connectionStrings, new Lazy(() => _factory.GetInstance()), DbProviderFactoryCreator); + protected internal virtual IUmbracoDatabaseFactory CreateDatabaseFactory() + => new UmbracoDatabaseFactory(Logger, Options.Create(_globalSettings), Options.Create(_connectionStrings), new Lazy(() => _factory.GetInstance()), DbProviderFactoryCreator); #endregion + #region Events + + protected void OnRuntimeBoot() + { + RuntimeOptions.DoRuntimeBoot(ProfilingLogger); + RuntimeBooting?.Invoke(this, ProfilingLogger); + } + + protected void OnRuntimeEssentials(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory) + { + RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory); + RuntimeEssentials?.Invoke(this, new RuntimeEssentialsEventArgs(composition, appCaches, typeLoader, databaseFactory)); + } + + public event TypedEventHandler RuntimeBooting; + public event TypedEventHandler RuntimeEssentials; + + #endregion + } } diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeEssentialsEventArgs.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeEssentialsEventArgs.cs new file mode 100644 index 0000000000..78d068cb9c --- /dev/null +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeEssentialsEventArgs.cs @@ -0,0 +1,23 @@ +using System; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.Persistence; + +namespace Umbraco.Core.Runtime +{ + public class RuntimeEssentialsEventArgs : EventArgs + { + public RuntimeEssentialsEventArgs(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory) + { + Composition = composition; + AppCaches = appCaches; + TypeLoader = typeLoader; + DatabaseFactory = databaseFactory; + } + + public Composition Composition { get; } + public AppCaches AppCaches { get; } + public TypeLoader TypeLoader { get; } + public IUmbracoDatabaseFactory DatabaseFactory { get; } + } +} diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index d3bb7eefac..4cbe8f088a 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -7,6 +7,7 @@ using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; @@ -31,7 +32,7 @@ namespace Umbraco.Core.Runtime private bool _errorDuringAcquiring; private object _locker = new object(); - public SqlMainDomLock(ILogger logger, IGlobalSettings globalSettings, IConnectionStrings connectionStrings, IDbProviderFactoryCreator dbProviderFactoryCreator, IHostingEnvironment hostingEnvironment) + public SqlMainDomLock(ILogger logger, GlobalSettings globalSettings, ConnectionStrings connectionStrings, IDbProviderFactoryCreator dbProviderFactoryCreator, IHostingEnvironment hostingEnvironment) { // 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(); @@ -40,7 +41,6 @@ namespace Umbraco.Core.Runtime _dbFactory = new UmbracoDatabaseFactory(_logger, globalSettings, connectionStrings, - Constants.System.UmbracoConnectionName, new Lazy(() => new MapperCollection(Enumerable.Empty())), dbProviderFactoryCreator); diff --git a/src/Umbraco.Infrastructure/RuntimeOptions.cs b/src/Umbraco.Infrastructure/RuntimeOptions.cs index 562a7e3c5c..23abd474a4 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(IFactory factory) + internal static void DoRuntimeEssentials(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory) { if (_onEssentials== null) return; foreach (var action in _onEssentials) - action(factory); + action(composition, appCaches, typeLoader, databaseFactory); } /// @@ -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 4a33291314..4adf9fdf7c 100644 --- a/src/Umbraco.Infrastructure/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/RuntimeState.cs @@ -1,10 +1,9 @@ using System; using System.Threading; using Semver; -using Umbraco.Core.Collections; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Exceptions; -using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; @@ -16,16 +15,29 @@ namespace Umbraco.Core /// public class RuntimeState : IRuntimeState { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IUmbracoVersion _umbracoVersion; + private readonly IUmbracoDatabaseFactory _databaseFactory; + private readonly ILogger _logger; + + /// + /// The initial + /// + public static RuntimeState Booting() => new RuntimeState() { Level = RuntimeLevel.Boot }; + + private RuntimeState() + { + } /// /// Initializes a new instance of the class. /// - public RuntimeState(IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion) + public RuntimeState(GlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IUmbracoDatabaseFactory databaseFactory, ILogger logger) { _globalSettings = globalSettings; _umbracoVersion = umbracoVersion; + _databaseFactory = databaseFactory; + _logger = logger; } @@ -53,16 +65,14 @@ namespace Umbraco.Core /// public BootFailedException BootFailedException { get; internal set; } - /// - /// Determines the runtime level. - /// - public void DetermineRuntimeLevel(IUmbracoDatabaseFactory databaseFactory, ILogger logger) + /// + public void DetermineRuntimeLevel() { - if (databaseFactory.Configured == false) + if (_databaseFactory.Configured == false) { // local version *does* match code version, but the database is not configured // install - may happen with Deploy/Cloud/etc - logger.Debug("Database is not configured, need to install Umbraco."); + _logger.Debug("Database is not configured, need to install Umbraco."); Level = RuntimeLevel.Install; Reason = RuntimeLevelReason.InstallNoDatabase; return; @@ -75,16 +85,16 @@ namespace Umbraco.Core var tries = _globalSettings.InstallMissingDatabase ? 2 : 5; for (var i = 0;;) { - connect = databaseFactory.CanConnect; + connect = _databaseFactory.CanConnect; if (connect || ++i == tries) break; - logger.Debug("Could not immediately connect to database, trying again."); + _logger.Debug("Could not immediately connect to database, trying again."); Thread.Sleep(1000); } if (connect == false) { // cannot connect to configured database, this is bad, fail - logger.Debug("Could not connect to database."); + _logger.Debug("Could not connect to database."); if (_globalSettings.InstallMissingDatabase) { @@ -108,12 +118,12 @@ namespace Umbraco.Core bool noUpgrade; try { - noUpgrade = EnsureUmbracoUpgradeState(databaseFactory, logger); + noUpgrade = EnsureUmbracoUpgradeState(_databaseFactory, _logger); } catch (Exception e) { // can connect to the database but cannot check the upgrade state... oops - logger.Warn(e, "Could not check the upgrade state."); + _logger.Warn(e, "Could not check the upgrade state."); if (_globalSettings.InstallEmptyDatabase) { @@ -145,14 +155,14 @@ namespace Umbraco.Core // although the files version matches the code version, the database version does not // which means the local files have been upgraded but not the database - need to upgrade - logger.Debug("Has not reached the final upgrade step, need to upgrade Umbraco."); + _logger.Debug("Has not reached the final upgrade step, need to upgrade Umbraco."); Level = RuntimeLevel.Upgrade; Reason = RuntimeLevelReason.UpgradeMigrations; } private bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger) { - var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion, _globalSettings)); + var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion)); var stateValueKey = upgrader.StateValueKey; // no scope, no service - just directly accessing the database diff --git a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs index adae7b3828..e681538e12 100644 --- a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs +++ b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs @@ -2,7 +2,7 @@ using System.Threading; using System.Threading.Tasks; using Umbraco.Core; -using Umbraco.Core.Configuration.HealthChecks; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; using Umbraco.Core.Sync; @@ -17,7 +17,7 @@ namespace Umbraco.Web.Scheduling private readonly HealthCheckNotificationMethodCollection _notifications; private readonly IScopeProvider _scopeProvider; private readonly IProfilingLogger _logger; - private readonly IHealthChecksSettings _healthChecksSettingsConfig; + private readonly HealthChecksSettings _healthChecksSettings; private readonly IServerRegistrar _serverRegistrar; private readonly IRuntimeState _runtimeState; @@ -29,7 +29,7 @@ namespace Umbraco.Web.Scheduling HealthCheckNotificationMethodCollection notifications, IMainDom mainDom, IProfilingLogger logger, - IHealthChecksSettings healthChecksSettingsConfig, + HealthChecksSettings healthChecksSettings, IServerRegistrar serverRegistrar, IRuntimeState runtimeState, IScopeProvider scopeProvider) @@ -41,7 +41,7 @@ namespace Umbraco.Web.Scheduling _scopeProvider = scopeProvider; _runtimeState = runtimeState; _logger = logger; - _healthChecksSettingsConfig = healthChecksSettingsConfig; + _healthChecksSettings = healthChecksSettings; _serverRegistrar = serverRegistrar; _runtimeState = runtimeState; } @@ -74,7 +74,7 @@ namespace Umbraco.Web.Scheduling using (var scope = _scopeProvider.CreateScope()) using (_logger.DebugDuration("Health checks executing", "Health checks complete")) { - var healthCheckConfig = _healthChecksSettingsConfig; + var healthCheckConfig = _healthChecksSettings; // 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 b3e30a7353..51c62de581 100644 --- a/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs +++ b/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs @@ -1,5 +1,7 @@ using System; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; @@ -8,30 +10,29 @@ using Umbraco.Core.Sync; namespace Umbraco.Web.Scheduling { - public class LogScrubber : RecurringTaskBase { private readonly IMainDom _mainDom; private readonly IServerRegistrar _serverRegistrar; private readonly IAuditService _auditService; - private readonly ILoggingSettings _settings; + private readonly LoggingSettings _settings; private readonly IProfilingLogger _logger; private readonly IScopeProvider _scopeProvider; public LogScrubber(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, - IMainDom mainDom, IServerRegistrar serverRegistrar, IAuditService auditService, ILoggingSettings settings, IScopeProvider scopeProvider, IProfilingLogger logger) + IMainDom mainDom, IServerRegistrar serverRegistrar, IAuditService auditService, IOptions settings, IScopeProvider scopeProvider, IProfilingLogger logger) : base(runner, delayMilliseconds, periodMilliseconds) { _mainDom = mainDom; _serverRegistrar = serverRegistrar; _auditService = auditService; - _settings = settings; + _settings = settings.Value; _scopeProvider = scopeProvider; _logger = logger; } // maximum age, in minutes - private int GetLogScrubbingMaximumAge(ILoggingSettings settings) + private int GetLogScrubbingMaximumAge(LoggingSettings settings) { var maximumAge = 24 * 60; // 24 hours, in minutes try diff --git a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs index 6ec0250d90..674012e797 100644 --- a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs @@ -14,13 +14,14 @@ namespace Umbraco.Web.Scheduling private readonly IMainDom _mainDom; private readonly IRuntimeState _runtime; private readonly IServerMessenger _serverMessenger; + private readonly IBackofficeSecurityFactory _backofficeSecurityFactory; private readonly IServerRegistrar _serverRegistrar; private readonly IUmbracoContextFactory _umbracoContextFactory; public ScheduledPublishing(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar, IContentService contentService, - IUmbracoContextFactory umbracoContextFactory, ILogger logger, IServerMessenger serverMessenger) + IUmbracoContextFactory umbracoContextFactory, ILogger logger, IServerMessenger serverMessenger, IBackofficeSecurityFactory backofficeSecurityFactory) : base(runner, delayMilliseconds, periodMilliseconds) { _runtime = runtime; @@ -30,6 +31,7 @@ namespace Umbraco.Web.Scheduling _umbracoContextFactory = umbracoContextFactory; _logger = logger; _serverMessenger = serverMessenger; + _backofficeSecurityFactory = backofficeSecurityFactory; } public override bool IsAsync => false; @@ -76,6 +78,7 @@ namespace Umbraco.Web.Scheduling // but then what should be its "scope"? could we attach it to scopes? // - and we should definitively *not* have to flush it here (should be auto) // + _backofficeSecurityFactory.EnsureBackofficeSecurity(); using (var contextReference = _umbracoContextFactory.EnsureUmbracoContext()) { try diff --git a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs index a5850719ab..5fb4f19473 100644 --- a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs +++ b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs @@ -3,12 +3,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.HealthChecks; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; using Umbraco.Core.Services; @@ -18,7 +18,7 @@ using Umbraco.Web.Routing; namespace Umbraco.Web.Scheduling { - internal sealed class SchedulerComponent : IComponent + public sealed class SchedulerComponent : IComponent { private const int DefaultDelayMilliseconds = 180000; // 3 mins private const int OneMinuteMilliseconds = 60000; @@ -36,11 +36,12 @@ namespace Umbraco.Web.Scheduling private readonly HealthCheckCollection _healthChecks; private readonly HealthCheckNotificationMethodCollection _notifications; private readonly IUmbracoContextFactory _umbracoContextFactory; - private readonly IHealthChecksSettings _healthChecksSettingsConfig; + private readonly HealthChecksSettings _healthChecksSettings; private readonly IServerMessenger _serverMessenger; private readonly IRequestAccessor _requestAccessor; - private readonly ILoggingSettings _loggingSettings; - private readonly IKeepAliveSettings _keepAliveSettings; + private readonly IBackofficeSecurityFactory _backofficeSecurityFactory; + private readonly LoggingSettings _loggingSettings; + private readonly KeepAliveSettings _keepAliveSettings; private readonly IHostingEnvironment _hostingEnvironment; private BackgroundTaskRunner _keepAliveRunner; @@ -57,10 +58,11 @@ namespace Umbraco.Web.Scheduling IContentService contentService, IAuditService auditService, HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger logger, - IApplicationShutdownRegistry applicationShutdownRegistry, IHealthChecksSettings healthChecksSettingsConfig, + IApplicationShutdownRegistry applicationShutdownRegistry, IOptions healthChecksSettings, IServerMessenger serverMessenger, IRequestAccessor requestAccessor, - ILoggingSettings loggingSettings, IKeepAliveSettings keepAliveSettings, - IHostingEnvironment hostingEnvironment) + IOptions loggingSettings, IOptions keepAliveSettings, + IHostingEnvironment hostingEnvironment, + IBackofficeSecurityFactory backofficeSecurityFactory) { _runtime = runtime; _mainDom = mainDom; @@ -74,11 +76,12 @@ namespace Umbraco.Web.Scheduling _healthChecks = healthChecks; _notifications = notifications; - _healthChecksSettingsConfig = healthChecksSettingsConfig ?? throw new ArgumentNullException(nameof(healthChecksSettingsConfig)); + _healthChecksSettings = healthChecksSettings.Value ?? throw new ArgumentNullException(nameof(healthChecksSettings)); _serverMessenger = serverMessenger; _requestAccessor = requestAccessor; - _loggingSettings = loggingSettings; - _keepAliveSettings = keepAliveSettings; + _backofficeSecurityFactory = backofficeSecurityFactory; + _loggingSettings = loggingSettings.Value; + _keepAliveSettings = keepAliveSettings.Value; _hostingEnvironment = hostingEnvironment; } @@ -129,7 +132,7 @@ namespace Umbraco.Web.Scheduling tasks.Add(RegisterLogScrubber(_loggingSettings)); tasks.Add(RegisterTempFileCleanup()); - var healthCheckConfig = _healthChecksSettingsConfig; + var healthCheckConfig = _healthChecksSettings; if (healthCheckConfig.NotificationSettings.Enabled) tasks.Add(RegisterHealthCheckNotifier(healthCheckConfig, _healthChecks, _notifications, _logger)); @@ -137,11 +140,11 @@ namespace Umbraco.Web.Scheduling }); } - private IBackgroundTask RegisterKeepAlive(IKeepAliveSettings keepAliveSettings) + private IBackgroundTask RegisterKeepAlive(KeepAliveSettings keepAliveSettings) { // ping/keepalive // on all servers - var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _requestAccessor, _mainDom, keepAliveSettings, _logger, _serverRegistrar); + var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _requestAccessor, _mainDom, Options.Create(keepAliveSettings), _logger, _serverRegistrar); _keepAliveRunner.TryAdd(task); return task; } @@ -150,12 +153,12 @@ 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, _mainDom, _serverRegistrar, _contentService, _umbracoContextFactory, _logger, _serverMessenger); + var task = new ScheduledPublishing(_publishingRunner, DefaultDelayMilliseconds, OneMinuteMilliseconds, _runtime, _mainDom, _serverRegistrar, _contentService, _umbracoContextFactory, _logger, _serverMessenger, _backofficeSecurityFactory); _publishingRunner.TryAdd(task); return task; } - private IBackgroundTask RegisterHealthCheckNotifier(IHealthChecksSettings healthCheckSettingsConfig, + private IBackgroundTask RegisterHealthCheckNotifier(HealthChecksSettings healthCheckSettingsConfig, HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, IProfilingLogger logger) { @@ -176,16 +179,16 @@ namespace Umbraco.Web.Scheduling } var periodInMilliseconds = healthCheckSettingsConfig.NotificationSettings.PeriodInHours * 60 * 60 * 1000; - var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _mainDom, logger, _healthChecksSettingsConfig, _serverRegistrar, _runtime, _scopeProvider); + var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _mainDom, logger, _healthChecksSettings, _serverRegistrar, _runtime, _scopeProvider); _healthCheckRunner.TryAdd(task); return task; } - private IBackgroundTask RegisterLogScrubber(ILoggingSettings settings) + private IBackgroundTask RegisterLogScrubber(LoggingSettings settings) { // log scrubbing // install on all, will only run on non-replica servers - var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(), _mainDom, _serverRegistrar, _auditService, settings, _scopeProvider, _logger); + var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(), _mainDom, _serverRegistrar, _auditService, Options.Create(settings), _scopeProvider, _logger); _scrubberRunner.TryAdd(task); return task; } diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index 3b17ae876d..b7ccf539f6 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -2,11 +2,11 @@ using System.Data; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; +using CoreDebugSettings = Umbraco.Core.Configuration.Models.CoreDebugSettings; namespace Umbraco.Core.Scoping { @@ -17,7 +17,7 @@ namespace Umbraco.Core.Scoping internal class Scope : IScope { private readonly ScopeProvider _scopeProvider; - private readonly ICoreDebugSettings _coreDebugSettings; + private readonly CoreDebugSettings _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, - ICoreDebugSettings coreDebugSettings, + CoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, IScopeContext scopeContext, bool detachable, IsolationLevel isolationLevel = IsolationLevel.Unspecified, @@ -118,7 +118,7 @@ namespace Umbraco.Core.Scoping // initializes a new scope public Scope(ScopeProvider scopeProvider, - ICoreDebugSettings coreDebugSettings, + CoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, bool detachable, IScopeContext scopeContext, IsolationLevel isolationLevel = IsolationLevel.Unspecified, @@ -132,7 +132,7 @@ namespace Umbraco.Core.Scoping // initializes a new scope in a nested scopes chain, with its parent public Scope(ScopeProvider scopeProvider, - ICoreDebugSettings coreDebugSettings, + CoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, IsolationLevel isolationLevel = IsolationLevel.Unspecified, diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index 610f308b96..a2f626909b 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -1,14 +1,13 @@ using System; -using System.Collections.Generic; using System.Data; +using Microsoft.Extensions.Options; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; -using Current = Umbraco.Composing.Current; +using CoreDebugSettings = Umbraco.Core.Configuration.Models.CoreDebugSettings; #if DEBUG_SCOPES using System.Linq; @@ -26,14 +25,14 @@ namespace Umbraco.Core.Scoping private readonly ITypeFinder _typeFinder; private readonly IRequestCache _requestCache; private readonly FileSystems _fileSystems; - private readonly ICoreDebugSettings _coreDebugSettings; + private readonly CoreDebugSettings _coreDebugSettings; private readonly IMediaFileSystem _mediaFileSystem; - public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, ICoreDebugSettings coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, IRequestCache requestCache) + public ScopeProvider(IUmbracoDatabaseFactory databaseFactory, FileSystems fileSystems, IOptions coreDebugSettings, IMediaFileSystem mediaFileSystem, ILogger logger, ITypeFinder typeFinder, IRequestCache requestCache) { DatabaseFactory = databaseFactory; _fileSystems = fileSystems; - _coreDebugSettings = coreDebugSettings; + _coreDebugSettings = coreDebugSettings.Value; _mediaFileSystem = mediaFileSystem; _logger = logger; _typeFinder = typeFinder; diff --git a/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs b/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs index 1946e2041b..d18480eb82 100644 --- a/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs +++ b/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs @@ -12,7 +12,7 @@ namespace Umbraco.Web.Search /// /// Utility to rebuild all indexes on a background thread /// - public sealed class BackgroundIndexRebuilder + public class BackgroundIndexRebuilder { private static readonly object RebuildLocker = new object(); private readonly IndexRebuilder _indexRebuilder; @@ -34,7 +34,7 @@ namespace Umbraco.Web.Search /// /// /// - public void RebuildIndexes(bool onlyEmptyIndexes, int waitMilliseconds = 0) + public virtual void RebuildIndexes(bool onlyEmptyIndexes, int waitMilliseconds = 0) { // TODO: need a way to disable rebuilding on startup diff --git a/src/Umbraco.Infrastructure/Search/ExamineComponent.cs b/src/Umbraco.Infrastructure/Search/ExamineComponent.cs index 35a8804ecb..ae5bfd628b 100644 --- a/src/Umbraco.Infrastructure/Search/ExamineComponent.cs +++ b/src/Umbraco.Infrastructure/Search/ExamineComponent.cs @@ -24,7 +24,6 @@ namespace Umbraco.Web.Search private readonly IValueSetBuilder _mediaValueSetBuilder; private readonly IValueSetBuilder _memberValueSetBuilder; private readonly BackgroundIndexRebuilder _backgroundIndexRebuilder; - private static object _isConfiguredLocker = new object(); private readonly IScopeProvider _scopeProvider; private readonly ServiceContext _services; private readonly IMainDom _mainDom; @@ -104,7 +103,13 @@ namespace Umbraco.Web.Search } public void Terminate() - { } + { + ContentCacheRefresher.CacheUpdated -= ContentCacheRefresherUpdated; + ContentTypeCacheRefresher.CacheUpdated -= ContentTypeCacheRefresherUpdated; + MediaCacheRefresher.CacheUpdated -= MediaCacheRefresherUpdated; + MemberCacheRefresher.CacheUpdated -= MemberCacheRefresherUpdated; + LanguageCacheRefresher.CacheUpdated -= LanguageCacheRefresherUpdated; + } #region Cache refresher updated event handlers diff --git a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs index 7d3be1d52b..4fa7dad253 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs @@ -4,7 +4,6 @@ using System.Linq; using Umbraco.Core.Events; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; diff --git a/src/Umbraco.Infrastructure/Services/Implement/FileService.cs b/src/Umbraco.Infrastructure/Services/Implement/FileService.cs index 188fad4c7b..e82c71d1a5 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/FileService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/FileService.cs @@ -3,8 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using Microsoft.Extensions.Options; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.IO; @@ -29,7 +31,7 @@ namespace Umbraco.Core.Services.Implement private readonly IPartialViewMacroRepository _partialViewMacroRepository; private readonly IAuditRepository _auditRepository; private readonly IShortStringHelper _shortStringHelper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private const string PartialViewHeader = "@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage"; @@ -38,7 +40,7 @@ namespace Umbraco.Core.Services.Implement public FileService(IScopeProvider uowProvider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IStylesheetRepository stylesheetRepository, IScriptRepository scriptRepository, ITemplateRepository templateRepository, IPartialViewRepository partialViewRepository, IPartialViewMacroRepository partialViewMacroRepository, - IAuditRepository auditRepository, IShortStringHelper shortStringHelper, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + IAuditRepository auditRepository, IShortStringHelper shortStringHelper, IOptions globalSettings, IHostingEnvironment hostingEnvironment) : base(uowProvider, logger, eventMessagesFactory) { _stylesheetRepository = stylesheetRepository; @@ -48,7 +50,7 @@ namespace Umbraco.Core.Services.Implement _partialViewMacroRepository = partialViewMacroRepository; _auditRepository = auditRepository; _shortStringHelper = shortStringHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs index cf53fb34cd..47e4ebed2c 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs @@ -3,12 +3,11 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Net; using System.Net.Mail; using System.Text; using System.Threading; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -26,18 +25,18 @@ namespace Umbraco.Core.Services.Implement private readonly IContentService _contentService; private readonly ILocalizationService _localizationService; private readonly INotificationsRepository _notificationsRepository; - private readonly IGlobalSettings _globalSettings; - private readonly IContentSettings _contentSettings; + private readonly GlobalSettings _globalSettings; + private readonly ContentSettings _contentSettings; private readonly IEmailSender _emailSender; 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, IContentSettings contentSettings, IEmailSender emailSender) + ILogger logger, IIOHelper ioHelper, INotificationsRepository notificationsRepository, IOptions globalSettings, IOptions contentSettings, IEmailSender emailSender) { _notificationsRepository = notificationsRepository; - _globalSettings = globalSettings; - _contentSettings = contentSettings; + _globalSettings = globalSettings.Value; + _contentSettings = contentSettings.Value; _emailSender = emailSender; _uowProvider = provider ?? throw new ArgumentNullException(nameof(provider)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); @@ -303,7 +302,7 @@ namespace Umbraco.Core.Services.Implement if (content.ContentType.VariesByNothing()) { - if (!_contentSettings.DisableHtmlEmail) + if (!_contentSettings.Notifications.DisableHtmlEmail) { //create the HTML summary for invariant content @@ -345,7 +344,7 @@ namespace Umbraco.Core.Services.Implement { //it's variant, so detect what cultures have changed - if (!_contentSettings.DisableHtmlEmail) + if (!_contentSettings.Notifications.DisableHtmlEmail) { //Create the HTML based summary (ul of culture names) @@ -406,15 +405,15 @@ namespace Umbraco.Core.Services.Implement string.Concat(siteUri.Authority, _ioHelper.ResolveUrl(_globalSettings.UmbracoPath)), summary.ToString()); - var fromMail = _contentSettings.NotificationEmailAddress ?? _globalSettings.SmtpSettings.From; + var fromMail = _contentSettings.Notifications.Email ?? _globalSettings.Smtp.From; // create the mail message - var mail = new MailMessage(fromMail, mailingUser.Email); + var mail = new MailMessage(fromMail, fromMail); // populate the message mail.Subject = createSubject((mailingUser, subjectVars)); - if (_contentSettings.DisableHtmlEmail) + if (_contentSettings.Notifications.DisableHtmlEmail) { mail.IsBodyHtml = false; mail.Body = createBody((user: mailingUser, body: bodyVars, false)); diff --git a/src/Umbraco.Infrastructure/Services/Implement/PackagingService.cs b/src/Umbraco.Infrastructure/Services/Implement/PackagingService.cs index 561b410786..238258b8c2 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/PackagingService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/PackagingService.cs @@ -21,7 +21,6 @@ namespace Umbraco.Core.Services.Implement /// public class PackagingService : IPackagingService { - private readonly IPackageInstallation _packageInstallation; private readonly IIOHelper _ioHelper; private readonly IAuditService _auditService; diff --git a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs index faf7889fbf..fdd79e7264 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs @@ -4,7 +4,9 @@ using System.Data.Common; using System.Globalization; using System.Linq; using System.Linq.Expressions; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.Logging; using Umbraco.Core.Models.Membership; @@ -22,16 +24,16 @@ namespace Umbraco.Core.Services.Implement { private readonly IUserRepository _userRepository; private readonly IUserGroupRepository _userGroupRepository; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly bool _isUpgrading; public UserService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IRuntimeState runtimeState, - IUserRepository userRepository, IUserGroupRepository userGroupRepository, IGlobalSettings globalSettings) + IUserRepository userRepository, IUserGroupRepository userGroupRepository, IOptions globalSettings) : base(provider, logger, eventMessagesFactory) { _userRepository = userRepository; _userGroupRepository = userGroupRepository; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _isUpgrading = runtimeState.Level == RuntimeLevel.Install || runtimeState.Level == RuntimeLevel.Upgrade; } diff --git a/src/Umbraco.Infrastructure/Trees/TreeNode.cs b/src/Umbraco.Infrastructure/Trees/TreeNode.cs index 1b6945bcdd..5cf1054fc8 100644 --- a/src/Umbraco.Infrastructure/Trees/TreeNode.cs +++ b/src/Umbraco.Infrastructure/Trees/TreeNode.cs @@ -4,6 +4,7 @@ using System.Runtime.Serialization; using Umbraco.Composing; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Trees @@ -113,7 +114,11 @@ namespace Umbraco.Web.Models.Trees return Current.IOHelper.ResolveUrl("~" + Icon.TrimStart('~')); //legacy icon path - var backOfficePath = Current.Configs.Global().GetUmbracoMvcArea(Current.HostingEnvironment); + + // TODO: replace this when we have something other than Current.Configs available + var backOfficePath = Current.GlobalSettings.GetUmbracoMvcArea(Current.HostingEnvironment); + + return string.Format("{0}images/umbraco/{1}", backOfficePath.EnsureEndsWith("/"), Icon); } } diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj index adb2a95202..bcd3773ac8 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -10,38 +10,38 @@ - - + + - - - + + + - - - - + + + + - + - + - - + + - - + + - - + + diff --git a/src/Umbraco.Infrastructure/Users/EmailSender.cs b/src/Umbraco.Infrastructure/Users/EmailSender.cs index 9a2f425021..c45a9af0d3 100644 --- a/src/Umbraco.Infrastructure/Users/EmailSender.cs +++ b/src/Umbraco.Infrastructure/Users/EmailSender.cs @@ -2,9 +2,11 @@ using System.Linq; using System.Net.Mail; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using MimeKit; using MimeKit.Text; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using SmtpClient = MailKit.Net.Smtp.SmtpClient; @@ -17,16 +19,16 @@ namespace Umbraco.Core { // TODO: This should encapsulate a BackgroundTaskRunner with a queue to send these emails! - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly bool _enableEvents; - public EmailSender(IGlobalSettings globalSettings) : this(globalSettings, false) + public EmailSender(IOptions globalSettings) : this(globalSettings, false) { } - public EmailSender(IGlobalSettings globalSettings, bool enableEvents) + public EmailSender(IOptions globalSettings, bool enableEvents) { - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _enableEvents = enableEvents; _smtpConfigured = new Lazy(() => _globalSettings.IsSmtpServerConfigured); @@ -49,12 +51,12 @@ namespace Umbraco.Core using (var client = new SmtpClient()) { - client.Connect(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port); + client.Connect(_globalSettings.Smtp.Host, _globalSettings.Smtp.Port); - if (!(_globalSettings.SmtpSettings.Username is null && - _globalSettings.SmtpSettings.Password is null)) + if (!(_globalSettings.Smtp.Username is null && + _globalSettings.Smtp.Password is null)) { - client.Authenticate(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password); + client.Authenticate(_globalSettings.Smtp.Username, _globalSettings.Smtp.Password); } client.Send(ConstructEmailMessage(message)); @@ -78,16 +80,16 @@ namespace Umbraco.Core { using (var client = new SmtpClient()) { - await client.ConnectAsync(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port); + await client.ConnectAsync(_globalSettings.Smtp.Host, _globalSettings.Smtp.Port); - if (!(_globalSettings.SmtpSettings.Username is null && - _globalSettings.SmtpSettings.Password is null)) + if (!(_globalSettings.Smtp.Username is null && + _globalSettings.Smtp.Password is null)) { - await client.AuthenticateAsync(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password); + await client.AuthenticateAsync(_globalSettings.Smtp.Username, _globalSettings.Smtp.Password); } var mailMessage = ConstructEmailMessage(message); - if (_globalSettings.SmtpSettings.DeliveryMethod == SmtpDeliveryMethod.Network) + if (_globalSettings.Smtp.DeliveryMethod == SmtpDeliveryMethod.Network) { await client.SendAsync(mailMessage); } @@ -107,7 +109,7 @@ namespace Umbraco.Core /// /// We assume this is possible if either an event handler is registered or an smtp server is configured /// - public static bool CanSendRequiredEmail(IGlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured; + public static bool CanSendRequiredEmail(GlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured; /// /// returns true if an event handler has been registered @@ -132,7 +134,7 @@ namespace Umbraco.Core { var fromEmail = mailMessage.From?.Address; if(string.IsNullOrEmpty(fromEmail)) - fromEmail = _globalSettings.SmtpSettings.From; + fromEmail = _globalSettings.Smtp.From; var messageToSend = new MimeMessage { diff --git a/src/Umbraco.Infrastructure/WebAssets/BackOfficeJavaScriptInitializer.cs b/src/Umbraco.Infrastructure/WebAssets/BackOfficeJavaScriptInitializer.cs index 18279e35ba..77db7bcbfd 100644 --- a/src/Umbraco.Infrastructure/WebAssets/BackOfficeJavaScriptInitializer.cs +++ b/src/Umbraco.Infrastructure/WebAssets/BackOfficeJavaScriptInitializer.cs @@ -2,6 +2,7 @@ using System.Text; using System.Text.RegularExpressions; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; @@ -31,7 +32,7 @@ namespace Umbraco.Web.WebAssets /// /// /// - public static string GetJavascriptInitialization(IEnumerable scripts, string angularModule, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + public static string GetJavascriptInitialization(IEnumerable scripts, string angularModule, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { var jarray = new StringBuilder(); jarray.AppendLine("["); diff --git a/src/Umbraco.Infrastructure/WebAssets/BackOfficeWebAssets.cs b/src/Umbraco.Infrastructure/WebAssets/BackOfficeWebAssets.cs index fcb27f7189..5e4a1e2c7a 100644 --- a/src/Umbraco.Infrastructure/WebAssets/BackOfficeWebAssets.cs +++ b/src/Umbraco.Infrastructure/WebAssets/BackOfficeWebAssets.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Manifest; @@ -25,7 +27,7 @@ namespace Umbraco.Web.WebAssets private readonly IRuntimeMinifier _runtimeMinifier; private readonly IManifestParser _parser; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly PropertyEditorCollection _propertyEditorCollection; @@ -34,13 +36,13 @@ namespace Umbraco.Web.WebAssets IManifestParser parser, PropertyEditorCollection propertyEditorCollection, IHostingEnvironment hostingEnvironment, - IGlobalSettings globalSettings) + IOptions globalSettings) { _runtimeMinifier = runtimeMinifier; _parser = parser; _propertyEditorCollection = propertyEditorCollection; _hostingEnvironment = hostingEnvironment; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } public void CreateBundles() diff --git a/src/Umbraco.Infrastructure/WebAssets/RuntimeMinifierExtensions.cs b/src/Umbraco.Infrastructure/WebAssets/RuntimeMinifierExtensions.cs index 072afa5816..cc3be4d785 100644 --- a/src/Umbraco.Infrastructure/WebAssets/RuntimeMinifierExtensions.cs +++ b/src/Umbraco.Infrastructure/WebAssets/RuntimeMinifierExtensions.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; using System.Text; using System.Threading.Tasks; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.WebAssets; namespace Umbraco.Web.WebAssets @@ -15,7 +13,7 @@ namespace Umbraco.Web.WebAssets /// Returns the JavaScript to load the back office's assets /// /// - public static async Task GetScriptForLoadingBackOfficeAsync(this IRuntimeMinifier minifier, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + public static async Task GetScriptForLoadingBackOfficeAsync(this IRuntimeMinifier minifier, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { var files = await minifier.GetAssetPathsAsync(BackOfficeWebAssets.UmbracoJsBundleName); var result = BackOfficeJavaScriptInitializer.GetJavascriptInitialization(files, "umbraco", globalSettings, hostingEnvironment); diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidator.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidator.cs index 75affe09e7..5f806883f0 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidator.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidator.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.ModelsBuilder.Embedded.BackOffice @@ -10,7 +11,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice // ReSharper disable once UnusedMember.Global - This is typed scanned public class ContentTypeModelValidator : ContentTypeModelValidatorBase { - public ContentTypeModelValidator(IModelsBuilderConfig config) : base(config) + public ContentTypeModelValidator(IOptions config) : base(config) { } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidatorBase.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidatorBase.cs index 1e96e64df8..c1684dde7a 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidatorBase.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ContentTypeModelValidatorBase.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Editors; using Umbraco.Web.Models.ContentEditing; @@ -13,9 +14,9 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice where TModel : ContentTypeSave where TProperty : PropertyTypeBasic { - private readonly IModelsBuilderConfig _config; + private readonly IOptions _config; - public ContentTypeModelValidatorBase(IModelsBuilderConfig config) + public ContentTypeModelValidatorBase(IOptions config) { _config = config; } @@ -23,7 +24,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice protected override IEnumerable Validate(TModel model) { //don't do anything if we're not enabled - if (!_config.Enable) yield break; + if (!_config.Value.Enable) yield break; var properties = model.Groups.SelectMany(x => x.Properties) .Where(x => x.Inherited == false) diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/DashboardReport.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/DashboardReport.cs index 6e22313474..a0928fafcf 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/DashboardReport.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/DashboardReport.cs @@ -1,18 +1,20 @@ using System.Text; +using Microsoft.Extensions.Options; using Umbraco.Configuration; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.ModelsBuilder.Embedded.BackOffice { internal class DashboardReport { - private readonly IModelsBuilderConfig _config; + private readonly ModelsBuilderConfig _config; private readonly OutOfDateModelsStatus _outOfDateModels; private readonly ModelsGenerationError _mbErrors; - public DashboardReport(IModelsBuilderConfig config, OutOfDateModelsStatus outOfDateModels, ModelsGenerationError mbErrors) + public DashboardReport(IOptions config, OutOfDateModelsStatus outOfDateModels, ModelsGenerationError mbErrors) { - _config = config; + _config = config.Value; _outOfDateModels = outOfDateModels; _mbErrors = mbErrors; } diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/MediaTypeModelValidator.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/MediaTypeModelValidator.cs index fcd42908e7..b6cc135e7c 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/MediaTypeModelValidator.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/MediaTypeModelValidator.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.ModelsBuilder.Embedded.BackOffice @@ -10,7 +11,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice // ReSharper disable once UnusedMember.Global - This is typed scanned public class MediaTypeModelValidator : ContentTypeModelValidatorBase { - public MediaTypeModelValidator(IModelsBuilderConfig config) : base(config) + public MediaTypeModelValidator(IOptions config) : base(config) { } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/MemberTypeModelValidator.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/MemberTypeModelValidator.cs index 2e249eed4d..c930642155 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/MemberTypeModelValidator.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/MemberTypeModelValidator.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.ModelsBuilder.Embedded.BackOffice @@ -10,7 +11,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice // ReSharper disable once UnusedMember.Global - This is typed scanned public class MemberTypeModelValidator : ContentTypeModelValidatorBase { - public MemberTypeModelValidator(IModelsBuilderConfig config) : base(config) + public MemberTypeModelValidator(IOptions config) : base(config) { } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ModelsBuilderDashboardController.cs b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ModelsBuilderDashboardController.cs index 17b694de56..1339c79052 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ModelsBuilderDashboardController.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/BackOffice/ModelsBuilderDashboardController.cs @@ -1,14 +1,14 @@ using System; -using System.Net; -using System.Net.Http; using System.Runtime.Serialization; -using System.Web.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Configuration; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Exceptions; +using Umbraco.Core.Hosting; using Umbraco.ModelsBuilder.Embedded.Building; -using Umbraco.Web.Editors; -using Umbraco.Web.WebApi.Filters; +using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.Filters; namespace Umbraco.ModelsBuilder.Embedded.BackOffice { @@ -23,27 +23,29 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice [UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)] public class ModelsBuilderDashboardController : UmbracoAuthorizedJsonController { - private readonly IModelsBuilderConfig _config; + private readonly ModelsBuilderConfig _config; private readonly ModelsGenerator _modelGenerator; private readonly OutOfDateModelsStatus _outOfDateModels; private readonly ModelsGenerationError _mbErrors; private readonly DashboardReport _dashboardReport; + private readonly IHostingEnvironment _hostingEnvironment; - public ModelsBuilderDashboardController(IModelsBuilderConfig config, ModelsGenerator modelsGenerator, OutOfDateModelsStatus outOfDateModels, ModelsGenerationError mbErrors) + public ModelsBuilderDashboardController(IOptions config, ModelsGenerator modelsGenerator, OutOfDateModelsStatus outOfDateModels, ModelsGenerationError mbErrors, IHostingEnvironment hostingEnvironment) { //_umbracoServices = umbracoServices; - _config = config; + _config = config.Value; _modelGenerator = modelsGenerator; _outOfDateModels = outOfDateModels; _mbErrors = mbErrors; _dashboardReport = new DashboardReport(config, outOfDateModels, mbErrors); + _hostingEnvironment = hostingEnvironment; } // invoked by the dashboard // requires that the user is logged into the backoffice and has access to the settings section // beware! the name of the method appears in modelsbuilder.controller.js - [System.Web.Http.HttpPost] // use the http one, not mvc, with api controllers! - public HttpResponseMessage BuildModels() + [HttpPost] // use the http one, not mvc, with api controllers! + public IActionResult BuildModels() { try { @@ -52,10 +54,10 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice if (!config.ModelsMode.SupportsExplicitGeneration()) { var result2 = new BuildResult { Success = false, Message = "Models generation is not enabled." }; - return Request.CreateResponse(HttpStatusCode.OK, result2, Configuration.Formatters.JsonFormatter); + return Ok(result2); } - var bin = HostingEnvironment.MapPath("~/bin"); + var bin = _hostingEnvironment.MapPathContentRoot("~/bin"); if (bin == null) throw new PanicException("bin is null."); @@ -68,13 +70,13 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice _mbErrors.Report("Failed to build models.", e); } - return Request.CreateResponse(HttpStatusCode.OK, GetDashboardResult(), Configuration.Formatters.JsonFormatter); + return Ok(GetDashboardResult()); } // invoked by the back-office // requires that the user is logged into the backoffice and has access to the settings section - [System.Web.Http.HttpGet] // use the http one, not mvc, with api controllers! - public HttpResponseMessage GetModelsOutOfDateStatus() + [HttpGet] // use the http one, not mvc, with api controllers! + public ActionResult GetModelsOutOfDateStatus() { var status = _outOfDateModels.IsEnabled ? _outOfDateModels.IsOutOfDate @@ -82,16 +84,16 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice : new OutOfDateStatus { Status = OutOfDateType.Current } : new OutOfDateStatus { Status = OutOfDateType.Unknown }; - return Request.CreateResponse(HttpStatusCode.OK, status, Configuration.Formatters.JsonFormatter); + return status; } // invoked by the back-office // requires that the user is logged into the backoffice and has access to the settings section // beware! the name of the method appears in modelsbuilder.controller.js - [System.Web.Http.HttpGet] // use the http one, not mvc, with api controllers! - public HttpResponseMessage GetDashboard() + [HttpGet] // use the http one, not mvc, with api controllers! + public ActionResult GetDashboard() { - return Request.CreateResponse(HttpStatusCode.OK, GetDashboardResult(), Configuration.Formatters.JsonFormatter); + return GetDashboardResult(); } private Dashboard GetDashboardResult() @@ -107,7 +109,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice } [DataContract] - internal class BuildResult + public class BuildResult { [DataMember(Name = "success")] public bool Success; @@ -116,7 +118,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice } [DataContract] - internal class Dashboard + public class Dashboard { [DataMember(Name = "enable")] public bool Enable; @@ -130,7 +132,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice public string LastError; } - internal enum OutOfDateType + public enum OutOfDateType { OutOfDate, Current, @@ -138,7 +140,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice } [DataContract] - internal class OutOfDateStatus + public class OutOfDateStatus { [DataMember(Name = "status")] public OutOfDateType Status { get; set; } diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/Builder.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/Builder.cs index f64e5ed1ce..4c90234fab 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/Builder.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/Builder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.ModelsBuilder.Embedded.Building { @@ -16,11 +17,8 @@ namespace Umbraco.ModelsBuilder.Embedded.Building /// /// Provides a base class for all builders. /// - internal abstract class Builder + public abstract class Builder { - - - private readonly IList _typeModels; protected Dictionary ModelsMap { get; } = new Dictionary(); @@ -29,13 +27,11 @@ namespace Umbraco.ModelsBuilder.Embedded.Building protected readonly IList TypesUsing = new List { "System", - "System.Collections.Generic", "System.Linq.Expressions", - "System.Web", - "Umbraco.Core.Models", "Umbraco.Core.Models.PublishedContent", - "Umbraco.Web", - "Umbraco.ModelsBuilder.Embedded" + "Umbraco.Web.PublishedCache", + "Umbraco.ModelsBuilder.Embedded", + "Umbraco.Core" }; /// @@ -62,7 +58,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building /// Gets the list of all models. /// /// Includes those that are ignored. - internal IList TypeModels => _typeModels; + public IList TypeModels => _typeModels; /// /// Initializes a new instance of the class with a list of models to generate, @@ -70,7 +66,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building /// /// The list of models to generate. /// The models namespace. - protected Builder(IModelsBuilderConfig config, IList typeModels) + protected Builder(ModelsBuilderConfig config, IList typeModels) { _typeModels = typeModels ?? throw new ArgumentNullException(nameof(typeModels)); @@ -87,7 +83,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building protected Builder() { } - protected IModelsBuilderConfig Config { get; } + protected ModelsBuilderConfig Config { get; } /// /// Prepares generation by processing the result of code parsing. @@ -199,7 +195,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building return true; } - internal string ModelsNamespaceForTests; + public string ModelsNamespaceForTests; public string GetModelsNamespace() { diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs index 648a2e76fa..0348c287cd 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/ModelsGenerator.cs @@ -1,28 +1,31 @@ using System.IO; using System.Text; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; +using Umbraco.Core.Hosting; namespace Umbraco.ModelsBuilder.Embedded.Building { public class ModelsGenerator { private readonly UmbracoServices _umbracoService; - private readonly IModelsBuilderConfig _config; + private readonly ModelsBuilderConfig _config; private readonly OutOfDateModelsStatus _outOfDateModels; - private readonly IIOHelper _ioHelper; + private readonly IHostingEnvironment _hostingEnvironment; - public ModelsGenerator(UmbracoServices umbracoService, IModelsBuilderConfig config, OutOfDateModelsStatus outOfDateModels, IIOHelper ioHelper) + public ModelsGenerator(UmbracoServices umbracoService, IOptions config, OutOfDateModelsStatus outOfDateModels, IHostingEnvironment hostingEnvironment) { _umbracoService = umbracoService; - _config = config; + _config = config.Value; _outOfDateModels = outOfDateModels; - _ioHelper = ioHelper; + _hostingEnvironment = hostingEnvironment; } internal void GenerateModels() { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs index 723ee10f35..607aa129b1 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/TextBuilder.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.ModelsBuilder.Embedded.Building { @@ -17,12 +18,12 @@ namespace Umbraco.ModelsBuilder.Embedded.Building /// and the result of code parsing. /// /// The list of models to generate. - public TextBuilder(IModelsBuilderConfig config, IList typeModels) + public TextBuilder(ModelsBuilderConfig config, IList typeModels) : base(config, typeModels) { } // internal for unit tests only - internal TextBuilder() + public TextBuilder() { } /// @@ -184,16 +185,17 @@ namespace Umbraco.ModelsBuilder.Embedded.Building sb.AppendFormat("\t\tpublic new const PublishedItemType ModelItemType = PublishedItemType.{0};\n", itemType); WriteGeneratedCodeAttribute(sb, "\t\t"); - sb.Append("\t\tpublic new static IPublishedContentType GetModelContentType()\n"); - sb.Append("\t\t\t=> PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias);\n"); + sb.Append("\t\tpublic new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor)\n"); + sb.Append("\t\t\t=> PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias);\n"); WriteGeneratedCodeAttribute(sb, "\t\t"); - sb.AppendFormat("\t\tpublic static IPublishedPropertyType GetModelPropertyType(Expression> selector)\n", + sb.AppendFormat("\t\tpublic static IPublishedPropertyType GetModelPropertyType(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression> selector)\n", type.ClrName); - sb.Append("\t\t\t=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector);\n"); + sb.Append("\t\t\t=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector);\n"); sb.Append("#pragma warning restore 0109\n\n"); + sb.Append("\t\tprivate IPublishedValueFallback _publishedValueFallback;"); // write the ctor - sb.AppendFormat("\t\t// ctor\n\t\tpublic {0}(IPublished{1} content)\n\t\t\t: base(content)\n\t\t{{ }}\n\n", + sb.AppendFormat("\n\n\t\t// ctor\n\t\tpublic {0}(IPublished{1} content, IPublishedValueFallback publishedValueFallback)\n\t\t\t: base(content)\n\t\t{{\n\t\t\t_publishedValueFallback = publishedValueFallback; \n\t\t}}\n\n", type.ClrName, type.IsElement ? "Element" : "Content"); // write the properties @@ -324,7 +326,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building WriteClrType(sb, property.ClrTypeName); sb.Append(">"); } - sb.AppendFormat("(\"{0}\");\n", + sb.AppendFormat("(_publishedValueFallback, \"{0}\");\n", property.Alias); } @@ -416,7 +418,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Building } // internal for unit tests - internal void WriteClrType(StringBuilder sb, Type type) + public void WriteClrType(StringBuilder sb, Type type) { var s = type.ToString(); diff --git a/src/Umbraco.ModelsBuilder.Embedded/Building/TypeModelHasher.cs b/src/Umbraco.ModelsBuilder.Embedded/Building/TypeModelHasher.cs index 2f14bec875..c5b053ca07 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Building/TypeModelHasher.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Building/TypeModelHasher.cs @@ -1,5 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; +using System.Text; +using Umbraco.Core; namespace Umbraco.ModelsBuilder.Embedded.Building { @@ -7,38 +11,38 @@ namespace Umbraco.ModelsBuilder.Embedded.Building { public static string Hash(IEnumerable typeModels) { - var hash = new HashCombiner(); + var builder = new StringBuilder(); // see Umbraco.ModelsBuilder.Umbraco.Application for what's important to hash // ie what comes from Umbraco (not computed by ModelsBuilder) and makes a difference foreach (var typeModel in typeModels.OrderBy(x => x.Alias)) { - hash.Add("--- CONTENT TYPE MODEL ---"); - hash.Add(typeModel.Id); - hash.Add(typeModel.Alias); - hash.Add(typeModel.ClrName); - hash.Add(typeModel.ParentId); - hash.Add(typeModel.Name); - hash.Add(typeModel.Description); - hash.Add(typeModel.ItemType.ToString()); - hash.Add("MIXINS:" + string.Join(",", typeModel.MixinTypes.OrderBy(x => x.Id).Select(x => x.Id))); + builder.AppendLine("--- CONTENT TYPE MODEL ---"); + builder.AppendLine(typeModel.Id.ToString()); + builder.AppendLine(typeModel.Alias); + builder.AppendLine(typeModel.ClrName); + builder.AppendLine(typeModel.ParentId.ToString()); + builder.AppendLine(typeModel.Name); + builder.AppendLine(typeModel.Description); + builder.AppendLine(typeModel.ItemType.ToString()); + builder.AppendLine("MIXINS:" + string.Join(",", typeModel.MixinTypes.OrderBy(x => x.Id).Select(x => x.Id))); foreach (var prop in typeModel.Properties.OrderBy(x => x.Alias)) { - hash.Add("--- PROPERTY ---"); - hash.Add(prop.Alias); - hash.Add(prop.ClrName); - hash.Add(prop.Name); - hash.Add(prop.Description); - hash.Add(prop.ModelClrType.ToString()); // see ModelType tests, want ToString() not FullName + builder.AppendLine("--- PROPERTY ---"); + builder.AppendLine(prop.Alias); + builder.AppendLine(prop.ClrName); + builder.AppendLine(prop.Name); + builder.AppendLine(prop.Description); + builder.AppendLine(prop.ModelClrType.ToString()); // see ModelType tests, want ToString() not FullName } } // Include the MB version in the hash so that if the MB version changes, models are rebuilt - hash.Add(ApiVersion.Current.Version.ToString()); + builder.AppendLine(ApiVersion.Current.Version.ToString()); - return hash.GetCombinedHashCode(); + return builder.ToString().GenerateHash(); } } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/DisabledModelsBuilderComponent.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/DisabledModelsBuilderComponent.cs index c599785711..9d63f65f64 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/DisabledModelsBuilderComponent.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/DisabledModelsBuilderComponent.cs @@ -1,5 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.Composing; +using Umbraco.Core.Composing; using Umbraco.ModelsBuilder.Embedded.BackOffice; using Umbraco.Web.Features; diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs index 32cfd3057e..1088dfb470 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs @@ -1,37 +1,46 @@ using System; using System.Collections.Generic; using System.Reflection; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; using Umbraco.Configuration; -using Umbraco.Core.Configuration; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; +using Umbraco.Extensions; using Umbraco.ModelsBuilder.Embedded.BackOffice; -using Umbraco.Web; -using Umbraco.Web.Mvc; +using Umbraco.Net; +using Umbraco.Web.Common.Lifetime; +using Umbraco.Web.Common.ModelBinders; using Umbraco.Web.WebAssets; namespace Umbraco.ModelsBuilder.Embedded.Compose { internal class ModelsBuilderComponent : IComponent { - private readonly IModelsBuilderConfig _config; + private readonly ModelsBuilderConfig _config; private readonly IShortStringHelper _shortStringHelper; private readonly LiveModelsProvider _liveModelsProvider; private readonly OutOfDateModelsStatus _outOfDateModels; + private readonly LinkGenerator _linkGenerator; + private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; + private readonly IUmbracoRequestLifetime _umbracoRequestLifetime; - public ModelsBuilderComponent(IModelsBuilderConfig config, IShortStringHelper shortStringHelper, LiveModelsProvider liveModelsProvider, OutOfDateModelsStatus outOfDateModels) + public ModelsBuilderComponent(IOptions config, IShortStringHelper shortStringHelper, + LiveModelsProvider liveModelsProvider, OutOfDateModelsStatus outOfDateModels, LinkGenerator linkGenerator, + IUmbracoRequestLifetime umbracoRequestLifetime, IUmbracoApplicationLifetime umbracoApplicationLifetime) { - _config = config; + _config = config.Value; _shortStringHelper = shortStringHelper; _liveModelsProvider = liveModelsProvider; _outOfDateModels = outOfDateModels; _shortStringHelper = shortStringHelper; + _linkGenerator = linkGenerator; + _umbracoRequestLifetime = umbracoRequestLifetime; + _umbracoApplicationLifetime = umbracoApplicationLifetime; } public void Initialize() @@ -39,6 +48,7 @@ namespace Umbraco.ModelsBuilder.Embedded.Compose // always setup the dashboard // note: UmbracoApiController instances are automatically registered InstallServerVars(); + _umbracoApplicationLifetime.ApplicationInit += InitializeApplication; ContentModelBinder.ModelBindingException += ContentModelBinder_ModelBindingException; @@ -53,32 +63,40 @@ namespace Umbraco.ModelsBuilder.Embedded.Compose } public void Terminate() - { } + { + ServerVariablesParser.Parsing -= ServerVariablesParser_Parsing; + ContentModelBinder.ModelBindingException -= ContentModelBinder_ModelBindingException; + FileService.SavingTemplate -= FileService_SavingTemplate; + } + + private void InitializeApplication(object sender, EventArgs args) + { + _umbracoRequestLifetime.RequestEnd += (sender, context) => _liveModelsProvider.AppEndRequest(context); + } private void InstallServerVars() { // register our url - for the backoffice api - ServerVariablesParser.Parsing += (sender, serverVars) => - { - if (!serverVars.ContainsKey("umbracoUrls")) - throw new ArgumentException("Missing umbracoUrls."); - var umbracoUrlsObject = serverVars["umbracoUrls"]; - if (umbracoUrlsObject == null) - throw new ArgumentException("Null umbracoUrls"); - if (!(umbracoUrlsObject is Dictionary umbracoUrls)) - throw new ArgumentException("Invalid umbracoUrls"); + ServerVariablesParser.Parsing += ServerVariablesParser_Parsing; + } - if (!serverVars.ContainsKey("umbracoPlugins")) - throw new ArgumentException("Missing umbracoPlugins."); - if (!(serverVars["umbracoPlugins"] is Dictionary umbracoPlugins)) - throw new ArgumentException("Invalid umbracoPlugins"); + private void ServerVariablesParser_Parsing(object sender, Dictionary serverVars) + { + if (!serverVars.ContainsKey("umbracoUrls")) + throw new ArgumentException("Missing umbracoUrls."); + var umbracoUrlsObject = serverVars["umbracoUrls"]; + if (umbracoUrlsObject == null) + throw new ArgumentException("Null umbracoUrls"); + if (!(umbracoUrlsObject is Dictionary umbracoUrls)) + throw new ArgumentException("Invalid umbracoUrls"); - if (HttpContext.Current == null) throw new InvalidOperationException("HttpContext is null"); - var urlHelper = new UrlHelper(new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData())); + if (!serverVars.ContainsKey("umbracoPlugins")) + throw new ArgumentException("Missing umbracoPlugins."); + if (!(serverVars["umbracoPlugins"] is Dictionary umbracoPlugins)) + throw new ArgumentException("Invalid umbracoPlugins"); - umbracoUrls["modelsBuilderBaseUrl"] = urlHelper.GetUmbracoApiServiceBaseUrl(controller => controller.BuildModels()); + umbracoUrls["modelsBuilderBaseUrl"] = _linkGenerator.GetUmbracoApiServiceBaseUrl(controller => controller.BuildModels()); umbracoPlugins["modelsBuilder"] = GetModelsBuilderSettings(); - }; } private Dictionary GetModelsBuilderSettings() diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs index e582301740..fd5472b223 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -6,91 +6,61 @@ using Umbraco.Core.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded.Building; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.ModelsBuilder.Embedded.Compose { - - [ComposeBefore(typeof(IPublishedCacheComposer))] [RuntimeLevel(MinLevel = RuntimeLevel.Run)] public sealed class ModelsBuilderComposer : ICoreComposer { public void Compose(Composition composition) { - var isLegacyModelsBuilderInstalled = IsLegacyModelsBuilderInstalled(); - - if (isLegacyModelsBuilderInstalled) - { - ComposeForLegacyModelsBuilder(composition); - return; - } - composition.Components().Append(); composition.Register(Lifetime.Singleton); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); - - if (composition.Configs.ModelsBuilder().ModelsMode == ModelsMode.PureLive) - ComposeForLiveModels(composition); - else if (composition.Configs.ModelsBuilder().EnableFactory) - ComposeForDefaultModelsFactory(composition); - } - private static bool IsLegacyModelsBuilderInstalled() - { - Assembly legacyMbAssembly = null; - try - { - legacyMbAssembly = Assembly.Load("Umbraco.ModelsBuilder"); - } - catch (System.Exception) - { - //swallow exception, DLL must not be there - } - return legacyMbAssembly != null; - } - - private void ComposeForLegacyModelsBuilder(Composition composition) - { - composition.Logger.Info("ModelsBuilder.Embedded is disabled, the external ModelsBuilder was detected."); - composition.Components().Append(); - composition.Dashboards().Remove(); - } - - private void ComposeForDefaultModelsFactory(Composition composition) - { composition.RegisterUnique(factory => { - var typeLoader = factory.GetInstance(); - var types = typeLoader - .GetTypes() // element models - .Concat(typeLoader.GetTypes()); // content models - return new PublishedModelFactory(types); + var config = factory.GetInstance>().Value; + if (config.ModelsMode == ModelsMode.PureLive) + { + composition.RegisterUnique(); + + // the following would add @using statement in every view so user's don't + // have to do it - however, then noone understands where the @using statement + // comes from, and it cannot be avoided / removed --- DISABLED + // + /* + // no need for @using in views + // note: + // we are NOT using the in-code attribute here, config is required + // because that would require parsing the code... and what if it changes? + // we can AddGlobalImport not sure we can remove one anyways + var modelsNamespace = Configuration.Config.ModelsNamespace; + if (string.IsNullOrWhiteSpace(modelsNamespace)) + modelsNamespace = Configuration.Config.DefaultModelsNamespace; + System.Web.WebPages.Razor.WebPageRazorHost.AddGlobalImport(modelsNamespace); + */ + } + else if (config.EnableFactory) + { + var typeLoader = factory.GetInstance(); + var publishedValueFallback = factory.GetInstance(); + var types = typeLoader + .GetTypes() // element models + .Concat(typeLoader.GetTypes()); // content models + return new PublishedModelFactory(types, publishedValueFallback); + } + + return null; }); - } - private void ComposeForLiveModels(Composition composition) - { - composition.RegisterUnique(); - - // the following would add @using statement in every view so user's don't - // have to do it - however, then noone understands where the @using statement - // comes from, and it cannot be avoided / removed --- DISABLED - // - /* - // no need for @using in views - // note: - // we are NOT using the in-code attribute here, config is required - // because that would require parsing the code... and what if it changes? - // we can AddGlobalImport not sure we can remove one anyways - var modelsNamespace = Configuration.Config.ModelsNamespace; - if (string.IsNullOrWhiteSpace(modelsNamespace)) - modelsNamespace = Configuration.Config.DefaultModelsNamespace; - System.Web.WebPages.Razor.WebPageRazorHost.AddGlobalImport(modelsNamespace); - */ } } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderInitializer.cs b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderInitializer.cs deleted file mode 100644 index a86669b135..0000000000 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderInitializer.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Web; -using System.Web.Compilation; -using Umbraco.ModelsBuilder.Embedded.Compose; - -[assembly: PreApplicationStartMethod(typeof(ModelsBuilderInitializer), "Initialize")] - -namespace Umbraco.ModelsBuilder.Embedded.Compose -{ - public static class ModelsBuilderInitializer - { - public static void Initialize() - { - // for some reason, netstandard is missing from BuildManager.ReferencedAssemblies and yet, is part of - // the references that CSharpCompiler receives - in some cases eg when building views - but not when - // using BuildManager to build the PureLive models - where is it coming from? cannot figure it out - - // so... cheating here - - // this is equivalent to adding - // - // to web.config system.web/compilation/assemblies - - var netStandard = ReferencedAssemblies.GetNetStandardAssembly(); - if (netStandard != null) - BuildManager.AddReferencedAssembly(netStandard); - } - } -} diff --git a/src/Umbraco.ModelsBuilder.Embedded/ConfigsExtensions.cs b/src/Umbraco.ModelsBuilder.Embedded/ConfigsExtensions.cs deleted file mode 100644 index d625c754c5..0000000000 --- a/src/Umbraco.ModelsBuilder.Embedded/ConfigsExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Umbraco.Core.Configuration; - -namespace Umbraco.ModelsBuilder.Embedded -{ - /// - /// Provides extension methods for the class. - /// - public static class ConfigsExtensions - { - /// - /// Gets the models builder configuration. - /// - /// Getting the models builder configuration freezes its state, - /// and any attempt at modifying the configuration using the Setup method - /// will be ignored. - public static IModelsBuilderConfig ModelsBuilder(this Configs configs) - => configs.GetConfig(); - } -} diff --git a/src/Umbraco.ModelsBuilder.Embedded/HashCombiner.cs b/src/Umbraco.ModelsBuilder.Embedded/HashCombiner.cs deleted file mode 100644 index 1c1fca6f73..0000000000 --- a/src/Umbraco.ModelsBuilder.Embedded/HashCombiner.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Globalization; - -namespace Umbraco.ModelsBuilder.Embedded -{ - // because, of course, it's internal in Umbraco - // see also System.Web.Util.HashCodeCombiner - internal class HashCombiner - { - private long _combinedHash = 5381L; - - public void Add(int i) - { - _combinedHash = (_combinedHash << 5) + _combinedHash ^ i; - } - - public void Add(object o) - { - Add(o.GetHashCode()); - } - - public void Add(DateTime d) - { - Add(d.GetHashCode()); - } - - public void Add(string s) - { - if (s == null) return; - Add(StringComparer.InvariantCulture.GetHashCode(s)); - } - - public string GetCombinedHashCode() - { - return _combinedHash.ToString("x", CultureInfo.InvariantCulture); - } - } -} diff --git a/src/Umbraco.ModelsBuilder.Embedded/ImplementPropertyTypeAttribute.cs b/src/Umbraco.ModelsBuilder.Embedded/ImplementPropertyTypeAttribute.cs index b7b2695a08..6f52a7faa9 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/ImplementPropertyTypeAttribute.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/ImplementPropertyTypeAttribute.cs @@ -6,7 +6,7 @@ namespace Umbraco.ModelsBuilder.Embedded /// Indicates that a property implements a given property alias. /// /// And therefore it should not be generated. - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + [AttributeUsage(AttributeTargets.Property , AllowMultiple = false, Inherited = false)] public class ImplementPropertyTypeAttribute : Attribute { public ImplementPropertyTypeAttribute(string alias) diff --git a/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs b/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs index 61d39cd373..48a79ba953 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs @@ -1,11 +1,16 @@ using System; using System.Threading; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; using Umbraco.Core.Configuration; using Umbraco.Configuration; +using Umbraco.Core; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.ModelsBuilder.Embedded.Building; using Umbraco.Web.Cache; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.ModelsBuilder.Embedded { @@ -15,7 +20,7 @@ namespace Umbraco.ModelsBuilder.Embedded private static Mutex _mutex; private static int _req; private readonly ILogger _logger; - private readonly IModelsBuilderConfig _config; + private readonly ModelsBuilderConfig _config; private readonly ModelsGenerator _modelGenerator; private readonly ModelsGenerationError _mbErrors; private readonly IHostingEnvironment _hostingEnvironment; @@ -23,10 +28,10 @@ namespace Umbraco.ModelsBuilder.Embedded // we do not manage pure live here internal bool IsEnabled => _config.ModelsMode.IsLiveNotPure(); - public LiveModelsProvider(ILogger logger, IModelsBuilderConfig config, ModelsGenerator modelGenerator, ModelsGenerationError mbErrors, IHostingEnvironment hostingEnvironment) + public LiveModelsProvider(ILogger logger, IOptions config, ModelsGenerator modelGenerator, ModelsGenerationError mbErrors, IHostingEnvironment hostingEnvironment) { _logger = logger; - _config = config ?? throw new ArgumentNullException(nameof(config)); + _config = config.Value ?? throw new ArgumentNullException(nameof(config)); _modelGenerator = modelGenerator; _mbErrors = mbErrors; _hostingEnvironment = hostingEnvironment; @@ -69,7 +74,7 @@ namespace Umbraco.ModelsBuilder.Embedded Interlocked.Exchange(ref _req, 1); } - public void GenerateModelsIfRequested(object sender, EventArgs args) + public void GenerateModelsIfRequested() { //if (HttpContext.Current.Items[this] == null) return; if (Interlocked.Exchange(ref _req, 0) == 0) return; @@ -108,6 +113,15 @@ namespace Umbraco.ModelsBuilder.Embedded _modelGenerator.GenerateModels(); } + public void AppEndRequest(HttpContext context) + { + var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute); + if (requestUri.IsClientSideRequest()) + return; + + if (!IsEnabled) return; + GenerateModelsIfRequested(); + } } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProviderModule.cs b/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProviderModule.cs deleted file mode 100644 index a04723a05e..0000000000 --- a/src/Umbraco.ModelsBuilder.Embedded/LiveModelsProviderModule.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Web; -using Umbraco.Core; -using Umbraco.Web.Composing; -using Umbraco.ModelsBuilder.Embedded; - -// will install only if configuration says it needs to be installed -[assembly: PreApplicationStartMethod(typeof(LiveModelsProviderModule), "Install")] - -namespace Umbraco.ModelsBuilder.Embedded -{ - // have to do this because it's the only way to subscribe to EndRequest, - // module is installed by assembly attribute at the top of this file - public class LiveModelsProviderModule : IHttpModule - { - private static LiveModelsProvider _liveModelsProvider; - - public void Init(HttpApplication app) - { - app.EndRequest += App_EndRequest; - } - - private void App_EndRequest(object sender, EventArgs e) - { - if (((HttpApplication)sender).Request.Url.IsClientSideRequest()) - return; - - // here we're using "Current." since we're in a module, it is possible in a round about way to inject into a module but for now we'll just use Current - if (_liveModelsProvider == null) - _liveModelsProvider = Current.Factory.TryGetInstance(); // will be null in upgrade mode or if embedded MB is disabled - - if (_liveModelsProvider?.IsEnabled ?? false) - _liveModelsProvider.GenerateModelsIfRequested(sender, e); - } - - public void Dispose() - { - // nothing - } - - public static void Install() - { - // always - don't read config in PreApplicationStartMethod - HttpApplication.RegisterModule(typeof(LiveModelsProviderModule)); - } - } -} diff --git a/src/Umbraco.ModelsBuilder.Embedded/ModelsBuilderDashboard.cs b/src/Umbraco.ModelsBuilder.Embedded/ModelsBuilderDashboard.cs index b8b1945f32..867b22d14b 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/ModelsBuilderDashboard.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/ModelsBuilderDashboard.cs @@ -15,5 +15,4 @@ namespace Umbraco.ModelsBuilder.Embedded public IAccessRule[] AccessRules => Array.Empty(); } - } diff --git a/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs b/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs index f8f6e8c7bc..a5911bc9c6 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/ModelsGenerationError.cs @@ -1,20 +1,22 @@ using System; using System.IO; using System.Text; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; +using Umbraco.Core.Hosting; +using Umbraco.Core.Configuration.Models; namespace Umbraco.ModelsBuilder.Embedded { public sealed class ModelsGenerationError { - private readonly IModelsBuilderConfig _config; - private readonly IIOHelper _ioHelper; + private readonly ModelsBuilderConfig _config; + private readonly IHostingEnvironment _hostingEnvironment; - public ModelsGenerationError(IModelsBuilderConfig config, IIOHelper ioHelper) + public ModelsGenerationError(IOptions config, IHostingEnvironment hostingEnvironment) { - _config = config; - _ioHelper = ioHelper; + _config = config.Value; + _hostingEnvironment = hostingEnvironment; } public void Clear() @@ -59,7 +61,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GetErrFile() { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) return null; diff --git a/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs b/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs index b8105eeef2..85d08ee975 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/OutOfDateModelsStatus.cs @@ -1,19 +1,21 @@ using System.IO; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; +using Umbraco.Core.Hosting; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.Cache; namespace Umbraco.ModelsBuilder.Embedded { public sealed class OutOfDateModelsStatus { - private readonly IModelsBuilderConfig _config; - private readonly IIOHelper _ioHelper; + private readonly ModelsBuilderConfig _config; + private readonly IHostingEnvironment _hostingEnvironment; - public OutOfDateModelsStatus(IModelsBuilderConfig config, IIOHelper ioHelper) + public OutOfDateModelsStatus(IOptions config, IHostingEnvironment hostingEnvironment) { - _config = config; - _ioHelper = ioHelper; + _config = config.Value; + _hostingEnvironment = hostingEnvironment; } internal void Install() @@ -28,7 +30,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GetFlagPath() { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); 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 deleted file mode 100644 index 5fa17d3c77..0000000000 --- a/src/Umbraco.ModelsBuilder.Embedded/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Umbraco.ModelsBuilder.Embedded")] -[assembly: AssemblyDescription("Umbraco ModelsBuilder")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyProduct("Umbraco CMS")] - -[assembly: ComVisible(false)] -[assembly: Guid("52ac0ba8-a60e-4e36-897b-e8b97a54ed1c")] - -[assembly: InternalsVisibleTo("Umbraco.Tests")] diff --git a/src/Umbraco.ModelsBuilder.Embedded/PublishedElementExtensions.cs b/src/Umbraco.ModelsBuilder.Embedded/PublishedElementExtensions.cs index 8a0a688942..0611d466dc 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/PublishedElementExtensions.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/PublishedElementExtensions.cs @@ -2,12 +2,11 @@ using System.Linq.Expressions; using System.Reflection; using Umbraco.Core.Models.PublishedContent; -using Umbraco.ModelsBuilder; using Umbraco.ModelsBuilder.Embedded; // same namespace as original Umbraco.Web PublishedElementExtensions // ReSharper disable once CheckNamespace -namespace Umbraco.Web +namespace Umbraco.Core { /// /// Provides extension methods to models. @@ -17,11 +16,11 @@ namespace Umbraco.Web /// /// Gets the value of a property. /// - public static TValue ValueFor(this TModel model, Expression> property, string culture = null, string segment = null, Fallback fallback = default, TValue defaultValue = default) + public static TValue ValueFor(this TModel model, IPublishedValueFallback publishedValueFallback, Expression> property, string culture = null, string segment = null, Fallback fallback = default, TValue defaultValue = default) where TModel : IPublishedElement { var alias = GetAlias(model, property); - return model.Value(alias, culture, segment, fallback, defaultValue); + return model.Value(publishedValueFallback, alias, culture, segment, fallback, defaultValue); } // fixme that one should be public so ppl can use it diff --git a/src/Umbraco.ModelsBuilder.Embedded/PublishedModelUtility.cs b/src/Umbraco.ModelsBuilder.Embedded/PublishedModelUtility.cs index 8a6ed83ce9..fd1d5128a0 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/PublishedModelUtility.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/PublishedModelUtility.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Linq.Expressions; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Composing; +using Umbraco.Web.PublishedCache; namespace Umbraco.ModelsBuilder.Embedded { @@ -29,10 +29,10 @@ namespace Umbraco.ModelsBuilder.Embedded // var contentType = PublishedContentType.Get(itemType, alias); // // etc... //} - - public static IPublishedContentType GetModelContentType(PublishedItemType itemType, string alias) + + public static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor, PublishedItemType itemType, string alias) { - var facade = Current.UmbracoContext.PublishedSnapshot; // fixme inject! + var facade = publishedSnapshotAccessor.PublishedSnapshot; switch (itemType) { case PublishedItemType.Content: diff --git a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs index 7809d2bf48..596cc9ed26 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs @@ -8,23 +8,20 @@ using System.Reflection.Emit; using System.Text; using System.Text.RegularExpressions; using System.Threading; -using System.Web; -using System.Web.Compilation; -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; using File = System.IO.File; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.ModelsBuilder.Embedded { internal class PureLiveModelFactory : ILivePublishedModelFactory, IRegisteredObject { - private Assembly _modelsAssembly; private Infos _infos = new Infos { ModelInfos = null, ModelTypeMap = new Dictionary() }; private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(); private volatile bool _hasModels; // volatile 'cos reading outside lock @@ -33,41 +30,40 @@ namespace Umbraco.ModelsBuilder.Embedded private readonly FileSystemWatcher _watcher; private int _ver, _skipver; private readonly int _debugLevel; - private BuildManager _theBuildManager; + private RoslynCompiler _roslynCompiler; + private UmbracoAssemblyLoadContext _currentAssemblyLoadContext; private readonly Lazy _umbracoServices; // fixme: this is because of circular refs :( private UmbracoServices UmbracoServices => _umbracoServices.Value; private static readonly Regex AssemblyVersionRegex = new Regex("AssemblyVersion\\(\"[0-9]+.[0-9]+.[0-9]+.[0-9]+\"\\)", RegexOptions.Compiled); - private const string ProjVirt = "~/App_Data/Models/all.generated.cs"; - private static readonly string[] OurFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err" }; + private static readonly string[] OurFiles = { "models.hash", "models.generated.cs", "all.generated.cs", "all.dll.path", "models.err", "Compiled" }; - private readonly IModelsBuilderConfig _config; + private readonly ModelsBuilderConfig _config; + private readonly IHostingEnvironment _hostingEnvironment; private readonly IApplicationShutdownRegistry _hostingLifetime; - private readonly IIOHelper _ioHelper; private readonly ModelsGenerationError _errors; + private readonly IPublishedValueFallback _publishedValueFallback; public PureLiveModelFactory( Lazy umbracoServices, IProfilingLogger logger, - IModelsBuilderConfig config, + IOptions config, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, - IIOHelper ioHelper) + IPublishedValueFallback publishedValueFallback) { _umbracoServices = umbracoServices; _logger = logger; - _config = config; + _config = config.Value; + _hostingEnvironment = hostingEnvironment; _hostingLifetime = hostingLifetime; - _ioHelper = ioHelper; - _errors = new ModelsGenerationError(config, ioHelper); + _publishedValueFallback = publishedValueFallback; + _errors = new ModelsGenerationError(config, _hostingEnvironment); _ver = 1; // zero is for when we had no version _skipver = -1; // nothing to skip - - RazorBuildProvider.CodeGenerationStarted += RazorBuildProvider_CodeGenerationStarted; - if (!hostingEnvironment.IsHosted) return; - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -113,7 +109,7 @@ namespace Umbraco.ModelsBuilder.Embedded infos.TryGetValue(contentTypeAlias, out var info); // create model - return info == null ? element : info.Ctor(element); + return info == null ? element : info.Ctor(element, _publishedValueFallback); } // this runs only once the factory is ready @@ -158,7 +154,6 @@ namespace Umbraco.ModelsBuilder.Embedded #endregion #region Compilation - // deadlock note // // when RazorBuildProvider_CodeGenerationStarted runs, the thread has Monitor.Enter-ed the BuildManager @@ -188,32 +183,33 @@ namespace Umbraco.ModelsBuilder.Embedded // // well, that's what we are doing in this class' TheBuildManager property, using reflection. - private void RazorBuildProvider_CodeGenerationStarted(object sender, EventArgs e) - { - try - { - _locker.EnterReadLock(); + // private void RazorBuildProvider_CodeGenerationStarted(object sender, EventArgs e) + // { + // try + // { + // _locker.EnterReadLock(); + // + // // just be safe - can happen if the first view is not an Umbraco view, + // // or if something went wrong and we don't have an assembly at all + // if (_modelsAssembly == null) return; + // + // if (_debugLevel > 0) + // _logger.Debug("RazorBuildProvider.CodeGenerationStarted"); + // if (!(sender is RazorBuildProvider provider)) return; + // + // // add the assembly, and add a dependency to a text file that will change on each + // // compilation as in some environments (could not figure which/why) the BuildManager + // // would not re-compile the views when the models assembly is rebuilt. + // provider.AssemblyBuilder.AddAssemblyReference(_modelsAssembly); + // provider.AddVirtualPathDependency(ProjVirt); + // } + // finally + // { + // if (_locker.IsReadLockHeld) + // _locker.ExitReadLock(); + // } + // } - // just be safe - can happen if the first view is not an Umbraco view, - // or if something went wrong and we don't have an assembly at all - if (_modelsAssembly == null) return; - - if (_debugLevel > 0) - _logger.Debug("RazorBuildProvider.CodeGenerationStarted"); - if (!(sender is RazorBuildProvider provider)) return; - - // add the assembly, and add a dependency to a text file that will change on each - // compilation as in some environments (could not figure which/why) the BuildManager - // would not re-compile the views when the models assembly is rebuilt. - provider.AssemblyBuilder.AddAssemblyReference(_modelsAssembly); - provider.AddVirtualPathDependency(ProjVirt); - } - finally - { - if (_locker.IsReadLockHeld) - _locker.ExitReadLock(); - } - } // tells the factory that it should build a new generation of models private void ResetModels() @@ -227,14 +223,12 @@ namespace Umbraco.ModelsBuilder.Embedded _hasModels = false; _pendingRebuild = true; - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); // clear stuff var modelsHashFile = Path.Combine(modelsDirectory, "models.hash"); - //var modelsSrcFile = Path.Combine(modelsDirectory, "models.generated.cs"); - //var projFile = Path.Combine(modelsDirectory, "all.generated.cs"); var dllPathFile = Path.Combine(modelsDirectory, "all.dll.path"); if (File.Exists(dllPathFile)) File.Delete(dllPathFile); @@ -247,17 +241,14 @@ namespace Umbraco.ModelsBuilder.Embedded } } - // gets "the" build manager - private BuildManager TheBuildManager + // gets the RoslynCompiler + private RoslynCompiler RoslynCompiler { get { - if (_theBuildManager != null) return _theBuildManager; - var prop = typeof(BuildManager).GetProperty("TheBuildManager", BindingFlags.NonPublic | BindingFlags.Static); - if (prop == null) - throw new InvalidOperationException("Could not get BuildManager.TheBuildManager property."); - _theBuildManager = (BuildManager)prop.GetValue(null); - return _theBuildManager; + if (_roslynCompiler != null) return _roslynCompiler; + _roslynCompiler = new RoslynCompiler(System.Runtime.Loader.AssemblyLoadContext.All.SelectMany(x => x.Assemblies)); + return _roslynCompiler; } } @@ -280,12 +271,12 @@ namespace Umbraco.ModelsBuilder.Embedded _locker.ExitReadLock(); } - var buildManagerLocked = false; + var roslynLocked = false; try { // always take the BuildManager lock *before* taking the _locker lock // to avoid possible deadlock situations (see notes above) - Monitor.Enter(TheBuildManager, ref buildManagerLocked); + Monitor.Enter(RoslynCompiler, ref roslynLocked); _locker.EnterUpgradeableReadLock(); @@ -308,9 +299,6 @@ namespace Umbraco.ModelsBuilder.Embedded // this is for U4-8043 which is an obvious issue but I cannot replicate //_modelsAssembly = _modelsAssembly ?? assembly; - // the one below is the normal one - _modelsAssembly = assembly; - var types = assembly.ExportedTypes.Where(x => x.Inherits() || x.Inherits()); _infos = RegisterModels(types); _errors.Clear(); @@ -325,7 +313,6 @@ namespace Umbraco.ModelsBuilder.Embedded } finally { - _modelsAssembly = null; _infos = new Infos { ModelInfos = null, ModelTypeMap = new Dictionary() }; } } @@ -342,14 +329,36 @@ namespace Umbraco.ModelsBuilder.Embedded _locker.ExitWriteLock(); if (_locker.IsUpgradeableReadLockHeld) _locker.ExitUpgradeableReadLock(); - if (buildManagerLocked) - Monitor.Exit(TheBuildManager); + if (roslynLocked) + Monitor.Exit(RoslynCompiler); + } + } + + private Assembly ReloadAssembly(string pathToAssembly) + { + // If there's a current AssemblyLoadContext, unload it before creating a new one. + if(!(_currentAssemblyLoadContext is null)) + { + _currentAssemblyLoadContext.Unload(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + + // We must create a new assembly load context + // as long as theres a reference to the assembly load context we can't delete the assembly it loaded + _currentAssemblyLoadContext = new UmbracoAssemblyLoadContext(); + + // Use filestream to load in the new assembly, otherwise it'll be locked + // See https://www.strathweb.com/2019/01/collectible-assemblies-in-net-core-3-0/ for more info + using (var fs = new FileStream(pathToAssembly, FileMode.Open, FileAccess.Read)) + { + return _currentAssemblyLoadContext.LoadFromStream(fs); } } private Assembly GetModelsAssembly(bool forceRebuild) { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -392,23 +401,16 @@ namespace Umbraco.ModelsBuilder.Embedded // ensure that the .dll file does not have a corresponding .dll.delete file // as that would mean the the .dll file is going to be deleted and should not // be re-used - that should not happen in theory, but better be safe - // - // ensure that the .dll file is in the current codegen directory - when IIS - // or Express does a full restart, it can switch to an entirely new codegen - // directory, and then we end up referencing a dll which is *not* in that - // directory, and BuildManager fails to instantiate views ("the view found - // at ... was not created"). - // if (File.Exists(dllPathFile)) { var dllPath = File.ReadAllText(dllPathFile); - var codegen = HttpRuntime.CodegenDir; _logger.Debug($"Cached models dll at {dllPath}."); - if (File.Exists(dllPath) && !File.Exists(dllPath + ".delete") && dllPath.StartsWith(codegen)) + if (File.Exists(dllPath) && !File.Exists(dllPath + ".delete")) { - assembly = Assembly.LoadFile(dllPath); + assembly = ReloadAssembly(dllPath); + var attr = assembly.GetCustomAttribute(); if (attr != null && attr.PureLive && attr.SourceHash == currentHash) { @@ -428,8 +430,6 @@ namespace Umbraco.ModelsBuilder.Embedded _logger.Debug("Cached models dll does not exist."); else if (File.Exists(dllPath + ".delete")) _logger.Debug("Cached models dll is marked for deletion."); - else if (!dllPath.StartsWith(codegen)) - _logger.Debug("Cached models dll is in a different codegen directory."); else _logger.Debug("Cached models dll cannot be loaded (why?)."); } @@ -444,16 +444,15 @@ namespace Umbraco.ModelsBuilder.Embedded File.WriteAllText(projFile, text); } - // generate a marker file that will be a dependency - // see note in RazorBuildProvider_CodeGenerationStarted - // NO: using all.generated.cs as a dependency - //File.WriteAllText(Path.Combine(modelsDirectory, "models.dep"), "VER:" + _ver); - _ver++; try { - assembly = BuildManager.GetCompiledAssembly(ProjVirt); + var assemblyPath = GetOutputAssemblyPath(currentHash); + RoslynCompiler.CompileToFile(_hostingEnvironment.MapPathContentRoot(projFile), assemblyPath); + assembly = ReloadAssembly(assemblyPath); File.WriteAllText(dllPathFile, assembly.Location); + File.WriteAllText(modelsHashFile, currentHash); + TryDeleteUnusedAssemblies(dllPathFile); } catch { @@ -490,9 +489,12 @@ namespace Umbraco.ModelsBuilder.Embedded // compile and register try { - assembly = BuildManager.GetCompiledAssembly(ProjVirt); - File.WriteAllText(dllPathFile, assembly.Location); + var assemblyPath = GetOutputAssemblyPath(currentHash); + RoslynCompiler.CompileToFile(_hostingEnvironment.MapPathContentRoot(projFile), assemblyPath); + assembly = ReloadAssembly(assemblyPath); + File.WriteAllText(dllPathFile, assemblyPath); File.WriteAllText(modelsHashFile, currentHash); + TryDeleteUnusedAssemblies(dllPathFile); } catch { @@ -504,6 +506,37 @@ namespace Umbraco.ModelsBuilder.Embedded return assembly; } + private void TryDeleteUnusedAssemblies(string dllPathFile) + { + if (File.Exists(dllPathFile)) + { + var dllPath = File.ReadAllText(dllPathFile); + var dirInfo = new DirectoryInfo(dllPath).Parent; + var files = dirInfo.GetFiles().Where(f => f.FullName != dllPath); + foreach(var file in files) + { + try + { + File.Delete(file.FullName); + } + catch(UnauthorizedAccessException) + { + // The file is in use, we'll try again next time... + // This shouldn't happen anymore. + } + } + + } + } + + private string GetOutputAssemblyPath(string currentHash) + { + var dirInfo = new DirectoryInfo(Path.Combine(_config.ModelsDirectoryAbsolute(_hostingEnvironment), "Compiled")); + if (!dirInfo.Exists) + Directory.CreateDirectory(dirInfo.FullName); + return Path.Combine(dirInfo.FullName, $"generated.cs{currentHash}.dll"); + } + private void ClearOnFailingToCompile(string dllPathFile, string modelsHashFile, string projFile) { _logger.Debug("Failed to compile."); @@ -523,7 +556,7 @@ namespace Umbraco.ModelsBuilder.Embedded private static Infos RegisterModels(IEnumerable types) { - var ctorArgTypes = new[] { typeof(IPublishedElement) }; + var ctorArgTypes = new[] { typeof(IPublishedElement), typeof(IPublishedValueFallback) }; var modelInfos = new Dictionary(StringComparer.InvariantCultureIgnoreCase); var map = new Dictionary(); @@ -535,7 +568,7 @@ namespace Umbraco.ModelsBuilder.Embedded foreach (var ctor in type.GetConstructors()) { var parms = ctor.GetParameters(); - if (parms.Length == 1 && typeof(IPublishedElement).IsAssignableFrom(parms[0].ParameterType)) + if (parms.Length == 2 && typeof(IPublishedElement).IsAssignableFrom(parms[0].ParameterType) && typeof(IPublishedValueFallback).IsAssignableFrom(parms[1].ParameterType)) { if (constructor != null) throw new InvalidOperationException($"Type {type.FullName} has more than one public constructor with one argument of type, or implementing, IPropertySet."); @@ -560,9 +593,10 @@ namespace Umbraco.ModelsBuilder.Embedded var meth = new DynamicMethod(string.Empty, typeof(IPublishedElement), ctorArgTypes, type.Module, true); var gen = meth.GetILGenerator(); gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Newobj, constructor); gen.Emit(OpCodes.Ret); - var func = (Func)meth.CreateDelegate(typeof(Func)); + var func = (Func)meth.CreateDelegate(typeof(Func)); modelInfos[typeName] = new ModelInfo { ParameterType = parameterType, Ctor = func, ModelType = type }; map[typeName] = type; @@ -573,7 +607,7 @@ namespace Umbraco.ModelsBuilder.Embedded private string GenerateModelsCode(IList typeModels) { - var modelsDirectory = _config.ModelsDirectoryAbsolute(_ioHelper); + var modelsDirectory = _config.ModelsDirectoryAbsolute(_hostingEnvironment); if (!Directory.Exists(modelsDirectory)) Directory.CreateDirectory(modelsDirectory); @@ -651,7 +685,7 @@ namespace Umbraco.ModelsBuilder.Embedded internal class ModelInfo { public Type ParameterType { get; set; } - public Func Ctor { get; set; } + public Func Ctor { get; set; } public Type ModelType { get; set; } public Func ListCtor { get; set; } } diff --git a/src/Umbraco.ModelsBuilder.Embedded/ReferencedAssemblies.cs b/src/Umbraco.ModelsBuilder.Embedded/ReferencedAssemblies.cs deleted file mode 100644 index 8886afa1c8..0000000000 --- a/src/Umbraco.ModelsBuilder.Embedded/ReferencedAssemblies.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Web.Compilation; -using System.Web.Hosting; -using Umbraco.Core; - -namespace Umbraco.ModelsBuilder.Embedded -{ - internal static class ReferencedAssemblies - { - private static readonly Lazy> LazyLocations; - - static ReferencedAssemblies() - { - LazyLocations = new Lazy>(() => HostingEnvironment.IsHosted - ? GetAllReferencedAssembliesLocationFromBuildManager() - : GetAllReferencedAssembliesFromDomain()); - } - - /// - /// Gets the assembly locations of all the referenced assemblies, that - /// are not dynamic, and have a non-null nor empty location. - /// - public static IEnumerable Locations => LazyLocations.Value; - - public static Assembly GetNetStandardAssembly(List assemblies) - { - if (assemblies == null) - assemblies = BuildManager.GetReferencedAssemblies().Cast().ToList(); - - // for some reason, netstandard is also missing from BuildManager.ReferencedAssemblies and yet, is part of - // the references that CSharpCompiler (above) receives - where is it coming from? cannot figure it out - try - { - // so, resorting to an ugly trick - // we should have System.Reflection.Metadata around, and it should reference netstandard - var someAssembly = assemblies.First(x => x.FullName.StartsWith("System.Reflection.Metadata,")); - var netStandardAssemblyName = someAssembly.GetReferencedAssemblies().First(x => x.FullName.StartsWith("netstandard,")); - var netStandard = Assembly.Load(netStandardAssemblyName.FullName); - return netStandard; - } - catch { /* never mind */ } - - return null; - } - - public static Assembly GetNetStandardAssembly() - { - // in PreApplicationStartMethod we cannot get BuildManager.Referenced assemblies, do it differently - try - { - var someAssembly = Assembly.Load("System.Reflection.Metadata"); - var netStandardAssemblyName = someAssembly.GetReferencedAssemblies().First(x => x.FullName.StartsWith("netstandard,")); - var netStandard = Assembly.Load(netStandardAssemblyName.FullName); - return netStandard; - } - catch { /* never mind */ } - - return null; - } - - // hosted, get referenced assemblies from the BuildManager and filter - private static IEnumerable GetAllReferencedAssembliesLocationFromBuildManager() - { - var assemblies = BuildManager.GetReferencedAssemblies().Cast().ToList(); - - assemblies.Add(typeof(ReferencedAssemblies).Assembly); // always include ourselves - - // see https://github.com/aspnet/RoslynCodeDomProvider/blob/master/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs: - // mentions "Bug 913691: Explicitly add System.Runtime as a reference." - // and explicitly adds System.Runtime to references before invoking csc.exe - // so, doing the same here - try - { - var systemRuntime = Assembly.Load("System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - assemblies.Add(systemRuntime); - } - catch { /* never mind */ } - - // for some reason, netstandard is also missing from BuildManager.ReferencedAssemblies and yet, is part of - // the references that CSharpCompiler (above) receives - where is it coming from? cannot figure it out - var netStandard = GetNetStandardAssembly(assemblies); - if (netStandard != null) assemblies.Add(netStandard); - - return assemblies - .Where(x => !x.IsDynamic && !x.Location.IsNullOrWhiteSpace()) - .Select(x => x.Location) - .Distinct() - .ToList(); - } - - // non-hosted, do our best - private static IEnumerable GetAllReferencedAssembliesFromDomain() - { - //TODO: This method has bugs since I've been stuck in an infinite loop with it, though this shouldn't - // execute while in the web application anyways. - - var assemblies = new List(); - var tmp1 = new List(); - var failed = new List(); - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies() - .Where(x => x.IsDynamic == false) - .Where(x => !string.IsNullOrWhiteSpace(x.Location))) // though... IsDynamic should be enough? - { - assemblies.Add(assembly); - tmp1.Add(assembly); - } - - // fixme - AssemblyUtility questions - // - should we also load everything that's in the same directory? - // - do we want to load in the current app domain? - // - if this runs within Umbraco then we have already loaded them all? - - while (tmp1.Count > 0) - { - var tmp2 = tmp1 - .SelectMany(x => x.GetReferencedAssemblies()) - .Distinct() - .Where(x => assemblies.All(xx => x.FullName != xx.FullName)) // we don't have it already - .Where(x => failed.All(xx => x.FullName != xx.FullName)) // it hasn't failed already - .ToArray(); - tmp1.Clear(); - foreach (var assemblyName in tmp2) - { - try - { - var assembly = AppDomain.CurrentDomain.Load(assemblyName); - assemblies.Add(assembly); - tmp1.Add(assembly); - } - catch - { - failed.Add(assemblyName); - } - } - } - return assemblies.Select(x => x.Location).Distinct(); - } - - - // ---- - - - private static Assembly TryLoad(AssemblyName name) - { - try - { - return AppDomain.CurrentDomain.Load(name); - } - catch (Exception) - { - //Console.WriteLine(name); - return null; - } - } - } -} diff --git a/src/Umbraco.ModelsBuilder.Embedded/RoslynCompiler.cs b/src/Umbraco.ModelsBuilder.Embedded/RoslynCompiler.cs new file mode 100644 index 0000000000..7f1443b156 --- /dev/null +++ b/src/Umbraco.ModelsBuilder.Embedded/RoslynCompiler.cs @@ -0,0 +1,69 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Umbraco.ModelsBuilder.Embedded +{ + public class RoslynCompiler + { + private OutputKind _outputKind; + private CSharpParseOptions _parseOptions; + private List _refs; + + /// + /// Roslyn compiler which can be used to compile a c# file to a Dll assembly + /// + /// Referenced assemblies used in the source file + public RoslynCompiler(IEnumerable referenceAssemblies) + { + _outputKind = OutputKind.DynamicallyLinkedLibrary; + _parseOptions = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Latest); // What languageversion should we default to? + + // The references should be the same every time GetCompiledAssembly is called + // Making it kind of a waste to convert the Assembly types into MetadataReference + // every time GetCompiledAssembly is called, so that's why I do it in the ctor + _refs = new List(); + foreach(var assembly in referenceAssemblies.Where(x => !x.IsDynamic && !string.IsNullOrWhiteSpace(x.Location)).Distinct()) + { + _refs.Add(MetadataReference.CreateFromFile(assembly.Location)); + }; + + // Might have to do this another way, see + // see https://github.com/aspnet/RoslynCodeDomProvider/blob/master/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs: + // mentions "Bug 913691: Explicitly add System.Runtime as a reference." + // and explicitly adds System.Runtime to references + _refs.Add(MetadataReference.CreateFromFile(typeof(System.Runtime.AssemblyTargetedPatchBandAttribute).Assembly.Location)); + _refs.Add(MetadataReference.CreateFromFile(typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).Assembly.Location)); + } + + /// + /// Compile a source file to a dll + /// + /// Path to the source file containing the code to be compiled. + /// The path where the output assembly will be saved. + public void CompileToFile(string pathToSourceFile, string savePath) + { + var sourceCode = File.ReadAllText(pathToSourceFile); + + var sourceText = SourceText.From(sourceCode); + + var syntaxTree = SyntaxFactory.ParseSyntaxTree(sourceText, _parseOptions); + + var compilation = CSharpCompilation.Create("ModelsGeneratedAssembly", + new[] { syntaxTree }, + references: _refs, + options: new CSharpCompilationOptions(_outputKind, + optimizationLevel: OptimizationLevel.Release, + // Not entirely certain that assemblyIdentityComparer is nececary? + assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default)); + + compilation.Emit(savePath); + + } + } +} diff --git a/src/Umbraco.ModelsBuilder.Embedded/Umbraco.ModelsBuilder.Embedded.csproj b/src/Umbraco.ModelsBuilder.Embedded/Umbraco.ModelsBuilder.Embedded.csproj index 87c20eca72..f2b264dcb0 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Umbraco.ModelsBuilder.Embedded.csproj +++ b/src/Umbraco.ModelsBuilder.Embedded/Umbraco.ModelsBuilder.Embedded.csproj @@ -1,119 +1,37 @@ - - - - - Debug - AnyCPU - {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C} - Library - Properties - Umbraco.ModelsBuilder.Embedded - Umbraco.ModelsBuilder.Embedded - v4.7.2 - 512 - true - 8 - - - true - portable - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - portable - true - bin\Release\ - TRACE - prompt - 4 - bin\Release\Umbraco.ModelsBuilder.Embedded.xml - - - - - - - - - - - - - - - - Properties\SolutionInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2.10.0 - - - 1.0.0 - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - 4.7.0 - - - - - {29aa69d9-b597-4395-8d42-43b1263c240a} - Umbraco.Core - - - {3ae7bf57-966b-45a5-910a-954d7c554441} - Umbraco.Infrastructure - - - {651e1350-91b6-44b7-bd60-7207006d7003} - Umbraco.Web - - - - - 5.2.7 - - - - \ No newline at end of file + + + + netcoreapp3.1 + Library + latest + + + + bin\Release\Umbraco.ModelsBuilder.Embedded.xml + + + + + + + + + + + + + + + <_Parameter1>Umbraco.Tests + + + <_Parameter1>Umbraco.Tests.UnitTests + + + <_Parameter1>Umbraco.Tests.Benchmarks + + + <_Parameter1>Umbraco.Tests.Integration + + + diff --git a/src/Umbraco.ModelsBuilder.Embedded/UmbracoAssemblyLoadContext.cs b/src/Umbraco.ModelsBuilder.Embedded/UmbracoAssemblyLoadContext.cs new file mode 100644 index 0000000000..b7feeaaaeb --- /dev/null +++ b/src/Umbraco.ModelsBuilder.Embedded/UmbracoAssemblyLoadContext.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.Loader; +using System.Text; + +namespace Umbraco.ModelsBuilder.Embedded +{ + class UmbracoAssemblyLoadContext : AssemblyLoadContext + { + + /// + /// Collectible AssemblyLoadContext used to load in the compiled generated models. + /// Must be a collectible assembly in order to be able to be unloaded. + /// + public UmbracoAssemblyLoadContext() : base(isCollectible: true) + { + + } + + protected override Assembly Load(AssemblyName assemblyName) + { + return null; + } + } +} diff --git a/src/Umbraco.Persistance.SqlCe/SqlCeSyntaxProvider.cs b/src/Umbraco.Persistance.SqlCe/SqlCeSyntaxProvider.cs index dbb48efa50..5bf0cf04be 100644 --- a/src/Umbraco.Persistance.SqlCe/SqlCeSyntaxProvider.cs +++ b/src/Umbraco.Persistance.SqlCe/SqlCeSyntaxProvider.cs @@ -237,5 +237,11 @@ where table_name=@0 and column_name=@1", tableName, columnName).FirstOrDefault() public override string DropIndex { get { return "DROP INDEX {1}.{0}"; } } + public override string GetSpecialDbType(SpecialDbTypes dbTypes) + { + if (dbTypes == SpecialDbTypes.NVARCHARMAX) // SqlCE does not have nvarchar(max) for now + return "NTEXT"; + return base.GetSpecialDbType(dbTypes); + } } } diff --git a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs index 337c61b30f..1bdb3711d1 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs @@ -3,9 +3,11 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Xml.XPath; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Xml; using Umbraco.Core.Xml.XPath; @@ -19,7 +21,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IAppCache _snapshotCache; private readonly IAppCache _elementsCache; private readonly IDomainCache _domainCache; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IVariationContextAccessor _variationContextAccessor; #region Constructor @@ -29,14 +31,14 @@ namespace Umbraco.Web.PublishedCache.NuCache // it's too late for UmbracoContext which has captured previewDefault and stuff into these ctor vars // but, no, UmbracoContext returns snapshot.Content which comes from elements SO a resync should create a new cache - public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache, IDomainCache domainCache, IGlobalSettings globalSettings, IVariationContextAccessor variationContextAccessor) + public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache, IDomainCache domainCache, IOptions globalSettings, IVariationContextAccessor variationContextAccessor) : base(previewDefault) { _snapshot = snapshot; _snapshotCache = snapshotCache; _elementsCache = elementsCache; _domainCache = domainCache; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _variationContextAccessor = variationContextAccessor; } diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.cs index 00e7fd34d1..ae7393a91a 100644 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.cs +++ b/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.cs @@ -2,12 +2,13 @@ using CSharpTest.Net.Collections; using CSharpTest.Net.Serialization; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.PublishedCache.NuCache.DataSource { internal class BTree { - public static BPlusTree GetTree(string filepath, bool exists, INuCacheSettings settings) + public static BPlusTree GetTree(string filepath, bool exists, NuCacheSettings settings) { var keySerializer = new PrimitiveSerializer(); var valueSerializer = new ContentNodeKitSerializer(); @@ -22,7 +23,6 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource // default is 4096, min 2^9 = 512, max 2^16 = 64K FileBlockSize = GetBlockSize(settings), - //HACK: Forces FileOptions to be WriteThrough here: https://github.com/mamift/CSharpTest.Net.Collections/blob/9f93733b3af7ee0e2de353e822ff54d908209b0b/src/CSharpTest.Net.Collections/IO/TransactedCompoundFile.cs#L316-L327, // as the reflection uses otherwise will failed in .NET Core as the "_handle" field in FileStream is renamed to "_fileHandle". StoragePerformance = StoragePerformance.CommitToDisk, @@ -40,7 +40,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource return tree; } - private static int GetBlockSize(INuCacheSettings settings) + private static int GetBlockSize(NuCacheSettings settings) { var blockSize = 4096; diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index 815fe0a168..adadef337f 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -6,11 +6,13 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CSharpTest.Net.Collections; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Install; using Umbraco.Core.IO; @@ -45,7 +47,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IDocumentRepository _documentRepository; private readonly IMediaRepository _mediaRepository; private readonly IMemberRepository _memberRepository; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IEntityXmlSerializer _entitySerializer; private readonly IPublishedModelFactory _publishedModelFactory; private readonly IDefaultCultureAccessor _defaultCultureAccessor; @@ -53,7 +55,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IHostingEnvironment _hostingEnvironment; private readonly IShortStringHelper _shortStringHelper; private readonly IIOHelper _ioHelper; - private readonly INuCacheSettings _config; + private readonly NuCacheSettings _config; // volatile because we read it with no lock private volatile bool _isReady; @@ -84,14 +86,15 @@ namespace Umbraco.Web.PublishedCache.NuCache IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IProfilingLogger logger, IScopeProvider scopeProvider, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, - IDataSource dataSource, IGlobalSettings globalSettings, + IDataSource dataSource, + IOptions globalSettings, IEntityXmlSerializer entitySerializer, IPublishedModelFactory publishedModelFactory, UrlSegmentProviderCollection urlSegmentProviders, IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper, IIOHelper ioHelper, - INuCacheSettings config) + IOptions config) : base(publishedSnapshotAccessor, variationContextAccessor) { //if (Interlocked.Increment(ref _singletonCheck) > 1) @@ -106,12 +109,12 @@ namespace Umbraco.Web.PublishedCache.NuCache _mediaRepository = mediaRepository; _memberRepository = memberRepository; _defaultCultureAccessor = defaultCultureAccessor; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _urlSegmentProviders = urlSegmentProviders; _hostingEnvironment = hostingEnvironment; _shortStringHelper = shortStringHelper; _ioHelper = ioHelper; - _config = config; + _config = config.Value; // we need an Xml serializer here so that the member cache can support XPath, // for members this is done by navigating the serialized-to-xml member @@ -1236,7 +1239,7 @@ namespace Umbraco.Web.PublishedCache.NuCache return new PublishedSnapshot.PublishedSnapshotElements { - ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainCache, _globalSettings, VariationContextAccessor), + ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainCache, Options.Create(_globalSettings), VariationContextAccessor), MediaCache = new MediaCache(previewDefault, mediaSnap, VariationContextAccessor), MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _entitySerializer, _publishedModelFactory), DomainCache = domainCache, diff --git a/src/Umbraco.Tests.AcceptanceTest/README.md b/src/Umbraco.Tests.AcceptanceTest/README.md index e8699b0733..541efd40f8 100644 --- a/src/Umbraco.Tests.AcceptanceTest/README.md +++ b/src/Umbraco.Tests.AcceptanceTest/README.md @@ -1,18 +1,18 @@ # Umbraco Acceptance Tests -### Prerequisite +### Prerequisites - NodeJS 12+ - A running installed Umbraco on url: [https://localhost:44331](https://localhost:44331) (Default development port) - Install using a `SqlServer`/`LocalDb` as the tests execute too fast for `SqlCE` to handle. - User information in `cypress.env.json` (See [Getting started](#getting-started)) ### Getting started -The tests is located in the project/folder named `Umbraco.Tests.AcceptanceTests`. Ensur to run `npm install` in that folder, or let your IDE do that. +The tests are located in the project/folder as `Umbraco.Tests.AcceptanceTests`. Make sure you run `npm install` in that folder, or let your IDE do that. -Next, it is important you create a new file in the root of the project called `cypress.env.json`. -This file is already added to `.gitignore` and can contain values that is different for each developer machine. +Next, it is important that you create a new file in the root of the project called `cypress.env.json`. +This file is already added to `.gitignore` and can contain values that are different for each developer machine. -The file need the following content: +The file needs the following content: ``` { "username": "", @@ -24,8 +24,7 @@ Replace the `` and `` placeholder ### Executing tests - -There exists two npm scripts, that can be used to execute the test. +There are two npm scripts that can be used to execute the test: 1. `npm run test` - Executes the tests headless. diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts new file mode 100644 index 0000000000..23e97043b0 --- /dev/null +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Content/content.ts @@ -0,0 +1,502 @@ +/// +import { DocumentTypeBuilder, ContentBuilder } from 'umbraco-cypress-testhelpers'; +context('Content', () => { + + beforeEach(() => { + cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); + }); + + it('Copy content', () => { + const rootDocTypeName = "Test document type"; + const childDocTypeName = "Child test document type"; + const nodeName = "1) Home"; + const childNodeName = "1) Child"; + const anotherNodeName = "2) Home"; + + const childDocType = new DocumentTypeBuilder() + .withName(childDocTypeName) + .build(); + + cy.deleteAllContent(); + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + cy.umbracoEnsureDocumentTypeNameNotExists(childDocTypeName); + + cy.saveDocumentType(childDocType).then((generatedChildDocType) => { + const rootDocTypeAlias; + const createdChildDocType = generatedChildDocType; + + cy.get('li .umb-tree-root:contains("Content")').should("be.visible"); + + const rootDocType = new DocumentTypeBuilder() + .withName(rootDocTypeName) + .withAllowAsRoot(true) + .withAllowedContentTypes(createdChildDocType["id"]) + .build(); + + cy.saveDocumentType(rootDocType).then((generatedRootDocType) => { + rootDocTypeAlias = generatedRootDocType["alias"]; + + const rootContentNode = new ContentBuilder() + .withContentTypeAlias(rootDocTypeAlias) + .withAction("saveNew") + .addVariant() + .withName(nodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(rootContentNode).then((contentNode) => { + // Add an item under root node + const childContentNode = new ContentBuilder() + .withContentTypeAlias(createdChildDocType["alias"]) + .withAction("saveNew") + .withParent(contentNode["id"]) + .addVariant() + .withName(childNodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(childContentNode); + }); + + const anotherRootContentNode = new ContentBuilder() + .withContentTypeAlias(rootDocTypeAlias) + .withAction("saveNew") + .addVariant() + .withName(anotherNodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(anotherRootContentNode); + }); + }); + + // Refresh to update the tree + cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); + cy.umbracoContextMenuAction("action-refreshNode").click(); + + // Copy node + cy.umbracoTreeItem("content", [nodeName, childNodeName]).rightclick({ force: true }); + cy.umbracoContextMenuAction("action-copy").click(); + cy.get('.umb-pane [data-element="tree-item-' + anotherNodeName + '"]').click(); + cy.get('.umb-dialog-footer > .btn-primary').click(); + + // Assert + cy.get('.alert-success').should('exist'); + + // Clean up (content is automatically deleted when document types are gone) + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + cy.umbracoEnsureDocumentTypeNameNotExists(childDocTypeName); + }); + + it('Move content', () => { + const rootDocTypeName = "Test document type"; + const childDocTypeName = "Child test document type"; + const nodeName = "1) Home"; + const childNodeName = "1) Child"; + const anotherNodeName = "2) Home"; + + const childDocType = new DocumentTypeBuilder() + .withName(childDocTypeName) + .build(); + + cy.deleteAllContent(); + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + cy.umbracoEnsureDocumentTypeNameNotExists(childDocTypeName); + + cy.saveDocumentType(childDocType).then((generatedChildDocType) => { + const rootDocTypeAlias; + const createdChildDocType = generatedChildDocType; + + cy.get('li .umb-tree-root:contains("Content")').should("be.visible"); + + const rootDocType = new DocumentTypeBuilder() + .withName(rootDocTypeName) + .withAllowAsRoot(true) + .withAllowedContentTypes(createdChildDocType["id"]) + .build(); + + cy.saveDocumentType(rootDocType).then((generatedRootDocType) => { + rootDocTypeAlias = generatedRootDocType["alias"]; + + const rootContentNode = new ContentBuilder() + .withContentTypeAlias(rootDocTypeAlias) + .withAction("saveNew") + .addVariant() + .withName(nodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(rootContentNode).then((contentNode) => { + // Add an item under root node + const childContentNode = new ContentBuilder() + .withContentTypeAlias(createdChildDocType["alias"]) + .withAction("saveNew") + .withParent(contentNode["id"]) + .addVariant() + .withName(childNodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(childContentNode); + }); + + const anotherRootContentNode = new ContentBuilder() + .withContentTypeAlias(rootDocTypeAlias) + .withAction("saveNew") + .addVariant() + .withName(anotherNodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(anotherRootContentNode); + }); + }); + + // Refresh to update the tree + cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); + cy.umbracoContextMenuAction("action-refreshNode").click(); + + // Move node + cy.umbracoTreeItem("content", [nodeName, childNodeName]).rightclick({ force: true }); + cy.umbracoContextMenuAction("action-move").click(); + cy.get('.umb-pane [data-element="tree-item-' + anotherNodeName + '"]').click(); + cy.get('.umb-dialog-footer > .btn-primary').click(); + + // Assert + cy.get('.alert-success').should('exist'); + + // Clean up (content is automatically deleted when document types are gone) + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + cy.umbracoEnsureDocumentTypeNameNotExists(childDocTypeName); + }); + + it('Sort content', () => { + const rootDocTypeName = "Test document type"; + const childDocTypeName = "Child test document type"; + const nodeName = "1) Home"; + const firstChildNodeName = "1) Child"; + const secondChildNodeName = "2) Child"; + + const childDocType = new DocumentTypeBuilder() + .withName(childDocTypeName) + .build(); + + cy.deleteAllContent(); + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + cy.umbracoEnsureDocumentTypeNameNotExists(childDocTypeName); + + cy.saveDocumentType(childDocType).then((generatedChildDocType) => { + const createdChildDocType = generatedChildDocType; + + cy.get('li .umb-tree-root:contains("Content")').should("be.visible"); + + const rootDocType = new DocumentTypeBuilder() + .withName(rootDocTypeName) + .withAllowAsRoot(true) + .withAllowedContentTypes(createdChildDocType["id"]) + .build(); + + cy.saveDocumentType(rootDocType).then((generatedRootDocType) => { + const parentId; + + const rootContentNode = new ContentBuilder() + .withContentTypeAlias(generatedRootDocType["alias"]) + .withAction("saveNew") + .addVariant() + .withName(nodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(rootContentNode).then((contentNode) => { + parentId = contentNode["id"]; + + // Add an item under root node + const firstChildContentNode = new ContentBuilder() + .withContentTypeAlias(createdChildDocType["alias"]) + .withAction("saveNew") + .withParent(parentId) + .addVariant() + .withName(firstChildNodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(firstChildContentNode); + + // Add a second item under root node + const secondChildContentNode = new ContentBuilder() + .withContentTypeAlias(createdChildDocType["alias"]) + .withAction("saveNew") + .withParent(parentId) + .addVariant() + .withName(secondChildNodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(secondChildContentNode); + }); + }); + }); + + // Refresh to update the tree + cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); + cy.umbracoContextMenuAction("action-refreshNode").click(); + + // Sort nodes + cy.umbracoTreeItem("content", [nodeName]).rightclick({ force: true }); + cy.umbracoContextMenuAction("action-sort").click(); + + //Drag and drop + cy.get('.ui-sortable .ui-sortable-handle :nth-child(2)').eq(0).trigger('mousedown', { which: 1 }) + cy.get('.ui-sortable .ui-sortable-handle :nth-child(2)').eq(1).trigger("mousemove").trigger("mouseup") + + // Save and close dialog + cy.get('.umb-modalcolumn .btn-success').click(); + cy.get('.umb-modalcolumn .btn-link').click(); + + // Assert + cy.get('.umb-tree-item [node="child"]').eq(0).should('contain.text', secondChildNodeName); + cy.get('.umb-tree-item [node="child"]').eq(1).should('contain.text', firstChildNodeName); + + // Clean up (content is automatically deleted when document types are gone) + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + cy.umbracoEnsureDocumentTypeNameNotExists(childDocTypeName); + }); + + it('Rollback content', () => { + const rootDocTypeName = "Test document type"; + const initialNodeName = "Home node"; + const nodeName = "Home"; + + const rootDocType = new DocumentTypeBuilder() + .withName(rootDocTypeName) + .withAllowAsRoot(true) + .build(); + + cy.deleteAllContent(); + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + + cy.saveDocumentType(rootDocType).then((generatedRootDocType) => { + const rootContentNode = new ContentBuilder() + .withContentTypeAlias(generatedRootDocType["alias"]) + .addVariant() + .withName(initialNodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(rootContentNode) + }); + + // Refresh to update the tree + cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); + cy.umbracoContextMenuAction("action-refreshNode").click(); + + // Access node + cy.umbracoTreeItem("content", [initialNodeName]).click(); + + // Edit header + cy.get('#headerName').clear(); + cy.umbracoEditorHeaderName(nodeName); + + // Save and publish + cy.get('.btn-success').first().click(); + + // Rollback + cy.get('.umb-box-header :button').click(); + + cy.get('.umb-box-content > .ng-scope > .input-block-level') + .find('option[label*=' + new Date().getDate() + ']') + .then(elements => { + const option = elements[[elements.length - 1]].getAttribute('value'); + cy.get('.umb-box-content > .ng-scope > .input-block-level') + .select(option); + }); + + cy.get('.umb-editor-footer-content__right-side > [button-style="success"] > .umb-button > .btn-success').click(); + + cy.reload(); + + // Assert + cy.get('.history').find('.umb-badge').eq(0).should('contain.text', "Save"); + cy.get('.history').find('.umb-badge').eq(1).should('contain.text', "Rollback"); + cy.get('#headerName').should('have.value', initialNodeName); + + // Clean up (content is automatically deleted when document types are gone) + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + }); + + it('View audit trail', () => { + const rootDocTypeName = "Test document type"; + const nodeName = "Home"; + const labelName = "Name"; + + const rootDocType = new DocumentTypeBuilder() + .withName(rootDocTypeName) + .withAllowAsRoot(true) + .addGroup() + .addTextBoxProperty() + .withLabel(labelName) + .done() + .done() + .build(); + + cy.deleteAllContent(); + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + + cy.saveDocumentType(rootDocType).then((generatedRootDocType) => { + const rootContentNode = new ContentBuilder() + .withContentTypeAlias(generatedRootDocType["alias"]) + .addVariant() + .withName(nodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(rootContentNode) + }); + + // Refresh to update the tree + cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); + cy.umbracoContextMenuAction("action-refreshNode").click(); + + // Access node + cy.umbracoTreeItem("content", [nodeName]).click(); + + // Navigate to Info app + cy.get(':nth-child(2) > [ng-show="navItem.alias !== \'more\'"]').click(); + + // Assert + cy.get('.history').should('exist'); + + // Clean up (content is automatically deleted when document types are gone) + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + }); + + it('Save draft', () => { + const rootDocTypeName = "Test document type"; + const nodeName = "Home"; + + const rootDocType = new DocumentTypeBuilder() + .withName(rootDocTypeName) + .withAllowAsRoot(true) + .build(); + + cy.deleteAllContent(); + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + + cy.saveDocumentType(rootDocType).then((generatedRootDocType) => { + const rootContentNode = new ContentBuilder() + .withContentTypeAlias(generatedRootDocType["alias"]) + .withAction("saveNew") + .addVariant() + .withName(nodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(rootContentNode) + }); + + // Refresh to update the tree + cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); + cy.umbracoContextMenuAction("action-refreshNode").click(); + + // Access node + cy.umbracoTreeItem("content", [nodeName]).click(); + + // Assert + cy.get('[data-element="node-info-status"]').find('.umb-badge').should('contain.text', "Draft"); + + // Clean up (content is automatically deleted when document types are gone) + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + }); + + it('Preview draft', () => { + const rootDocTypeName = "Test document type"; + const nodeName = "Home"; + + const rootDocType = new DocumentTypeBuilder() + .withName(rootDocTypeName) + .withAllowAsRoot(true) + .build(); + + cy.deleteAllContent(); + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + + cy.saveDocumentType(rootDocType).then((generatedRootDocType) => { + const rootContentNode = new ContentBuilder() + .withContentTypeAlias(generatedRootDocType["alias"]) + .withAction("saveNew") + .addVariant() + .withName(nodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(rootContentNode) + }); + + // Refresh to update the tree + cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); + cy.umbracoContextMenuAction("action-refreshNode").click(); + + // Access node + cy.umbracoTreeItem("content", [nodeName]).click(); + + // Preview + cy.get('[alias="preview"]').should('be.visible').click(); + + // Assert + cy.umbracoSuccessNotification({ multiple: true }).should('be.visible'); + + // Clean up (content is automatically deleted when document types are gone) + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + }); + + it('Publish draft', () => { + const rootDocTypeName = "Test document type"; + const nodeName = "Home"; + + const rootDocType = new DocumentTypeBuilder() + .withName(rootDocTypeName) + .withAllowAsRoot(true) + .build(); + + cy.deleteAllContent(); + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + + cy.saveDocumentType(rootDocType).then((generatedRootDocType) => { + const rootContentNode = new ContentBuilder() + .withContentTypeAlias(generatedRootDocType["alias"]) + .addVariant() + .withName(nodeName) + .withSave(true) + .done() + .build(); + + cy.saveContent(rootContentNode) + }); + + // Refresh to update the tree + cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick(); + cy.umbracoContextMenuAction("action-refreshNode").click(); + + // Access node + cy.umbracoTreeItem("content", [nodeName]).click(); + + // Assert + cy.get('[data-element="node-info-status"]').find('.umb-badge').should('contain.text', "Published"); + + // Clean up (content is automatically deleted when document types are gone) + cy.umbracoEnsureDocumentTypeNameNotExists(rootDocTypeName); + }); +}); diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts deleted file mode 100644 index ed891a2eea..0000000000 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts +++ /dev/null @@ -1,49 +0,0 @@ -/// -context('Backoffice Tour', () => { - - beforeEach(() => { - cy.umbracoLogin(Cypress.env('username'), Cypress.env('password')); - }); - - it('Backoffice introduction tour should run', () => { - //arrange - cy.umbracoGlobalHelp().should("be.visible"); - - //act - cy.umbracoGlobalHelp().click() - //assert - cy.get('[data-element="help-tours"]').should("be.visible"); - //act - cy.get('[data-element="help-tours"]').click(); - //assert - cy.get('[data-element="tour-umbIntroIntroduction"] .umb-button').should("be.visible"); - //act - cy.get('[data-element="tour-umbIntroIntroduction"] .umb-button').click(); - //assert - cy.get('.umb-tour-step', { timeout: 60000 }).should('be.visible'); - cy.get('.umb-tour-step__footer').should('be.visible'); - cy.get('.umb-tour-step__counter').should('be.visible'); - - for(let i=1;i<7;i++){ - cy.get('.umb-tour-step__counter').contains(i + '/12'); - cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click(); - } - cy.umbracoGlobalUser().click() - cy.get('.umb-tour-step__counter').contains('8/12'); - cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click(); - cy.get('.umb-tour-step__counter').contains('9/12'); - cy.get('.umb-overlay-drawer__align-right .umb-button').should('be.visible').click(); - cy.get('.umb-tour-step__counter').contains('10/12'); - cy.umbracoGlobalHelp().click() - - for(let i=11;i<13;i++){ - cy.get('.umb-tour-step__counter').contains(i + '/12'); - cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click(); - } - cy.get('.umb-tour-step__footer .umb-button').should('be.visible').click(); - - //assert - cy.umbracoGlobalHelp().should("be.visible"); - cy.get('[data-element="help-tours"] .umb-progress-circle').contains('17%'); - }); -}); diff --git a/src/Umbraco.Tests.AcceptanceTest/package.json b/src/Umbraco.Tests.AcceptanceTest/package.json index 867b7f5cf3..2017142d1e 100644 --- a/src/Umbraco.Tests.AcceptanceTest/package.json +++ b/src/Umbraco.Tests.AcceptanceTest/package.json @@ -5,9 +5,9 @@ }, "devDependencies": { "cross-env": "^7.0.2", - "cypress": "^4.12.1", + "cypress": "^5.1.0", "ncp": "^2.0.0", - "umbraco-cypress-testhelpers": "^1.0.0-beta-48" + "umbraco-cypress-testhelpers": "^1.0.0-beta-50" }, "dependencies": { "typescript": "^3.9.2" diff --git a/src/Umbraco.Tests.Common/Builders/ConnectionStringsBuilder.cs b/src/Umbraco.Tests.Common/Builders/ConnectionStringsBuilder.cs new file mode 100644 index 0000000000..4aba98fccd --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/ConnectionStringsBuilder.cs @@ -0,0 +1,27 @@ +using Umbraco.Core; +using Umbraco.Core.Configuration; +using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; + +namespace Umbraco.Tests.Common.Builders +{ + public class ConnectionStringsBuilder : BuilderBase + { + private string _umbracoConnectionString; + + public ConnectionStringsBuilder WithUmbracoConnectionString(string umbracoConnectionString) + { + _umbracoConnectionString = umbracoConnectionString; + return this; + } + + public override ConnectionStrings Build() + { + var umbracoConnectionString = _umbracoConnectionString ?? string.Empty; + + return new ConnectionStrings + { + UmbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, umbracoConnectionString), + }; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/ContentSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/ContentSettingsBuilder.cs new file mode 100644 index 0000000000..f5fb1fc08f --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/ContentSettingsBuilder.cs @@ -0,0 +1,12 @@ +using Umbraco.Core.Configuration.Models; + +namespace Umbraco.Tests.Common.Builders +{ + public class ContentSettingsBuilder : BuilderBase + { + public override ContentSettings Build() + { + return new ContentSettings(); + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/CoreDebugSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/CoreDebugSettingsBuilder.cs new file mode 100644 index 0000000000..e14fb0ade5 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/CoreDebugSettingsBuilder.cs @@ -0,0 +1,34 @@ +using CoreDebugSettings = Umbraco.Core.Configuration.Models.CoreDebugSettings; + +namespace Umbraco.Tests.Common.Builders +{ + public class CoreDebugSettingsBuilder : BuilderBase + { + private bool? _dumpOnTimeoutThreadAbort; + private bool? _logUncompletedScopes; + + public CoreDebugSettingsBuilder WithDumpOnTimeoutThreadAbort(bool dumpOnTimeoutThreadAbort) + { + _dumpOnTimeoutThreadAbort = dumpOnTimeoutThreadAbort; + return this; + } + + public CoreDebugSettingsBuilder WithLogUncompletedScopes(bool logUncompletedScopes) + { + _logUncompletedScopes = logUncompletedScopes; + return this; + } + + public override CoreDebugSettings Build() + { + var dumpOnTimeoutThreadAbort = _dumpOnTimeoutThreadAbort ?? false; + var logUncompletedScopes = _logUncompletedScopes ?? false; + + return new CoreDebugSettings + { + DumpOnTimeoutThreadAbort = dumpOnTimeoutThreadAbort, + LogUncompletedScopes = logUncompletedScopes, + }; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs index b1fe45f1f7..d39bd71d2e 100644 --- a/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Tests.Common.Builders { @@ -9,7 +9,7 @@ namespace Umbraco.Tests.Common.Builders } } - public class GlobalSettingsBuilder : ChildBuilderBase + public class GlobalSettingsBuilder : ChildBuilderBase { private string _configurationStatus; private string _databaseFactoryServerVersion; @@ -18,15 +18,13 @@ namespace Umbraco.Tests.Common.Builders private bool? _hideTopLevelNodeFromPath; private bool? _installEmptyDatabase; private bool? _installMissingDatabase; - private bool? _isSmtpServerConfigured; - private string _path; + private string _umbracoPath; 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; @@ -83,15 +81,9 @@ namespace Umbraco.Tests.Common.Builders return this; } - public GlobalSettingsBuilder WithIsSmtpServerConfigured(bool isSmtpServerConfigured) + public GlobalSettingsBuilder WithUmbracoPath(string umbracoPath) { - _isSmtpServerConfigured = isSmtpServerConfigured; - return this; - } - - public GlobalSettingsBuilder WithPath(string path) - { - _path = path; + _umbracoPath = umbracoPath; return this; } @@ -113,12 +105,6 @@ namespace Umbraco.Tests.Common.Builders return this; } - public GlobalSettingsBuilder WithUmbracoPath(string umbracoPath) - { - _umbracoPath = umbracoPath; - return this; - } - public GlobalSettingsBuilder WithUseHttps(bool useHttps) { _useHttps = useHttps; @@ -166,7 +152,7 @@ namespace Umbraco.Tests.Common.Builders return this; } - public override IGlobalSettings Build() + public override GlobalSettings Build() { var configurationStatus = _configurationStatus ?? "9.0.0"; var databaseFactoryServerVersion = _databaseFactoryServerVersion ?? null; @@ -175,11 +161,9 @@ namespace Umbraco.Tests.Common.Builders 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 reservedPaths = _reservedPaths ?? GlobalSettings.StaticReservedPaths; + var reservedUrls = _reservedUrls ?? GlobalSettings.StaticReservedUrls; var umbracoPath = _umbracoPath ?? "~/umbraco"; var useHttps = _useHttps ?? false; var umbracoCssPath = _umbracoCssPath ?? "~/css"; @@ -191,7 +175,7 @@ namespace Umbraco.Tests.Common.Builders var mainDomLock = _mainDomLock ?? string.Empty; var noNodesViewPath = _noNodesViewPath ?? "~/config/splashes/NoNodes.cshtml"; - return new TestGlobalSettings + return new GlobalSettings { ConfigurationStatus = configurationStatus, DatabaseFactoryServerVersion = databaseFactoryServerVersion, @@ -200,8 +184,6 @@ namespace Umbraco.Tests.Common.Builders HideTopLevelNodeFromPath = hideTopLevelNodeFromPath, InstallEmptyDatabase = installEmptyDatabase, InstallMissingDatabase = installMissingDatabase, - IsSmtpServerConfigured = isSmtpServerConfigured, - Path = path, RegisterType = registerType, ReservedPaths = reservedPaths, ReservedUrls = reservedUrls, @@ -212,40 +194,14 @@ namespace Umbraco.Tests.Common.Builders UmbracoScriptsPath = umbracoScriptsPath, VersionCheckPeriod = versionCheckPeriod, TimeOutInMinutes = timeOutInMinutes, - SmtpSettings = smtpSettings, + Smtp = smtpSettings, MainDomLock = mainDomLock, NoNodesViewPath = noNodesViewPath, }; } - - private class TestGlobalSettings : IGlobalSettings - { private string _iconsPath; - public string ReservedUrls { get; set; } - public string ReservedPaths { get; set; } public string IconsPath{ 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/HostingSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/HostingSettingsBuilder.cs new file mode 100644 index 0000000000..3e5e1db391 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/HostingSettingsBuilder.cs @@ -0,0 +1,44 @@ +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; + +namespace Umbraco.Tests.Common.Builders +{ + public class HostingSettingsBuilder : BuilderBase + { + private string _applicationVirtualPath; + private bool? _debug; + private LocalTempStorage? _localTempStorageLocation; + + public HostingSettingsBuilder WithApplicationVirtualPath(string applicationVirtualPath) + { + _applicationVirtualPath = applicationVirtualPath; + return this; + } + + public HostingSettingsBuilder WithDebug(bool debug) + { + _debug = debug; + return this; + } + + public HostingSettingsBuilder WithLocalTempStorageLocation(LocalTempStorage localTempStorageLocation) + { + _localTempStorageLocation = localTempStorageLocation; + return this; + } + + public override HostingSettings Build() + { + var debug = _debug ?? false; + var localTempStorageLocation = _localTempStorageLocation ?? LocalTempStorage.Default; + var applicationVirtualPath = _applicationVirtualPath ?? null; + + return new HostingSettings + { + ApplicationVirtualPath = applicationVirtualPath, + Debug = debug, + LocalTempStorageLocation = localTempStorageLocation, + }; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs b/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs index 88c8fa4639..7174baaba1 100644 --- a/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs @@ -1,7 +1,6 @@ using System; using System.Globalization; -using Moq; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders.Interfaces; @@ -58,6 +57,7 @@ namespace Umbraco.Tests.Common.Builders public override ILanguage Build() { var cultureInfo = _cultureInfo ?? CultureInfo.GetCultureInfo("en-US"); + var globalSettings = new GlobalSettingsBuilder().WithDefaultUiLanguage(cultureInfo.Name).Build(); var key = _key ?? Guid.NewGuid(); var createDate = _createDate ?? DateTime.Now; var updateDate = _updateDate ?? DateTime.Now; @@ -66,7 +66,7 @@ namespace Umbraco.Tests.Common.Builders var isDefault = _isDefault ?? false; var isMandatory = _isMandatory ?? false; - return new Language(Mock.Of(), cultureInfo.Name) + return new Language(globalSettings, cultureInfo.Name) { Id = _id ?? 0, CultureName = cultureInfo.EnglishName, diff --git a/src/Umbraco.Tests.Common/Builders/ModelsBuilderConfigBuilder.cs b/src/Umbraco.Tests.Common/Builders/ModelsBuilderConfigBuilder.cs new file mode 100644 index 0000000000..4b94339dc0 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/ModelsBuilderConfigBuilder.cs @@ -0,0 +1,12 @@ +using Umbraco.Core.Configuration.Models; + +namespace Umbraco.Tests.Common.Builders +{ + public class ModelsBuilderConfigBuilder : BuilderBase + { + public override ModelsBuilderConfig Build() + { + return new ModelsBuilderConfig(); + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/NuCacheSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/NuCacheSettingsBuilder.cs new file mode 100644 index 0000000000..35d5c66e4a --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/NuCacheSettingsBuilder.cs @@ -0,0 +1,12 @@ +using Umbraco.Core.Configuration.Models; + +namespace Umbraco.Tests.Common.Builders +{ + public class NuCacheSettingsBuilder : BuilderBase + { + public override NuCacheSettings Build() + { + return new NuCacheSettings(); + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/RequestHandlerSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/RequestHandlerSettingsBuilder.cs new file mode 100644 index 0000000000..3c6f652014 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/RequestHandlerSettingsBuilder.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Tests.Common.Builders +{ + public class RequestHandlerSettingsBuilder : BuilderBase + { + private bool? _addTrailingSlash; + private string _convertUrlsToAscii; + private IEnumerable _charCollection; + + public RequestHandlerSettingsBuilder WithAddTrailingSlash(bool addTrailingSlash) + { + _addTrailingSlash = addTrailingSlash; + return this; + } + + public RequestHandlerSettingsBuilder WithConvertUrlsToAscii(string convertUrlsToAscii) + { + _convertUrlsToAscii = convertUrlsToAscii; + return this; + } + + public RequestHandlerSettingsBuilder WithCharCollection(IEnumerable charCollection) + { + _charCollection = charCollection; + return this; + } + + public override RequestHandlerSettings Build() + { + var addTrailingSlash = _addTrailingSlash ?? false; + var convertUrlsToAscii = _convertUrlsToAscii ?? "false"; + var charCollection = _charCollection ?? RequestHandlerSettings.DefaultCharCollection; + + return new RequestHandlerSettings + { + AddTrailingSlash = addTrailingSlash, + ConvertUrlsToAscii = convertUrlsToAscii, + CharCollection = charCollection, + }; + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs index bd85807203..f979197e4c 100644 --- a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs @@ -1,6 +1,5 @@ using System.Net.Mail; -using Umbraco.Core.Configuration; -using Umbraco.Core.Models.Membership; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Tests.Common.Builders { @@ -12,7 +11,7 @@ namespace Umbraco.Tests.Common.Builders } public class SmtpSettingsBuilder - : ChildBuilderBase + : ChildBuilderBase { private string _from; private string _host; @@ -68,7 +67,7 @@ namespace Umbraco.Tests.Common.Builders return this; } - public override ISmtpSettings Build() + public override SmtpSettings Build() { var from = _from ?? null; var host = _host ?? null; @@ -78,7 +77,7 @@ namespace Umbraco.Tests.Common.Builders var username = _username ?? null; var password = _password ?? null; - return new TestSmtpSettings() + return new SmtpSettings() { From = from, Host = host, @@ -89,16 +88,5 @@ namespace Umbraco.Tests.Common.Builders Password = password, }; } - - private class TestSmtpSettings : ISmtpSettings - { - public string From { get; set; } - public string Host { get; set; } - public int Port { get; set; } - public string PickupDirectoryLocation { get; set; } - public SmtpDeliveryMethod DeliveryMethod { get; set; } - public string Username { get; set; } - public string Password { get; set; } - } } } diff --git a/src/Umbraco.Tests.Common/Builders/UserPasswordConfigurationSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/UserPasswordConfigurationSettingsBuilder.cs new file mode 100644 index 0000000000..3a0dfc3e9a --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/UserPasswordConfigurationSettingsBuilder.cs @@ -0,0 +1,12 @@ +using Umbraco.Core.Configuration.Models; + +namespace Umbraco.Tests.Common.Builders +{ + public class UserPasswordConfigurationSettingsBuilder : BuilderBase + { + public override UserPasswordConfigurationSettings Build() + { + return new UserPasswordConfigurationSettings(); + } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/WebRoutingSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/WebRoutingSettingsBuilder.cs new file mode 100644 index 0000000000..e32fff31fa --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/WebRoutingSettingsBuilder.cs @@ -0,0 +1,89 @@ +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Tests.Common.Builders +{ + public class WebRoutingSettingsBuilder : BuilderBase + { + private bool? _trySkipIisCustomErrors; + private bool? _internalRedirectPreservesTemplate; + private bool? _disableAlternativeTemplates; + private bool? _validateAlternativeTemplates; + private bool? _disableFindContentByIdPath; + private bool? _disableRedirectUrlTracking; + private string _urlProviderMode; + private string _umbracoApplicationUrl; + + public WebRoutingSettingsBuilder WithTrySkipIisCustomErrors(bool trySkipIisCustomErrors) + { + _trySkipIisCustomErrors = trySkipIisCustomErrors; + return this; + } + + public WebRoutingSettingsBuilder WithInternalRedirectPreservesTemplate(bool internalRedirectPreservesTemplate) + { + _internalRedirectPreservesTemplate = internalRedirectPreservesTemplate; + return this; + } + + public WebRoutingSettingsBuilder WithDisableAlternativeTemplates(bool disableAlternativeTemplates) + { + _disableAlternativeTemplates = disableAlternativeTemplates; + return this; + } + + public WebRoutingSettingsBuilder WithValidateAlternativeTemplates(bool validateAlternativeTemplates) + { + _validateAlternativeTemplates = validateAlternativeTemplates; + return this; + } + + public WebRoutingSettingsBuilder WithDisableFindContentByIdPath(bool disableFindContentByIdPath) + { + _disableFindContentByIdPath = disableFindContentByIdPath; + return this; + } + + public WebRoutingSettingsBuilder WithDisableRedirectUrlTracking(bool disableRedirectUrlTracking) + { + _disableRedirectUrlTracking = disableRedirectUrlTracking; + return this; + } + + public WebRoutingSettingsBuilder WithUrlProviderMode(string urlProviderMode) + { + _urlProviderMode = urlProviderMode; + return this; + } + + public WebRoutingSettingsBuilder WithUmbracoApplicationUrl(string umbracoApplicationUrl) + { + _umbracoApplicationUrl = umbracoApplicationUrl; + return this; + } + + public override WebRoutingSettings Build() + { + var trySkipIisCustomErrors = _trySkipIisCustomErrors ?? false; + var internalRedirectPreservesTemplate = _internalRedirectPreservesTemplate ?? false; + var disableAlternativeTemplates = _disableAlternativeTemplates ?? false; + var validateAlternativeTemplates = _validateAlternativeTemplates ?? false; + var disableFindContentByIdPath = _disableFindContentByIdPath ?? false; + var disableRedirectUrlTracking = _disableRedirectUrlTracking ?? false; + var urlProviderMode = _urlProviderMode ?? UrlMode.Auto.ToString(); + var umbracoApplicationUrl = _umbracoApplicationUrl ?? string.Empty; + + return new WebRoutingSettings + { + TrySkipIisCustomErrors = trySkipIisCustomErrors, + InternalRedirectPreservesTemplate = internalRedirectPreservesTemplate, + DisableAlternativeTemplates = disableAlternativeTemplates, + ValidateAlternativeTemplates = validateAlternativeTemplates, + DisableFindContentByIdPath = disableFindContentByIdPath, + DisableRedirectUrlTracking = disableRedirectUrlTracking, + UrlProviderMode = urlProviderMode, + UmbracoApplicationUrl = umbracoApplicationUrl, + }; + } + } +} diff --git a/src/Umbraco.Tests/Published/PublishedSnapshotTestObjects.cs b/src/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs similarity index 53% rename from src/Umbraco.Tests/Published/PublishedSnapshotTestObjects.cs rename to src/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs index fcb462e5c5..1c618380a0 100644 --- a/src/Umbraco.Tests/Published/PublishedSnapshotTestObjects.cs +++ b/src/Umbraco.Tests.Common/Published/PublishedSnapshotTestObjects.cs @@ -1,52 +1,52 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using Moq; +using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web; -using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published { public class PublishedSnapshotTestObjects { + [PublishedModel("element1")] public class TestElementModel1 : PublishedElementModel { - public TestElementModel1(IPublishedElement content) + public TestElementModel1(IPublishedElement content, IPublishedValueFallback fallback) : base(content) { } - public string Prop1 => this.Value("prop1"); + public string Prop1 => this.Value(Mock.Of(), "prop1"); } [PublishedModel("element2")] public class TestElementModel2 : PublishedElementModel { - public TestElementModel2(IPublishedElement content) + public TestElementModel2(IPublishedElement content, IPublishedValueFallback fallback) : base(content) { } - public IEnumerable Prop2 => this.Value>("prop2"); + public IEnumerable Prop2 => this.Value>(Mock.Of(), "prop2"); } [PublishedModel("content1")] public class TestContentModel1 : PublishedContentModel { - public TestContentModel1(IPublishedContent content) + public TestContentModel1(IPublishedContent content, IPublishedValueFallback fallback) : base(content) { } - public string Prop1 => this.Value("prop1"); + public string Prop1 => this.Value(Mock.Of(), "prop1"); } [PublishedModel("content2")] public class TestContentModel2 : PublishedContentModel { - public TestContentModel2(IPublishedContent content) + public TestContentModel2(IPublishedContent content, IPublishedValueFallback fallback) : base(content) { } - public IEnumerable Prop2 => this.Value>("prop2"); + public IEnumerable Prop2 => this.Value>(Mock.Of(), "prop2"); } - + } } diff --git a/src/Umbraco.Tests.Common/SettingsForTests.cs b/src/Umbraco.Tests.Common/SettingsForTests.cs deleted file mode 100644 index 1a14dc6bc1..0000000000 --- a/src/Umbraco.Tests.Common/SettingsForTests.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System.Collections.Generic; -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.UseHttps == false && - settings.HideTopLevelNodeFromPath == false && - 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.Clear(); - _defaultHostingSettings = null; - } - - private readonly Dictionary _defaultGlobalSettings = new Dictionary(); - private IHostingSettings _defaultHostingSettings; - - public IGlobalSettings GetDefaultGlobalSettings(IUmbracoVersion umbVersion) - { - if (_defaultGlobalSettings.TryGetValue(umbVersion.SemanticVersion, out var settings)) - return settings; - - settings = GenerateMockGlobalSettings(umbVersion); - _defaultGlobalSettings[umbVersion.SemanticVersion] = settings; - return settings; - } - - public IHostingSettings DefaultHostingSettings => _defaultHostingSettings ?? (_defaultHostingSettings = GenerateMockHostingSettings()); - - public 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.Common/TestHelperBase.cs b/src/Umbraco.Tests.Common/TestHelperBase.cs index 85a463ddfa..7b5fed3000 100644 --- a/src/Umbraco.Tests.Common/TestHelperBase.cs +++ b/src/Umbraco.Tests.Common/TestHelperBase.cs @@ -6,6 +6,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Diagnostics; using Umbraco.Core.Hosting; @@ -18,6 +19,7 @@ using Umbraco.Core.Serialization; using Umbraco.Core.Strings; using Umbraco.Web; using Umbraco.Web.Routing; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Common { @@ -33,7 +35,6 @@ namespace Umbraco.Tests.Common protected TestHelperBase(Assembly entryAssembly) { - SettingsForTests = new SettingsForTests(); MainDom = new SimpleMainDom(); _typeFinder = new TypeFinder(Mock.Of(), new DefaultUmbracoAssemblyProvider(entryAssembly), new VaryingRuntimeHash()); } @@ -45,18 +46,11 @@ namespace Umbraco.Tests.Common return new TypeLoader(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(), - GetUmbracoVersion()); - } + // public Configs GetConfigs() => GetConfigsFactory().Create(); public abstract IBackOfficeInfo GetBackOfficeInfo(); - public IConfigsFactory GetConfigsFactory() => new ConfigsFactory(); + //public IConfigsFactory GetConfigsFactory() => new ConfigsFactory(); /// /// Gets the working directory of the test project. @@ -82,14 +76,14 @@ namespace Umbraco.Tests.Common public abstract IDbProviderFactoryCreator DbProviderFactoryCreator { get; } public abstract IBulkSqlInsertProvider BulkSqlInsertProvider { get; } public abstract IMarchal Marchal { get; } - public ICoreDebugSettings CoreDebugSettings { get; } = new CoreDebugSettings(); + public CoreDebugSettings CoreDebugSettings { get; } = new CoreDebugSettings(); public IIOHelper IOHelper { get { if (_ioHelper == null) - _ioHelper = new IOHelper(GetHostingEnvironment(), SettingsForTests.GenerateMockGlobalSettings()); + _ioHelper = new IOHelper(GetHostingEnvironment()); return _ioHelper; } } @@ -104,10 +98,6 @@ namespace Umbraco.Tests.Common return _uriUtility; } } - - public SettingsForTests SettingsForTests { get; } - public IWebRoutingSettings WebRoutingSettings => SettingsForTests.GenerateMockWebRoutingSettings(); - /// /// Some test files are copied to the /bin (/bin/debug) on build, this is a utility to return their physical path based on a virtual path name /// @@ -126,11 +116,11 @@ namespace Umbraco.Tests.Common return relativePath.Replace("~/", bin + "/"); } - public IUmbracoVersion GetUmbracoVersion() => new UmbracoVersion(GetConfigs().Global()); + public IUmbracoVersion GetUmbracoVersion() => new UmbracoVersion(); public IRegister GetRegister() { - return RegisterFactory.Create(GetConfigs().Global()); + return RegisterFactory.Create(new GlobalSettingsBuilder().Build()); } public abstract IHostingEnvironment GetHostingEnvironment(); diff --git a/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs b/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs new file mode 100644 index 0000000000..954dedd3b4 --- /dev/null +++ b/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs @@ -0,0 +1,27 @@ +using Moq; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; + +namespace Umbraco.Tests.TestHelpers.Entities +{ + public class MockedValueEditors + { + public static DataValueEditor CreateDataValueEditor(string name) + { + var valueType = (ValueTypes.IsValue(name)) ? name : ValueTypes.String; + + return new DataValueEditor( + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + new DataEditorAttribute(name, name, name) + { + ValueType = valueType + } + + ); + } + } +} diff --git a/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs new file mode 100644 index 0000000000..1eef61a29e --- /dev/null +++ b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs @@ -0,0 +1,445 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Tests.Common.PublishedContent +{ + public class SolidPublishedSnapshot : IPublishedSnapshot + { + public readonly SolidPublishedContentCache InnerContentCache = new SolidPublishedContentCache(); + public readonly SolidPublishedContentCache InnerMediaCache = new SolidPublishedContentCache(); + + public IPublishedContentCache Content => InnerContentCache; + + public IPublishedMediaCache Media => InnerMediaCache; + + public IPublishedMemberCache Members => null; + + public IDomainCache Domains => null; + + public IDisposable ForcedPreview(bool forcedPreview, Action callback = null) + { + throw new NotImplementedException(); + } + + public void Resync() + { } + + public IAppCache SnapshotCache => null; + + public IAppCache ElementsCache => null; + + public void Dispose() + { } + } + + public class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache + { + private readonly Dictionary _content = new Dictionary(); + + public SolidPublishedContentCache() + : base(false) + { } + + public void Add(SolidPublishedContent content) + { + _content[content.Id] = content.CreateModel(Mock.Of()); + } + + public void Clear() + { + _content.Clear(); + } + + public IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string culture = null) + { + throw new NotImplementedException(); + } + + public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string culture = null) + { + throw new NotImplementedException(); + } + + public string GetRouteById(bool preview, int contentId, string culture = null) + { + throw new NotImplementedException(); + } + + public string GetRouteById(int contentId, string culture = null) + { + throw new NotImplementedException(); + } + + public override IPublishedContent GetById(bool preview, int contentId) + { + return _content.ContainsKey(contentId) ? _content[contentId] : null; + } + + public override IPublishedContent GetById(bool preview, Guid contentId) + { + throw new NotImplementedException(); + } + + public override IPublishedContent GetById(bool preview, Udi nodeId) + => throw new NotSupportedException(); + + public override bool HasById(bool preview, int contentId) + { + return _content.ContainsKey(contentId); + } + + public override IEnumerable GetAtRoot(bool preview, string culture = null) + { + return _content.Values.Where(x => x.Parent == null); + } + + public override IPublishedContent GetSingleByXPath(bool preview, string xpath, Core.Xml.XPathVariable[] vars) + { + throw new NotImplementedException(); + } + + public override IPublishedContent GetSingleByXPath(bool preview, System.Xml.XPath.XPathExpression xpath, Core.Xml.XPathVariable[] vars) + { + throw new NotImplementedException(); + } + + public override IEnumerable GetByXPath(bool preview, string xpath, Core.Xml.XPathVariable[] vars) + { + throw new NotImplementedException(); + } + + public override IEnumerable GetByXPath(bool preview, System.Xml.XPath.XPathExpression xpath, Core.Xml.XPathVariable[] vars) + { + throw new NotImplementedException(); + } + + public override System.Xml.XPath.XPathNavigator CreateNavigator(bool preview) + { + throw new NotImplementedException(); + } + + public override System.Xml.XPath.XPathNavigator CreateNodeNavigator(int id, bool preview) + { + throw new NotImplementedException(); + } + + public override bool HasContent(bool preview) + { + return _content.Count > 0; + } + + public override IPublishedContentType GetContentType(int id) + { + throw new NotImplementedException(); + } + + public override IPublishedContentType GetContentType(string alias) + { + throw new NotImplementedException(); + } + + public override IPublishedContentType GetContentType(Guid key) + { + throw new NotImplementedException(); + } + + public override IEnumerable GetByContentType(IPublishedContentType contentType) + { + throw new NotImplementedException(); + } + } + + public class SolidPublishedContent : IPublishedContent + { + #region Constructor + + public SolidPublishedContent(IPublishedContentType contentType) + { + // initialize boring stuff + TemplateId = 0; + WriterId = CreatorId = 0; + CreateDate = UpdateDate = DateTime.Now; + Version = Guid.Empty; + + ContentType = contentType; + } + + #endregion + + #region Content + + private Dictionary _cultures; + + private Dictionary GetCultures() + { + return new Dictionary { { "", new PublishedCultureInfo("", Name, UrlSegment, UpdateDate) } }; + } + + public int Id { get; set; } + public Guid Key { get; set; } + public int? TemplateId { get; set; } + public int SortOrder { get; set; } + public string Name { get; set; } + public IReadOnlyDictionary Cultures => _cultures ?? (_cultures = GetCultures()); + public string UrlSegment { get; set; } + public int WriterId { get; set; } + public int CreatorId { get; set; } + public string Path { get; set; } + public DateTime CreateDate { get; set; } + public DateTime UpdateDate { get; set; } + public Guid Version { get; set; } + public int Level { get; set; } + + public PublishedItemType ItemType => PublishedItemType.Content; + public bool IsDraft(string culture = null) => false; + public bool IsPublished(string culture = null) => true; + + #endregion + + #region Tree + + public int ParentId { get; set; } + public IEnumerable ChildIds { get; set; } + + public IPublishedContent Parent { get; set; } + public IEnumerable Children { get; set; } + public IEnumerable ChildrenForAllCultures => Children; + + #endregion + + #region ContentType + + public IPublishedContentType ContentType { get; set; } + + #endregion + + #region Properties + + public IEnumerable Properties { get; set; } + + public IPublishedProperty GetProperty(string alias) + { + return Properties.FirstOrDefault(p => p.Alias.InvariantEquals(alias)); + } + + public IPublishedProperty GetProperty(string alias, bool recurse) + { + var property = GetProperty(alias); + if (recurse == false) return property; + + IPublishedContent content = this; + while (content != null && (property == null || property.HasValue() == false)) + { + content = content.Parent; + property = content?.GetProperty(alias); + } + + return property; + } + + public object this[string alias] + { + get + { + var property = GetProperty(alias); + return property == null || property.HasValue() == false ? null : property.GetValue(); + } + } + + #endregion + } + + public class SolidPublishedProperty : IPublishedProperty + { + public IPublishedPropertyType PropertyType { get; set; } + public string Alias { get; set; } + public object SolidSourceValue { get; set; } + public object SolidValue { get; set; } + public bool SolidHasValue { get; set; } + public object SolidXPathValue { get; set; } + + public virtual object GetSourceValue(string culture = null, string segment = null) => SolidSourceValue; + public virtual object GetValue(string culture = null, string segment = null) => SolidValue; + public virtual object GetXPathValue(string culture = null, string segment = null) => SolidXPathValue; + public virtual bool HasValue(string culture = null, string segment = null) => SolidHasValue; + } + + public class SolidPublishedPropertyWithLanguageVariants : SolidPublishedProperty + { + private readonly IDictionary _solidSourceValues = new Dictionary(); + private readonly IDictionary _solidValues = new Dictionary(); + private readonly IDictionary _solidXPathValues = new Dictionary(); + + public override object GetSourceValue(string culture = null, string segment = null) + { + if (string.IsNullOrEmpty(culture)) + { + return base.GetSourceValue(culture, segment); + } + + return _solidSourceValues.ContainsKey(culture) ? _solidSourceValues[culture] : null; + } + + public override object GetValue(string culture = null, string segment = null) + { + if (string.IsNullOrEmpty(culture)) + { + return base.GetValue(culture, segment); + } + + return _solidValues.ContainsKey(culture) ? _solidValues[culture] : null; + } + + public override object GetXPathValue(string culture = null, string segment = null) + { + if (string.IsNullOrEmpty(culture)) + { + return base.GetXPathValue(culture, segment); + } + + return _solidXPathValues.ContainsKey(culture) ? _solidXPathValues[culture] : null; + } + + public override bool HasValue(string culture = null, string segment = null) + { + if (string.IsNullOrEmpty(culture)) + { + return base.HasValue(culture, segment); + } + + return _solidSourceValues.ContainsKey(culture); + } + + public void SetSourceValue(string culture, object value, bool defaultValue = false) + { + _solidSourceValues.Add(culture, value); + if (defaultValue) + { + SolidSourceValue = value; + SolidHasValue = true; + } + } + + public void SetValue(string culture, object value, bool defaultValue = false) + { + _solidValues.Add(culture, value); + if (defaultValue) + { + SolidValue = value; + SolidHasValue = true; + } + } + + public void SetXPathValue(string culture, object value, bool defaultValue = false) + { + _solidXPathValues.Add(culture, value); + if (defaultValue) + { + SolidXPathValue = value; + } + } + } + + [PublishedModel("ContentType2")] + public class ContentType2 : PublishedContentModel + { + #region Plumbing + + public ContentType2(IPublishedContent content, IPublishedValueFallback fallback) + : base(content) + { } + + #endregion + + public int Prop1 => this.Value(Mock.Of(), "prop1"); + } + + [PublishedModel("ContentType2Sub")] + public class ContentType2Sub : ContentType2 + { + #region Plumbing + + public ContentType2Sub(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) + { } + + #endregion + } + + public class PublishedContentStrong1 : PublishedContentModel + { + public PublishedContentStrong1(IPublishedContent content, IPublishedValueFallback fallback) + : base(content) + { } + + public int StrongValue => this.Value(Mock.Of(), "strongValue"); + } + + public class PublishedContentStrong1Sub : PublishedContentStrong1 + { + public PublishedContentStrong1Sub(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) + { } + + public int AnotherValue => this.Value(Mock.Of(), "anotherValue"); + } + + public class PublishedContentStrong2 : PublishedContentModel + { + public PublishedContentStrong2(IPublishedContent content, IPublishedValueFallback fallback) + : base(content) + { } + + public int StrongValue => this.Value(Mock.Of(), "strongValue"); + } + + public class AutoPublishedContentType : PublishedContentType + { + private static readonly IPublishedPropertyType Default; + + static AutoPublishedContentType() + { + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 666 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); + + var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeServiceMock.Object); + Default = factory.CreatePropertyType("*", 666); + } + + public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable propertyTypes) + : base(key, id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, ContentVariation.Nothing) + { } + + public AutoPublishedContentType(Guid key, int id, string alias, Func> propertyTypes) + : base(key, id, alias, PublishedItemType.Content, Enumerable.Empty(), propertyTypes, ContentVariation.Nothing) + { } + + public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable compositionAliases, IEnumerable propertyTypes) + : base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing) + { } + + public AutoPublishedContentType(Guid key, int id, string alias, IEnumerable compositionAliases, Func> propertyTypes) + : base(key, id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, ContentVariation.Nothing) + { } + + public override IPublishedPropertyType GetPropertyType(string alias) + { + var propertyType = base.GetPropertyType(alias); + return propertyType ?? Default; + } + } +} diff --git a/src/Umbraco.Tests/StringNewlineExtensions.cs b/src/Umbraco.Tests.Common/TestHelpers/StringNewlineExtensions.cs similarity index 96% rename from src/Umbraco.Tests/StringNewlineExtensions.cs rename to src/Umbraco.Tests.Common/TestHelpers/StringNewlineExtensions.cs index b26f345788..6de58f84b2 100644 --- a/src/Umbraco.Tests/StringNewlineExtensions.cs +++ b/src/Umbraco.Tests.Common/TestHelpers/StringNewlineExtensions.cs @@ -1,6 +1,6 @@ namespace Umbraco.Tests { - static class StringNewLineExtensions + public static class StringNewLineExtensions { /// /// Ensures Lf only everywhere. diff --git a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj index 68d3f23ac4..ecef075c0f 100644 --- a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj +++ b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj @@ -5,15 +5,14 @@ - - - - + + + + - diff --git a/src/Umbraco.Tests.Integration/ContainerTests.cs b/src/Umbraco.Tests.Integration/ContainerTests.cs index 2098b7241e..00d6c14be3 100644 --- a/src/Umbraco.Tests.Integration/ContainerTests.cs +++ b/src/Umbraco.Tests.Integration/ContainerTests.cs @@ -36,15 +36,15 @@ namespace Umbraco.Tests.Integration serviceProviderFactory.CreateBuilder(services); // called during Host Builder, needed to capture services // Dependencies needed for creating composition/register essentials - var testHelper = new TestHelper(); + var testHelper = new TestHelper(); var runtimeState = Mock.Of(); var umbracoDatabaseFactory = Mock.Of(); - var dbProviderFactoryCreator = 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); + testHelper.Logger, runtimeState, 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, @@ -83,7 +83,7 @@ namespace Umbraco.Tests.Integration // 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 = UmbracoIntegrationTest.GetUmbracoContainer(out var serviceProviderFactory); + var umbracoContainer = UmbracoIntegrationTest.CreateUmbracoContainer(out var serviceProviderFactory); IHostApplicationLifetime lifetime1 = null; diff --git a/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs deleted file mode 100644 index edbdcd0722..0000000000 --- a/src/Umbraco.Tests.Integration/Extensions/ApplicationBuilderExtensions.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Data.Common; -using System.Data.SqlClient; -using System.IO; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Tests.Integration.Testing; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Integration.Extensions -{ - public static class ApplicationBuilderExtensions - { - /// - /// Creates a LocalDb instance to use for the test - /// - /// - /// - /// - /// - /// - public static IApplicationBuilder UseTestLocalDb(this IApplicationBuilder app, - string workingDirectory, - UmbracoIntegrationTest integrationTest, out string connectionString) - { - connectionString = null; - var dbFilePath = Path.Combine(workingDirectory, "LocalDb"); - - // get the currently set db options - var testOptions = TestOptionAttributeBase.GetTestOptions(); - - if (testOptions.Database == UmbracoTestOptions.Database.None) - return app; - - // need to manually register this factory - DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance); - - if (!Directory.Exists(dbFilePath)) - Directory.CreateDirectory(dbFilePath); - - var db = UmbracoIntegrationTest.GetOrCreate(dbFilePath, - app.ApplicationServices.GetRequiredService(), - app.ApplicationServices.GetRequiredService(), - app.ApplicationServices.GetRequiredService()); - - - switch (testOptions.Database) - { - case UmbracoTestOptions.Database.NewSchemaPerTest: - - // New DB + Schema - var newSchemaDbId = db.AttachSchema(); - - // Add teardown callback - integrationTest.OnTestTearDown(() => db.Detach(newSchemaDbId)); - - // We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings - var dbFactory = app.ApplicationServices.GetRequiredService(); - if (!dbFactory.Configured) - { - dbFactory.Configure(db.ConnectionString, Constants.DatabaseProviders.SqlServer); - } - - // In the case that we've initialized the schema, it means that we are installed so we'll want to ensure that - // the runtime state is configured correctly so we'll force update the configuration flag and re-run the - // runtime state checker. - // TODO: This wouldn't be required if we don't store the Umbraco version in config - - // right now we are an an 'Install' state - var runtimeState = (RuntimeState)app.ApplicationServices.GetRequiredService(); - Assert.AreEqual(RuntimeLevel.Install, runtimeState.Level); - - // dynamically change the config status - var umbVersion = app.ApplicationServices.GetRequiredService(); - var config = app.ApplicationServices.GetRequiredService(); - config[Constants.Configuration.ConfigGlobalPrefix + "ConfigurationStatus"] = umbVersion.SemanticVersion.ToString(); - - // re-run the runtime level check - var profilingLogger = app.ApplicationServices.GetRequiredService(); - runtimeState.DetermineRuntimeLevel(dbFactory, profilingLogger); - - Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level); - - break; - case UmbracoTestOptions.Database.NewEmptyPerTest: - - var newEmptyDbId = db.AttachEmpty(); - - // Add teardown callback - integrationTest.OnTestTearDown(() => db.Detach(newEmptyDbId)); - - - break; - case UmbracoTestOptions.Database.NewSchemaPerFixture: - - // New DB + Schema - var newSchemaFixtureDbId = db.AttachSchema(); - - // Add teardown callback - integrationTest.OnFixtureTearDown(() => db.Detach(newSchemaFixtureDbId)); - - break; - case UmbracoTestOptions.Database.NewEmptyPerFixture: - - throw new NotImplementedException(); - - //// Add teardown callback - //integrationTest.OnFixtureTearDown(() => db.Detach()); - - break; - default: - throw new ArgumentOutOfRangeException(nameof(testOptions), testOptions, null); - } - connectionString = db.ConnectionString; - return app; - } - } - - -} diff --git a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs index a6cd372411..0e46941904 100644 --- a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs +++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs @@ -1,24 +1,27 @@ - -using System; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Hosting; -using Moq; +using System; using System.Data.Common; using System.IO; using System.Net; using System.Reflection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using Moq; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; 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.Net; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Web.Common.AspNetCore; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; +using Microsoft.Extensions.FileProviders; namespace Umbraco.Tests.Integration.Implementations { @@ -39,11 +42,17 @@ namespace Umbraco.Tests.Integration.Implementations _httpContextAccessor = Mock.Of(x => x.HttpContext == httpContext); _ipResolver = new AspNetCoreIpResolver(_httpContextAccessor); + var contentRoot = Assembly.GetExecutingAssembly().GetRootDirectorySafe(); var hostEnvironment = new Mock(); - hostEnvironment.Setup(x => x.ApplicationName).Returns("UmbracoIntegrationTests"); - hostEnvironment.Setup(x => x.ContentRootPath) - .Returns(() => Assembly.GetExecutingAssembly().GetRootDirectorySafe()); + // this must be the assembly name for the WebApplicationFactory to work + hostEnvironment.Setup(x => x.ApplicationName).Returns(GetType().Assembly.GetName().Name); + hostEnvironment.Setup(x => x.ContentRootPath).Returns(() => contentRoot); + hostEnvironment.Setup(x => x.ContentRootFileProvider).Returns(() => new PhysicalFileProvider(contentRoot)); hostEnvironment.Setup(x => x.WebRootPath).Returns(() => WorkingDirectory); + hostEnvironment.Setup(x => x.WebRootFileProvider).Returns(() => new PhysicalFileProvider(WorkingDirectory)); + // we also need to expose it as the obsolete interface since netcore's WebApplicationFactory casts it + hostEnvironment.As(); + _hostEnvironment = hostEnvironment.Object; _hostingLifetime = new AspNetCoreApplicationShutdownRegistry(Mock.Of()); @@ -102,16 +111,26 @@ namespace Umbraco.Tests.Integration.Implementations public override IBackOfficeInfo GetBackOfficeInfo() { if (_backOfficeInfo == null) - _backOfficeInfo = - new AspNetCoreBackOfficeInfo(SettingsForTests.GetDefaultGlobalSettings(GetUmbracoVersion())); + { + var globalSettings = new GlobalSettingsBuilder().Build(); + var mockedOptionsMonitorOfGlobalSettings = Mock.Of>(x => x.CurrentValue == globalSettings); + _backOfficeInfo = new AspNetCoreBackOfficeInfo(mockedOptionsMonitorOfGlobalSettings); + } + return _backOfficeInfo; } public override IHostingEnvironment GetHostingEnvironment() => _hostingEnvironment ??= new TestHostingEnvironment( - SettingsForTests.DefaultHostingSettings, + GetIOptionsMonitorOfHostingSettings(), _hostEnvironment); + private IOptionsMonitor GetIOptionsMonitorOfHostingSettings() + { + var hostingSettings = new HostingSettingsBuilder().Build(); + return Mock.Of>(x => x.CurrentValue == hostingSettings); + } + 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 index 076cecef4a..1a3415634b 100644 --- a/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs +++ b/src/Umbraco.Tests.Integration/Implementations/TestHostingEnvironment.cs @@ -1,15 +1,14 @@ using Microsoft.AspNetCore.Hosting; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.Common.AspNetCore; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Tests.Integration.Implementations { - public class TestHostingEnvironment : AspNetCoreHostingEnvironment, IHostingEnvironment { - public TestHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment) + public TestHostingEnvironment(IOptionsMonitor hostingSettings, IWebHostEnvironment webHostEnvironment) : base(hostingSettings, webHostEnvironment) { } diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs index a85873a761..be9a0ce5ed 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; @@ -288,7 +288,8 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(); - var languageNo = new Language(GlobalSettings, "nb-NO") { CultureName = "nb-NO" }; + var globalSettings = new GlobalSettingsBuilder().Build(); + var languageNo = new Language(globalSettings, "nb-NO") { CultureName = "nb-NO" }; localizationService.Save(languageNo); // Act @@ -368,7 +369,8 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var localizationService = GetRequiredService(); var language = localizationService.GetLanguageByIsoCode("en-US"); - var languageDK = new Language(GlobalSettings, "da-DK") { CultureName = "da-DK" }; + var globalSettings = new GlobalSettingsBuilder().Build(); + var languageDK = new Language(globalSettings, "da-DK") { CultureName = "da-DK" }; localizationService.Save(languageDK);//Id 2 var readMore = new DictionaryItem("Read More"); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs index e127a58cee..550f32adb1 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs @@ -3,12 +3,13 @@ using System.Globalization; using System.Linq; using NUnit.Framework; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; @@ -18,15 +19,18 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class LanguageRepositoryTest : UmbracoIntegrationTest { + private GlobalSettings _globalSettings; + [SetUp] public void SetUp() { CreateTestData(); + _globalSettings = new GlobalSettingsBuilder().Build(); } private LanguageRepository CreateRepository(IScopeProvider provider) { - return new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, GlobalSettings); + return new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Microsoft.Extensions.Options.Options.Create(_globalSettings)); } [Test] @@ -60,7 +64,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var repository = CreateRepository(provider); var au = CultureInfo.GetCultureInfo("en-AU"); - var language = (ILanguage)new Language(GlobalSettings, au.Name) + var language = (ILanguage)new Language(_globalSettings, au.Name) { CultureName = au.DisplayName, FallbackLanguageId = 1 @@ -184,7 +188,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var repository = CreateRepository(provider); // Act - var languageBR = new Language(GlobalSettings, "pt-BR") { CultureName = "pt-BR" }; + var languageBR = new Language(_globalSettings, "pt-BR") { CultureName = "pt-BR" }; repository.Save(languageBR); // Assert @@ -206,7 +210,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var repository = CreateRepository(provider); // Act - var languageBR = new Language(GlobalSettings, "pt-BR") { CultureName = "pt-BR", IsDefault = true, IsMandatory = true }; + var languageBR = new Language(_globalSettings, "pt-BR") { CultureName = "pt-BR", IsDefault = true, IsMandatory = true }; repository.Save(languageBR); // Assert @@ -228,7 +232,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var repository = CreateRepository(provider); // Act - var languageBR = new Language(GlobalSettings, "pt-BR") + var languageBR = new Language(_globalSettings, "pt-BR") { CultureName = "pt-BR", FallbackLanguageId = 1 @@ -251,16 +255,16 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(provider); - var languageBR = (ILanguage)new Language(GlobalSettings, "pt-BR") { CultureName = "pt-BR", IsDefault = true, IsMandatory = true }; + var languageBR = (ILanguage)new Language(_globalSettings, "pt-BR") { CultureName = "pt-BR", IsDefault = true, IsMandatory = true }; repository.Save(languageBR); - var languageEN = new Language(GlobalSettings, "en-AU") { CultureName = "en-AU" }; + var languageEN = new Language(_globalSettings, "en-AU") { CultureName = "en-AU" }; repository.Save(languageEN); Assert.IsTrue(languageBR.IsDefault); Assert.IsTrue(languageBR.IsMandatory); // Act - var languageNZ = new Language(GlobalSettings, "en-NZ") { CultureName = "en-NZ", IsDefault = true, IsMandatory = true }; + var languageNZ = new Language(_globalSettings, "en-NZ") { CultureName = "en-NZ", IsDefault = true, IsMandatory = true }; repository.Save(languageNZ); languageBR = repository.Get(languageBR.Id); @@ -383,16 +387,16 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories //Id 1 is en-US - when Umbraco is installed var localizationService = GetRequiredService(); - var languageDK = new Language(GlobalSettings, "da-DK") { CultureName = "da-DK" }; + var languageDK = new Language(_globalSettings, "da-DK") { CultureName = "da-DK" }; localizationService.Save(languageDK);//Id 2 - var languageSE = new Language(GlobalSettings, "sv-SE") { CultureName = "sv-SE" }; + var languageSE = new Language(_globalSettings, "sv-SE") { CultureName = "sv-SE" }; localizationService.Save(languageSE);//Id 3 - var languageDE = new Language(GlobalSettings, "de-DE") { CultureName = "de-DE" }; + var languageDE = new Language(_globalSettings, "de-DE") { CultureName = "de-DE" }; localizationService.Save(languageDE);//Id 4 - var languagePT = new Language(GlobalSettings, "pt-PT") { CultureName = "pt-PT" }; + var languagePT = new Language(_globalSettings, "pt-PT") { CultureName = "pt-PT" }; localizationService.Save(languagePT);//Id 5 } } diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs index ebab6e5d17..4cb0217fe4 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; @@ -98,7 +99,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories Assert.That(repository.Get("test"), Is.Not.Null); Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); Assert.AreEqual( - @"@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = null;}".StripWhitespace(), + @"@usingUmbraco.Web.PublishedModels;@inheritsUmbraco.Web.Common.AspNetCore.UmbracoViewPage@{Layout=null;}".StripWhitespace(), template.Content.StripWhitespace()); } } @@ -126,7 +127,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories Assert.That(repository.Get("test2"), Is.Not.Null); Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test2.cshtml"), Is.True); Assert.AreEqual( - "@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = \"test.cshtml\";}".StripWhitespace(), + "@usingUmbraco.Web.PublishedModels;@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = \"test.cshtml\";}".StripWhitespace(), template2.Content.StripWhitespace()); } } @@ -259,10 +260,10 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories using (provider.CreateScope()) { var templateRepository = CreateRepository(provider); - + var globalSettings = new GlobalSettingsBuilder().Build(); var tagRepository = new TagRepository(scopeAccessor, AppCaches.Disabled, Logger); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, GlobalSettings); + var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(scopeAccessor); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs index dddcff4331..5084e5ae15 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs @@ -1,10 +1,11 @@ using System; using System.Linq; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; @@ -25,7 +26,7 @@ namespace Umbraco.Tests.Persistence.Repositories private UserRepository CreateRepository(IScopeProvider provider) { var accessor = (IScopeAccessor) provider; - var repository = new UserRepository(accessor, AppCaches.Disabled, Logger, Mappers, GlobalSettings, Mock.Of(), new JsonNetSerializer()); + var repository = new UserRepository(accessor, AppCaches.Disabled, Logger, Mappers, Options.Create(GlobalSettings), Options.Create(new UserPasswordConfigurationSettings()), new JsonNetSerializer()); return repository; } @@ -117,7 +118,7 @@ namespace Umbraco.Tests.Persistence.Repositories var id = user.Id; - var repository2 = new UserRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(),GlobalSettings, Mock.Of(), new JsonNetSerializer()); + var repository2 = new UserRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Mock.Of(), Options.Create(GlobalSettings), Options.Create(new UserPasswordConfigurationSettings()), new JsonNetSerializer()); repository2.Delete(user); diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index bd7684fcae..a5b421fcd3 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -17,6 +17,8 @@ using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.Integration.Testing; using Umbraco.Web.Common.AspNetCore; using Umbraco.Extensions; +using Umbraco.Tests.Common.Builders; +using Microsoft.Extensions.Options; namespace Umbraco.Tests.Integration { @@ -54,13 +56,16 @@ namespace Umbraco.Tests.Integration var testHelper = new TestHelper(); + var globalSettings = new GlobalSettingsBuilder().Build(); + var connectionStrings = new ConnectionStringsBuilder().Build(); + // Create the core runtime - var coreRuntime = new CoreRuntime(testHelper.GetConfigs(), testHelper.GetUmbracoVersion(), + var coreRuntime = new CoreRuntime(globalSettings, connectionStrings, testHelper.GetUmbracoVersion(), testHelper.IOHelper, testHelper.Logger, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker, testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator, - testHelper.MainDom, testHelper.GetTypeFinder(), NoAppCache.Instance); + testHelper.MainDom, testHelper.GetTypeFinder(), AppCaches.NoCache); - // boot it! + // boot it! var factory = coreRuntime.Configure(umbracoContainer); Assert.IsTrue(coreRuntime.MainDom.IsMainDom); @@ -70,6 +75,23 @@ namespace Umbraco.Tests.Integration Assert.IsFalse(MyComponent.IsInit); Assert.IsFalse(MyComponent.IsTerminated); + // TODO: found these registration were necessary here (as we haven't called the HostBuilder?), as dependencies for ComponentCollection + // are not resolved. Need to check this if these explicit registrations are the best way to handle this. + var contentSettings = new ContentSettingsBuilder().Build(); + var coreDebugSettings = new CoreDebugSettingsBuilder().Build(); + var nuCacheSettings = new NuCacheSettingsBuilder().Build(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettingsBuilder().Build(); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + + umbracoContainer.Register(x => Options.Create(globalSettings)); + umbracoContainer.Register(x => Options.Create(contentSettings)); + umbracoContainer.Register(x => Options.Create(coreDebugSettings)); + umbracoContainer.Register(x => Options.Create(nuCacheSettings)); + umbracoContainer.Register(x => Options.Create(requestHandlerSettings)); + umbracoContainer.Register(x => Options.Create(userPasswordConfigurationSettings)); + umbracoContainer.Register(x => Options.Create(webRoutingSettings)); + coreRuntime.Start(); Assert.IsTrue(MyComponent.IsInit); @@ -88,7 +110,7 @@ namespace Umbraco.Tests.Integration [Test] public async Task AddUmbracoCore() { - var umbracoContainer = UmbracoIntegrationTest.GetUmbracoContainer(out var serviceProviderFactory); + var umbracoContainer = UmbracoIntegrationTest.CreateUmbracoContainer(out var serviceProviderFactory); var testHelper = new TestHelper(); var hostBuilder = new HostBuilder() @@ -101,7 +123,7 @@ namespace Umbraco.Tests.Integration // Add it! services.AddUmbracoConfiguration(hostContext.Configuration); - services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, testHelper.GetLoggingConfiguration(), out _); + services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), out _); }); var host = await hostBuilder.StartAsync(); @@ -128,7 +150,7 @@ namespace Umbraco.Tests.Integration [Test] public async Task UseUmbracoCore() { - var umbracoContainer = UmbracoIntegrationTest.GetUmbracoContainer(out var serviceProviderFactory); + var umbracoContainer = UmbracoIntegrationTest.CreateUmbracoContainer(out var serviceProviderFactory); var testHelper = new TestHelper(); var hostBuilder = new HostBuilder() @@ -141,7 +163,7 @@ namespace Umbraco.Tests.Integration // Add it! services.AddUmbracoConfiguration(hostContext.Configuration); - services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, testHelper.GetLoggingConfiguration(), out _); + services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, AppCaches.NoCache, testHelper.GetLoggingConfiguration(), out _); }); var host = await hostBuilder.StartAsync(); diff --git a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs index a9a272ac59..9a1b335c62 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs @@ -18,7 +18,6 @@ using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Tests.Integration.TestServerTest.Controllers { [TestFixture] - [Explicit("Need to figure out whats wrong with these tests when executed all in one run.")] public class ContentControllerTests : UmbracoTestServerTestBase { diff --git a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/UsersControllerTests.cs b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/UsersControllerTests.cs index e2d66373ec..c001eb2d92 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/UsersControllerTests.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/UsersControllerTests.cs @@ -149,7 +149,7 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers } [Test] - public async Task PostUnlockUsers_When_User_Does_Not_Exist_Expect_InvalidOperationException() + public async Task PostUnlockUsers_When_User_Does_Not_Exist_Expect_Zero_Users_Message() { var userId = 42; // Must not exist var url = PrepareUrl(x => x.PostUnlockUsers(new []{userId})); @@ -158,18 +158,15 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers var response = await Client.PostAsync(url, new StringContent(string.Empty)); var body = await response.Content.ReadAsStringAsync(); body = body.TrimStart(AngularJsonMediaTypeFormatter.XsrfPrefix); - Assert.AreEqual(HttpStatusCode.InternalServerError, response.StatusCode); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var actual = JsonConvert.DeserializeObject(body, new JsonSerializerSettings + var actual = JsonConvert.DeserializeObject(body, new JsonSerializerSettings { ContractResolver = new IgnoreRequiredAttributesResolver() }); Assert.Multiple(() => { - var expected = new InvalidOperationException(); - Assert.IsNotNull(actual); - Assert.AreEqual(expected.GetType(), actual.ExceptionType); - Assert.AreEqual(expected.Message, actual.ExceptionMessage); + Assert.AreEqual($"Unlocked 0 users", actual.Message); }); } @@ -230,8 +227,6 @@ namespace Umbraco.Tests.Integration.TestServerTest.Controllers userService.Save(user); } - - var url = PrepareUrl(x => x.PostUnlockUsers(users.Select(x=>x.Id).ToArray())); // Act diff --git a/src/Umbraco.Tests.Integration/TestServerTest/TestAuthHandler.cs b/src/Umbraco.Tests.Integration/TestServerTest/TestAuthHandler.cs new file mode 100644 index 0000000000..08cd49bd81 --- /dev/null +++ b/src/Umbraco.Tests.Integration/TestServerTest/TestAuthHandler.cs @@ -0,0 +1,40 @@ +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.BackOffice; +using Umbraco.Core.Mapping; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Services; +using Umbraco.Web.Common.Security; + +namespace Umbraco.Tests.Integration.TestServerTest +{ + public class TestAuthHandler : AuthenticationHandler + { + private readonly BackOfficeSignInManager _backOfficeSignInManager; + + private readonly BackOfficeIdentityUser _fakeUser; + public TestAuthHandler(IOptionsMonitor options, + ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, BackOfficeSignInManager backOfficeSignInManager, IUserService userService, UmbracoMapper umbracoMapper) + : base(options, logger, encoder, clock) + { + _backOfficeSignInManager = backOfficeSignInManager; + + var user = userService.GetUserById(Constants.Security.SuperUserId); + _fakeUser = umbracoMapper.Map(user); + _fakeUser.SecurityStamp = "Needed"; + } + + protected override async Task HandleAuthenticateAsync() + { + + var principal = await _backOfficeSignInManager.CreateUserPrincipalAsync(_fakeUser); + var ticket = new AuthenticationTicket(principal, "Test"); + + return AuthenticateResult.Success(ticket); + } + } +} diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs new file mode 100644 index 0000000000..953be73c27 --- /dev/null +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs @@ -0,0 +1,57 @@ +using System; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing.LightInject; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Runtime; +using Umbraco.Extensions; +using Umbraco.Tests.Integration.Implementations; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Web.Common.Builder; + +namespace Umbraco.Tests.Integration.TestServerTest +{ + public static class UmbracoBuilderExtensions + { + /// + /// Uses a test version of Umbraco Core with a test IRuntime + /// + /// + /// + public static IUmbracoBuilder WithTestCore(this IUmbracoBuilder builder, TestHelper testHelper, + LightInjectContainer container, + Action dbInstallEventHandler) + { + return builder.AddWith(nameof(global::Umbraco.Web.Common.Builder.UmbracoBuilderExtensions.WithCore), + () => + { + builder.Services.AddUmbracoCore( + builder.WebHostEnvironment, + container, + typeof(UmbracoBuilderExtensions).Assembly, + AppCaches.NoCache, // Disable caches in integration tests + testHelper.GetLoggingConfiguration(), + (globalSettings, connectionStrings, umbVersion, ioHelper, logger, profiler, hostingEnv, + backOfficeInfo, typeFinder, appCaches, dbProviderFactoryCreator) => + { + var runtime = UmbracoIntegrationTest.CreateTestRuntime( + globalSettings, + connectionStrings, + umbVersion, + ioHelper, + logger, + profiler, + hostingEnv, + backOfficeInfo, + typeFinder, + appCaches, + dbProviderFactoryCreator, + testHelper.MainDom, // SimpleMainDom + dbInstallEventHandler); // DB Installation event handler + + return runtime; + }, + out _); + }); + } + } +} diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs index b666cc40f2..465305cd24 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -2,20 +2,26 @@ using System; using System.Linq.Expressions; using System.Net.Http; -using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; using Umbraco.Composing; +using Umbraco.Core; using Umbraco.Extensions; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web; +using Umbraco.Web.Common.Builder; using Umbraco.Web.Common.Controllers; using Umbraco.Web.Editors; - +using Microsoft.Extensions.Hosting; namespace Umbraco.Tests.Integration.TestServerTest { @@ -24,19 +30,55 @@ namespace Umbraco.Tests.Integration.TestServerTest public abstract class UmbracoTestServerTestBase : UmbracoIntegrationTest { [SetUp] - public void SetUp() + public override Task Setup() { - Factory = new UmbracoWebApplicationFactory(TestDBConnectionString); - Client = Factory.CreateClient(new WebApplicationFactoryClientOptions(){ + InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = null; + InMemoryConfiguration["Umbraco:CMS:Hosting:Debug"] = "true"; + + // create new WebApplicationFactory specifying 'this' as the IStartup instance + var factory = new UmbracoWebApplicationFactory(CreateHostBuilder); + + // additional host configuration for web server integration tests + Factory = factory.WithWebHostBuilder(builder => + { + // Executes after the standard ConfigureServices method + builder.ConfigureTestServices(services => + { + services.AddAuthentication("Test").AddScheme("Test", options => { }); + }); + }); + + Client = Factory.CreateClient(new WebApplicationFactoryClientOptions + { AllowAutoRedirect = false }); + LinkGenerator = Factory.Services.GetRequiredService(); + + return Task.CompletedTask; } - /// - /// Get the service from the underlying container that is also used by the . - /// - protected T GetRequiredService() => Factory.Services.GetRequiredService(); + public override IHostBuilder CreateHostBuilder() + { + var builder = base.CreateHostBuilder(); + builder.ConfigureWebHost(builder => + { + // need to configure the IWebHostEnvironment too + builder.ConfigureServices((c, s) => + { + c.HostingEnvironment = TestHelper.GetWebHostEnvironment(); + }); + + // call startup + builder.Configure(app => + { + Services = app.ApplicationServices; + Configure(app); + }); + }).UseEnvironment(Environments.Development); + + return builder; + } /// /// Prepare a url before using . @@ -48,6 +90,7 @@ namespace Umbraco.Tests.Integration.TestServerTest { var url = LinkGenerator.GetUmbracoApiService(methodSelector); + var backofficeSecurityFactory = GetRequiredService(); var umbracoContextFactory = GetRequiredService(); var httpContextAccessor = GetRequiredService(); @@ -62,18 +105,20 @@ namespace Umbraco.Tests.Integration.TestServerTest } }; + backofficeSecurityFactory.EnsureBackofficeSecurity(); umbracoContextFactory.EnsureUmbracoContext(); return url; } - protected HttpClient Client { get; set; } - protected LinkGenerator LinkGenerator { get; set; } - protected UmbracoWebApplicationFactory Factory { get; set; } + protected HttpClient Client { get; private set; } + protected LinkGenerator LinkGenerator { get; private set; } + protected WebApplicationFactory Factory { get; private set; } [TearDown] - public void TearDown() + public override void TearDown() { + base.TearDown(); Factory.Dispose(); @@ -81,7 +126,36 @@ namespace Umbraco.Tests.Integration.TestServerTest { Current.IsInitialized = false; } - } + + #region IStartup + + public override void ConfigureServices(IServiceCollection services) + { + var umbracoBuilder = services.AddUmbraco(TestHelper.GetWebHostEnvironment(), Configuration); + umbracoBuilder + .WithConfiguration() + .WithTestCore(TestHelper, UmbracoContainer, UseTestLocalDb) // This is the important one! + .WithWebComponents() + .WithRuntimeMinifier() + .WithBackOffice() + .WithBackOfficeIdentity() + //.WithMiniProfiler() // we don't want this running in tests + .WithMvcAndRazor(mvcBuilding: mvcBuilder => + { + mvcBuilder.AddApplicationPart(typeof(ContentController).Assembly); + }) + .WithWebServer() + .Build(); + } + + public override void Configure(IApplicationBuilder app) + { + app.UseUmbraco(); + } + + #endregion + + } } diff --git a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoWebApplicationFactory.cs b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoWebApplicationFactory.cs index ea2b64c790..251f155d2c 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoWebApplicationFactory.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoWebApplicationFactory.cs @@ -1,97 +1,23 @@ -using System.Collections.Generic; -using System.Net.Http; -using System.Security.Claims; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Hosting; +using System; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Core; -using Umbraco.Core.BackOffice; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Mapping; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Services; -using Umbraco.Web.Common.Security; -using Umbraco.Web.UI.NetCore; namespace Umbraco.Tests.Integration.TestServerTest { - public class UmbracoWebApplicationFactory : CustomWebApplicationFactory + + public class UmbracoWebApplicationFactory : WebApplicationFactory where TStartup : class { - public UmbracoWebApplicationFactory(string testDbConnectionString) :base(testDbConnectionString) - { - } - } + private readonly Func _createHostBuilder; - public abstract class CustomWebApplicationFactory : WebApplicationFactory where TStartup : class - { - private readonly string _testDbConnectionString; - - protected CustomWebApplicationFactory(string testDbConnectionString) + /// + /// Constructor to create a new WebApplicationFactory + /// + /// Method to create the IHostBuilder + public UmbracoWebApplicationFactory(Func createHostBuilder) { - _testDbConnectionString = testDbConnectionString; + _createHostBuilder = createHostBuilder; } - protected override void ConfigureWebHost(IWebHostBuilder builder) - { - base.ConfigureWebHost(builder); - - builder.ConfigureTestServices(services => - { - services.AddAuthentication("Test").AddScheme("Test", options => {}); - }); - - builder.ConfigureAppConfiguration(x => - { - x.AddInMemoryCollection(new Dictionary() - { - ["ConnectionStrings:"+ Constants.System.UmbracoConnectionName] = _testDbConnectionString, - ["Umbraco:CMS:Hosting:Debug"] = "true", - }); - }); - - } - - protected override IHostBuilder CreateHostBuilder() - { - - var builder = base.CreateHostBuilder(); - builder.UseUmbraco(); - return builder; - } - } - - public class TestAuthHandler : AuthenticationHandler - { - private readonly BackOfficeSignInManager _backOfficeSignInManager; - - private readonly BackOfficeIdentityUser _fakeUser; - public TestAuthHandler(IOptionsMonitor options, - ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, BackOfficeSignInManager backOfficeSignInManager, IUserService userService, UmbracoMapper umbracoMapper) - : base(options, logger, encoder, clock) - { - _backOfficeSignInManager = backOfficeSignInManager; - - var user = userService.GetUserById(Constants.Security.SuperUserId); - _fakeUser = umbracoMapper.Map(user); - _fakeUser.SecurityStamp = "Needed"; - } - - protected override async Task HandleAuthenticateAsync() - { - - var principal = await _backOfficeSignInManager.CreateUserPrincipalAsync(_fakeUser); - var ticket = new AuthenticationTicket(principal, "Test"); - - return AuthenticateResult.Success(ticket); - } + protected override IHostBuilder CreateHostBuilder() => _createHostBuilder(); } } diff --git a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComponent.cs b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComponent.cs new file mode 100644 index 0000000000..69819c9bef --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComponent.cs @@ -0,0 +1,43 @@ +using Examine; +using Examine.LuceneEngine.Providers; +using Umbraco.Core.Composing; +using Umbraco.Examine; + +namespace Umbraco.Tests.Integration.Testing +{ + /// + /// A component to customize some services to work nicely with integration tests + /// + public class IntegrationTestComponent : IComponent + { + private readonly IExamineManager _examineManager; + + public IntegrationTestComponent(IExamineManager examineManager) + { + _examineManager = examineManager; + } + + public void Initialize() + { + ConfigureExamineIndexes(); + } + + public void Terminate() + { + } + + /// + /// Configure all indexes to run sync (non-backbround threads) and to use RAMDirectory + /// + private void ConfigureExamineIndexes() + { + foreach (var index in _examineManager.Indexes) + { + if (index is LuceneIndex luceneIndex) + { + luceneIndex.ProcessNonAsync(); + } + } + } + } +} diff --git a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs index 844877b1fd..ebbfb0be25 100644 --- a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs +++ b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs @@ -1,7 +1,25 @@ using Moq; +using NUnit.Framework; +using System; +using System.IO; +using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Core.WebAssets; +using Umbraco.Examine; +using Umbraco.Web.Compose; +using Umbraco.Web.PublishedCache.NuCache; +using Umbraco.Web.Scheduling; +using Umbraco.Web.Search; namespace Umbraco.Tests.Integration.Testing { @@ -13,11 +31,74 @@ namespace Umbraco.Tests.Integration.Testing /// This is a IUserComposer so that it runs after all core composers /// [RuntimeLevel(MinLevel = RuntimeLevel.Boot)] - public class IntegrationTestComposer : IUserComposer + public class IntegrationTestComposer : ComponentComposer { - public void Compose(Composition composition) + public override void Compose(Composition composition) { + base.Compose(composition); + + composition.Components().Remove(); + composition.Components().Remove(); + composition.RegisterUnique(); composition.RegisterUnique(factory => Mock.Of()); + + // we don't want persisted nucache files in tests + composition.Register(factory => new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }); + + // ensure all lucene indexes are using RAM directory (no file system) + composition.RegisterUnique(); + + // replace this service so that it can lookup the correct file locations + composition.RegisterUnique(GetLocalizedTextService); } + + /// + /// Used to register a replacement for where the file sources are the ones within the netcore project so + /// we don't need to copy files + /// + /// + private ILocalizedTextService GetLocalizedTextService(IFactory factory) + { + var globalSettings = factory.GetInstance>(); + var logger = factory.GetInstance(); + var appCaches = factory.GetInstance(); + + var localizedTextService = new LocalizedTextService( + new Lazy(() => + { + // get the src folder + var currFolder = new DirectoryInfo(TestContext.CurrentContext.TestDirectory); + while(!currFolder.Name.Equals("src", StringComparison.InvariantCultureIgnoreCase)) + { + currFolder = currFolder.Parent; + } + var netcoreUI = currFolder.GetDirectories("Umbraco.Web.UI.NetCore", SearchOption.TopDirectoryOnly).First(); + var mainLangFolder = new DirectoryInfo(Path.Combine(netcoreUI.FullName, globalSettings.Value.UmbracoPath.TrimStart("~/"), "config", "lang")); + + return new LocalizedTextServiceFileSources( + logger, + appCaches, + mainLangFolder); + + }), + logger); + + return localizedTextService; + } + + // replace the default so there is no background index rebuilder + private class TestBackgroundIndexRebuilder : BackgroundIndexRebuilder + { + public TestBackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger logger, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) + : base(mainDom, logger, hostingEnvironment, indexRebuilder) + { + } + + public override void RebuildIndexes(bool onlyEmptyIndexes, int waitMilliseconds = 0) + { + // noop + } + } + } } diff --git a/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs b/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs index 9988362d3b..01abe90b32 100644 --- a/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs +++ b/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Persistence; @@ -25,7 +26,6 @@ namespace Umbraco.Tests.Integration.Testing public const string DatabaseName = "UmbracoTests"; private readonly ILogger _logger; - private readonly IGlobalSettings _globalSettings; private readonly LocalDb _localDb; private readonly IUmbracoVersion _umbracoVersion; private static LocalDb.Instance _instance; @@ -38,11 +38,10 @@ namespace Umbraco.Tests.Integration.Testing private DatabasePool _currentPool; //It's internal because `Umbraco.Core.Persistence.LocalDb` is internal - internal LocalDbTestDatabase(ILogger logger, IGlobalSettings globalSettings, LocalDb localDb, string filesPath, IUmbracoDatabaseFactory dbFactory) + internal LocalDbTestDatabase(ILogger logger, LocalDb localDb, string filesPath, IUmbracoDatabaseFactory dbFactory) { _umbracoVersion = new UmbracoVersion(); _logger = logger; - _globalSettings = globalSettings; _localDb = localDb; _filesPath = filesPath; _dbFactory = dbFactory; @@ -130,7 +129,7 @@ namespace Umbraco.Tests.Integration.Testing using var trans = database.GetTransaction(); - var creator = new DatabaseSchemaCreator(database, _logger, _umbracoVersion, _globalSettings); + var creator = new DatabaseSchemaCreator(database, _logger, _umbracoVersion); creator.InitializeDatabaseSchema(); trans.Complete(); // commit it diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 89cbfa992d..705690b898 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Core.Composing; @@ -22,9 +21,21 @@ using Umbraco.Extensions; using Umbraco.Tests.Testing; using Umbraco.Web; using ILogger = Umbraco.Core.Logging.ILogger; +using Umbraco.Core.Runtime; +using Umbraco.Core; +using Moq; +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; +using System.Data.SqlClient; +using System.Data.Common; +using System.IO; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; +using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; namespace Umbraco.Tests.Integration.Testing { + /// /// Abstract class for integration tests /// @@ -35,7 +46,7 @@ namespace Umbraco.Tests.Integration.Testing [NonParallelizable] public abstract class UmbracoIntegrationTest { - public static LightInjectContainer GetUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory) + public static LightInjectContainer CreateUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory) { var container = UmbracoServiceProviderFactory.CreateServiceContainer(); serviceProviderFactory = new UmbracoServiceProviderFactory(container, false); @@ -43,6 +54,230 @@ namespace Umbraco.Tests.Integration.Testing return umbracoContainer; } + private List _testTeardown = null; + private List _fixtureTeardown = new List(); + + public void OnTestTearDown(Action tearDown) + { + if (_testTeardown == null) + _testTeardown = new List(); + _testTeardown.Add(tearDown); + } + + public void OnFixtureTearDown(Action tearDown) => _fixtureTeardown.Add(tearDown); + + [OneTimeTearDown] + public void FixtureTearDown() + { + foreach (var a in _fixtureTeardown) a(); + } + + [TearDown] + public virtual void TearDown() + { + foreach (var a in _testTeardown) a(); + _testTeardown = null; + } + + [SetUp] + public virtual async Task Setup() + { + var hostBuilder = CreateHostBuilder(); + var host = await hostBuilder.StartAsync(); + Services = host.Services; + var app = new ApplicationBuilder(host.Services); + Configure(app); + + OnFixtureTearDown(() => host.Dispose()); + } + + #region Generic Host Builder and Runtime + + /// + /// Create the Generic Host and execute startup ConfigureServices/Configure calls + /// + /// + public virtual IHostBuilder CreateHostBuilder() + { + UmbracoContainer = CreateUmbracoContainer(out var serviceProviderFactory); + _serviceProviderFactory = serviceProviderFactory; + + var hostBuilder = Host.CreateDefaultBuilder() + // IMPORTANT: We Cannot use UseStartup, there's all sorts of threads about this with testing. Although this can work + // if you want to setup your tests this way, it is a bit annoying to do that as the WebApplicationFactory will + // create separate Host instances. So instead of UseStartup, we just call ConfigureServices/Configure ourselves, + // and in the case of the UmbracoTestServerTestBase it will use the ConfigureWebHost to Configure the IApplicationBuilder directly. + //.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(GetType()); }) + .UseUmbraco(_serviceProviderFactory) + .ConfigureAppConfiguration((context, configBuilder) => + { + context.HostingEnvironment = TestHelper.GetWebHostEnvironment(); + Configuration = context.Configuration; + configBuilder.AddInMemoryCollection(InMemoryConfiguration); + }) + .ConfigureServices((hostContext, services) => + { + ConfigureServices(services); + }); + return hostBuilder; + } + + /// + /// Creates a instance for testing and registers an event handler for database install + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public CoreRuntime CreateTestRuntime( + GlobalSettings globalSettings, + ConnectionStrings connectionStrings, + IUmbracoVersion umbracoVersion, IIOHelper ioHelper, + ILogger logger, IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, + ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator) + { + var runtime = CreateTestRuntime( + globalSettings, + connectionStrings, + umbracoVersion, + ioHelper, + logger, + profiler, + hostingEnvironment, + backOfficeInfo, + typeFinder, + appCaches, + dbProviderFactoryCreator, + TestHelper.MainDom, // SimpleMainDom + UseTestLocalDb // DB Installation event handler + ); + + return runtime; + } + + /// + /// Creates a instance for testing and registers an event handler for database install + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The event handler used for DB installation + /// + /// + public static CoreRuntime CreateTestRuntime( + GlobalSettings globalSettings, + ConnectionStrings connectionStrings, + IUmbracoVersion umbracoVersion, IIOHelper ioHelper, + ILogger logger, IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, + ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator, + IMainDom mainDom, Action eventHandler) + { + var runtime = new CoreRuntime( + globalSettings, + connectionStrings, + umbracoVersion, + ioHelper, + logger, + profiler, + Mock.Of(), + hostingEnvironment, + backOfficeInfo, + dbProviderFactoryCreator, + mainDom, + typeFinder, + appCaches); + + runtime.RuntimeEssentials += (sender, args) => eventHandler(sender, args); + + return runtime; + } + + #endregion + + #region IStartup + + public virtual void ConfigureServices(IServiceCollection services) + { + services.AddSingleton(TestHelper.DbProviderFactoryCreator); + var webHostEnvironment = TestHelper.GetWebHostEnvironment(); + services.AddRequiredNetCoreServices(TestHelper, webHostEnvironment); + + // Add it! + services.AddUmbracoConfiguration(Configuration); + services.AddUmbracoCore( + webHostEnvironment, + UmbracoContainer, + GetType().Assembly, + AppCaches.NoCache, // Disable caches for integration tests + TestHelper.GetLoggingConfiguration(), + CreateTestRuntime, + out _); + + services.AddUmbracoWebComponents(); + services.AddUmbracoRuntimeMinifier(Configuration); + services.AddUmbracoBackOffice(); + services.AddUmbracoBackOfficeIdentity(); + + services.AddMvc(); + + services.AddSingleton(new ConsoleLogger(new MessageTemplates())); + + CustomTestSetup(services); + } + + public virtual void Configure(IApplicationBuilder app) + { + Services.GetRequiredService().EnsureBackofficeSecurity(); + Services.GetRequiredService().EnsureUmbracoContext(); + + // get the currently set ptions + var testOptions = TestOptionAttributeBase.GetTestOptions(); + if (testOptions.Boot) + { + app.UseUmbracoCore(); + } + } + + #endregion + + #region LocalDb + + + private static readonly object _dbLocker = new object(); + private static LocalDbTestDatabase _dbInstance; + + /// + /// Event handler for the to install the database and register the to Terminate + /// + /// + /// + protected void UseTestLocalDb(CoreRuntime runtime, RuntimeEssentialsEventArgs args) + { + // MUST be terminated on teardown + OnTestTearDown(() => runtime.Terminate()); + + // This will create a db, install the schema and ensure the app is configured to run + InstallTestLocalDb(args.DatabaseFactory, runtime.ProfilingLogger, runtime.State, TestHelper.WorkingDirectory, out var connectionString); + TestDBConnectionString = connectionString; + InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = TestDBConnectionString; + } + /// /// Get or create an instance of /// @@ -54,7 +289,7 @@ namespace Umbraco.Tests.Integration.Testing /// /// There must only be ONE instance shared between all tests in a session /// - public static LocalDbTestDatabase GetOrCreate(string filesPath, ILogger logger, IGlobalSettings globalSettings, IUmbracoDatabaseFactory dbFactory) + private static LocalDbTestDatabase GetOrCreateDatabase(string filesPath, ILogger logger, IUmbracoDatabaseFactory dbFactory) { lock (_dbLocker) { @@ -63,91 +298,109 @@ namespace Umbraco.Tests.Integration.Testing var localDb = new LocalDb(); if (localDb.IsAvailable == false) throw new InvalidOperationException("LocalDB is not available."); - _dbInstance = new LocalDbTestDatabase(logger, globalSettings, localDb, filesPath, dbFactory); + _dbInstance = new LocalDbTestDatabase(logger, localDb, filesPath, dbFactory); return _dbInstance; } } - private static readonly object _dbLocker = new object(); - private static LocalDbTestDatabase _dbInstance; - - private Action _testTeardown = null; - private Action _fixtureTeardown = null; - - public void OnTestTearDown(Action tearDown) + /// + /// Creates a LocalDb instance to use for the test + /// + /// + /// + /// + /// + /// + private void InstallTestLocalDb( + IUmbracoDatabaseFactory databaseFactory, IProfilingLogger logger, + IRuntimeState runtimeState, string workingDirectory, out string connectionString) { - _testTeardown = tearDown; - } + connectionString = null; + var dbFilePath = Path.Combine(workingDirectory, "LocalDb"); - public void OnFixtureTearDown(Action tearDown) - { - _fixtureTeardown = tearDown; - } - - [OneTimeTearDown] - public void FixtureTearDown() - { - _fixtureTeardown?.Invoke(); - } - - [TearDown] - public void TearDown() - { - _testTeardown?.Invoke(); - } - - [SetUp] - public async Task Setup() - { - var umbracoContainer = GetUmbracoContainer(out var serviceProviderFactory); - var testHelper = new TestHelper(); // get the currently set db options var testOptions = TestOptionAttributeBase.GetTestOptions(); - var hostBuilder = new HostBuilder() - .UseUmbraco(serviceProviderFactory) - .ConfigureServices((hostContext, services) => - { - services.AddSingleton(testHelper.DbProviderFactoryCreator); - var webHostEnvironment = testHelper.GetWebHostEnvironment(); - services.AddRequiredNetCoreServices(testHelper, webHostEnvironment); + if (testOptions.Database == UmbracoTestOptions.Database.None) + return; - // Add it! - services.AddUmbracoConfiguration(hostContext.Configuration); - services.AddUmbracoCore(webHostEnvironment, umbracoContainer, GetType().Assembly, NoAppCache.Instance, testHelper.GetLoggingConfiguration(), out _); - services.AddUmbracoWebComponents(); - services.AddUmbracoRuntimeMinifier(hostContext.Configuration); - services.AddUmbracoBackOffice(); - services.AddUmbracoBackOfficeIdentity(); + // need to manually register this factory + DbProviderFactories.RegisterFactory(Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance); - services.AddMvc(); + if (!Directory.Exists(dbFilePath)) + Directory.CreateDirectory(dbFilePath); + var db = GetOrCreateDatabase(dbFilePath, logger, databaseFactory); - services.AddSingleton(new ConsoleLogger(new MessageTemplates())); - - CustomTestSetup(services); - }); - - var host = await hostBuilder.StartAsync(); - var app = new ApplicationBuilder(host.Services); - Services = app.ApplicationServices; - - Services.GetRequiredService().EnsureUmbracoContext(); - // This will create a db, install the schema and ensure the app is configured to run - app.UseTestLocalDb(testHelper.WorkingDirectory, this, out var connectionString); - TestDBConnectionString = connectionString; - - if (testOptions.Boot) + switch (testOptions.Database) { - app.UseUmbracoCore(); - } + case UmbracoTestOptions.Database.NewSchemaPerTest: + // New DB + Schema + var newSchemaDbId = db.AttachSchema(); + + // Add teardown callback + OnTestTearDown(() => db.Detach(newSchemaDbId)); + + // We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings + if (!databaseFactory.Configured) + { + databaseFactory.Configure(db.ConnectionString, Constants.DatabaseProviders.SqlServer); + } + + // re-run the runtime level check + runtimeState.DetermineRuntimeLevel(); + + Assert.AreEqual(RuntimeLevel.Run, runtimeState.Level); + + break; + case UmbracoTestOptions.Database.NewEmptyPerTest: + + var newEmptyDbId = db.AttachEmpty(); + + // Add teardown callback + OnTestTearDown(() => db.Detach(newEmptyDbId)); + + + break; + case UmbracoTestOptions.Database.NewSchemaPerFixture: + + // New DB + Schema + var newSchemaFixtureDbId = db.AttachSchema(); + + // Add teardown callback + OnFixtureTearDown(() => db.Detach(newSchemaFixtureDbId)); + + break; + case UmbracoTestOptions.Database.NewEmptyPerFixture: + + throw new NotImplementedException(); + + //// Add teardown callback + //integrationTest.OnFixtureTearDown(() => db.Detach()); + + break; + default: + throw new ArgumentOutOfRangeException(nameof(testOptions), testOptions, null); + } + connectionString = db.ConnectionString; } - protected T GetRequiredService() => Services.GetRequiredService(); + #endregion #region Common services + protected LightInjectContainer UmbracoContainer { get; private set; } + private UmbracoServiceProviderFactory _serviceProviderFactory; + + protected virtual T GetRequiredService() => Services.GetRequiredService(); + + public Dictionary InMemoryConfiguration { get; } = new Dictionary(); + + public IConfiguration Configuration { get; protected set; } + + public TestHelper TestHelper = new TestHelper(); + protected string TestDBConnectionString { get; private set; } protected virtual Action CustomTestSetup => services => { }; @@ -155,7 +408,7 @@ namespace Umbraco.Tests.Integration.Testing /// /// Returns the DI container /// - protected IServiceProvider Services { get; private set; } + protected IServiceProvider Services { get; set; } /// /// Returns the @@ -175,7 +428,7 @@ namespace Umbraco.Tests.Integration.Testing protected AppCaches AppCaches => Services.GetRequiredService(); protected IIOHelper IOHelper => Services.GetRequiredService(); protected IShortStringHelper ShortStringHelper => Services.GetRequiredService(); - protected IGlobalSettings GlobalSettings => Services.GetRequiredService(); + protected GlobalSettings GlobalSettings => Services.GetRequiredService>().Value; protected IMapperCollection Mappers => Services.GetRequiredService(); #endregion diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/ContentElementDefaultTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/ContentElementDefaultTests.cs deleted file mode 100644 index 436fb45377..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/ContentElementDefaultTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Linq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class ContentElementDefaultTests : ContentElementTests - { - protected override bool TestingDefaults => true; - - [Test] - public override void DisableHtmlEmail() - { - Assert.IsTrue(ContentSettings.DisableHtmlEmail == false); - } - - [Test] - public override void Can_Set_Multiple() - { - 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(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"); - } - - /// - /// Whitelist is empty in default settings file and is not populated by default, but disallowed is empty and is populated by default - /// - /// - /// - [Test] - [TestCase("png", true)] - [TestCase("jpg", true)] - [TestCase("gif", true)] - [TestCase("bmp", true)] - [TestCase("php", true)] - [TestCase("ashx", false)] - [TestCase("config", false)] - [TestCase("test", true)] - public override void IsFileAllowedForUpload_WithWhitelist(string extension, bool expected) - { - Console.WriteLine("Extension being tested: {0}", extension); - Console.WriteLine("Expected IsAllowed?: {0}", expected); - Console.WriteLine("AllowedUploadFiles: {0}", ContentSettings.AllowedUploadFiles); - Console.WriteLine("DisallowedUploadFiles: {0}", ContentSettings.DisallowedUploadFiles); - - bool allowedContainsExtension = ContentSettings.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)); - bool disallowedContainsExtension = ContentSettings.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)); - - Console.WriteLine("AllowedContainsExtension: {0}", allowedContainsExtension); - Console.WriteLine("DisallowedContainsExtension: {0}", disallowedContainsExtension); - - Assert.AreEqual(expected, ContentSettings.IsFileAllowedForUpload(extension)); - } - - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/ContentElementTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/ContentElementTests.cs deleted file mode 100644 index 21fd59de3a..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/ContentElementTests.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Macros; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class ContentElementTests : UmbracoSettingsTests - { - [Test] - public void EmailAddress() - { - Assert.AreEqual(ContentSettings.NotificationEmailAddress, "robot@umbraco.dk"); - } - [Test] - public virtual void DisableHtmlEmail() - { - Assert.IsTrue(ContentSettings.DisableHtmlEmail); - } - - [Test] - public virtual void Can_Set_Multiple() - { - Assert.AreEqual(3, ContentSettings.Error404Collection.Count()); - Assert.AreEqual("default", ContentSettings.Error404Collection.ElementAt(0).Culture); - Assert.AreEqual(1047, ContentSettings.Error404Collection.ElementAt(0).ContentId); - Assert.IsTrue(ContentSettings.Error404Collection.ElementAt(0).HasContentId); - Assert.IsFalse(ContentSettings.Error404Collection.ElementAt(0).HasContentKey); - Assert.AreEqual("en-US", ContentSettings.Error404Collection.ElementAt(1).Culture); - Assert.AreEqual("$site/error [@name = 'error']", ContentSettings.Error404Collection.ElementAt(1).ContentXPath); - Assert.IsFalse(ContentSettings.Error404Collection.ElementAt(1).HasContentId); - Assert.IsFalse(ContentSettings.Error404Collection.ElementAt(1).HasContentKey); - Assert.AreEqual("en-UK", ContentSettings.Error404Collection.ElementAt(2).Culture); - Assert.AreEqual(new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC"), ContentSettings.Error404Collection.ElementAt(2).ContentKey); - Assert.IsTrue(ContentSettings.Error404Collection.ElementAt(2).HasContentKey); - Assert.IsFalse(ContentSettings.Error404Collection.ElementAt(2).HasContentId); - } - - [Test] - public void ImageFileTypes() - { - Assert.IsTrue(ContentSettings.ImageFileTypes.All(x => "jpeg,jpg,gif,bmp,png,tiff,tif".Split(',').Contains(x))); - } - - [Test] - public virtual void ImageAutoFillProperties() - { - Assert.AreEqual(2, ContentSettings.ImageAutoFillProperties.Count()); - Assert.AreEqual("umbracoFile", ContentSettings.ImageAutoFillProperties.ElementAt(0).Alias); - Assert.AreEqual("umbracoWidth", ContentSettings.ImageAutoFillProperties.ElementAt(0).WidthFieldAlias); - Assert.AreEqual("umbracoHeight", ContentSettings.ImageAutoFillProperties.ElementAt(0).HeightFieldAlias); - Assert.AreEqual("umbracoBytes", ContentSettings.ImageAutoFillProperties.ElementAt(0).LengthFieldAlias); - Assert.AreEqual("umbracoExtension", ContentSettings.ImageAutoFillProperties.ElementAt(0).ExtensionFieldAlias); - Assert.AreEqual("umbracoFile2", ContentSettings.ImageAutoFillProperties.ElementAt(1).Alias); - Assert.AreEqual("umbracoWidth2", ContentSettings.ImageAutoFillProperties.ElementAt(1).WidthFieldAlias); - Assert.AreEqual("umbracoHeight2", ContentSettings.ImageAutoFillProperties.ElementAt(1).HeightFieldAlias); - Assert.AreEqual("umbracoBytes2", ContentSettings.ImageAutoFillProperties.ElementAt(1).LengthFieldAlias); - Assert.AreEqual("umbracoExtension2", ContentSettings.ImageAutoFillProperties.ElementAt(1).ExtensionFieldAlias); - } - - [Test] - public void PreviewBadge() - { - Assert.AreEqual(ContentSettings.PreviewBadge, @"
Preview modeClick to end
"); - } - [Test] - public void ResolveUrlsFromTextString() - { - Assert.IsFalse(ContentSettings.ResolveUrlsFromTextString); - } - [Test] - public void MacroErrors() - { - Assert.AreEqual(ContentSettings.MacroErrorBehaviour, MacroErrorBehaviour.Inline); - } - - [Test] - public void DisallowedUploadFiles() - { - Assert.IsTrue(ContentSettings.DisallowedUploadFiles.All(x => "ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd".Split(',').Contains(x))); - } - - [Test] - public void AllowedUploadFiles() - { - Assert.IsTrue(ContentSettings.AllowedUploadFiles.All(x => "jpg,gif,png".Split(',').Contains(x))); - } - - [Test] - [TestCase("png", true)] - [TestCase("jpg", true)] - [TestCase("gif", true)] - [TestCase("bmp", false)] - [TestCase("php", false)] - [TestCase("ashx", false)] - [TestCase("config", false)] - [TestCase("test", false)] - public virtual void IsFileAllowedForUpload_WithWhitelist(string extension, bool expected) - { - Console.WriteLine("Extension being tested: {0}", extension); - Console.WriteLine("Expected IsAllowed?: {0}", expected); - Console.WriteLine("AllowedUploadFiles: {0}", ContentSettings.AllowedUploadFiles); - Console.WriteLine("DisallowedUploadFiles: {0}", ContentSettings.DisallowedUploadFiles); - - bool allowedContainsExtension = ContentSettings.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)); - bool disallowedContainsExtension = ContentSettings.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)); - - Console.WriteLine("AllowedContainsExtension: {0}", allowedContainsExtension); - Console.WriteLine("DisallowedContainsExtension: {0}", disallowedContainsExtension); - - Assert.AreEqual(expected, ContentSettings.IsFileAllowedForUpload(extension)); - } - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/LoggingElementDefaultTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/LoggingElementDefaultTests.cs deleted file mode 100644 index 084c649f11..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/LoggingElementDefaultTests.cs +++ /dev/null @@ -1,16 +0,0 @@ -using NUnit.Framework; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class LoggingElementDefaultTests : LoggingElementTests - { - protected override bool TestingDefaults => true; - - [Test] - public override void MaxLogAge() - { - Assert.IsTrue(LoggingSettings.MaxLogAge == -1); - } - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/LoggingElementTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/LoggingElementTests.cs deleted file mode 100644 index 3fd8041540..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/LoggingElementTests.cs +++ /dev/null @@ -1,17 +0,0 @@ -using NUnit.Framework; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class LoggingElementTests : UmbracoSettingsTests - { - - [Test] - public virtual void MaxLogAge() - { - Assert.IsTrue(LoggingSettings.MaxLogAge == 1440); - - } - - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/RequestHandlerElementDefaultTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/RequestHandlerElementDefaultTests.cs deleted file mode 100644 index c2e21c5e2c..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/RequestHandlerElementDefaultTests.cs +++ /dev/null @@ -1,10 +0,0 @@ -using NUnit.Framework; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class RequestHandlerElementDefaultTests : RequestHandlerElementTests - { - protected override bool TestingDefaults => true; - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/RequestHandlerElementTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/RequestHandlerElementTests.cs deleted file mode 100644 index 01a2b48e16..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/RequestHandlerElementTests.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Linq; -using NUnit.Framework; -using Umbraco.Core; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class RequestHandlerElementTests : UmbracoSettingsTests - { - [Test] - public void AddTrailingSlash() - { - Assert.IsTrue(RequestHandlerSettings.AddTrailingSlash == true); - } - - [Test] - public void CharCollection() - { - var chars = @" ,"",',%,.,;,/,\,:,#,+,*,&,?,æ,ø,å,ä,ö,ü,ß,Ä,Ö,|,<,>"; - var items = chars.Split(','); - 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, 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.Integration/Umbraco.Configuration/UmbracoSettings/SecurityElementDefaultTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/SecurityElementDefaultTests.cs deleted file mode 100644 index f5566df5ed..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/SecurityElementDefaultTests.cs +++ /dev/null @@ -1,10 +0,0 @@ -using NUnit.Framework; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class SecurityElementDefaultTests : SecurityElementTests - { - protected override bool TestingDefaults => true; - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/SecurityElementTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/SecurityElementTests.cs deleted file mode 100644 index 6a8fc854d7..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/SecurityElementTests.cs +++ /dev/null @@ -1,123 +0,0 @@ -using NUnit.Framework; -using Umbraco.Core; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class SecurityElementTests : UmbracoSettingsTests - { - [Test] - public void KeepUserLoggedIn() - { - Assert.IsTrue(SecuritySettings.KeepUserLoggedIn == true); - } - - [Test] - public void HideDisabledUsersInBackoffice() - { - Assert.IsTrue(SecuritySettings.HideDisabledUsersInBackoffice == false); - } - - [Test] - public void AllowPasswordReset() - { - Assert.IsTrue(SecuritySettings.AllowPasswordReset == true); - } - - [Test] - public void AuthCookieDomain() - { - Assert.IsTrue(SecuritySettings.AuthCookieDomain == null); - } - - [Test] - public void AuthCookieName() - { - Assert.IsTrue(SecuritySettings.AuthCookieName == "UMB_UCONTEXT"); - } - - [Test] - public void UserPasswordConfiguration_RequiredLength() - { - Assert.IsTrue(UserPasswordConfiguration.RequiredLength == 12); - } - - [Test] - public void UserPasswordConfiguration_RequireNonLetterOrDigit() - { - Assert.IsTrue(UserPasswordConfiguration.RequireNonLetterOrDigit == false); - } - - [Test] - public void UserPasswordConfiguration_RequireDigit() - { - Assert.IsTrue(UserPasswordConfiguration.RequireDigit == false); - } - - [Test] - public void UserPasswordConfiguration_RequireLowercase() - { - Assert.IsTrue(UserPasswordConfiguration.RequireLowercase == false); - } - - [Test] - public void UserPasswordConfiguration_RequireUppercase() - { - Assert.IsTrue(UserPasswordConfiguration.RequireUppercase == false); - } - - [Test] - public void UserPasswordConfiguration_HashAlgorithmType() - { - Assert.AreEqual(Constants.Security.AspNetCoreV3PasswordHashAlgorithmName, UserPasswordConfiguration.HashAlgorithmType); - } - - [Test] - public void UserPasswordConfiguration_MaxFailedAccessAttemptsBeforeLockout() - { - Assert.IsTrue(UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout == 5); - } - - [Test] - public void MemberPasswordConfiguration_RequiredLength() - { - Assert.IsTrue(MemberPasswordConfiguration.RequiredLength == 12); - } - - [Test] - public void MemberPasswordConfiguration_RequireNonLetterOrDigit() - { - Assert.IsTrue(MemberPasswordConfiguration.RequireNonLetterOrDigit == false); - } - - [Test] - public void MemberPasswordConfiguration_RequireDigit() - { - Assert.IsTrue(MemberPasswordConfiguration.RequireDigit == false); - } - - [Test] - public void MemberPasswordConfiguration_RequireLowercase() - { - Assert.IsTrue(MemberPasswordConfiguration.RequireLowercase == false); - } - - [Test] - public void MemberPasswordConfiguration_RequireUppercase() - { - Assert.IsTrue(MemberPasswordConfiguration.RequireUppercase == false); - } - - [Test] - public void MemberPasswordConfiguration_HashAlgorithmType() - { - Assert.AreEqual(Constants.Security.AspNetCoreV3PasswordHashAlgorithmName, MemberPasswordConfiguration.HashAlgorithmType); - } - - [Test] - public void MemberPasswordConfiguration_MaxFailedAccessAttemptsBeforeLockout() - { - Assert.IsTrue(MemberPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout == 5); - } - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsTests.cs deleted file mode 100644 index e869a972f5..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/UmbracoSettingsTests.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Configuration; -using System.Diagnostics; -using System.IO; -using NUnit.Framework; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Tests.Integration.Implementations; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - public abstract class UmbracoSettingsTests - { - protected virtual bool TestingDefaults { get; set; } - - [SetUp] - public void Init() - { - var testHelper = new TestHelper(); - var config = new FileInfo(testHelper.MapPathForTestFiles("~/Umbraco.Configuration/Configurations/web.config")); - - var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = config.FullName }; - var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); - - Debug.WriteLine("Testing defaults? {0}", TestingDefaults); - if (TestingDefaults) - { - Settings = configuration.GetSection("umbracoConfiguration/defaultSettings") as UmbracoSettingsSection; - } - else - { - Settings = configuration.GetSection("umbracoConfiguration/settings") as UmbracoSettingsSection; - } - - Assert.IsNotNull(Settings); - } - private UmbracoSettingsSection Settings { get; 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.Integration/Umbraco.Configuration/UmbracoSettings/WebRoutingElementDefaultTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/WebRoutingElementDefaultTests.cs deleted file mode 100644 index e85911d559..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/WebRoutingElementDefaultTests.cs +++ /dev/null @@ -1,40 +0,0 @@ -using NUnit.Framework; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class WebRoutingElementDefaultTests : WebRoutingElementTests - { - protected override bool TestingDefaults => true; - - [Test] - public override void UrlProviderMode() - { - Assert.IsTrue(WebRoutingSettings.UrlProviderMode == "Auto"); - } - - [Test] - public void DisableAlternativeTemplates() - { - Assert.IsTrue(WebRoutingSettings.DisableAlternativeTemplates == false); - } - - [Test] - public void ValidateAlternativeTemplates() - { - Assert.IsTrue(WebRoutingSettings.ValidateAlternativeTemplates == false); - } - - [Test] - public void DisableFindContentByIdPath() - { - Assert.IsTrue(WebRoutingSettings.DisableFindContentByIdPath == false); - } - - [Test] - public void DisableRedirectUrlTracking() - { - Assert.IsTrue(WebRoutingSettings.DisableRedirectUrlTracking == false); - } - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/WebRoutingElementTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/WebRoutingElementTests.cs deleted file mode 100644 index 532b27494f..0000000000 --- a/src/Umbraco.Tests.Integration/Umbraco.Configuration/UmbracoSettings/WebRoutingElementTests.cs +++ /dev/null @@ -1,26 +0,0 @@ -using NUnit.Framework; - -namespace Umbraco.Tests.Integration.Umbraco.Configuration.UmbracoSettings -{ - [TestFixture] - public class WebRoutingElementTests : UmbracoSettingsTests - { - [Test] - public void TrySkipIisCustomErrors() - { - Assert.IsTrue(WebRoutingSettings.TrySkipIisCustomErrors == false); - } - - [Test] - public void InternalRedirectPreservesTemplate() - { - Assert.IsTrue(WebRoutingSettings.InternalRedirectPreservesTemplate == false); - } - - [Test] - public virtual void UrlProviderMode() - { - Assert.IsTrue(WebRoutingSettings.UrlProviderMode == "Auto"); - } - } -} diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index ba986ebd86..1bfbd8afe8 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -11,20 +11,26 @@ + + + - + + - + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice.Security/BackOfficeCookieManagerTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice.Security/BackOfficeCookieManagerTests.cs index 3464259052..6fd5672085 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice.Security/BackOfficeCookieManagerTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice.Security/BackOfficeCookieManagerTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Hosting; using Umbraco.Extensions; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Implementations; using Umbraco.Web; using Umbraco.Web.BackOffice.Controllers; @@ -25,7 +26,7 @@ namespace Umbraco.Tests.Security var testHelper = new TestHelper(); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettingsBuilder().Build(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Install); var mgr = new BackOfficeCookieManager( @@ -50,8 +51,8 @@ namespace Umbraco.Tests.Security //hostingEnvironment.ToAbsolute(globalSettings.UmbracoPath); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); - + var globalSettings = new GlobalSettingsBuilder().Build(); + var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); var mgr = new BackOfficeCookieManager( Mock.Of(), @@ -72,7 +73,7 @@ namespace Umbraco.Tests.Security var testHelper = new TestHelper(); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettingsBuilder().Build(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); @@ -97,7 +98,7 @@ namespace Umbraco.Tests.Security var testHelper = new TestHelper(); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettingsBuilder().Build(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); @@ -119,7 +120,7 @@ namespace Umbraco.Tests.Security var testHelper = new TestHelper(); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettingsBuilder().Build(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs index 236338390b..1a343a1e0b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs @@ -18,6 +18,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Mapping; using Umbraco.Core.Models; + using Umbraco.Core.Security; using Umbraco.Core.Strings; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; @@ -138,12 +139,14 @@ public void Validating_ContentItemSave() { var logger = Services.GetRequiredService(); - var webSecurity = Services.GetRequiredService(); + var backofficeSecurityFactory = Services.GetRequiredService(); + backofficeSecurityFactory.EnsureBackofficeSecurity(); + var backofficeSecurityAccessor = Services.GetRequiredService(); var localizedTextService = Services.GetRequiredService(); var propertyValidationService = Services.GetRequiredService(); var umbracoMapper = Services.GetRequiredService(); - var validator = new ContentSaveModelValidator(logger, webSecurity, localizedTextService, propertyValidationService); + var validator = new ContentSaveModelValidator(logger, backofficeSecurityAccessor.BackofficeSecurity, localizedTextService, propertyValidationService); var content = MockedContent.CreateTextpageContent(_contentType, "test", -1); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs index 51fce283f8..58be305b91 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/UmbracoBackOfficeServiceCollectionExtensionsTests.cs @@ -32,7 +32,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions [Test] public void AddUmbracoBackOfficeIdentity_ExpectBackOfficeUserManagerResolvable() { - var userManager = Services.GetService(); + var userManager = Services.GetService(); Assert.NotNull(userManager); } diff --git a/src/Umbraco.Tests.Integration/Views/template1.cshtml b/src/Umbraco.Tests.Integration/Views/template1.cshtml deleted file mode 100644 index 3fa17ab54c..0000000000 --- a/src/Umbraco.Tests.Integration/Views/template1.cshtml +++ /dev/null @@ -1,4 +0,0 @@ -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Tests.Integration/Views/template2.cshtml b/src/Umbraco.Tests.Integration/Views/template2.cshtml deleted file mode 100644 index 3fa17ab54c..0000000000 --- a/src/Umbraco.Tests.Integration/Views/template2.cshtml +++ /dev/null @@ -1,4 +0,0 @@ -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Tests.Integration/Views/test.cshtml b/src/Umbraco.Tests.Integration/Views/test.cshtml deleted file mode 100644 index 3fa17ab54c..0000000000 --- a/src/Umbraco.Tests.Integration/Views/test.cshtml +++ /dev/null @@ -1,4 +0,0 @@ -@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage -@{ - Layout = null; -} \ No newline at end of file diff --git a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs index 625e1ca619..c2ef2b4f04 100644 --- a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs +++ b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs @@ -1,14 +1,19 @@ using System; +using System.Linq; +using System.Reflection; using AutoFixture; using AutoFixture.AutoMoq; using AutoFixture.Kernel; using AutoFixture.NUnit3; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; using Moq; +using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Tests.Common.Builders; using Umbraco.Web.BackOffice.Controllers; -using Umbraco.Core; using Umbraco.Web.Common.Install; namespace Umbraco.Tests.UnitTests.AutoFixture @@ -35,15 +40,15 @@ namespace Umbraco.Tests.UnitTests.AutoFixture { fixture.Customize( u => u.FromFactory( - (a,b,c) => BackOfficeIdentityUser.CreateNew(Mock.Of(),a,b,c))); + (a,b,c) => BackOfficeIdentityUser.CreateNew(new GlobalSettingsBuilder().Build(),a,b,c))); fixture .Customize(new ConstructorCustomization(typeof(UsersController), new GreedyConstructorQuery())) .Customize(new ConstructorCustomization(typeof(InstallController), new GreedyConstructorQuery())) .Customize(new ConstructorCustomization(typeof(PreviewController), new GreedyConstructorQuery())) .Customize(new ConstructorCustomization(typeof(BackOfficeController), new GreedyConstructorQuery())) - .Customize(new ConstructorCustomization(typeof(BackOfficeUserManager), new GreedyConstructorQuery())) - .Customize(new AutoMoqCustomization()); + .Customize(new ConstructorCustomization(typeof(BackOfficeUserManager), new GreedyConstructorQuery())); + fixture.Customize(new AutoMoqCustomization()); // When requesting an IUserStore ensure we actually uses a IUserLockoutStore fixture.Customize>(cc => cc.FromFactory(() => Mock.Of>())); @@ -55,9 +60,9 @@ namespace Umbraco.Tests.UnitTests.AutoFixture u => u.FromFactory( () => new UmbracoVersion())); - var connectionStrings = Mock.Of(); - Mock.Get(connectionStrings).Setup(x => x[Constants.System.UmbracoConnectionName]).Returns((ConfigConnectionString)new ConfigConnectionString(string.Empty, string.Empty, string.Empty)); - fixture.Customize(x => x.FromFactory(() => connectionStrings )); + var connectionStrings = new ConnectionStrings(); + fixture.Customize(x => x.FromFactory(() => connectionStrings )); + diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs index c5acba362b..544765ee9c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Configuration/Models/ConnectionStringsTests.cs @@ -1,8 +1,7 @@ -using Microsoft.Extensions.Configuration; -using Moq; -using NUnit.Framework; -using Umbraco.Configuration.Models; +using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Tests.UnitTests.Umbraco.Configuration.Models { @@ -15,25 +14,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Configuration.Models [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) + var connectionStrings = new ConnectionStrings { - configuration.Setup(x => x.GetSection("ConnectionStrings")[key]).Returns(connectionString); - } + UmbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, connectionString) + }; - - var connectionStrings = new ConnectionStrings(configuration.Object); - - var actual = connectionStrings[key]; + var actual = connectionStrings.UmbracoConnectionString; Assert.AreEqual(connectionString, actual.ConnectionString); - Assert.AreEqual(key, actual.Name); + Assert.AreEqual(Constants.System.UmbracoConnectionName, actual.Name); - return connectionStrings[key].ProviderName; + return connectionStrings.UmbracoConnectionString.ProviderName; } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs index 87cff07475..7d977fe686 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs @@ -11,6 +11,7 @@ using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; using Umbraco.Core.Models.Membership; using Umbraco.Extensions; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice { @@ -137,10 +138,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice [SetUp] public void Setup() { - var mockGlobalSettings = new Mock(); - mockGlobalSettings.Setup(x => x.DefaultUILanguage).Returns("test"); + var globalSettings = new GlobalSettingsBuilder().WithDefaultUiLanguage("test").Build(); - _testUser = new BackOfficeIdentityUser(mockGlobalSettings.Object, _testUserId, new List()) + _testUser = new BackOfficeIdentityUser(globalSettings, _testUserId, new List()) { UserName = _testUserName, Name = _testUserGivenName, diff --git a/src/Umbraco.Tests/CoreThings/CallContextTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/CallContextTests.cs similarity index 100% rename from src/Umbraco.Tests/CoreThings/CallContextTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/CallContextTests.cs diff --git a/src/Umbraco.Tests/CoreThings/ObjectExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs similarity index 93% rename from src/Umbraco.Tests/CoreThings/ObjectExtensionsTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs index 544c6335e1..3b09de2d0b 100644 --- a/src/Umbraco.Tests/CoreThings/ObjectExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/ObjectExtensionsTests.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; -using System.Web.UI.WebControls; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.PropertyEditors; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.CoreThings { @@ -29,20 +28,6 @@ namespace Umbraco.Tests.CoreThings Thread.CurrentThread.CurrentCulture = _savedCulture; } - [Test] - public void CanParseStringToUnit() - { - const string stringUnit = "1234px"; - object objUnit = "1234px"; - var result = stringUnit.TryConvertTo(); - var result2 = objUnit.TryConvertTo(); - var unit = new Unit("1234px"); - Assert.IsTrue(result.Success); - Assert.IsTrue(result2.Success); - Assert.AreEqual(unit, result.Result); - Assert.AreEqual(unit, result2.Result); - } - [Test] public void Can_Convert_List_To_Enumerable() { @@ -301,7 +286,7 @@ namespace Umbraco.Tests.CoreThings [Test] public void Value_Editor_Can_Convert_Decimal_To_Decimal_Clr_Type() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var result = valueEditor.TryConvertValueToCrlType(12.34d); Assert.IsTrue(result.Success); diff --git a/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs similarity index 90% rename from src/Umbraco.Tests/CoreThings/TryConvertToTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs index fbb89b1c5d..c5c027ac65 100644 --- a/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs @@ -1,6 +1,8 @@ using System; +using Microsoft.Extensions.Options; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Strings; using Umbraco.Tests.Testing; @@ -8,15 +10,8 @@ using Umbraco.Tests.Testing; namespace Umbraco.Tests.CoreThings { [TestFixture] - public class TryConvertToTests : UmbracoTestBase + public class TryConvertToTests { - protected void Compose() - { - base.Compose(); - - Composition.RegisterUnique(f => new DefaultShortStringHelper(f.GetInstance())); - } - [Test] public void ConvertToIntegerTest() { diff --git a/src/Umbraco.Tests/CoreThings/UdiTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs similarity index 100% rename from src/Umbraco.Tests/CoreThings/UdiTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs diff --git a/src/Umbraco.Tests/CoreXml/FrameworkXmlTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/FrameworkXmlTests.cs similarity index 100% rename from src/Umbraco.Tests/CoreXml/FrameworkXmlTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/FrameworkXmlTests.cs diff --git a/src/Umbraco.Tests/CoreXml/NavigableNavigatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs similarity index 99% rename from src/Umbraco.Tests/CoreXml/NavigableNavigatorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs index 91ac3aacc2..c0d5d9af6d 100644 --- a/src/Umbraco.Tests/CoreXml/NavigableNavigatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs @@ -15,7 +15,7 @@ using Umbraco.Tests.Testing; namespace Umbraco.Tests.CoreXml { [TestFixture] - public class NavigableNavigatorTests : UmbracoTestBase + public class NavigableNavigatorTests { [Test] public void NewNavigatorIsAtRoot() diff --git a/src/Umbraco.Tests/CoreXml/RenamedRootNavigatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs similarity index 100% rename from src/Umbraco.Tests/CoreXml/RenamedRootNavigatorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/UriExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/UriExtensionsTests.cs index 4c8903735a..77a7ba1732 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/UriExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Extensions/UriExtensionsTests.cs @@ -1,11 +1,12 @@ using System; -using System.Reflection; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Web.Common.AspNetCore; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Extensions @@ -16,14 +17,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Extensions [OneTimeSetUp] public void Setup() { - _settingsForTests = new SettingsForTests(); _hostEnvironment = Mock.Of(); - _globalSettings = _settingsForTests.GenerateMockGlobalSettings(); + _globalSettings = new GlobalSettingsBuilder().Build(); } - private SettingsForTests _settingsForTests; private IWebHostEnvironment _hostEnvironment; - private IGlobalSettings _globalSettings; + private GlobalSettings _globalSettings; [TestCase("http://www.domain.com/umbraco/preview/frame?id=1234", "", true)] [TestCase("http://www.domain.com/umbraco", "", true)] @@ -47,12 +46,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Extensions [TestCase("http://www.domain.com/umbraco/test/legacyAjaxCalls.ashx?some=query&blah=js", "", true)] public void Is_Back_Office_Request(string input, string virtualPath, bool expected) { - - var mockHostingSettings = Mock.Get(_settingsForTests.GenerateMockHostingSettings()); - mockHostingSettings.Setup(x => x.ApplicationVirtualPath).Returns(virtualPath); - var hostingEnvironment = new AspNetCoreHostingEnvironment(mockHostingSettings.Object, _hostEnvironment); - var source = new Uri(input); + var hostingEnvironment = CreateHostingEnvironment(virtualPath); Assert.AreEqual(expected, source.IsBackOfficeRequest(_globalSettings, hostingEnvironment)); } @@ -68,11 +63,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Extensions public void Is_Installer_Request(string input, bool expected) { var source = new Uri(input); - var mockHostingSettings = Mock.Get(_settingsForTests.GenerateMockHostingSettings()); - var hostingEnvironment = new AspNetCoreHostingEnvironment(mockHostingSettings.Object, _hostEnvironment); + var hostingEnvironment = CreateHostingEnvironment(); Assert.AreEqual(expected, source.IsInstallerRequest(hostingEnvironment)); } + private AspNetCoreHostingEnvironment CreateHostingEnvironment(string virtualPath = "") + { + var hostingSettings = new HostingSettingsBuilder().WithApplicationVirtualPath(virtualPath).Build(); + var mockedOptionsMonitorOfHostingSettings = Mock.Of>(x => x.CurrentValue == hostingSettings); + return new AspNetCoreHostingEnvironment(mockedOptionsMonitorOfHostingSettings, _hostEnvironment); + } + [TestCase("http://www.domain.com/foo/bar", "/", "http://www.domain.com/")] [TestCase("http://www.domain.com/foo/bar#hop", "/", "http://www.domain.com/")] [TestCase("http://www.domain.com/foo/bar?q=2#hop", "/", "http://www.domain.com/?q=2")] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs new file mode 100644 index 0000000000..1636936615 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockEditorComponentTests.cs @@ -0,0 +1,261 @@ +using Newtonsoft.Json; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core; +using Umbraco.Web.Compose; + +namespace Umbraco.Tests.PropertyEditors +{ + [TestFixture] + public class BlockEditorComponentTests + { + private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings + { + Formatting = Formatting.None, + NullValueHandling = NullValueHandling.Ignore, + + }; + + private const string _contentGuid1 = "036ce82586a64dfba2d523a99ed80f58"; + private const string _contentGuid2 = "48288c21a38a40ef82deb3eda90a58f6"; + private const string _settingsGuid1 = "ffd35c4e2eea4900abfa5611b67b2492"; + private const string _subContentGuid1 = "4c44ce6b3a5c4f5f8f15e3dc24819a9e"; + private const string _subContentGuid2 = "a062c06d6b0b44ac892b35d90309c7f8"; + private const string _subSettingsGuid1 = "4d998d980ffa4eee8afdc23c4abd6d29"; + + [Test] + public void Cannot_Have_Null_Udi() + { + var component = new BlockEditorComponent(); + var json = GetBlockListJson(null, string.Empty); + Assert.Throws(() => component.ReplaceBlockListUdis(json)); + } + + [Test] + public void No_Nesting() + { + var guids = Enumerable.Range(0, 3).Select(x => Guid.NewGuid()).ToList(); + var guidCounter = 0; + Func guidFactory = () => guids[guidCounter++]; + + var json = GetBlockListJson(null); + + var expected = ReplaceGuids(json, guids, _contentGuid1, _contentGuid2, _settingsGuid1); + + var component = new BlockEditorComponent(); + var result = component.ReplaceBlockListUdis(json, guidFactory); + + var expectedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(expected, _serializerSettings), _serializerSettings); + var resultJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result, _serializerSettings), _serializerSettings); + Console.WriteLine(expectedJson); + Console.WriteLine(resultJson); + Assert.AreEqual(expectedJson, resultJson); + } + + [Test] + public void One_Level_Nesting_Escaped() + { + var guids = Enumerable.Range(0, 6).Select(x => Guid.NewGuid()).ToList(); + + var guidCounter = 0; + Func guidFactory = () => guids[guidCounter++]; + + var innerJson = GetBlockListJson(null, _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + + // we need to ensure the escaped json is consistent with how it will be re-escaped after parsing + // and this is how to do that, the result will also include quotes around it. + var innerJsonEscaped = JsonConvert.ToString(innerJson); + + // get the json with the subFeatures as escaped + var json = GetBlockListJson(innerJsonEscaped); + + var component = new BlockEditorComponent(); + var result = component.ReplaceBlockListUdis(json, guidFactory); + + // the expected result is that the subFeatures data is no longer escaped + var expected = ReplaceGuids(GetBlockListJson(innerJson), guids, + _contentGuid1, _contentGuid2, _settingsGuid1, + _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + + var expectedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(expected, _serializerSettings), _serializerSettings); + var resultJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result, _serializerSettings), _serializerSettings); + Console.WriteLine(expectedJson); + Console.WriteLine(resultJson); + Assert.AreEqual(expectedJson, resultJson); + } + + [Test] + public void One_Level_Nesting_Unescaped() + { + var guids = Enumerable.Range(0, 6).Select(x => Guid.NewGuid()).ToList(); + var guidCounter = 0; + Func guidFactory = () => guids[guidCounter++]; + + // nested blocks without property value escaping used in the conversion + var innerJson = GetBlockListJson(null, _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + + // get the json with the subFeatures as unescaped + var json = GetBlockListJson(innerJson); + + var expected = ReplaceGuids(GetBlockListJson(innerJson), guids, + _contentGuid1, _contentGuid2, _settingsGuid1, + _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + + var component = new BlockEditorComponent(); + var result = component.ReplaceBlockListUdis(json, guidFactory); + + var expectedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(expected, _serializerSettings), _serializerSettings); + var resultJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result, _serializerSettings), _serializerSettings); + Console.WriteLine(expectedJson); + Console.WriteLine(resultJson); + Assert.AreEqual(expectedJson, resultJson); + } + + [Test] + public void Nested_In_Complex_Editor_Escaped() + { + var guids = Enumerable.Range(0, 6).Select(x => Guid.NewGuid()).ToList(); + var guidCounter = 0; + Func guidFactory = () => guids[guidCounter++]; + + var innerJson = GetBlockListJson(null, _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + + // we need to ensure the escaped json is consistent with how it will be re-escaped after parsing + // and this is how to do that, the result will also include quotes around it. + var innerJsonEscaped = JsonConvert.ToString(innerJson); + + // Complex editor such as the grid + var complexEditorJsonEscaped = GetGridJson(innerJsonEscaped); + + var json = GetBlockListJson(complexEditorJsonEscaped); + + var component = new BlockEditorComponent(); + var result = component.ReplaceBlockListUdis(json, guidFactory); + + // the expected result is that the subFeatures data is no longer escaped + var expected = ReplaceGuids(GetBlockListJson(GetGridJson(innerJson)), guids, + _contentGuid1, _contentGuid2, _settingsGuid1, + _subContentGuid1, _subContentGuid2, _subSettingsGuid1); + + var expectedJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(expected, _serializerSettings), _serializerSettings); + var resultJson = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(result, _serializerSettings), _serializerSettings); + Console.WriteLine(expectedJson); + Console.WriteLine(resultJson); + Assert.AreEqual(expectedJson, resultJson); + } + + private string GetBlockListJson(string subFeatures, + string contentGuid1 = _contentGuid1, + string contentGuid2 = _contentGuid2, + string settingsGuid1 = _settingsGuid1) + { + return @"{ + ""layout"": + { + ""Umbraco.BlockList"": [ + { + ""contentUdi"": """ + (contentGuid1.IsNullOrWhiteSpace() ? string.Empty : GuidUdi.Create(Constants.UdiEntityType.Element, Guid.Parse(contentGuid1)).ToString()) + @""" + }, + { + ""contentUdi"": ""umb://element/" + contentGuid2 + @""", + ""settingsUdi"": ""umb://element/" + settingsGuid1 + @""" + } + ] + }, + ""contentData"": [ + { + ""contentTypeKey"": ""d6ce4a86-91a2-45b3-a99c-8691fc1fb020"", + ""udi"": """ + (contentGuid1.IsNullOrWhiteSpace() ? string.Empty : GuidUdi.Create(Constants.UdiEntityType.Element, Guid.Parse(contentGuid1)).ToString()) + @""", + ""featureName"": ""Hello"", + ""featureDetails"": ""World"" + }, + { + ""contentTypeKey"": ""d6ce4a86-91a2-45b3-a99c-8691fc1fb020"", + ""udi"": ""umb://element/" + contentGuid2 + @""", + ""featureName"": ""Another"", + ""featureDetails"": ""Feature""" + (subFeatures == null ? string.Empty : (@", ""subFeatures"": " + subFeatures)) + @" + } + ], + ""settingsData"": [ + { + ""contentTypeKey"": ""d6ce4a86-91a2-45b3-a99c-8691fc1fb020"", + ""udi"": ""umb://element/" + settingsGuid1 + @""", + ""featureName"": ""Setting 1"", + ""featureDetails"": ""Setting 2"" + }, + ] +}"; + } + + private string GetGridJson(string subBlockList) + { + return @"{ + ""name"": ""1 column layout"", + ""sections"": [ + { + ""grid"": ""12"", + ""rows"": [ + { + ""name"": ""Article"", + ""id"": ""b4f6f651-0de3-ef46-e66a-464f4aaa9c57"", + ""areas"": [ + { + ""grid"": ""4"", + ""controls"": [ + { + ""value"": ""I am quote"", + ""editor"": { + ""alias"": ""quote"", + ""view"": ""textstring"" + }, + ""styles"": null, + ""config"": null + }], + ""styles"": null, + ""config"": null + }, + { + ""grid"": ""8"", + ""controls"": [ + { + ""value"": ""Header"", + ""editor"": { + ""alias"": ""headline"", + ""view"": ""textstring"" + }, + ""styles"": null, + ""config"": null + }, + { + ""value"": " + subBlockList + @", + ""editor"": { + ""alias"": ""madeUpNestedContent"", + ""view"": ""madeUpNestedContentInGrid"" + }, + ""styles"": null, + ""config"": null + }], + ""styles"": null, + ""config"": null + }], + ""styles"": null, + ""config"": null + }] + }] +}"; + } + + private string ReplaceGuids(string json, List newGuids, params string[] oldGuids) + { + for (var i = 0; i < oldGuids.Length; i++) + { + var old = oldGuids[i]; + json = json.Replace(old, newGuids[i].ToString("N")); + } + return json; + } + + } +} diff --git a/src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs similarity index 100% rename from src/Umbraco.Tests/PropertyEditors/BlockListPropertyValueConverterTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/BlockListPropertyValueConverterTests.cs diff --git a/src/Umbraco.Tests/PropertyEditors/ColorListValidatorTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs similarity index 82% rename from src/Umbraco.Tests/PropertyEditors/ColorListValidatorTest.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs index f140e6a239..feb1b53b96 100644 --- a/src/Umbraco.Tests/PropertyEditors/ColorListValidatorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs @@ -2,8 +2,10 @@ using Moq; using NUnit.Framework; using Newtonsoft.Json.Linq; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Services; +using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; @@ -16,7 +18,7 @@ namespace Umbraco.Tests.PropertyEditors public void Only_Tests_On_JArray() { var validator = new ColorPickerConfigurationEditor.ColorListValidator(); - var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -24,7 +26,7 @@ namespace Umbraco.Tests.PropertyEditors public void Only_Tests_On_JArray_Of_Item_JObject() { var validator = new ColorPickerConfigurationEditor.ColorListValidator(); - var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -37,7 +39,7 @@ namespace Umbraco.Tests.PropertyEditors JObject.FromObject(new { value = "zxcvzxcvxzcv" }), JObject.FromObject(new { value = "ABC" }), JObject.FromObject(new { value = "1234567" })), - null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(2, result.Count()); } } diff --git a/src/Umbraco.Tests/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs similarity index 99% rename from src/Umbraco.Tests/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs index 24ac9cdbf4..aea4dab134 100644 --- a/src/Umbraco.Tests/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs @@ -21,7 +21,7 @@ namespace Umbraco.Tests.PropertyEditors public class DataValueReferenceFactoryCollectionTests { IDataTypeService DataTypeService { get; } = Mock.Of(); - private IIOHelper IOHelper { get; } = TestHelper.IOHelper; + private IIOHelper IOHelper { get; } = Mock.Of(); ILocalizedTextService LocalizedTextService { get; } = Mock.Of(); ILocalizationService LocalizationService { get; } = Mock.Of(); IShortStringHelper ShortStringHelper { get; } = Mock.Of(); diff --git a/src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs similarity index 81% rename from src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs index f3c3fb4672..930d039625 100644 --- a/src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs @@ -2,8 +2,10 @@ using Moq; using NUnit.Framework; using Newtonsoft.Json.Linq; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Services; +using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; @@ -16,7 +18,7 @@ namespace Umbraco.Tests.PropertyEditors public void Only_Tests_On_JArray() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate("hello", null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -24,7 +26,7 @@ namespace Umbraco.Tests.PropertyEditors public void Only_Tests_On_JArray_Of_Item_JObject() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate(new JArray("hello", "world"), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -32,7 +34,7 @@ namespace Umbraco.Tests.PropertyEditors public void Allows_Unique_Values() { var validator = new ValueListUniqueValueValidator(); - var result = validator.Validate(new JArray(JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "world" })), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + var result = validator.Validate(new JArray(JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "world" })), null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -41,7 +43,7 @@ namespace Umbraco.Tests.PropertyEditors { var validator = new ValueListUniqueValueValidator(); var result = validator.Validate(new JArray(JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "hello" })), - null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(1, result.Count()); } @@ -54,7 +56,7 @@ namespace Umbraco.Tests.PropertyEditors JObject.FromObject(new { value = "hello" }), JObject.FromObject(new { value = "world" }), JObject.FromObject(new { value = "world" })), - null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())); + null, new ColorPickerPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(2, result.Count()); } } diff --git a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs similarity index 83% rename from src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs index 152a751a7b..262d55b6d7 100644 --- a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs @@ -1,18 +1,14 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using Moq; using Newtonsoft.Json; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.PropertyEditors @@ -31,7 +27,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void DropDownMultipleValueEditor_Format_Data_For_Cache() { - var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, Mock.Of())) + var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Configuration = new ValueListConfiguration { @@ -45,14 +41,17 @@ namespace Umbraco.Tests.PropertyEditors Id = 1 }; - var dataTypeService = new TestObjects.TestDataTypeService(dataType); + var dataTypeServiceMock = new Mock(); + dataTypeServiceMock + .Setup(x=>x.GetDataType(It.IsAny())) + .Returns(dataType); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, dataType)); + var prop = new Property(1, new PropertyType(Mock.Of(), dataType)); prop.SetValue("Value 1,Value 2,Value 3"); var valueEditor = dataType.Editor.GetValueEditor(); ((DataValueEditor) valueEditor).Configuration = dataType.Configuration; - var result = valueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService); + var result = valueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeServiceMock.Object); Assert.AreEqual("Value 1,Value 2,Value 3", result); } @@ -60,7 +59,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void DropDownValueEditor_Format_Data_For_Cache() { - var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), TestHelper.IOHelper, Mock.Of())) + var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Configuration = new ValueListConfiguration { @@ -74,12 +73,15 @@ namespace Umbraco.Tests.PropertyEditors Id = 1 }; - var dataTypeService = new TestObjects.TestDataTypeService(dataType); + var dataTypeServiceMock = new Mock(); + dataTypeServiceMock + .Setup(x=>x.GetDataType(It.IsAny())) + .Returns(dataType); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, dataType)); + var prop = new Property(1, new PropertyType(Mock.Of(), dataType)); prop.SetValue("Value 2"); - var result = dataType.Editor.GetValueEditor().ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService); + var result = dataType.Editor.GetValueEditor().ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeServiceMock.Object); Assert.AreEqual("Value 2", result); } @@ -114,7 +116,7 @@ namespace Umbraco.Tests.PropertyEditors } }; - var editor = new ValueListConfigurationEditor(Mock.Of(), TestHelper.IOHelper); + var editor = new ValueListConfigurationEditor(Mock.Of(), Mock.Of()); var result = editor.ToConfigurationEditor(configuration); diff --git a/src/Umbraco.Tests/PropertyEditors/NestedContentPropertyComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs similarity index 99% rename from src/Umbraco.Tests/PropertyEditors/NestedContentPropertyComponentTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs index 1b83c048d2..5b7e220123 100644 --- a/src/Umbraco.Tests/PropertyEditors/NestedContentPropertyComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/NestedContentPropertyComponentTests.cs @@ -9,6 +9,7 @@ using Umbraco.Web.Compose; namespace Umbraco.Tests.PropertyEditors { + [TestFixture] public class NestedContentPropertyComponentTests { diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs similarity index 97% rename from src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs index e8aa4f987c..dfd0e29674 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueConverterTests.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Serialization; +using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; using Umbraco.Web.PropertyEditors.ValueConverters; @@ -96,7 +97,7 @@ namespace Umbraco.Tests.PropertyEditors var publishedPropType = new PublishedPropertyType( new PublishedContentType(Guid.NewGuid(),1234, "test", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Nothing), - new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Nvarchar) { DataTypeId = 123 }, + new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar) { DataTypeId = 123 }, new PropertyValueConverterCollection(Enumerable.Empty()), Mock.Of(), mockPublishedContentTypeFactory.Object); diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs similarity index 61% rename from src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs index 6301be051d..043f682a3f 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -1,54 +1,27 @@ using System; -using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Strings; -using Umbraco.Tests.Components; -using Umbraco.Tests.TestHelpers; -using Current = Umbraco.Web.Composing.Current; +using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.PropertyEditors { [TestFixture] public class PropertyEditorValueEditorTests { - [SetUp] - public virtual void TestSetup() - { - //normalize culture - Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; - - var register = TestHelper.GetRegister(); - 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.GenerateMockRequestHandlerSettings()))); - - Current.Factory = composition.CreateFactory(); - } - - [TearDown] - public virtual void TestTearDown() - { - Current.Reset(); - } - [TestCase("{prop1: 'val1', prop2: 'val2'}", true)] [TestCase("{1,2,3,4}", false)] [TestCase("[1,2,3,4]", true)] [TestCase("hello world", false)] public void Value_Editor_Can_Convert_To_Json_Object_For_Editor(string value, bool isOk) { - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Nvarchar)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar)); prop.SetValue(value); - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.String); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.String); var result = valueEditor.ToEditor(prop); Assert.AreEqual(isOk, !(result is string)); @@ -61,7 +34,7 @@ namespace Umbraco.Tests.PropertyEditors [TestCase("DATETIME", "", null)] //test empty string for date public void Value_Editor_Can_Convert_To_Clr_Type(string valueType, string val, object expected) { - var valueEditor = TestHelper.CreateDataValueEditor(valueType); + var valueEditor = MockedValueEditors.CreateDataValueEditor(valueType); var result = valueEditor.TryConvertValueToCrlType(val); Assert.IsTrue(result.Success); @@ -73,7 +46,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var result = valueEditor.TryConvertValueToCrlType("12.34"); Assert.IsTrue(result.Success); @@ -83,7 +56,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type_With_Other_Separator() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var result = valueEditor.TryConvertValueToCrlType("12,34"); Assert.IsTrue(result.Success); @@ -93,7 +66,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Decimal_Clr_Type_With_Empty_String() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); var result = valueEditor.TryConvertValueToCrlType(string.Empty); Assert.IsTrue(result.Success); @@ -103,7 +76,7 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Convert_To_Date_Clr_Type() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Date); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Date); var result = valueEditor.TryConvertValueToCrlType("2010-02-05"); Assert.IsTrue(result.Success); @@ -117,10 +90,10 @@ namespace Umbraco.Tests.PropertyEditors [TestCase(ValueTypes.DateTime, "", "")] //test empty string for date public void Value_Editor_Can_Serialize_Value(string valueType, object val, string expected) { - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Nvarchar)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Nvarchar)); prop.SetValue(val); - var valueEditor = TestHelper.CreateDataValueEditor(valueType); + var valueEditor = MockedValueEditors.CreateDataValueEditor(valueType); var result = valueEditor.ToEditor(prop); Assert.AreEqual(expected, result); @@ -130,9 +103,9 @@ namespace Umbraco.Tests.PropertyEditors public void Value_Editor_Can_Serialize_Decimal_Value() { var value = 12.34M; - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Decimal)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Decimal)); prop.SetValue(value); var result = valueEditor.ToEditor(prop); @@ -142,9 +115,9 @@ namespace Umbraco.Tests.PropertyEditors [Test] public void Value_Editor_Can_Serialize_Decimal_Value_With_Empty_String() { - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Decimal); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Decimal); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Decimal)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Decimal)); prop.SetValue(string.Empty); var result = valueEditor.ToEditor(prop); @@ -155,9 +128,9 @@ namespace Umbraco.Tests.PropertyEditors public void Value_Editor_Can_Serialize_Date_Value() { var now = DateTime.Now; - var valueEditor = TestHelper.CreateDataValueEditor(ValueTypes.Date); + var valueEditor = MockedValueEditors.CreateDataValueEditor(ValueTypes.Date); - var prop = new Property(1, new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Date)); + var prop = new Property(1, new PropertyType(Mock.Of(), "test", ValueStorageType.Date)); prop.SetValue(now); var result = valueEditor.ToEditor(prop); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs new file mode 100644 index 0000000000..04c7abb72f --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common.PublishedContent; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Tests.Published +{ + [TestFixture] + public class ConvertersTests + { + #region SimpleConverter1 + + [Test] + public void SimpleConverter1Test() + { + var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] + { + new SimpleConverter1(), + }); + + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); + + var contentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); + + IEnumerable CreatePropertyTypes(IPublishedContentType contentType) + { + yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); + } + + var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); + + var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); + + Assert.AreEqual(1234, element1.Value(Mock.Of(), "prop1")); + + // 'null' would be considered a 'missing' value by the default, magic logic + var e = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", null } }, false); + Assert.IsFalse(e.HasValue("prop1")); + + // '0' would not - it's a valid integer - but the converter knows better + e = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "0" } }, false); + Assert.IsFalse(e.HasValue("prop1")); + } + + private class SimpleConverter1 : IPropertyValueConverter + { + public bool? IsValue(object value, PropertyValueLevel level) + { + switch (level) + { + case PropertyValueLevel.Source: + return null; + case PropertyValueLevel.Inter: + return value is int ivalue && ivalue != 0; + default: + throw new NotSupportedException($"Invalid level: {level}."); + } + } + + public bool IsConverter(IPublishedPropertyType propertyType) + => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); + + public Type GetPropertyValueType(IPublishedPropertyType propertyType) + => typeof(int); + + public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) + => PropertyCacheLevel.Element; + + public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) + => int.TryParse(source as string, out int i) ? i : 0; + + public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + => (int)inter; + + public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + => ((int)inter).ToString(); + } + + #endregion + + #region SimpleConverter2 + + [Test] + public void SimpleConverter2Test() + { + var cacheMock = new Mock(); + var cacheContent = new Dictionary(); + cacheMock.Setup(x => x.GetById(It.IsAny())).Returns(id => cacheContent.TryGetValue(id, out IPublishedContent content) ? content : null); + var publishedSnapshotMock = new Mock(); + publishedSnapshotMock.Setup(x => x.Content).Returns(cacheMock.Object); + var publishedSnapshotAccessorMock = new Mock(); + publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot).Returns(publishedSnapshotMock.Object); + var publishedSnapshotAccessor = publishedSnapshotAccessorMock.Object; + + var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] + { + new SimpleConverter2(publishedSnapshotAccessor), + }); + + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); + + var contentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); + + IEnumerable CreatePropertyTypes(IPublishedContentType contentType) + { + yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); + } + + var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); + + var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); + + var cntType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1001, "cnt1", t => Enumerable.Empty()); + var cnt1 = new SolidPublishedContent(cntType1) { Id = 1234 }; + cacheContent[cnt1.Id] = cnt1; + + Assert.AreSame(cnt1, element1.Value(Mock.Of(), "prop1")); + } + + private class SimpleConverter2 : IPropertyValueConverter + { + private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; + private readonly PropertyCacheLevel _cacheLevel; + + public SimpleConverter2(IPublishedSnapshotAccessor publishedSnapshotAccessor, PropertyCacheLevel cacheLevel = PropertyCacheLevel.None) + { + _publishedSnapshotAccessor = publishedSnapshotAccessor; + _cacheLevel = cacheLevel; + } + + public bool? IsValue(object value, PropertyValueLevel level) + => value != null && (!(value is string) || string.IsNullOrWhiteSpace((string)value) == false); + + public bool IsConverter(IPublishedPropertyType propertyType) + => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); + + public Type GetPropertyValueType(IPublishedPropertyType propertyType) + // the first version would be the "generic" version, but say we want to be more precise + // and return: whatever Clr type is generated for content type with alias "cnt1" -- which + // we cannot really typeof() at the moment because it has not been generated, hence ModelType. + // => typeof (IPublishedContent); + => ModelType.For("cnt1"); + + public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) + => _cacheLevel; + + public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) + => int.TryParse(source as string, out int i) ? i : -1; + + public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + => _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById((int)inter); + + public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + => ((int)inter).ToString(); + } + + #endregion + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs new file mode 100644 index 0000000000..43d5b56d6b --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ModelTypeTests.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Tests.Published +{ + [TestFixture] + public class ModelTypeTests + { + [Test] + public void ModelTypeEqualityTests() + { + Assert.AreNotEqual(ModelType.For("alias1"), ModelType.For("alias1")); + + Assert.IsTrue(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias1"))); + Assert.IsFalse(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias2"))); + + Assert.IsTrue(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")))); + Assert.IsFalse(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias2")))); + + Assert.IsTrue(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias1").MakeArrayType())); + Assert.IsFalse(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias2").MakeArrayType())); + } + + [Test] + public void TypeToStringTests() + { + var type = typeof(int); + Assert.AreEqual("System.Int32", type.ToString()); + Assert.AreEqual("System.Int32[]", type.MakeArrayType().ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[System.Int32[]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).ToString()); + } + + [Test] + public void TypeFullNameTests() + { + var type = typeof(int); + Assert.AreEqual("System.Int32", type.FullName); + Assert.AreEqual("System.Int32[]", type.MakeArrayType().FullName); + // note the inner assembly qualified name + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.Int32[], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).FullName); + } + + [Test] + public void ModelTypeMapTests() + { + var map = new Dictionary + { + { "alias1", typeof (PublishedSnapshotTestObjects.TestElementModel1) }, + { "alias2", typeof (PublishedSnapshotTestObjects.TestElementModel2) }, + }; + + Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1", + ModelType.Map(ModelType.For("alias1"), map).ToString()); + Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]", + ModelType.Map(ModelType.For("alias1").MakeArrayType(), map).ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1]", + ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), map).ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]]", + ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()), map).ToString()); + } + } +} diff --git a/src/Umbraco.Tests/Published/NestedContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs similarity index 92% rename from src/Umbraco.Tests/Published/NestedContentTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs index b4b941733c..49362183a9 100644 --- a/src/Umbraco.Tests/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs @@ -5,24 +5,22 @@ using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Web.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using Umbraco.Tests.PublishedContent; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common.PublishedContent; using Umbraco.Web.PropertyEditors; using Umbraco.Web.PropertyEditors.ValueConverters; using Umbraco.Web.PublishedCache; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.Published { [TestFixture] - public class NestedContentTests : UmbracoTestBase + public class NestedContentTests { private (IPublishedContentType, IPublishedContentType) CreateContentTypes() { @@ -32,7 +30,7 @@ namespace Umbraco.Tests.Published var localizationService = Mock.Of(); PropertyEditorCollection editors = null; - var editor = new NestedContentPropertyEditor(logger, new Lazy(() => editors), Mock.Of(),localizationService, Mock.Of(), TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of()); + var editor = new NestedContentPropertyEditor(logger, new Lazy(() => editors), Mock.Of(),localizationService, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); editors = new PropertyEditorCollection(new DataEditorCollection(new DataEditor[] { editor })); var dataType1 = new DataType(editor) @@ -63,13 +61,14 @@ namespace Umbraco.Tests.Published } }; - var dataType3 = new DataType(new TextboxPropertyEditor(logger, Mock.Of(), localizationService, TestHelper.IOHelper, TestHelper.ShortStringHelper, Mock.Of())) + var dataType3 = new DataType(new TextboxPropertyEditor(logger, Mock.Of(), localizationService, Mock.Of(), Mock.Of(), Mock.Of())) { Id = 3 }; // mocked dataservice returns nested content preValues - var dataTypeService = new TestObjects.TestDataTypeService(dataType1, dataType2, dataType3); + var dataTypeServiceMock = new Mock(); + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new []{dataType1, dataType2, dataType3}); var publishedModelFactory = new Mock(); @@ -123,7 +122,7 @@ namespace Umbraco.Tests.Published new NestedContentManyValueConverter(publishedSnapshotAccessor.Object, publishedModelFactory.Object, proflog), }); - var factory = new PublishedContentTypeFactory(publishedModelFactory.Object, converters, dataTypeService); + var factory = new PublishedContentTypeFactory(publishedModelFactory.Object, converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes1(IPublishedContentType contentType) { @@ -177,7 +176,7 @@ namespace Umbraco.Tests.Published ]") } }; - var value = content.Value("property1"); + var value = content.Value(Mock.Of(),"property1"); // nested single converter returns proper TestModel value Assert.IsInstanceOf(value); @@ -209,7 +208,7 @@ namespace Umbraco.Tests.Published ]") } }; - var value = content.Value("property2"); + var value = content.Value(Mock.Of(), ("property2")); // nested many converter returns proper IEnumerable value Assert.IsInstanceOf>(value); @@ -227,7 +226,7 @@ namespace Umbraco.Tests.Published : base(content) { } - public string PropValue => this.Value("propertyN1"); + public string PropValue => this.Value(Mock.Of(),"propertyN1"); } class TestPublishedProperty : PublishedPropertyBase diff --git a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs similarity index 84% rename from src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs index 8aeaf37f7f..cd0c3263dc 100644 --- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs @@ -4,22 +4,18 @@ using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Web; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published { [TestFixture] - public class PropertyCacheLevelTests : UmbracoTestBase + public class PropertyCacheLevelTests { [TestCase(PropertyCacheLevel.None, 2)] [TestCase(PropertyCacheLevel.Element, 1)] @@ -34,14 +30,18 @@ namespace Umbraco.Tests.Published converter, }); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); + + var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType) { - yield return publishedContentTypeFactory.CreatePropertyType(contentType, "prop1", 1); + yield return publishedContentTypeFactory.CreatePropertyType(contentType, "prop1", dataType.Id); } var setType1 = publishedContentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "set1", CreatePropertyTypes); @@ -61,14 +61,14 @@ namespace Umbraco.Tests.Published var set1 = new PublishedElement(setType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(1, converter.InterConverts); // source is always converted once and cached per content // inter conversion depends on the specified cache level - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(interConverts, converter.InterConverts); } @@ -115,10 +115,13 @@ namespace Umbraco.Tests.Published converter, }); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); + var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType) { @@ -143,14 +146,14 @@ namespace Umbraco.Tests.Published var set1 = new PublishedElement(setType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false, referenceCacheLevel, publishedSnapshotAccessor.Object); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(1, converter.InterConverts); Assert.AreEqual(elementsCount1, elementsCache.Count); Assert.AreEqual(snapshotCount1, snapshotCache.Count); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(interConverts, converter.InterConverts); @@ -160,7 +163,7 @@ namespace Umbraco.Tests.Published var oldSnapshotCache = snapshotCache; snapshotCache.Clear(); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(elementsCount2, elementsCache.Count); @@ -172,7 +175,7 @@ namespace Umbraco.Tests.Published var oldElementsCache = elementsCache; elementsCache.Clear(); - Assert.AreEqual(1234, set1.Value("prop1")); + Assert.AreEqual(1234, set1.Value(Mock.Of(), "prop1")); Assert.AreEqual(1, converter.SourceConverts); Assert.AreEqual(elementsCount2, elementsCache.Count); @@ -192,10 +195,13 @@ namespace Umbraco.Tests.Published converter, }); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); + var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType) { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs index 15a9599674..7a2a4c5965 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs @@ -4,6 +4,7 @@ using NUnit.Framework; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Hosting; +using Umbraco.Tests.Common.Builders; using Umbraco.Web; namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing @@ -70,12 +71,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing { // Arrange var sourceUri = new Uri(sourceUrl, UriKind.Relative); - var mockRequestHandlerSettings = new Mock(); - mockRequestHandlerSettings.Setup(x => x.AddTrailingSlash).Returns(trailingSlash); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(trailingSlash).Build(); var uriUtility = BuildUriUtility("/"); // Act - var resultUri = uriUtility.UriFromUmbraco(sourceUri, Mock.Of(), mockRequestHandlerSettings.Object); + var resultUri = uriUtility.UriFromUmbraco(sourceUri, requestHandlerSettings); // Assert var expectedUri = new Uri(expectedUrl, UriKind.Relative); diff --git a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs similarity index 72% rename from src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs index 84ffa3b696..ecdeb2b9e5 100644 --- a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs @@ -1,14 +1,21 @@ -using NUnit.Framework; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Strings { [TestFixture] - public class CmsHelperCasingTests : UmbracoTestBase + public class CmsHelperCasingTests { + private IShortStringHelper ShortStringHelper => new DefaultShortStringHelper(Options.Create(new RequestHandlerSettings())); + [TestCase("thisIsTheEnd", "This Is The End")] [TestCase("th", "Th")] [TestCase("t", "t")] @@ -30,8 +37,8 @@ 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.GenerateMockRequestHandlerSettings()); - var output = input.Length < 2 ? input : helper.SplitPascalCasing(input, ' ').ToFirstUpperInvariant(); + + var output = input.Length < 2 ? input : ShortStringHelper.SplitPascalCasing(input, ' ').ToFirstUpperInvariant(); Assert.AreEqual(expected, output); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs new file mode 100644 index 0000000000..e89fe680b3 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/DefaultShortStringHelperTests.cs @@ -0,0 +1,202 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Strings; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Strings +{ + [TestFixture] + public class DefaultShortStringHelperTests + { + private IShortStringHelper ShortStringHelper { get; set; } + + [SetUp] + public void SetUp() + { + + // NOTE pre-filters runs _before_ Recode takes place + // so there still may be utf8 chars even though you want ascii + + ShortStringHelper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) + .WithConfig(CleanStringType.FileName, new DefaultShortStringHelperConfig.Config + { + //PreFilter = ClearFileChars, // done in IsTerm + IsTerm = (c, leading) => (char.IsLetterOrDigit(c) || c == '_') && DefaultShortStringHelper.IsValidFileNameChar(c), + StringType = CleanStringType.LowerCase | CleanStringType.Ascii, + Separator = '-' + }) + .WithConfig(CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config + { + PreFilter = StripQuotes, + IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', + StringType = CleanStringType.LowerCase | CleanStringType.Ascii, + Separator = '-' + }) + .WithConfig("fr-FR", CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config + { + PreFilter = FilterFrenchElisions, + IsTerm = (c, leading) => leading ? char.IsLetter(c) : (char.IsLetterOrDigit(c) || c == '_'), + StringType = CleanStringType.LowerCase | CleanStringType.Ascii, + Separator = '-' + }) + .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config + { + PreFilter = StripQuotes, + IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), + StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii + }) + .WithConfig("fr-FR", CleanStringType.Alias, new DefaultShortStringHelperConfig.Config + { + PreFilter = WhiteQuotes, + IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), + StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii + }) + .WithConfig(CleanStringType.ConvertCase, new DefaultShortStringHelperConfig.Config + { + PreFilter = null, + IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore + StringType = CleanStringType.Ascii, + BreakTermsOnUpper = true + })); + } + + private static readonly Regex FrenchElisionsRegex = new Regex("\\b(c|d|j|l|m|n|qu|s|t)('|\u8217)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + private static string FilterFrenchElisions(string s) + { + return FrenchElisionsRegex.Replace(s, ""); + } + + private static string StripQuotes(string s) + { + s = s.ReplaceMany(new Dictionary {{"'", ""}, {"\u8217", ""}}); + return s; + } + + private static string WhiteQuotes(string s) + { + s = s.ReplaceMany(new Dictionary { { "'", " " }, { "\u8217", " " } }); + return s; + } + + #region Cases + [TestCase("foo", "foo")] + [TestCase(" foo ", "foo")] + [TestCase("Foo", "Foo")] + [TestCase("FoO", "FoO")] + [TestCase("FoO bar", "FoOBar")] + [TestCase("FoO bar NIL", "FoOBarNIL")] + [TestCase("FoO 33bar 22NIL", "FoO33bar22NIL")] + [TestCase("FoO 33bar 22NI", "FoO33bar22NI")] + [TestCase("0foo", "foo")] + [TestCase("2foo bar", "fooBar")] + [TestCase("9FOO", "FOO")] + [TestCase("foo-BAR", "fooBAR")] + [TestCase("foo-BA-dang", "fooBADang")] + [TestCase("foo_BAR", "fooBAR")] + [TestCase("foo'BAR", "fooBAR")] + [TestCase("sauté dans l'espace", "sauteDansLespace")] + [TestCase("foo\"\"bar", "fooBar")] + [TestCase("-foo-", "foo")] + [TestCase("_foo_", "foo")] + [TestCase("spécial", "special")] + [TestCase("brô dëk ", "broDek")] + [TestCase("1235brô dëk ", "broDek")] + [TestCase("汉#字*/漢?字", "")] + [TestCase("aa DB cd EFG X KLMN OP qrst", "aaDBCdEFGXKLMNOPQrst")] + [TestCase("AA db cd EFG X KLMN OP qrst", "AADbCdEFGXKLMNOPQrst")] + [TestCase("AAA db cd EFG X KLMN OP qrst", "AAADbCdEFGXKLMNOPQrst")] + [TestCase("4 ways selector", "waysSelector")] + [TestCase("WhatIfWeDoItAgain", "WhatIfWeDoItAgain")] + [TestCase("whatIfWeDoItAgain", "whatIfWeDoItAgain")] + [TestCase("WhatIfWEDOITAgain", "WhatIfWEDOITAgain")] + [TestCase("WhatIfWe doItAgain", "WhatIfWeDoItAgain")] + #endregion + public void CleanStringForSafeAlias(string input, string expected) + { + var output = ShortStringHelper.CleanStringForSafeAlias(input); + Assert.AreEqual(expected, output); + } + + #region Cases + [TestCase("Home Page", "home-page")] + [TestCase("Shannon's Home Page!", "shannons-home-page")] + [TestCase("#Someones's Twitter $h1z%n", "someoness-twitter-h1z-n")] + [TestCase("Räksmörgås", "raksmorgas")] + [TestCase("'em guys-over there, are#goin' a \"little\"bit crazy eh!! :)", "em-guys-over-there-are-goin-a-little-bit-crazy-eh")] + [TestCase("汉#字*/漢?字", "")] + [TestCase("Réalösk fix bran#lo'sk", "realosk-fix-bran-losk")] + [TestCase("200 ways to be happy", "200-ways-to-be-happy")] + #endregion + public void CleanStringForUrlSegment(string input, string expected) + { + var output = ShortStringHelper.CleanStringForUrlSegment(input); + Assert.AreEqual(expected, output); + } + + #region Cases + [TestCase("ThisIsTheEndMyFriend", "This Is The End My Friend")] + [TestCase("ThisIsTHEEndMyFriend", "This Is THE End My Friend")] + [TestCase("THISIsTHEEndMyFriend", "THIS Is THE End My Friend")] + [TestCase("This33I33sThe33EndMyFriend", "This33 I33s The33 End My Friend")] // works! + [TestCase("ThisIsTHEEndMyFriendX", "This Is THE End My Friend X")] + [TestCase("ThisIsTHEEndMyFriendXYZ", "This Is THE End My Friend XYZ")] + [TestCase("ThisIsTHEEndMyFriendXYZt", "This Is THE End My Friend XY Zt")] + [TestCase("UneÉlévationÀPartir", "Une Élévation À Partir")] + #endregion + public void SplitPascalCasing(string input, string expected) + { + var output = ShortStringHelper.SplitPascalCasing(input, ' '); + Assert.AreEqual(expected, output); + + output = ShortStringHelper.SplitPascalCasing(input, '*'); + expected = expected.Replace(' ', '*'); + Assert.AreEqual(expected, output); + } + + #region Cases + [TestCase("sauté dans l'espace", "saute-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] + [TestCase("sauté dans l'espace", "sauté-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Utf8 | CleanStringType.LowerCase)] + [TestCase("sauté dans l'espace", "SauteDansLEspace", "fr-FR", CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.PascalCase)] + [TestCase("he doesn't want", "he-doesnt-want", null, CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] + [TestCase("he doesn't want", "heDoesntWant", null, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase)] + #endregion + public void CleanStringWithTypeAndCulture(string input, string expected, string culture, CleanStringType stringType) + { + // picks the proper config per culture + // and overrides some stringType params (ascii...) + var output = ShortStringHelper.CleanString(input, stringType, culture); + Assert.AreEqual(expected, output); + } + + #region Cases + [TestCase("foo.txt", "foo.txt")] + [TestCase("foo", "foo")] + [TestCase(".txt", ".txt")] + [TestCase("nag*dog/poo:xit.txt", "nag-dog-poo-xit.txt")] + [TestCase("the dog is in the house.txt", "the-dog-is-in-the-house.txt")] + [TestCase("nil.nil.nil.txt", "nil-nil-nil.txt")] + [TestCase("taradabum", "taradabum")] + [TestCase("tara$$da:b/u (char.IsLetterOrDigit(c) || c == '_') && DefaultShortStringHelper.IsValidFileNameChar(c), - StringType = CleanStringType.LowerCase | CleanStringType.Ascii, - Separator = '-' - }) - .WithConfig(CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config - { - PreFilter = StripQuotes, - IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', - StringType = CleanStringType.LowerCase | CleanStringType.Ascii, - Separator = '-' - }) - .WithConfig("fr-FR", CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config - { - PreFilter = FilterFrenchElisions, - IsTerm = (c, leading) => leading ? char.IsLetter(c) : (char.IsLetterOrDigit(c) || c == '_'), - StringType = CleanStringType.LowerCase | CleanStringType.Ascii, - Separator = '-' - }) - .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config - { - PreFilter = StripQuotes, - IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), - StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii - }) - .WithConfig("fr-FR", CleanStringType.Alias, new DefaultShortStringHelperConfig.Config - { - PreFilter = WhiteQuotes, - IsTerm = (c, leading) => leading ? char.IsLetter(c) : char.IsLetterOrDigit(c), - StringType = CleanStringType.UmbracoCase | CleanStringType.Ascii - }) - .WithConfig(CleanStringType.ConvertCase, new DefaultShortStringHelperConfig.Config - { - PreFilter = null, - IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', // letter, digit or underscore - StringType = CleanStringType.Ascii, - BreakTermsOnUpper = true - })); - - // FIXME: move to a "compose" thing? - Composition.RegisterUnique(f => _helper); - } - - private static readonly Regex FrenchElisionsRegex = new Regex("\\b(c|d|j|l|m|n|qu|s|t)('|\u8217)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - - private static string FilterFrenchElisions(string s) - { - return FrenchElisionsRegex.Replace(s, ""); - } - - private static string StripQuotes(string s) - { - s = s.ReplaceMany(new Dictionary {{"'", ""}, {"\u8217", ""}}); - return s; - } - - private static string WhiteQuotes(string s) - { - s = s.ReplaceMany(new Dictionary { { "'", " " }, { "\u8217", " " } }); - return s; - } [Test] public void U4_4056() { - var settings = SettingsForTests.GenerateMockRequestHandlerSettings(); - var contentMock = Mock.Get(settings); - contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); - contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); + var requestHandlerSettings = new RequestHandlerSettings() + { + CharCollection = Enumerable.Empty(), + ConvertUrlsToAscii = "false" + }; const string input = "ÆØÅ and æøå and 中文测试 and אודות האתר and größer БбДдЖж page"; - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(settings)); // unicode + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings)); // unicode var output = helper.CleanStringForUrlSegment(input); Assert.AreEqual("æøå-and-æøå-and-中文测试-and-אודות-האתר-and-größer-ббдджж-page", output); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(settings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) .WithConfig(CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config { IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', @@ -119,19 +42,20 @@ namespace Umbraco.Tests.Strings [Test] public void U4_4056_TryAscii() { - var settings = SettingsForTests.GenerateMockRequestHandlerSettings(); - var contentMock = Mock.Get(settings); - contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); - contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); + var requestHandlerSettings = new RequestHandlerSettings() + { + CharCollection = Enumerable.Empty(), + ConvertUrlsToAscii = "false" + }; const string input1 = "ÆØÅ and æøå and 中文测试 and אודות האתר and größer БбДдЖж page"; const string input2 = "ÆØÅ and æøå and größer БбДдЖж page"; - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(settings)); // unicode + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings)); // unicode Assert.AreEqual("æøå-and-æøå-and-中文测试-and-אודות-האתר-and-größer-ббдджж-page", helper.CleanStringForUrlSegment(input1)); Assert.AreEqual("æøå-and-æøå-and-größer-ббдджж-page", helper.CleanStringForUrlSegment(input2)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(settings) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings) .WithConfig(CleanStringType.UrlSegment, new DefaultShortStringHelperConfig.Config { IsTerm = (c, leading) => char.IsLetterOrDigit(c) || c == '_', @@ -145,7 +69,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringUnderscoreInTerm() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // underscore is accepted within terms @@ -155,7 +79,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo_bar*nil", helper.CleanString("foo_bar nil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // underscore is not accepted within terms @@ -169,7 +93,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringLeadingChars() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // letters and digits are valid leading chars @@ -179,7 +103,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.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // only letters are valid leading chars @@ -190,14 +114,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.GenerateMockRequestHandlerSettings())); + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings() )); Assert.AreEqual("child2", helper.CleanStringForSafeAlias("1child2")); } [Test] public void CleanStringTermOnUpper() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -207,7 +131,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo*Bar", helper.CleanString("fooBar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -221,7 +145,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringAcronymOnNonUpper() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -234,7 +158,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.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -251,7 +175,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringGreedyAcronyms() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -264,7 +188,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.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -281,7 +205,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringWhiteSpace() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -294,7 +218,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringSeparator() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -302,7 +226,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo*bar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -310,14 +234,14 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo bar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .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.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -329,7 +253,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringSymbols() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -383,7 +307,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringEncoding() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -392,7 +316,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.GenerateMockRequestHandlerSettings()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Ascii | CleanStringType.Unchanged, @@ -405,12 +329,13 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringDefaultConfig() { - var settings = SettingsForTests.GenerateMockRequestHandlerSettings(); - var contentMock = Mock.Get(settings); - contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); - contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); + var requestHandlerSettings = new RequestHandlerSettings() + { + CharCollection = Enumerable.Empty(), + ConvertUrlsToAscii = "false" + }; - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(settings)); + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(requestHandlerSettings)); const string input = "0123 中文测试 中文测试 léger ZÔRG (2) a?? *x"; @@ -431,7 +356,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringCasing() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GenerateMockRequestHandlerSettings()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(new RequestHandlerSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -477,138 +402,29 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("Special Xml Writer", helper.CleanString("special XML writer", CleanStringType.Alias | CleanStringType.PascalCase)); } - #region Cases - [TestCase("foo", "foo")] - [TestCase(" foo ", "foo")] - [TestCase("Foo", "Foo")] - [TestCase("FoO", "FoO")] - [TestCase("FoO bar", "FoOBar")] - [TestCase("FoO bar NIL", "FoOBarNIL")] - [TestCase("FoO 33bar 22NIL", "FoO33bar22NIL")] - [TestCase("FoO 33bar 22NI", "FoO33bar22NI")] - [TestCase("0foo", "foo")] - [TestCase("2foo bar", "fooBar")] - [TestCase("9FOO", "FOO")] - [TestCase("foo-BAR", "fooBAR")] - [TestCase("foo-BA-dang", "fooBADang")] - [TestCase("foo_BAR", "fooBAR")] - [TestCase("foo'BAR", "fooBAR")] - [TestCase("sauté dans l'espace", "sauteDansLespace")] - [TestCase("foo\"\"bar", "fooBar")] - [TestCase("-foo-", "foo")] - [TestCase("_foo_", "foo")] - [TestCase("spécial", "special")] - [TestCase("brô dëk ", "broDek")] - [TestCase("1235brô dëk ", "broDek")] - [TestCase("汉#字*/漢?字", "")] - [TestCase("aa DB cd EFG X KLMN OP qrst", "aaDBCdEFGXKLMNOPQrst")] - [TestCase("AA db cd EFG X KLMN OP qrst", "AADbCdEFGXKLMNOPQrst")] - [TestCase("AAA db cd EFG X KLMN OP qrst", "AAADbCdEFGXKLMNOPQrst")] - [TestCase("4 ways selector", "waysSelector")] - [TestCase("WhatIfWeDoItAgain", "WhatIfWeDoItAgain")] - [TestCase("whatIfWeDoItAgain", "whatIfWeDoItAgain")] - [TestCase("WhatIfWEDOITAgain", "WhatIfWEDOITAgain")] - [TestCase("WhatIfWe doItAgain", "WhatIfWeDoItAgain")] - #endregion - public void CleanStringForSafeAlias(string input, string expected) - { - var output = _helper.CleanStringForSafeAlias(input); - Assert.AreEqual(expected, output); - } + // #region Cases + // [TestCase("This is my_little_house so cute.", "thisIsMyLittleHouseSoCute", false)] + // [TestCase("This is my_little_house so cute.", "thisIsMy_little_houseSoCute", true)] + // [TestCase("This is my_Little_House so cute.", "thisIsMyLittleHouseSoCute", false)] + // [TestCase("This is my_Little_House so cute.", "thisIsMy_Little_HouseSoCute", true)] + // [TestCase("An UPPER_CASE_TEST to check", "anUpperCaseTestToCheck", false)] + // [TestCase("An UPPER_CASE_TEST to check", "anUpper_case_testToCheck", true)] + // [TestCase("Trailing_", "trailing", false)] + // [TestCase("Trailing_", "trailing_", true)] + // [TestCase("_Leading", "leading", false)] + // [TestCase("_Leading", "leading", true)] + // [TestCase("Repeat___Repeat", "repeatRepeat", false)] + // [TestCase("Repeat___Repeat", "repeat___Repeat", true)] + // [TestCase("Repeat___repeat", "repeatRepeat", false)] + // [TestCase("Repeat___repeat", "repeat___repeat", true)] + // #endregion + // public void CleanStringWithUnderscore(string input, string expected, bool allowUnderscoreInTerm) + // { + // var helper = new DefaultShortStringHelper(SettingsForTests.GetDefault()) + // .WithConfig(allowUnderscoreInTerm: allowUnderscoreInTerm); + // var output = helper.CleanString(input, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase); + // Assert.AreEqual(expected, output); + // } - //#region Cases - //[TestCase("This is my_little_house so cute.", "thisIsMyLittleHouseSoCute", false)] - //[TestCase("This is my_little_house so cute.", "thisIsMy_little_houseSoCute", true)] - //[TestCase("This is my_Little_House so cute.", "thisIsMyLittleHouseSoCute", false)] - //[TestCase("This is my_Little_House so cute.", "thisIsMy_Little_HouseSoCute", true)] - //[TestCase("An UPPER_CASE_TEST to check", "anUpperCaseTestToCheck", false)] - //[TestCase("An UPPER_CASE_TEST to check", "anUpper_case_testToCheck", true)] - //[TestCase("Trailing_", "trailing", false)] - //[TestCase("Trailing_", "trailing_", true)] - //[TestCase("_Leading", "leading", false)] - //[TestCase("_Leading", "leading", true)] - //[TestCase("Repeat___Repeat", "repeatRepeat", false)] - //[TestCase("Repeat___Repeat", "repeat___Repeat", true)] - //[TestCase("Repeat___repeat", "repeatRepeat", false)] - //[TestCase("Repeat___repeat", "repeat___repeat", true)] - //#endregion - //public void CleanStringWithUnderscore(string input, string expected, bool allowUnderscoreInTerm) - //{ - // var helper = new DefaultShortStringHelper(SettingsForTests.GetDefault()) - // .WithConfig(allowUnderscoreInTerm: allowUnderscoreInTerm); - // var output = helper.CleanString(input, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase); - // Assert.AreEqual(expected, output); - //} - - #region Cases - [TestCase("Home Page", "home-page")] - [TestCase("Shannon's Home Page!", "shannons-home-page")] - [TestCase("#Someones's Twitter $h1z%n", "someoness-twitter-h1z-n")] - [TestCase("Räksmörgås", "raksmorgas")] - [TestCase("'em guys-over there, are#goin' a \"little\"bit crazy eh!! :)", "em-guys-over-there-are-goin-a-little-bit-crazy-eh")] - [TestCase("汉#字*/漢?字", "")] - [TestCase("Réalösk fix bran#lo'sk", "realosk-fix-bran-losk")] - [TestCase("200 ways to be happy", "200-ways-to-be-happy")] - #endregion - public void CleanStringForUrlSegment(string input, string expected) - { - var output = _helper.CleanStringForUrlSegment(input); - Assert.AreEqual(expected, output); - } - - #region Cases - [TestCase("ThisIsTheEndMyFriend", "This Is The End My Friend")] - [TestCase("ThisIsTHEEndMyFriend", "This Is THE End My Friend")] - [TestCase("THISIsTHEEndMyFriend", "THIS Is THE End My Friend")] - [TestCase("This33I33sThe33EndMyFriend", "This33 I33s The33 End My Friend")] // works! - [TestCase("ThisIsTHEEndMyFriendX", "This Is THE End My Friend X")] - [TestCase("ThisIsTHEEndMyFriendXYZ", "This Is THE End My Friend XYZ")] - [TestCase("ThisIsTHEEndMyFriendXYZt", "This Is THE End My Friend XY Zt")] - [TestCase("UneÉlévationÀPartir", "Une Élévation À Partir")] - #endregion - public void SplitPascalCasing(string input, string expected) - { - var output = _helper.SplitPascalCasing(input, ' '); - Assert.AreEqual(expected, output); - - output = _helper.SplitPascalCasing(input, '*'); - expected = expected.Replace(' ', '*'); - Assert.AreEqual(expected, output); - } - - #region Cases - [TestCase("sauté dans l'espace", "saute-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] - [TestCase("sauté dans l'espace", "sauté-dans-espace", "fr-FR", CleanStringType.UrlSegment | CleanStringType.Utf8 | CleanStringType.LowerCase)] - [TestCase("sauté dans l'espace", "SauteDansLEspace", "fr-FR", CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.PascalCase)] - [TestCase("he doesn't want", "he-doesnt-want", null, CleanStringType.UrlSegment | CleanStringType.Ascii | CleanStringType.LowerCase)] - [TestCase("he doesn't want", "heDoesntWant", null, CleanStringType.Alias | CleanStringType.Ascii | CleanStringType.CamelCase)] - #endregion - public void CleanStringWithTypeAndCulture(string input, string expected, string culture, CleanStringType stringType) - { - // picks the proper config per culture - // and overrides some stringType params (ascii...) - var output = _helper.CleanString(input, stringType, culture); - Assert.AreEqual(expected, output); - } - - #region Cases - [TestCase("foo.txt", "foo.txt")] - [TestCase("foo", "foo")] - [TestCase(".txt", ".txt")] - [TestCase("nag*dog/poo:xit.txt", "nag-dog-poo-xit.txt")] - [TestCase("the dog is in the house.txt", "the-dog-is-in-the-house.txt")] - [TestCase("nil.nil.nil.txt", "nil-nil-nil.txt")] - [TestCase("taradabum", "taradabum")] - [TestCase("tara$$da:b/u()); Assert.AreEqual(result, output.Success); } @@ -89,37 +88,6 @@ namespace Umbraco.Tests.Strings Assert.AreEqual(cleaned, result); } - [TestCase("This is a string to encrypt")] - [TestCase("This is a string to encrypt\nThis is a second line")] - [TestCase(" White space is preserved ")] - [TestCase("\nWhite space is preserved\n")] - public void Encrypt_And_Decrypt(string input) - { - var encrypted = input.EncryptWithMachineKey(); - var decrypted = encrypted.DecryptWithMachineKey(); - Assert.AreNotEqual(input, encrypted); - Assert.AreEqual(input, decrypted); - } - - [Test()] - public void Encrypt_And_Decrypt_Long_Value() - { - // Generate a really long string - char[] chars = { 'a', 'b', 'c', '1', '2', '3', '\n' }; - - string valueToTest = string.Empty; - - // Create a string 7035 chars long - for (int i = 0; i < 1005; i++) - for (int j = 0; j < chars.Length; j++) - valueToTest += chars[j].ToString(); - - var encrypted = valueToTest.EncryptWithMachineKey(); - var decrypted = encrypted.DecryptWithMachineKey(); - Assert.AreNotEqual(valueToTest, encrypted); - Assert.AreEqual(valueToTest, decrypted); - } - [TestCase("Hello this is my string", " string", "Hello this is my")] [TestCase("Hello this is my string strung", " string", "Hello this is my string strung")] [TestCase("Hello this is my string string", " string", "Hello this is my")] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs new file mode 100644 index 0000000000..4de74b2828 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StringValidationTests.cs @@ -0,0 +1,42 @@ +using System.ComponentModel.DataAnnotations; +using NUnit.Framework; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Strings +{ + [TestFixture] + public class StringValidationTests + { + [TestCase("someone@somewhere.com", ExpectedResult = true)] + [TestCase("someone@somewhere.co.uk", ExpectedResult = true)] + [TestCase("someone+tag@somewhere.net", ExpectedResult = true)] + [TestCase("futureTLD@somewhere.fooo", ExpectedResult = true)] + + [TestCase("abc@xyz.financial", ExpectedResult = true)] + [TestCase("admin+gmail-syntax@c.pizza", ExpectedResult = true)] + [TestCase("admin@c.pizza", ExpectedResult = true)] + + [TestCase("fdsa", ExpectedResult = false)] + [TestCase("fdsa@", ExpectedResult = false)] + + // IsValid can be either a powerful regex OR a dummy test, + // and by default it depends on System.ComponentModel.DataAnnotations.AppSettings.DisableRegEx + // which ends up using BinaryCompatibility.Current.TargetsAtLeastFramework472 so for some reason + // in 472 we are not using the regex anymore + // + // it can be forced, though with an app settings + // dataAnnotations:dataTypeAttribute:disableRegEx = false + // + // since Umbraco is now 4.7.2+, the setting is required for the following tests to pass + + //[TestCase("fdsa@fdsa", ExpectedResult = false)] + //[TestCase("fdsa@fdsa.", ExpectedResult = false)] + public bool Validate_Email_Address(string input) + { + var foo = new EmailAddressAttribute(); + + return foo.IsValid(input); + } + } +} diff --git a/src/Umbraco.Tests/Strings/StylesheetHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs similarity index 97% rename from src/Umbraco.Tests/Strings/StylesheetHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs index 5ae4c0511f..46efce7a5b 100644 --- a/src/Umbraco.Tests/Strings/StylesheetHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/StylesheetHelperTests.cs @@ -1,15 +1,12 @@ using System.Linq; -using System.Text; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Strings.Css; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.Strings { [TestFixture] - public class StylesheetHelperTests : UmbracoTestBase + public class StylesheetHelperTests { [Test] public void Replace_Rule() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/ConnectionStringsBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/ConnectionStringsBuilderTests.cs new file mode 100644 index 0000000000..7a95df708e --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/ConnectionStringsBuilderTests.cs @@ -0,0 +1,26 @@ +using NUnit.Framework; +using Umbraco.Tests.Common.Builders; + +namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders +{ + [TestFixture] + public class ConnectionStringsBuilderTests + { + [Test] + public void Is_Built_Correctly() + { + // Arrange + const string umbracoConnectionString = "Server=(LocalDB)\\Umbraco;Database=FakeName;Integrated Security=true"; + + var builder = new ConnectionStringsBuilder(); + + // Act + var connectionStrings = builder + .WithUmbracoConnectionString(umbracoConnectionString) + .Build(); + + // Assert + Assert.AreEqual(umbracoConnectionString, connectionStrings.UmbracoConnectionString.ConnectionString); + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/CoreDebugSettingsBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/CoreDebugSettingsBuilderTests.cs new file mode 100644 index 0000000000..d576f44072 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/CoreDebugSettingsBuilderTests.cs @@ -0,0 +1,29 @@ +using NUnit.Framework; +using Umbraco.Tests.Common.Builders; + +namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders +{ + [TestFixture] + public class CoreDebugSettingsBuilderTests + { + [Test] + public void Is_Built_Correctly() + { + // Arrange + const bool dumpOnTimeoutThreadAbort = true; + const bool logUncompletedScopes = true; + + var builder = new CoreDebugSettingsBuilder(); + + // Act + var coreDebugSettings = builder + .WithDumpOnTimeoutThreadAbort(dumpOnTimeoutThreadAbort) + .WithLogUncompletedScopes(logUncompletedScopes) + .Build(); + + // Assert + Assert.AreEqual(dumpOnTimeoutThreadAbort, coreDebugSettings.DumpOnTimeoutThreadAbort); + Assert.AreEqual(logUncompletedScopes, coreDebugSettings.LogUncompletedScopes); + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/HostingSettingsBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/HostingSettingsBuilderTests.cs new file mode 100644 index 0000000000..377e143b97 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/HostingSettingsBuilderTests.cs @@ -0,0 +1,30 @@ +using NUnit.Framework; +using Umbraco.Core.Configuration; +using Umbraco.Tests.Common.Builders; + +namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders +{ + [TestFixture] + public class HostingSettingsBuilderTests + { + [Test] + public void Is_Built_Correctly() + { + // Arrange + const bool debugMode = true; + const LocalTempStorage localTempStorageLocation = LocalTempStorage.AspNetTemp; + + var builder = new HostingSettingsBuilder(); + + // Act + var hostingSettings = builder + .WithDebug(debugMode) + .WithLocalTempStorageLocation(localTempStorageLocation) + .Build(); + + // Assert + Assert.AreEqual(debugMode, hostingSettings.Debug); + Assert.AreEqual(localTempStorageLocation, hostingSettings.LocalTempStorageLocation); + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RequestHandlerSettingsBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RequestHandlerSettingsBuilderTests.cs new file mode 100644 index 0000000000..199b3dadde --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/RequestHandlerSettingsBuilderTests.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Tests.Common.Builders; +using static Umbraco.Core.Configuration.Models.RequestHandlerSettings; + +namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders +{ + [TestFixture] + public class RequestHandlerSettingsBuilderTests + { + [Test] + public void Is_Built_Correctly() + { + // Arrange + const bool addTrailingSlash = true; + const string convertUrlsToAscii = "try"; + var charCollection = new List { new CharItem { Char = "a", Replacement = "b" } }; + + var builder = new RequestHandlerSettingsBuilder(); + + // Act + var requestHandlerSettings = builder + .WithAddTrailingSlash(addTrailingSlash) + .WithConvertUrlsToAscii(convertUrlsToAscii) + .WithCharCollection(charCollection) + .Build(); + + // Assert + Assert.AreEqual(addTrailingSlash, requestHandlerSettings.AddTrailingSlash); + Assert.AreEqual(convertUrlsToAscii, requestHandlerSettings.ConvertUrlsToAscii); + Assert.AreEqual("a-b", string.Join(",", requestHandlerSettings.CharCollection.Select(x => $"{x.Char}-{x.Replacement}"))); + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/WebRoutingSettingsBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/WebRoutingSettingsBuilderTests.cs new file mode 100644 index 0000000000..e3f4bcf04e --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/WebRoutingSettingsBuilderTests.cs @@ -0,0 +1,47 @@ +using NUnit.Framework; +using Umbraco.Tests.Common.Builders; + +namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders +{ + [TestFixture] + public class WebRoutingSettingsBuilderTests + { + [Test] + public void Is_Built_Correctly() + { + // Arrange + const bool disableAlternativeTemplates = true; + const bool disableFindContentByIdPath = true; + const bool disableRedirectUrlTracking = true; + const bool internalRedirectPreservesTemplate = true; + const bool trySkipIisCustomErrors = true; + const string umbracoApplicationUrl = "/test/"; + const string urlProviderMode = "test"; + const bool validateAlternativeTemplates = true; + + var builder = new WebRoutingSettingsBuilder(); + + // Act + var webRoutingSettings = builder + .WithDisableAlternativeTemplates(disableAlternativeTemplates) + .WithDisableFindContentByIdPath(disableFindContentByIdPath) + .WithDisableRedirectUrlTracking(disableRedirectUrlTracking) + .WithInternalRedirectPreservesTemplate(internalRedirectPreservesTemplate) + .WithTrySkipIisCustomErrors(trySkipIisCustomErrors) + .WithUmbracoApplicationUrl(umbracoApplicationUrl) + .WithUrlProviderMode(urlProviderMode) + .WithValidateAlternativeTemplates(validateAlternativeTemplates) + .Build(); + + // Assert + Assert.AreEqual(disableAlternativeTemplates, webRoutingSettings.DisableAlternativeTemplates); + Assert.AreEqual(disableFindContentByIdPath, webRoutingSettings.DisableFindContentByIdPath); + Assert.AreEqual(disableRedirectUrlTracking, webRoutingSettings.DisableRedirectUrlTracking); + Assert.AreEqual(internalRedirectPreservesTemplate, webRoutingSettings.InternalRedirectPreservesTemplate); + Assert.AreEqual(trySkipIisCustomErrors, webRoutingSettings.TrySkipIisCustomErrors); + Assert.AreEqual(umbracoApplicationUrl, webRoutingSettings.UmbracoApplicationUrl); + Assert.AreEqual(urlProviderMode, webRoutingSettings.UrlProviderMode); + Assert.AreEqual(validateAlternativeTemplates, webRoutingSettings.ValidateAlternativeTemplates); + } + } +} diff --git a/src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/ModelsBuilder/BuilderTests.cs similarity index 89% rename from src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/ModelsBuilder/BuilderTests.cs index 6065570b13..f185a56868 100644 --- a/src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/ModelsBuilder/BuilderTests.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded; using Umbraco.ModelsBuilder.Embedded.Building; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.ModelsBuilder { @@ -42,7 +43,8 @@ namespace Umbraco.Tests.ModelsBuilder { }; - var builder = new TextBuilder(Mock.Of(), types); + var modelsBuilderConfig = new ModelsBuilderConfigBuilder().Build(); + var builder = new TextBuilder(modelsBuilderConfig, types); var btypes = builder.TypeModels; var sb = new StringBuilder(); @@ -61,13 +63,11 @@ namespace Umbraco.Tests.ModelsBuilder //------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq.Expressions; -using System.Web; -using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web; +using Umbraco.Web.PublishedCache; using Umbraco.ModelsBuilder.Embedded; +using Umbraco.Core; namespace Umbraco.Web.PublishedModels { @@ -81,23 +81,27 @@ namespace Umbraco.Web.PublishedModels [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new const PublishedItemType ModelItemType = PublishedItemType.Content; [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] - public new static IPublishedContentType GetModelContentType() - => PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias); + public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor) + => PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias); [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] - public static IPublishedPropertyType GetModelPropertyType(Expression> selector) - => PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector); + public static IPublishedPropertyType GetModelPropertyType(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression> selector) + => PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector); #pragma warning restore 0109 + private IPublishedValueFallback _publishedValueFallback; + // ctor - public Type1(IPublishedContent content) + public Type1(IPublishedContent content, IPublishedValueFallback publishedValueFallback) : base(content) - { } + { + _publishedValueFallback = publishedValueFallback; + } // properties [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] [ImplementPropertyType(""prop1"")] - public string Prop1 => this.Value(""prop1""); + public string Prop1 => this.Value(_publishedValueFallback, ""prop1""); } } "; @@ -150,7 +154,8 @@ namespace Umbraco.Web.PublishedModels " } }; - var builder = new TextBuilder(Mock.Of(), types); + var modelsBuilderConfig = new ModelsBuilderConfigBuilder().Build(); + var builder = new TextBuilder(modelsBuilderConfig, types); var btypes = builder.TypeModels; builder.ModelsNamespace = "Umbraco.Web.PublishedModels"; @@ -176,13 +181,11 @@ namespace Umbraco.Web.PublishedModels //------------------------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Linq.Expressions; -using System.Web; -using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web; +using Umbraco.Web.PublishedCache; using Umbraco.ModelsBuilder.Embedded; +using Umbraco.Core; namespace Umbraco.Web.PublishedModels { @@ -196,23 +199,27 @@ namespace Umbraco.Web.PublishedModels [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new const PublishedItemType ModelItemType = PublishedItemType.Content; [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] - public new static IPublishedContentType GetModelContentType() - => PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias); + public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor) + => PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias); [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] - public static IPublishedPropertyType GetModelPropertyType(Expression> selector) - => PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector); + public static IPublishedPropertyType GetModelPropertyType(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression> selector) + => PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector); #pragma warning restore 0109 + private IPublishedValueFallback _publishedValueFallback; + // ctor - public Type1(IPublishedContent content) + public Type1(IPublishedContent content, IPublishedValueFallback publishedValueFallback) : base(content) - { } + { + _publishedValueFallback = publishedValueFallback; + } // properties [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] [ImplementPropertyType(""foo"")] - public global::System.Collections.Generic.IEnumerable Foo => this.Value>(""foo""); + public global::System.Collections.Generic.IEnumerable Foo => this.Value>(_publishedValueFallback, ""foo""); } } "; @@ -259,7 +266,8 @@ namespace Umbraco.Web.PublishedModels { }; - var builder = new TextBuilder(Mock.Of(), types); + var modelsBuilderConfig = new ModelsBuilderConfigBuilder().Build(); + var builder = new TextBuilder(modelsBuilderConfig, types); builder.ModelsNamespace = "Umbraco.ModelsBuilder.Models"; // forces conflict with Umbraco.ModelsBuilder.Umbraco var btypes = builder.TypeModels; diff --git a/src/Umbraco.Tests/ModelsBuilder/StringExtensions.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/ModelsBuilder/StringExtensions.cs similarity index 100% rename from src/Umbraco.Tests/ModelsBuilder/StringExtensions.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/ModelsBuilder/StringExtensions.cs diff --git a/src/Umbraco.Tests/ModelsBuilder/UmbracoApplicationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/ModelsBuilder/UmbracoApplicationTests.cs similarity index 100% rename from src/Umbraco.Tests/ModelsBuilder/UmbracoApplicationTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/ModelsBuilder/UmbracoApplicationTests.cs diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj index 2cbf1549dd..a0be703791 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj @@ -7,6 +7,7 @@ + @@ -16,8 +17,9 @@ - + - + + diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs index 4c038a58e6..97a90be908 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/UsersControllerUnitTests.cs @@ -15,14 +15,14 @@ namespace Umbraco.Tests.Web.Controllers { [Test,AutoMoqData] public void PostUnlockUsers_When_User_Lockout_Update_Fails_Expect_Failure_Response( - [Frozen] IUserStore userStore, + [Frozen] IBackOfficeUserManager backOfficeUserManager, UsersController sut, BackOfficeIdentityUser user, int[] userIds, string expectedMessage) { - Mock.Get(userStore) - .Setup(x => x.FindByIdAsync(It.IsAny(), It.IsAny())) + Mock.Get(backOfficeUserManager) + .Setup(x => x.FindByIdAsync(It.IsAny())) .ReturnsAsync(user); Assert.ThrowsAsync(() => sut.PostUnlockUsers(userIds)); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs index f087a4851c..6c725d1049 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttributeTests.cs @@ -91,16 +91,16 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Filters .SetupGet(x => x.Id) .Returns(100); - var webSecurityMock = new Mock(); - webSecurityMock + var backofficeSecurityMock = new Mock(); + backofficeSecurityMock .SetupGet(x => x.CurrentUser) .Returns(currentUserMock.Object); var serviceProviderMock = new Mock(); serviceProviderMock - .Setup(x => x.GetService(typeof(IWebSecurity))) - .Returns(webSecurityMock.Object); + .Setup(x => x.GetService(typeof(IBackofficeSecurity))) + .Returns(backofficeSecurityMock.Object); httpContext.RequestServices = serviceProviderMock.Object; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs index 54499d97ba..f6e551dc27 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs @@ -8,6 +8,7 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Tests.Common.TestHelpers.Entities; using Umbraco.Web.Actions; @@ -30,7 +31,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of() ); var result = att.GetValueFromResponse(new ObjectResult(expected)); @@ -48,7 +49,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of() ); var result = att.GetValueFromResponse(new ObjectResult(container)); @@ -66,7 +67,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of() ); var actual = att.GetValueFromResponse(new ObjectResult(container)); @@ -94,7 +95,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, userService, entityService, - Mock.Of() ); + Mock.Of() ); var path = ""; for (var i = 0; i < 10; i++) @@ -145,7 +146,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, userService, Mock.Of(), - Mock.Of() ); + Mock.Of() ); att.FilterBasedOnPermissions(list, user); Assert.AreEqual(3, list.Count); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs index c1c331903e..e7cf097dd5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs @@ -5,9 +5,11 @@ using System.Threading.Tasks; using AutoFixture.NUnit3; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Tests.UnitTests.AutoFixture; using Umbraco.Web.BackOffice.Controllers; @@ -53,10 +55,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] [AutoMoqData] public void PreviewViewExists( - [Frozen] IGlobalSettings globalSettings, + [Frozen] IOptions globalSettings, PreviewController sut) { - Mock.Get(globalSettings).Setup(x => x.UmbracoPath).Returns("/"); + globalSettings.Value.UmbracoPath = "/"; var viewResult = sut.Index() as ViewResult; var fileName = GetViewName(viewResult); @@ -69,12 +71,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] [AutoMoqData] public async Task BackOfficeDefaultExists( - [Frozen] IGlobalSettings globalSettings, + [Frozen] IOptions globalSettings, [Frozen] IHostingEnvironment hostingEnvironment, [Frozen] ITempDataDictionary tempDataDictionary, BackOfficeController sut) { - Mock.Get(globalSettings).Setup(x => x.UmbracoPath).Returns("/"); + globalSettings.Value.UmbracoPath = "/"; Mock.Get(hostingEnvironment).Setup(x => x.ToAbsolute("/")).Returns("http://localhost/"); Mock.Get(hostingEnvironment).SetupGet(x => x.ApplicationVirtualPath).Returns("/"); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs index 7d0c3c8e04..2a096bbd47 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using System.Linq; @@ -7,6 +8,7 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Extensions; +using Umbraco.Tests.Common.Builders; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Routing; using Umbraco.Web.Common.Attributes; @@ -94,8 +96,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing private BackOfficeAreaRoutes GetBackOfficeAreaRoutes(RuntimeLevel level) { + var globalSettings = new GlobalSettingsBuilder().Build(); var routes = new BackOfficeAreaRoutes( - Mock.Of(x => x.UmbracoPath == "~/umbraco"), + Options.Create(globalSettings), Mock.Of(x => x.ToAbsolute(It.IsAny()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty), Mock.Of(x => x.Level == level), new UmbracoApiControllerTypeCollection(new[] { typeof(Testing1Controller) })); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs index 7a202d7902..a1904cb0da 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs @@ -3,11 +3,13 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Core.Hosting; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Tests.Common; using Umbraco.Tests.Common.Builders; @@ -38,6 +40,8 @@ namespace Umbraco.Tests.Integration { var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); var globalSettings = new GlobalSettingsBuilder().Build(); var umbracoContextFactory = new UmbracoContextFactory( @@ -45,14 +49,14 @@ namespace Umbraco.Tests.Integration Mock.Of(), new TestVariationContextAccessor(), new TestDefaultCultureAccessor(), - globalSettings, + Options.Create(globalSettings), Mock.Of(), hostingEnvironment, new UriUtility(hostingEnvironment), httpContextAccessor, Mock.Of(), Mock.Of(), - Mock.Of()); + backofficeSecurityAccessor); var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); var umbracoContext = umbracoContextReference.UmbracoContext; @@ -72,20 +76,21 @@ namespace Umbraco.Tests.Integration var globalSettings = new GlobalSettingsBuilder().Build(); var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); - + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); var umbracoContextFactory = new UmbracoContextFactory( _umbracoContextAccessor, Mock.Of(), new TestVariationContextAccessor(), new TestDefaultCultureAccessor(), - globalSettings, + Options.Create(globalSettings), Mock.Of(), hostingEnvironment, new UriUtility(hostingEnvironment), httpContextAccessor, Mock.Of(), Mock.Of(), - Mock.Of()); + backofficeSecurityAccessor); var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); var umbCtx = umbracoContextReference.UmbracoContext; @@ -104,7 +109,8 @@ namespace Umbraco.Tests.Integration publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of()); var content = new Mock(); content.Setup(x => x.Id).Returns(2); - + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); var publishedSnapshotService = new Mock(); var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); @@ -115,14 +121,14 @@ namespace Umbraco.Tests.Integration publishedSnapshotService.Object, new TestVariationContextAccessor(), new TestDefaultCultureAccessor(), - globalSettings, + Options.Create(globalSettings), Mock.Of(), hostingEnvironment, new UriUtility(hostingEnvironment), httpContextAccessor, Mock.Of(), Mock.Of(), - Mock.Of()); + backofficeSecurityAccessor); var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); var umbracoContext = umbracoContextReference.UmbracoContext; @@ -146,20 +152,21 @@ namespace Umbraco.Tests.Integration var globalSettings = new GlobalSettingsBuilder().Build(); var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); - + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); var umbracoContextFactory = new UmbracoContextFactory( _umbracoContextAccessor, Mock.Of(), new TestVariationContextAccessor(), new TestDefaultCultureAccessor(), - globalSettings, + Options.Create(globalSettings), Mock.Of(), hostingEnvironment, new UriUtility(hostingEnvironment), httpContextAccessor, Mock.Of(), Mock.Of(), - Mock.Of()); + backofficeSecurityAccessor); var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); var umbracoContext = umbracoContextReference.UmbracoContext; diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index 09c025aeb4..2781babfbe 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -16,7 +16,7 @@ - + diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index 932a974b75..02f6f24779 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -5,9 +5,11 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Services; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -58,7 +60,7 @@ namespace Umbraco.Tests.Cache.PublishedCache _httpContextFactory = new FakeHttpContextFactory("~/Home"); - var globalSettings = Factory.GetInstance(); + var globalSettings = new GlobalSettingsBuilder().Build(); var umbracoContextAccessor = Factory.GetInstance(); _xml = new XmlDocument(); @@ -79,7 +81,7 @@ namespace Umbraco.Tests.Cache.PublishedCache _umbracoContext = new UmbracoContext( httpContextAccessor, publishedSnapshotService.Object, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/Components/ComponentTests.cs b/src/Umbraco.Tests/Components/ComponentTests.cs index a20b220940..e74516dab7 100644 --- a/src/Umbraco.Tests/Components/ComponentTests.cs +++ b/src/Umbraco.Tests/Components/ComponentTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -13,6 +14,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Components @@ -23,7 +25,6 @@ namespace Umbraco.Tests.Components private static readonly List Composed = new List(); private static readonly List Initialized = new List(); private static readonly List Terminated = new List(); - private static readonly Configs Configs = TestHelper.GetConfigs(); private static IFactory MockFactory(Action> setup = null) { @@ -33,11 +34,13 @@ namespace Umbraco.Tests.Components var logger = Mock.Of(); var typeFinder = TestHelper.GetTypeFinder(); - var f = new UmbracoDatabaseFactory(logger, SettingsForTests.DefaultGlobalSettings, Mock.Of(), new Lazy(() => new MapperCollection(Enumerable.Empty())), TestHelper.DbProviderFactoryCreator); - var fs = new FileSystems(mock.Object, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings(), TestHelper.GetHostingEnvironment()); - var coreDebug = Mock.Of(); + var globalSettings = new GlobalSettingsBuilder().Build(); + var connectionStrings = new ConnectionStringsBuilder().Build(); + var f = new UmbracoDatabaseFactory(logger, Options.Create(globalSettings), Options.Create(connectionStrings), new Lazy(() => new MapperCollection(Enumerable.Empty())), TestHelper.DbProviderFactoryCreator); + var fs = new FileSystems(mock.Object, logger, TestHelper.IOHelper, Options.Create(globalSettings), TestHelper.GetHostingEnvironment()); + var coreDebug = new CoreDebugSettingsBuilder().Build(); var mediaFileSystem = Mock.Of(); - var p = new ScopeProvider(f, fs, coreDebug, mediaFileSystem, logger, typeFinder, NoAppCache.Instance); + var p = new ScopeProvider(f, fs, Microsoft.Extensions.Options.Options.Create(coreDebug), mediaFileSystem, logger, typeFinder, NoAppCache.Instance); mock.Setup(x => x.GetInstance(typeof (ILogger))).Returns(logger); mock.Setup(x => x.GetInstance(typeof (IProfilingLogger))).Returns(new ProfilingLogger(Mock.Of(), Mock.Of())); @@ -71,7 +74,7 @@ namespace Umbraco.Tests.Components { var register = MockRegister(); var typeLoader = MockTypeLoader(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -110,7 +113,7 @@ namespace Umbraco.Tests.Components public void Boot1B() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); var types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -126,7 +129,7 @@ namespace Umbraco.Tests.Components public void Boot2() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -141,7 +144,7 @@ namespace Umbraco.Tests.Components public void Boot3() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -158,7 +161,7 @@ namespace Umbraco.Tests.Components public void BrokenRequire() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -181,7 +184,7 @@ namespace Umbraco.Tests.Components public void BrokenRequired() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = TypeArray(); var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -217,7 +220,7 @@ namespace Umbraco.Tests.Components throw new NotSupportedException(type.FullName); }); }); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer1), typeof(Composer5), typeof(Composer5a) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -243,7 +246,7 @@ namespace Umbraco.Tests.Components public void Requires1() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer6), typeof(Composer7), typeof(Composer8) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -258,7 +261,7 @@ namespace Umbraco.Tests.Components public void Requires2A() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), Configs, TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -276,7 +279,7 @@ namespace Umbraco.Tests.Components var register = MockRegister(); var typeLoader = MockTypeLoader(); var factory = MockFactory(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Run), Configs, TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -295,7 +298,7 @@ namespace Umbraco.Tests.Components public void WeakDependencies() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), Configs, TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer10) }; var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -334,7 +337,7 @@ namespace Umbraco.Tests.Components public void DisableMissing() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), Configs, TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer6), typeof(Composer8) }; // 8 disables 7 which is not in the list var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); @@ -349,7 +352,7 @@ namespace Umbraco.Tests.Components public void AttributesPriorities() { var register = MockRegister(); - var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), Configs, TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, MockTypeLoader(), Mock.Of(), MockRuntimeState(RuntimeLevel.Unknown), TestHelper.IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer26) }; var enableDisableAttributes = new[] { new DisableComposerAttribute(typeof(Composer26)) }; @@ -376,7 +379,7 @@ namespace Umbraco.Tests.Components var register = MockRegister(); var composition = new Composition(register, typeLoader, Mock.Of(), - MockRuntimeState(RuntimeLevel.Run), Configs, TestHelper.IOHelper, AppCaches.NoCache); + MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); var allComposers = typeLoader.GetTypes().ToList(); var types = allComposers.Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web")).ToList(); diff --git a/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs b/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs index 2d977e89c7..4986c3ac53 100644 --- a/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs +++ b/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs @@ -24,7 +24,7 @@ namespace Umbraco.Tests.Composing Current.Reset(); var register = TestHelper.GetRegister(); - _composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + _composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); } [TearDown] @@ -490,7 +490,7 @@ namespace Umbraco.Tests.Composing for (var i = 0; i < col1A.Length; i++) { Assert.AreNotSame(col1A[i], col2A[i]); - } + } } #endregion diff --git a/src/Umbraco.Tests/Composing/CompositionTests.cs b/src/Umbraco.Tests/Composing/CompositionTests.cs index 380511eaaa..229ba1102b 100644 --- a/src/Umbraco.Tests/Composing/CompositionTests.cs +++ b/src/Umbraco.Tests/Composing/CompositionTests.cs @@ -41,7 +41,7 @@ namespace Umbraco.Tests.Composing var typeFinder = TestHelper.GetTypeFinder(); var ioHelper = TestHelper.IOHelper; var typeLoader = new TypeLoader(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); + var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); // create the factory, ensure it is the mocked factory var factory = composition.CreateFactory(); diff --git a/src/Umbraco.Tests/Composing/LazyCollectionBuilderTests.cs b/src/Umbraco.Tests/Composing/LazyCollectionBuilderTests.cs index 4d0135d6c4..c17e80a34a 100644 --- a/src/Umbraco.Tests/Composing/LazyCollectionBuilderTests.cs +++ b/src/Umbraco.Tests/Composing/LazyCollectionBuilderTests.cs @@ -41,7 +41,7 @@ namespace Umbraco.Tests.Composing public void LazyCollectionBuilderHandlesTypes() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add() @@ -67,7 +67,7 @@ namespace Umbraco.Tests.Composing public void LazyCollectionBuilderHandlesProducers() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) }) @@ -92,7 +92,7 @@ namespace Umbraco.Tests.Composing public void LazyCollectionBuilderHandlesTypesAndProducers() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add() @@ -118,7 +118,7 @@ namespace Umbraco.Tests.Composing public void LazyCollectionBuilderThrowsOnIllegalTypes() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add() @@ -140,7 +140,7 @@ namespace Umbraco.Tests.Composing public void LazyCollectionBuilderCanExcludeTypes() { var container = CreateRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add() diff --git a/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs b/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs index 390997173b..118eaab41a 100644 --- a/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs +++ b/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs @@ -22,7 +22,7 @@ namespace Umbraco.Tests.Composing { var container = TestHelper.GetRegister(); - var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(container, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); var expectedPackageActions = TypeLoader.GetPackageActions(); composition.WithCollectionBuilder() diff --git a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs index 56237f562c..a7b148c8e5 100644 --- a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs +++ b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs @@ -1,7 +1,8 @@ using Moq; using NUnit.Framework; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; +using Umbraco.Core.Configuration.Models; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Hosting; @@ -18,17 +19,14 @@ 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 hostingEnvironment = new AspNetHostingEnvironment(Microsoft.Extensions.Options.Options.Create(new HostingSettings() + { + ApplicationVirtualPath = rootPath + })); - var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); - var mockHostingSettings = Mock.Get(SettingsForTests.GenerateMockHostingSettings()); - mockHostingSettings.Setup(x => x.ApplicationVirtualPath).Returns(rootPath); + var globalSettings = new GlobalSettingsBuilder().WithUmbracoPath(path).Build(); - var hostingEnvironment = new AspNetHostingEnvironment(mockHostingSettings.Object); - - var globalSettingsMock = Mock.Get(globalSettings); - globalSettingsMock.Setup(x => x.UmbracoPath).Returns(() => path); - - Assert.AreEqual(outcome, globalSettingsMock.Object.GetUmbracoMvcAreaNoCache(hostingEnvironment)); + Assert.AreEqual(outcome, globalSettings.GetUmbracoMvcAreaNoCache(hostingEnvironment)); } } } diff --git a/src/Umbraco.Tests/IO/FileSystemsTests.cs b/src/Umbraco.Tests/IO/FileSystemsTests.cs index c1d3fbb331..9d2df22739 100644 --- a/src/Umbraco.Tests/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests/IO/FileSystemsTests.cs @@ -16,6 +16,7 @@ using Umbraco.Tests.TestHelpers; using Umbraco.Core.Composing.CompositionExtensions; using Current = Umbraco.Web.Composing.Current; using FileSystems = Umbraco.Core.IO.FileSystems; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.IO { @@ -30,24 +31,21 @@ namespace Umbraco.Tests.IO { _register = TestHelper.GetRegister(); - var composition = new Composition(_register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(_register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); 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.RegisterUnique(TestHelper.GetHostingEnvironment()); - composition.Configs.Add(() => SettingsForTests.DefaultGlobalSettings); - composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); + var globalSettings = new GlobalSettingsBuilder().Build(); + composition.Register(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); composition.ComposeFileSystems(); - composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); - _factory = composition.CreateFactory(); Current.Reset(); diff --git a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs index 07a04479a4..50ba5a3223 100644 --- a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs +++ b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -10,6 +11,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.IO @@ -436,7 +438,8 @@ namespace Umbraco.Tests.IO var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); var container = Mock.Of(); - var fileSystems = new FileSystems(container, logger, ioHelper, SettingsForTests.GenerateMockGlobalSettings(), TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; + var globalSettings = Options.Create(new GlobalSettingsBuilder().Build()); + var fileSystems = new FileSystems(container, logger, ioHelper, globalSettings, TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem(phy); var sw = (ShadowWrapper) fs.InnerFileSystem; @@ -532,7 +535,8 @@ namespace Umbraco.Tests.IO var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); var container = Mock.Of(); - var fileSystems = new FileSystems(container, logger, ioHelper, SettingsForTests.GenerateMockGlobalSettings(), TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; + var globalSettings = Options.Create(new GlobalSettingsBuilder().Build()); + var fileSystems = new FileSystems(container, logger, ioHelper, globalSettings, TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem( phy); var sw = (ShadowWrapper) fs.InnerFileSystem; @@ -587,7 +591,8 @@ namespace Umbraco.Tests.IO var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); var container = Mock.Of(); - var fileSystems = new FileSystems(container, logger, ioHelper, SettingsForTests.GenerateMockGlobalSettings(), TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; + var globalSettings = Options.Create(new GlobalSettingsBuilder().Build()); + var fileSystems = new FileSystems(container, logger, ioHelper, globalSettings, TestHelper.GetHostingEnvironment()) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem( phy); var sw = (ShadowWrapper)fs.InnerFileSystem; diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs index afdb71c28e..fe02e6fa48 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs @@ -7,6 +7,7 @@ using System.Xml.XPath; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Xml; using Umbraco.Tests.TestHelpers; @@ -18,7 +19,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache internal class PublishedContentCache : PublishedCacheBase, IPublishedContentCache { private readonly IAppCache _appCache; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly RoutesCache _routesCache; private readonly IVariationContextAccessor _variationContextAccessor; private readonly IDomainCache _domainCache; @@ -33,7 +34,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache XmlStore xmlStore, // an XmlStore containing the master xml IDomainCache domainCache, // an IDomainCache implementation IAppCache appCache, // an IAppCache that should be at request-level - IGlobalSettings globalSettings, + GlobalSettings globalSettings, PublishedContentTypeCache contentTypeCache, // a PublishedContentType cache RoutesCache routesCache, // a RoutesCache IVariationContextAccessor variationContextAccessor, diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs index bf7cbe40c4..a913ba06bd 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs @@ -3,6 +3,7 @@ using System.Linq; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -35,7 +36,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache private readonly IMediaService _mediaService; private readonly IUserService _userService; private readonly IAppCache _requestCache; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly ISiteDomainHelper _siteDomainHelper; private readonly IEntityXmlSerializer _entitySerializer; @@ -56,7 +57,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, ILogger logger, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper, @@ -84,7 +85,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, ILogger logger, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper, diff --git a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs index 966c4109c6..90b2da5500 100644 --- a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -42,7 +43,7 @@ namespace Umbraco.Tests.Migrations upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); - var helper = new DatabaseSchemaCreator(scope.Database, logger, UmbracoVersion, TestObjects.GetGlobalSettings()); + var helper = new DatabaseSchemaCreator(scope.Database, logger, UmbracoVersion); var exists = helper.TableExists("umbracoUser"); Assert.IsTrue(exists); diff --git a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs index a9785697f4..31ceb1bdbf 100644 --- a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs @@ -9,10 +9,10 @@ using Umbraco.Core.Logging; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Persistance.SqlCe; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -139,7 +139,7 @@ namespace Umbraco.Tests.Migrations [Test] public void ValidateUmbracoPlan() { - var plan = new UmbracoPlan(TestHelper.GetUmbracoVersion(), SettingsForTests.GenerateMockGlobalSettings()); + var plan = new UmbracoPlan(TestHelper.GetUmbracoVersion()); plan.Validate(); Console.WriteLine(plan.FinalState); Assert.IsFalse(plan.FinalState.IsNullOrWhiteSpace()); diff --git a/src/Umbraco.Tests/Models/ContentExtensionsTests.cs b/src/Umbraco.Tests/Models/ContentExtensionsTests.cs index bab3a540be..1b2f30db16 100644 --- a/src/Umbraco.Tests/Models/ContentExtensionsTests.cs +++ b/src/Umbraco.Tests/Models/ContentExtensionsTests.cs @@ -29,7 +29,6 @@ namespace Umbraco.Tests.Models Composition.ComposeFileSystems(); 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 31e928159b..ca56a25f68 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -4,6 +4,8 @@ using System.Diagnostics; using System.Globalization; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.Options; +using Microsoft.Extensions.Options; using Moq; using Newtonsoft.Json; using Umbraco.Core; @@ -39,7 +41,6 @@ namespace Umbraco.Tests.Models Composition.ComposeFileSystems(); 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 632f433c5b..1a1f854e5e 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -8,7 +8,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -31,10 +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 contentSettings = new ContentSettingsBuilder().Build(); var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, logger, ShortStringHelper); - var ignored = new FileUploadPropertyEditor(Mock.Of(), mediaFileSystem, config, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper); + var ignored = new FileUploadPropertyEditor(Mock.Of(), mediaFileSystem, Microsoft.Extensions.Options.Options.Create(contentSettings), 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/VariationTests.cs b/src/Umbraco.Tests/Models/VariationTests.cs index e67cb10cf1..b8868a8d0d 100644 --- a/src/Umbraco.Tests/Models/VariationTests.cs +++ b/src/Umbraco.Tests/Models/VariationTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; using ILogger = Umbraco.Core.Logging.ILogger; using Current = Umbraco.Web.Composing.Current; @@ -23,9 +24,6 @@ namespace Umbraco.Tests.Models [SetUp] public void SetUp() { - // annoying, but content type wants short string helper ;( - SettingsForTests.Reset(); - // well, this is also annoying, but... // validating a value is performed by its data editor, // based upon the configuration in the data type, so we @@ -33,10 +31,6 @@ namespace Umbraco.Tests.Models Current.Reset(); - var configs = TestHelper.GetConfigs(); - configs.Add(() => SettingsForTests.DefaultGlobalSettings); - configs.Add(SettingsForTests.GenerateMockContentSettings); - _factory = Mock.Of(); var dataTypeService = Mock.Of(); @@ -44,7 +38,7 @@ namespace Umbraco.Tests.Models var dataEditors = new DataEditorCollection(new IDataEditor[] { - new DataEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) { Alias = "editor", ExplicitValueEditor = TestHelper.CreateDataValueEditor("view") } + new DataEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) { Alias = "editor", ExplicitValueEditor = MockedValueEditors.CreateDataValueEditor("view") } }); var propertyEditors = new PropertyEditorCollection(dataEditors); @@ -65,7 +59,7 @@ namespace Umbraco.Tests.Models .Setup(x => x.GetInstance(It.IsAny())) .Returns(x => { - if (x == typeof(Configs)) return configs; + //if (x == typeof(Configs)) return configs; if (x == typeof(PropertyEditorCollection)) return propertyEditors; if (x == typeof(ServiceContext)) return serviceContext; if (x == typeof(ILocalizedTextService)) return serviceContext.LocalizationService; diff --git a/src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs b/src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs deleted file mode 100644 index 5ed96365fd..0000000000 --- a/src/Umbraco.Tests/ModelsBuilder/ConfigTests.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Configuration; -using NUnit.Framework; -using Umbraco.Configuration; -using Umbraco.Configuration.Legacy; -using Umbraco.Core; -using Umbraco.Core.Configuration; - -namespace Umbraco.Tests.ModelsBuilder -{ - [TestFixture] - public class ModelsBuilderConfigTests - { - [Test] - public void Test1() - { - var config = new ModelsBuilderConfig(modelsNamespace: "test1"); - Assert.AreEqual("test1", config.ModelsNamespace); - } - - [Test] - public void Test2() - { - var config = new ModelsBuilderConfig(modelsNamespace: "test2"); - Assert.AreEqual("test2", config.ModelsNamespace); - } - - [Test] - public void DefaultModelsNamespace() - { - var config = new ModelsBuilderConfig(); - Assert.AreEqual(Constants.ModelsBuilder.DefaultModelsNamespace, config.ModelsNamespace); - } - - [TestCase("c:/path/to/root", "~/dir/models", false, "c:\\path\\to\\root\\dir\\models")] - [TestCase("c:/path/to/root", "~/../../dir/models", true, "c:\\path\\dir\\models")] - [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, ModelsBuilderConfigExtensions.GetModelsDirectory(root, config, acceptUnsafe)); - } - - [TestCase("c:/path/to/root", "~/../../dir/models", false)] - [TestCase("c:/path/to/root", "c:/another/path/to/elsewhere", false)] - public void GetModelsDirectoryThrowsTests(string root, string config, bool acceptUnsafe) - { - Assert.Throws(() => - { - var modelsDirectory = ModelsBuilderConfigExtensions.GetModelsDirectory(root, config, acceptUnsafe); - }); - } - } -} diff --git a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs index 6533dd6113..90a352ad39 100644 --- a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs +++ b/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs @@ -6,13 +6,10 @@ using System.Linq; using System.Xml.Linq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Services; -using Umbraco.Tests.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -44,7 +41,7 @@ namespace Umbraco.Tests.Packaging HostingEnvironment, Factory.GetInstance(), Logger, UmbracoVersion, - Factory.GetInstance(), + Microsoft.Extensions.Options.Options.Create(new GlobalSettingsBuilder().Build()), "createdPackages.config", //temp paths tempFolderPath: "~/" + _testBaseFolder + "/temp", diff --git a/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs b/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs index d089c4aaa2..ed1cd5424d 100644 --- a/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs +++ b/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs @@ -18,6 +18,7 @@ using Umbraco.Tests.Services.Importing; using Umbraco.Tests.Testing; using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Packaging { @@ -712,8 +713,9 @@ namespace Umbraco.Tests.Packaging private void AddLanguages() { - var norwegian = new Core.Models.Language(TestObjects.GetGlobalSettings(), "nb-NO"); - var english = new Core.Models.Language(TestObjects.GetGlobalSettings(), "en-GB"); + var globalSettings = new GlobalSettingsBuilder().Build(); + var norwegian = new Core.Models.Language(globalSettings, "nb-NO"); + var english = new Core.Models.Language(globalSettings, "en-GB"); ServiceContext.LocalizationService.Save(norwegian, 0); ServiceContext.LocalizationService.Save(english, 0); } diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index 90db389002..3b4edd28c1 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -16,6 +16,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using File = System.IO.File; @@ -46,7 +47,11 @@ namespace Umbraco.Tests.Packaging _testBaseFolder.Delete(true); } - private CompiledPackageXmlParser Parser => new CompiledPackageXmlParser(new ConflictingPackageData(ServiceContext.MacroService, ServiceContext.FileService),Factory.GetInstance()); + private CompiledPackageXmlParser Parser => new CompiledPackageXmlParser( + new ConflictingPackageData( + ServiceContext.MacroService, + ServiceContext.FileService), + Microsoft.Extensions.Options.Options.Create(new GlobalSettingsBuilder().Build())); private PackageDataInstallation PackageDataInstallation => new PackageDataInstallation( Logger, ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, @@ -55,9 +60,8 @@ namespace Umbraco.Tests.Packaging Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - Factory.GetInstance(), - Factory.GetInstance() - ); + Microsoft.Extensions.Options.Options.Create(new GlobalSettingsBuilder().Build()), + Factory.GetInstance()); private IPackageInstallation PackageInstallation => new PackageInstallation( PackageDataInstallation, diff --git a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs index ba9bd19db5..7483b5c611 100644 --- a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs +++ b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs @@ -3,6 +3,7 @@ using System.Configuration; using System.Data.SqlServerCe; using System.IO; using System.Threading; +using Microsoft.Extensions.Options; using Moq; using NPoco; using NUnit.Framework; @@ -15,6 +16,7 @@ using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Services; using Umbraco.Persistance.SqlCe; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Security; @@ -38,9 +40,9 @@ namespace Umbraco.Tests.Persistence _sqlSyntaxProviders = new[] { (ISqlSyntaxProvider) _sqlCeSyntaxProvider }; _logger = Mock.Of(); _umbracoVersion = TestHelper.GetUmbracoVersion(); - var globalSettings = TestHelper.GetConfigs().Global(); - var connectionStrings = TestHelper.GetConfigs().ConnectionStrings(); - _databaseFactory = new UmbracoDatabaseFactory(_logger, globalSettings, connectionStrings, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); + var globalSettings = new GlobalSettingsBuilder().Build(); + var connectionStrings = new ConnectionStringsBuilder().Build(); + _databaseFactory = new UmbracoDatabaseFactory(_logger, Options.Create(globalSettings), Options.Create(connectionStrings), new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); } [TearDown] @@ -94,7 +96,7 @@ namespace Umbraco.Tests.Persistence using (var database = _databaseFactory.CreateDatabase()) using (var transaction = database.GetTransaction()) { - schemaHelper = new DatabaseSchemaCreator(database, _logger, _umbracoVersion, SettingsForTests.GenerateMockGlobalSettings()); + schemaHelper = new DatabaseSchemaCreator(database, _logger, _umbracoVersion); schemaHelper.InitializeDatabaseSchema(); transaction.Complete(); } diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs index 53a632132d..0d6797bd9c 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -1,15 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -21,21 +24,25 @@ namespace Umbraco.Tests.Persistence.Repositories [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class ContentTypeRepositoryTest : TestWithDatabaseBase { + private IOptions _globalSettings; + public override void SetUp() { base.SetUp(); CreateTestData(); + + _globalSettings = Microsoft.Extensions.Options.Options.Create(new GlobalSettingsBuilder().Build()); } private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository) { - var langRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger,TestObjects.GetGlobalSettings()); + var langRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, _globalSettings); var templateRepository = new TemplateRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepository = new TagRepository(scopeAccessor, AppCaches.Disabled, Logger); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches.Disabled, ShortStringHelper); contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository, langRepository, ShortStringHelper); - var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, _globalSettings); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(scopeAccessor); var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository); @@ -47,7 +54,7 @@ namespace Umbraco.Tests.Persistence.Repositories private ContentTypeRepository CreateRepository(IScopeAccessor scopeAccessor) { - var langRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + var langRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, _globalSettings); var templateRepository = new TemplateRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches.Disabled, ShortStringHelper); var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository, langRepository, ShortStringHelper); @@ -58,7 +65,7 @@ namespace Umbraco.Tests.Persistence.Repositories { var templateRepository = new TemplateRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches.Disabled, ShortStringHelper); - var langRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + var langRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, _globalSettings); var contentTypeRepository = new MediaTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository, langRepository, ShortStringHelper); return contentTypeRepository; } diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index fe59e431ec..03cfe1af53 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -20,6 +20,7 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Tests.Testing; using Umbraco.Web.PropertyEditors; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Persistence.Repositories { @@ -62,12 +63,14 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository, AppCaches appCaches = null) { + var globalSettings = Microsoft.Extensions.Options.Options.Create(new GlobalSettingsBuilder().Build()); + appCaches = appCaches ?? AppCaches; templateRepository = new TemplateRepository(scopeAccessor, appCaches, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger, globalSettings); contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(scopeAccessor); diff --git a/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs index 91d129aeeb..c3bf9db5de 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -21,11 +22,13 @@ namespace Umbraco.Tests.Persistence.Repositories { private DomainRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository, out DocumentRepository documentRepository, out LanguageRepository languageRepository) { + var globalSettings = Microsoft.Extensions.Options.Options.Create(new GlobalSettingsBuilder().Build()); + var accessor = (IScopeAccessor) provider; var templateRepository = new TemplateRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepository = new TagRepository(accessor, Core.Cache.AppCaches.Disabled, Logger); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - languageRepository = new LanguageRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + languageRepository = new LanguageRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, globalSettings); contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(accessor); @@ -48,7 +51,8 @@ namespace Umbraco.Tests.Persistence.Repositories var repo = CreateRepository(provider, out contentTypeRepo, out documentRepo, out langRepo); - var lang = new Language(TestObjects.GetGlobalSettings(), isoName); + var globalSettings = new GlobalSettingsBuilder().Build(); + var lang = new Language(globalSettings, isoName); langRepo.Save(lang); ct = MockedContentTypes.CreateBasicContentType("test", "Test"); @@ -203,7 +207,8 @@ namespace Umbraco.Tests.Persistence.Repositories //more test data var lang1 = langRepo.GetByIsoCode("en-AU"); - var lang2 = new Language(TestObjects.GetGlobalSettings(), "es"); + var globalSettings = new GlobalSettingsBuilder().Build(); + var lang2 = new Language(globalSettings, "es"); langRepo.Save(lang2); var content2 = new Content("test", -1, ct) { CreatorId = 0, WriterId = 0 }; documentRepo.Save(content2); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs index 83572180af..119a207cb9 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs @@ -16,6 +16,7 @@ using Umbraco.Tests.Testing; using Umbraco.Core.Services; using Umbraco.Core; using Umbraco.Core.PropertyEditors; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Persistence.Repositories { @@ -34,10 +35,10 @@ namespace Umbraco.Tests.Persistence.Repositories { appCaches = appCaches ?? AppCaches; var scopeAccessor = (IScopeAccessor) provider; - + var globalSettings = new GlobalSettingsBuilder().Build(); var templateRepository = new TemplateRepository(scopeAccessor, appCaches, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, Logger, commonRepository, languageRepository, ShortStringHelper); var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs index 6ffbdaca10..fac2a6665a 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -21,9 +22,10 @@ namespace Umbraco.Tests.Persistence.Repositories private MediaTypeRepository CreateRepository(IScopeProvider provider) { var cacheHelper = AppCaches.Disabled; + var globalSettings = new GlobalSettingsBuilder().Build(); var templateRepository = new TemplateRepository((IScopeAccessor)provider, cacheHelper, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); return new MediaTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); } diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index b8c823f59e..37d5260dc0 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -30,9 +31,10 @@ namespace Umbraco.Tests.Persistence.Repositories private MemberRepository CreateRepository(IScopeProvider provider, out MemberTypeRepository memberTypeRepository, out MemberGroupRepository memberGroupRepository) { var accessor = (IScopeAccessor) provider; + var globalSettings = new GlobalSettingsBuilder().Build(); var templateRepository = Mock.Of(); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); memberTypeRepository = new MemberTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); memberGroupRepository = new MemberGroupRepository(accessor, AppCaches.Disabled, Logger); var tagRepo = new TagRepository(accessor, AppCaches.Disabled, Logger); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs index b8c60f97fe..be32305cfc 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -23,8 +24,9 @@ namespace Umbraco.Tests.Persistence.Repositories private MemberTypeRepository CreateRepository(IScopeProvider provider) { var templateRepository = Mock.Of(); + var globalSettings = new GlobalSettingsBuilder().Build(); var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches.Disabled, Mock.Of(), TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches.Disabled, Mock.Of(), Microsoft.Extensions.Options.Options.Create(globalSettings)); return new MemberTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of(), commonRepository, languageRepository, ShortStringHelper); } diff --git a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs index 4ba2c3eab6..b31d490578 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -306,10 +307,11 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; + var globalSettings = new GlobalSettingsBuilder().Build(); var templateRepository = new TemplateRepository(accessor, AppCaches, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepository = new TagRepository(accessor, AppCaches, Logger); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches, Logger); var entityRepository = new EntityRepository(accessor); diff --git a/src/Umbraco.Tests/Persistence/Repositories/ScriptRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ScriptRepositoryTest.cs index 7922af99b0..6a45dafa54 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ScriptRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ScriptRepositoryTest.cs @@ -7,12 +7,14 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -30,7 +32,7 @@ namespace Umbraco.Tests.Persistence.Repositories base.SetUp(); _fileSystems = Mock.Of(); - _fileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, SettingsForTests.GenerateMockGlobalSettings().UmbracoScriptsPath); + _fileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, new GlobalSettings().UmbracoScriptsPath); Mock.Get(_fileSystems).Setup(x => x.ScriptsFileSystem).Returns(_fileSystem); using (var stream = CreateStream("Umbraco.Sys.registerNamespace(\"Umbraco.Utils\");")) { @@ -40,7 +42,8 @@ namespace Umbraco.Tests.Persistence.Repositories private IScriptRepository CreateRepository() { - return new ScriptRepository(_fileSystems, IOHelper, TestObjects.GetGlobalSettings()); + var globalSettings = new GlobalSettingsBuilder().Build(); + return new ScriptRepository(_fileSystems, IOHelper, Microsoft.Extensions.Options.Options.Create(globalSettings)); } protected override void Compose() diff --git a/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs index f4558dca2d..028f99f89e 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs @@ -8,10 +8,12 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -29,7 +31,7 @@ namespace Umbraco.Tests.Persistence.Repositories base.SetUp(); _fileSystems = Mock.Of(); - _fileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, SettingsForTests.GenerateMockGlobalSettings().UmbracoCssPath); + _fileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, new GlobalSettings().UmbracoCssPath); Mock.Get(_fileSystems).Setup(x => x.StylesheetsFileSystem).Returns(_fileSystem); var stream = CreateStream("body {background:#EE7600; color:#FFF;}"); _fileSystem.AddFile("styles.css", stream); @@ -37,7 +39,8 @@ namespace Umbraco.Tests.Persistence.Repositories private IStylesheetRepository CreateRepository() { - return new StylesheetRepository(_fileSystems, IOHelper, TestObjects.GetGlobalSettings()); + var globalSettings = new GlobalSettingsBuilder().Build(); + return new StylesheetRepository(_fileSystems, IOHelper, Microsoft.Extensions.Options.Options.Create(globalSettings)); } [Test] diff --git a/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs index d4341cd128..913fc876fe 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -955,10 +956,11 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateDocumentRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; + var globalSettings = new GlobalSettingsBuilder().Build(); var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches.Disabled, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(accessor); @@ -972,10 +974,11 @@ namespace Umbraco.Tests.Persistence.Repositories private MediaRepository CreateMediaRepository(IScopeProvider provider, out MediaTypeRepository mediaTypeRepository) { var accessor = (IScopeAccessor) provider; + var globalSettings = new GlobalSettingsBuilder().Build(); var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches.Disabled, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(accessor); diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index fc7f4f4555..448fce9579 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -1,20 +1,21 @@ -using System.Linq; +using System; +using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -using Umbraco.Core.PropertyEditors; -using System; -using Umbraco.Core.Configuration; -using Umbraco.Core.Serialization; using MockedUser = Umbraco.Tests.TestHelpers.Entities.MockedUser; namespace Umbraco.Tests.Persistence.Repositories @@ -28,9 +29,10 @@ namespace Umbraco.Tests.Persistence.Repositories private MediaRepository CreateMediaRepository(IScopeProvider provider, out IMediaTypeRepository mediaTypeRepository) { var accessor = (IScopeAccessor) provider; + var globalSettings = new GlobalSettingsBuilder().Build(); var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches, Mock.Of(), commonRepository, languageRepository, ShortStringHelper); var tagRepository = new TagRepository(accessor, AppCaches, Mock.Of()); var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); @@ -52,10 +54,11 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateContentRepository(IScopeProvider provider, out IContentTypeRepository contentTypeRepository, out ITemplateRepository templateRepository) { var accessor = (IScopeAccessor) provider; + var globalSettings = new GlobalSettingsBuilder().Build(); templateRepository = new TemplateRepository(accessor, AppCaches, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepository = new TagRepository(accessor, AppCaches, Logger); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(accessor); @@ -69,7 +72,8 @@ namespace Umbraco.Tests.Persistence.Repositories private UserRepository CreateRepository(IScopeProvider provider) { var accessor = (IScopeAccessor) provider; - var repository = new UserRepository(accessor, AppCaches.Disabled, Logger, Mappers, TestObjects.GetGlobalSettings(), Mock.Of(), new JsonNetSerializer()); + var globalSettings = new GlobalSettingsBuilder().Build(); + var repository = new UserRepository(accessor, AppCaches.Disabled, Logger, Mappers, Microsoft.Extensions.Options.Options.Create(globalSettings), Microsoft.Extensions.Options.Options.Create(new UserPasswordConfigurationSettings()), new JsonNetSerializer()); return repository; } diff --git a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs index 0648e3bc21..704d64823c 100644 --- a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs +++ b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -22,7 +23,7 @@ namespace Umbraco.Tests.Persistence using (var scope = ScopeProvider.CreateScope()) { - var schema = new DatabaseSchemaCreator(scope.Database, Logger, UmbracoVersion, TestObjects.GetGlobalSettings()); + var schema = new DatabaseSchemaCreator(scope.Database, Logger, UmbracoVersion); result = schema.ValidateSchema( //TODO: When we remove the xml cache from tests we can remove this too DatabaseSchemaCreator.OrderedTables.Concat(new []{typeof(ContentXmlDto), typeof(PreviewXmlDto)})); diff --git a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs index 207e595598..1fe7153dd0 100644 --- a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs @@ -2,10 +2,12 @@ using NPoco; using NUnit.Framework; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -16,14 +18,14 @@ namespace Umbraco.Tests.Persistence [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class SqlCeTableByTableTest : TestWithDatabaseBase { - public IGlobalSettings GlobalSettings => SettingsForTests.GenerateMockGlobalSettings(); + public GlobalSettings GlobalSettings => new GlobalSettingsBuilder().Build(); [Test] public void Can_Create_umbracoNode_Table() { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); @@ -36,7 +38,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -50,7 +52,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -65,7 +67,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -79,7 +81,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -94,7 +96,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -108,7 +110,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -124,7 +126,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -140,7 +142,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -154,7 +156,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); @@ -167,7 +169,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -182,7 +184,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -196,7 +198,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -213,7 +215,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -229,7 +231,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -243,7 +245,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); @@ -256,7 +258,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); @@ -269,7 +271,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); @@ -282,7 +284,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -298,7 +300,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -315,7 +317,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -330,7 +332,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -347,7 +349,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -365,7 +367,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -382,7 +384,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -397,7 +399,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -412,7 +414,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); @@ -425,7 +427,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); @@ -438,7 +440,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -459,7 +461,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); @@ -472,7 +474,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -486,7 +488,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -500,7 +502,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -515,7 +517,7 @@ namespace Umbraco.Tests.Persistence { using (var scope = ScopeProvider.CreateScope()) { - var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion, GlobalSettings); + var helper = new DatabaseSchemaCreator(scope.Database, Mock.Of(), UmbracoVersion); helper.CreateTable(); helper.CreateTable(); diff --git a/src/Umbraco.Tests/Published/ConvertersTests.cs b/src/Umbraco.Tests/Published/ConvertersTests.cs index 3ecae51ea8..21f7be9a54 100644 --- a/src/Umbraco.Tests/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests/Published/ConvertersTests.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -15,165 +16,13 @@ using Umbraco.Core.Strings; using Umbraco.Tests.Components; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Web; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Published { [TestFixture] - public class ConvertersTests : UmbracoTestBase + public class ConvertersTests { - #region SimpleConverter1 - - [Test] - public void SimpleConverter1Test() - { - var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] - { - new SimpleConverter1(), - }); - - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); - - var contentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); - - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) - { - yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); - } - - var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); - - var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); - - Assert.AreEqual(1234, element1.Value("prop1")); - - // 'null' would be considered a 'missing' value by the default, magic logic - var e = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", null } }, false); - Assert.IsFalse(e.HasValue("prop1")); - - // '0' would not - it's a valid integer - but the converter knows better - e = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "0" } }, false); - Assert.IsFalse(e.HasValue("prop1")); - } - - private class SimpleConverter1 : IPropertyValueConverter - { - public bool? IsValue(object value, PropertyValueLevel level) - { - switch (level) - { - case PropertyValueLevel.Source: - return null; - case PropertyValueLevel.Inter: - return value is int ivalue && ivalue != 0; - default: - throw new NotSupportedException($"Invalid level: {level}."); - } - } - - public bool IsConverter(IPublishedPropertyType propertyType) - => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); - - public Type GetPropertyValueType(IPublishedPropertyType propertyType) - => typeof(int); - - public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) - => PropertyCacheLevel.Element; - - public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) - => int.TryParse(source as string, out int i) ? i : 0; - - public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => (int)inter; - - public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => ((int)inter).ToString(); - } - - #endregion - - #region SimpleConverter2 - - [Test] - public void SimpleConverter2Test() - { - var cacheMock = new Mock(); - var cacheContent = new Dictionary(); - cacheMock.Setup(x => x.GetById(It.IsAny())).Returns(id => cacheContent.TryGetValue(id, out IPublishedContent content) ? content : null); - var publishedSnapshotMock = new Mock(); - publishedSnapshotMock.Setup(x => x.Content).Returns(cacheMock.Object); - var publishedSnapshotAccessorMock = new Mock(); - publishedSnapshotAccessorMock.Setup(x => x.PublishedSnapshot).Returns(publishedSnapshotMock.Object); - var publishedSnapshotAccessor = publishedSnapshotAccessorMock.Object; - - var converters = new PropertyValueConverterCollection(new IPropertyValueConverter[] - { - new SimpleConverter2(publishedSnapshotAccessor), - }); - - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); - - var contentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); - - IEnumerable CreatePropertyTypes(IPublishedContentType contentType) - { - yield return contentTypeFactory.CreatePropertyType(contentType, "prop1", 1); - } - - var elementType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1000, "element1", CreatePropertyTypes); - - var element1 = new PublishedElement(elementType1, Guid.NewGuid(), new Dictionary { { "prop1", "1234" } }, false); - - var cntType1 = contentTypeFactory.CreateContentType(Guid.NewGuid(), 1001, "cnt1", t => Enumerable.Empty()); - var cnt1 = new SolidPublishedContent(cntType1) { Id = 1234 }; - cacheContent[cnt1.Id] = cnt1; - - Assert.AreSame(cnt1, element1.Value("prop1")); - } - - private class SimpleConverter2 : IPropertyValueConverter - { - private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - private readonly PropertyCacheLevel _cacheLevel; - - public SimpleConverter2(IPublishedSnapshotAccessor publishedSnapshotAccessor, PropertyCacheLevel cacheLevel = PropertyCacheLevel.None) - { - _publishedSnapshotAccessor = publishedSnapshotAccessor; - _cacheLevel = cacheLevel; - } - - public bool? IsValue(object value, PropertyValueLevel level) - => value != null && (!(value is string) || string.IsNullOrWhiteSpace((string)value) == false); - - public bool IsConverter(IPublishedPropertyType propertyType) - => propertyType.EditorAlias.InvariantEquals("Umbraco.Void"); - - public Type GetPropertyValueType(IPublishedPropertyType propertyType) - // the first version would be the "generic" version, but say we want to be more precise - // and return: whatever Clr type is generated for content type with alias "cnt1" -- which - // we cannot really typeof() at the moment because it has not been generated, hence ModelType. - // => typeof (IPublishedContent); - => ModelType.For("cnt1"); - - public PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) - => _cacheLevel; - - public object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview) - => int.TryParse(source as string, out int i) ? i : -1; - - public object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById((int)inter); - - public object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) - => ((int)inter).ToString(); - } - - #endregion - #region SimpleConverter3 [Test] @@ -182,7 +31,7 @@ namespace Umbraco.Tests.Published // Current.Reset(); var register = TestHelper.GetRegister(); - var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), Mock.Of(), AppCaches.NoCache); composition.WithCollectionBuilder() .Append() @@ -192,7 +41,7 @@ namespace Umbraco.Tests.Published { typeof (PublishedSnapshotTestObjects.TestElementModel1), typeof (PublishedSnapshotTestObjects.TestElementModel2), typeof (PublishedSnapshotTestObjects.TestContentModel1), typeof (PublishedSnapshotTestObjects.TestContentModel2), - }); + }, Mock.Of()); register.Register(f => factory); var registerFactory = composition.CreateFactory(); @@ -208,11 +57,17 @@ namespace Umbraco.Tests.Published var converters = registerFactory.GetInstance(); - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }, - new DataType(new VoidEditor("2", Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of(), Mock.Of())) { Id = 2 }); + var dataTypeServiceMock = new Mock(); + var dataType1 = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + var dataType2 = new DataType(new VoidEditor("2", Mock.Of(), Mock.Of(), + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 2 }; - var contentTypeFactory = new PublishedContentTypeFactory(factory, converters, dataTypeService); + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new []{dataType1, dataType2 }); + + var contentTypeFactory = new PublishedContentTypeFactory(factory, converters, dataTypeServiceMock.Object); IEnumerable CreatePropertyTypes(IPublishedContentType contentType, int i) { @@ -258,8 +113,8 @@ namespace Umbraco.Tests.Published var mmodel2 = (PublishedSnapshotTestObjects.TestElementModel2)model2; // and get direct property - Assert.IsInstanceOf(model2.Value("prop2")); - Assert.AreEqual(1, ((PublishedSnapshotTestObjects.TestContentModel1[])model2.Value("prop2")).Length); + Assert.IsInstanceOf(model2.Value(Mock.Of(), "prop2")); + Assert.AreEqual(1, ((PublishedSnapshotTestObjects.TestContentModel1[])model2.Value(Mock.Of(), "prop2")).Length); // and get model property Assert.IsInstanceOf>(mmodel2.Prop2); diff --git a/src/Umbraco.Tests/Published/ModelTypeTests.cs b/src/Umbraco.Tests/Published/ModelTypeTests.cs index f698c20fa2..43639c88a1 100644 --- a/src/Umbraco.Tests/Published/ModelTypeTests.cs +++ b/src/Umbraco.Tests/Published/ModelTypeTests.cs @@ -8,38 +8,21 @@ namespace Umbraco.Tests.Published [TestFixture] public class ModelTypeTests { - [Test] - public void ModelTypeEqualityTests() - { - Assert.AreNotEqual(ModelType.For("alias1"), ModelType.For("alias1")); - - Assert.IsTrue(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias1"))); - Assert.IsFalse(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias2"))); - - Assert.IsTrue(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")))); - Assert.IsFalse(ModelType.Equals(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias2")))); - - Assert.IsTrue(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias1").MakeArrayType())); - Assert.IsFalse(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias2").MakeArrayType())); - } + //TODO these is not easy to move to the Unittest project due to underlysing NotImplementedException of Type.IsSZArray [Test] public void ModelTypeToStringTests() { - Assert.AreEqual("{alias1}", ModelType.For("alias1").ToString()); + var modelType = ModelType.For("alias1"); + var modelTypeArray = modelType.MakeArrayType(); + + Assert.AreEqual("{alias1}", modelType.ToString()); // there's an "*" there because the arrays are not true SZArray - but that changes when we map - Assert.AreEqual("{alias1}[*]", ModelType.For("alias1").MakeArrayType().ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[{alias1}[*]]", typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()).ToString()); - } - [Test] - public void TypeToStringTests() - { - var type = typeof(int); - Assert.AreEqual("System.Int32", type.ToString()); - Assert.AreEqual("System.Int32[]", type.MakeArrayType().ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[System.Int32[]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).ToString()); + Assert.AreEqual("{alias1}[*]", modelTypeArray.ToString()); + var enumArray = typeof(IEnumerable<>).MakeGenericType(modelTypeArray); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[{alias1}[*]]", enumArray.ToString()); } [Test] @@ -56,33 +39,5 @@ namespace Umbraco.Tests.Published Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[{alias1}[*], Umbraco.Core, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null]]", typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()).FullName); } - [Test] - public void TypeFullNameTests() - { - var type = typeof(int); - Assert.AreEqual("System.Int32", type.FullName); - Assert.AreEqual("System.Int32[]", type.MakeArrayType().FullName); - // note the inner assembly qualified name - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.Int32[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", typeof(IEnumerable<>).MakeGenericType(type.MakeArrayType()).FullName); - } - - [Test] - public void ModelTypeMapTests() - { - var map = new Dictionary - { - { "alias1", typeof (PublishedSnapshotTestObjects.TestElementModel1) }, - { "alias2", typeof (PublishedSnapshotTestObjects.TestElementModel2) }, - }; - - Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1", - ModelType.Map(ModelType.For("alias1"), map).ToString()); - Assert.AreEqual("Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]", - ModelType.Map(ModelType.For("alias1").MakeArrayType(), map).ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1]", - ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), map).ToString()); - Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.Published.PublishedSnapshotTestObjects+TestElementModel1[]]", - ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()), map).ToString()); - } } } diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs index f0aa39fcf8..42eb083667 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs @@ -2,16 +2,13 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Microsoft.Extensions.Options; using Moq; 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; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -22,7 +19,7 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; using Umbraco.Tests.Common; -using Umbraco.Tests.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; @@ -60,12 +57,7 @@ namespace Umbraco.Tests.PublishedContent var factory = Mock.Of(); Current.Factory = factory; - var configs = TestHelper.GetConfigs(); - Mock.Get(factory).Setup(x => x.GetInstance(typeof(Configs))).Returns(configs); - var globalSettings = new GlobalSettings(); var hostingEnvironment = Mock.Of(); - configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); - configs.Add(() => globalSettings); Mock.Get(factory).Setup(x => x.GetInstance(typeof(IPublishedModelFactory))).Returns(PublishedModelFactory); @@ -145,8 +137,9 @@ namespace Umbraco.Tests.PublishedContent _source = new TestDataSource(kits()); var typeFinder = TestHelper.GetTypeFinder(); - var settings = Mock.Of(); + var globalSettings = new GlobalSettingsBuilder().Build(); + var nuCacheSettings = new NuCacheSettingsBuilder().Build(); // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; @@ -164,14 +157,14 @@ namespace Umbraco.Tests.PublishedContent Mock.Of(), new TestDefaultCultureAccessor(), _source, - globalSettings, + Options.Create(globalSettings), Mock.Of(), PublishedModelFactory, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), hostingEnvironment, - new MockShortStringHelper(), + Mock.Of(), TestHelper.IOHelper, - settings); + Options.Create(nuCacheSettings)); // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index 8003bdf236..f21ad1a3db 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -6,10 +6,7 @@ using Moq; 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; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -20,7 +17,7 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; using Umbraco.Tests.Common; -using Umbraco.Tests.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; @@ -53,12 +50,6 @@ namespace Umbraco.Tests.PublishedContent var factory = Mock.Of(); Current.Factory = factory; - var configs = TestHelper.GetConfigs(); - Mock.Get(factory).Setup(x => x.GetInstance(typeof(Configs))).Returns(configs); - var globalSettings = new GlobalSettings(); - configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); - configs.Add(() => globalSettings); - var publishedModelFactory = new NoopPublishedModelFactory(); Mock.Get(factory).Setup(x => x.GetInstance(typeof(IPublishedModelFactory))).Returns(publishedModelFactory); @@ -186,7 +177,9 @@ namespace Umbraco.Tests.PublishedContent _variationAccesor = new TestVariationContextAccessor(); var typeFinder = TestHelper.GetTypeFinder(); - var settings = Mock.Of(); + + var globalSettings = new GlobalSettingsBuilder().Build(); + var nuCacheSettings = new NuCacheSettingsBuilder().Build(); // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; @@ -204,14 +197,14 @@ namespace Umbraco.Tests.PublishedContent Mock.Of(), new TestDefaultCultureAccessor(), dataSource, - globalSettings, + Microsoft.Extensions.Options.Options.Create(globalSettings), Mock.Of(), publishedModelFactory, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), TestHelper.GetHostingEnvironment(), - new MockShortStringHelper(), + Mock.Of(), TestHelper.IOHelper, - settings); + Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); // invariant is the current default _variationAccesor.VariationContext = new VariationContext(); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs index 8c1024351b..50e82998f9 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Web; @@ -34,11 +35,11 @@ namespace Umbraco.Tests.PublishedContent private static void MockLocalizationService(ServiceContext serviceContext) { - var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); // Set up languages. // Spanish falls back to English and Italian to Spanish (and then to English). // French has no fall back. // Danish, Swedish and Norweigan create an invalid loop. + var globalSettings = new GlobalSettingsBuilder().Build(); var languages = new List { new Language(globalSettings, "en-US") { Id = 1, CultureName = "English", IsDefault = true }, diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index 5af889bcc0..1c70879da1 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -43,7 +43,7 @@ namespace Umbraco.Tests.PublishedContent { base.Compose(); - Composition.RegisterUnique(f => new PublishedModelFactory(f.GetInstance().GetTypes())); + Composition.RegisterUnique(f => new PublishedModelFactory(f.GetInstance().GetTypes(), f.GetInstance())); } protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache,IProfilingLogger logger, IHostingEnvironment hostingEnvironment) @@ -74,7 +74,7 @@ namespace Umbraco.Tests.PublishedContent var umbracoContext = new UmbracoContext( httpContextAccessor, publishedSnapshotService.Object, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 81b9318c57..53461d4b8f 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -42,7 +42,7 @@ namespace Umbraco.Tests.PublishedContent _publishedSnapshotAccessorMock = new Mock(); Composition.RegisterUnique(_publishedSnapshotAccessorMock.Object); - Composition.RegisterUnique(f => new PublishedModelFactory(f.GetInstance().GetTypes())); + Composition.RegisterUnique(f => new PublishedModelFactory(f.GetInstance().GetTypes(), f.GetInstance())); Composition.RegisterUnique(); Composition.RegisterUnique(); @@ -241,7 +241,7 @@ namespace Umbraco.Tests.PublishedContent [PublishedModel("Home")] internal class Home : PublishedContentModel { - public Home(IPublishedContent content) + public Home(IPublishedContent content, IPublishedValueFallback fallback) : base(content) {} } @@ -249,7 +249,7 @@ namespace Umbraco.Tests.PublishedContent [PublishedModel("anything")] internal class Anything : PublishedContentModel { - public Anything(IPublishedContent content) + public Anything(IPublishedContent content, IPublishedValueFallback fallback) : base(content) { } } diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index afe4596f54..0052ebe792 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -18,7 +18,7 @@ using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.PublishedContent { - class SolidPublishedSnapshot : IPublishedSnapshot + public class SolidPublishedSnapshot : IPublishedSnapshot { public readonly SolidPublishedContentCache InnerContentCache = new SolidPublishedContentCache(); public readonly SolidPublishedContentCache InnerMediaCache = new SolidPublishedContentCache(); @@ -47,7 +47,7 @@ namespace Umbraco.Tests.PublishedContent { } } - class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache + public class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache { private readonly Dictionary _content = new Dictionary(); @@ -164,7 +164,7 @@ namespace Umbraco.Tests.PublishedContent } } - internal class SolidPublishedContent : IPublishedContent + public class SolidPublishedContent : IPublishedContent { #region Constructor @@ -264,7 +264,7 @@ namespace Umbraco.Tests.PublishedContent #endregion } - internal class SolidPublishedProperty : IPublishedProperty + public class SolidPublishedProperty : IPublishedProperty { public IPublishedPropertyType PropertyType { get; set; } public string Alias { get; set; } @@ -279,7 +279,7 @@ namespace Umbraco.Tests.PublishedContent public virtual bool HasValue(string culture = null, string segment = null) => SolidHasValue; } - internal class SolidPublishedPropertyWithLanguageVariants : SolidPublishedProperty + public class SolidPublishedPropertyWithLanguageVariants : SolidPublishedProperty { private readonly IDictionary _solidSourceValues = new Dictionary(); private readonly IDictionary _solidValues = new Dictionary(); @@ -356,68 +356,71 @@ namespace Umbraco.Tests.PublishedContent } [PublishedModel("ContentType2")] - internal class ContentType2 : PublishedContentModel + public class ContentType2 : PublishedContentModel { #region Plumbing - public ContentType2(IPublishedContent content) + public ContentType2(IPublishedContent content, IPublishedValueFallback fallback) : base(content) { } #endregion - public int Prop1 => this.Value("prop1"); + public int Prop1 => this.Value(Mock.Of(), "prop1"); } [PublishedModel("ContentType2Sub")] - internal class ContentType2Sub : ContentType2 + public class ContentType2Sub : ContentType2 { #region Plumbing - public ContentType2Sub(IPublishedContent content) - : base(content) + public ContentType2Sub(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) { } #endregion } - internal class PublishedContentStrong1 : PublishedContentModel + public class PublishedContentStrong1 : PublishedContentModel { - public PublishedContentStrong1(IPublishedContent content) + public PublishedContentStrong1(IPublishedContent content, IPublishedValueFallback fallback) : base(content) { } - public int StrongValue => this.Value("strongValue"); + public int StrongValue => this.Value(Mock.Of(), "strongValue"); } - internal class PublishedContentStrong1Sub : PublishedContentStrong1 + public class PublishedContentStrong1Sub : PublishedContentStrong1 { - public PublishedContentStrong1Sub(IPublishedContent content) + public PublishedContentStrong1Sub(IPublishedContent content, IPublishedValueFallback fallback) + : base(content, fallback) + { } + + public int AnotherValue => this.Value(Mock.Of(), "anotherValue"); + } + + public class PublishedContentStrong2 : PublishedContentModel + { + public PublishedContentStrong2(IPublishedContent content, IPublishedValueFallback fallback) : base(content) { } - public int AnotherValue => this.Value("anotherValue"); + public int StrongValue => this.Value(Mock.Of(), "strongValue"); } - internal class PublishedContentStrong2 : PublishedContentModel - { - public PublishedContentStrong2(IPublishedContent content) - : base(content) - { } - - public int StrongValue => this.Value("strongValue"); - } - - internal class AutoPublishedContentType : PublishedContentType + public class AutoPublishedContentType : PublishedContentType { private static readonly IPublishedPropertyType Default; static AutoPublishedContentType() { - var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 666 }); + var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 666 }; + dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); - var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); + var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeServiceMock.Object); Default = factory.CreatePropertyType("*", 666); } diff --git a/src/Umbraco.Tests/Routing/BaseUrlProviderTest.cs b/src/Umbraco.Tests/Routing/BaseUrlProviderTest.cs new file mode 100644 index 0000000000..a4f472898e --- /dev/null +++ b/src/Umbraco.Tests/Routing/BaseUrlProviderTest.cs @@ -0,0 +1,45 @@ +using System.Linq; +using Moq; +using Umbraco.Core; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.TestHelpers; +using Umbraco.Web; +using Umbraco.Web.Routing; + +namespace Umbraco.Tests.Routing +{ + public abstract class BaseUrlProviderTest : BaseWebTest + { + protected IUmbracoContextAccessor UmbracoContextAccessor { get; } = new TestUmbracoContextAccessor(); + + protected abstract bool HideTopLevelNodeFromPath { get; } + + protected override void Compose() + { + base.Compose(); + Composition.Register(); + } + + protected override void ComposeSettings() + { + var contentSettings = new ContentSettingsBuilder().Build(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettingsBuilder().Build(); + + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); + } + + protected IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) + { + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + return new UrlProvider( + new TestUmbracoContextAccessor(umbracoContext), + Microsoft.Extensions.Options.Options.Create(webRoutingSettings), + new UrlProviderCollection(new[] { urlProvider }), + new MediaUrlProviderCollection(Enumerable.Empty()), + Mock.Of()); + } + } +} diff --git a/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs index d3c820d239..069aead6b3 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using Umbraco.Core; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Routing; @@ -17,7 +18,8 @@ namespace Umbraco.Tests.Routing var umbracoContext = GetUmbracoContext(urlAsString); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); - var lookup = new ContentFinderByIdPath(SettingsForTests.GenerateMockWebRoutingSettings(), Logger, Factory.GetInstance()); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + var lookup = new ContentFinderByIdPath(Microsoft.Extensions.Options.Options.Create(webRoutingSettings), 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 e8b8bab22b..14a7ec3ab1 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs @@ -8,6 +8,7 @@ using Umbraco.Web.Routing; using Umbraco.Core.Models; using Umbraco.Tests.Testing; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Routing { @@ -30,15 +31,17 @@ namespace Umbraco.Tests.Routing [TestCase("/home/Sub1.aspx/blah")] public void Match_Document_By_Url_With_Template(string urlAsString) { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var globalSettings = new GlobalSettingsBuilder() + .WithHideTopLevelNodeFromPath(false) + .Build(); var template1 = CreateTemplate("test"); var template2 = CreateTemplate("blah"); - var umbracoContext = GetUmbracoContext(urlAsString, template1.Id, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext(urlAsString, template1.Id, globalSettings: globalSettings); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); - var lookup = new ContentFinderByUrlAndTemplate(Logger, ServiceContext.FileService, ServiceContext.ContentTypeService, SettingsForTests.GenerateMockWebRoutingSettings()); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + var lookup = new ContentFinderByUrlAndTemplate(Logger, ServiceContext.FileService, ServiceContext.ContentTypeService, Microsoft.Extensions.Options.Options.Create(webRoutingSettings)); var result = lookup.TryFindContent(frequest); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs index f7b6762774..0614d4a2bb 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.Composing; using Umbraco.Core.Configuration; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Web.Routing; @@ -28,15 +29,15 @@ namespace Umbraco.Tests.Routing [TestCase("/test-page", 1172)] public void Match_Document_By_Url_Hide_Top_Level(string urlString, int expectedId) { - var globalSettingsMock = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(true).Build(); - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); + var snapshotService = CreatePublishedSnapshotService(globalSettings); + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings, snapshotService: snapshotService); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); var lookup = new ContentFinderByUrl(Logger); - Assert.IsTrue(Current.Configs.Global().HideTopLevelNodeFromPath); + Assert.IsTrue(globalSettings.HideTopLevelNodeFromPath); // FIXME: debugging - going further down, the routes cache is NOT empty?! if (urlString == "/home/sub1") @@ -63,15 +64,14 @@ namespace Umbraco.Tests.Routing [TestCase("/home/Sub1.aspx", 1173)] public void Match_Document_By_Url(string urlString, int expectedId) { - var globalSettingsMock = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); var lookup = new ContentFinderByUrl(Logger); - Assert.IsFalse(Current.Configs.Global().HideTopLevelNodeFromPath); + Assert.IsFalse(globalSettings.HideTopLevelNodeFromPath); var result = lookup.TryFindContent(frequest); @@ -88,10 +88,9 @@ namespace Umbraco.Tests.Routing [TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)] public void Match_Document_By_Url_With_Special_Characters(string urlString, int expectedId) { - var globalSettingsMock = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); var lookup = new ContentFinderByUrl(Logger); @@ -115,10 +114,9 @@ namespace Umbraco.Tests.Routing [TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)] public void Match_Document_By_Url_With_Special_Characters_Using_Hostname(string urlString, int expectedId) { - var globalSettingsMock = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); frequest.Domain = new DomainAndUri(new Domain(1, "mysite", -1, CultureInfo.CurrentCulture, false), new Uri("http://mysite/")); @@ -144,10 +142,9 @@ namespace Umbraco.Tests.Routing [TestCase("/æøå/home/sub1/custom-sub-4-with-æøå", 1180)] public void Match_Document_By_Url_With_Special_Characters_In_Hostname(string urlString, int expectedId) { - var globalSettingsMock = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); frequest.Domain = new DomainAndUri(new Domain(1, "mysite/æøå", -1, CultureInfo.CurrentCulture, false), new Uri("http://mysite/æøå")); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs index ac2e62b1ef..622df53d9e 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs @@ -4,6 +4,7 @@ using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; @@ -127,10 +128,9 @@ namespace Umbraco.Tests.Routing { SetDomains3(); - var globalSettingsMock = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(true).Build(); - var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettingsMock.Object); + var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -169,10 +169,9 @@ namespace Umbraco.Tests.Routing // defaults depend on test environment expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name; - var globalSettingsMock = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(true).Build(); - var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettingsMock.Object); + var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); diff --git a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs index a81f345e38..0d39092b88 100644 --- a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs +++ b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs @@ -6,6 +6,7 @@ using Umbraco.Web.Routing; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Routing { @@ -266,10 +267,10 @@ namespace Umbraco.Tests.Routing { SetDomains1(); - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings.Object); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); + + var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -315,10 +316,9 @@ namespace Umbraco.Tests.Routing // defaults depend on test environment expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name; - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -370,9 +370,8 @@ namespace Umbraco.Tests.Routing { SetDomains3(); - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings.Object); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); + var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); diff --git a/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs b/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs index 4f11802b43..27027c007f 100644 --- a/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs +++ b/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs @@ -1,26 +1,35 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.Linq; using Moq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Web.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Web; -using Umbraco.Web.Routing; using Umbraco.Tests.Common; -using SettingsForTests = Umbraco.Tests.TestHelpers.SettingsForTests; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Web.Routing; namespace Umbraco.Tests.Routing { [TestFixture] public class GetContentUrlsTests : UrlRoutingTestBase { + private GlobalSettings _globalSettings; + private WebRoutingSettings _webRoutingSettings; + private RequestHandlerSettings _requestHandlerSettings; + + public override void SetUp() + { + base.SetUp(); + + _globalSettings = new GlobalSettingsBuilder().Build(); + _webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + _requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); + } + private ILocalizedTextService GetTextService() { var textService = Mock.Of( @@ -34,7 +43,7 @@ namespace Umbraco.Tests.Routing { var allLangs = isoCodes .Select(CultureInfo.GetCultureInfo) - .Select(culture => new Language(TestObjects.GetGlobalSettings(), culture.Name) + .Select(culture => new Language(_globalSettings, culture.Name) { CultureName = culture.DisplayName, IsDefault = true, @@ -78,15 +87,17 @@ namespace Umbraco.Tests.Routing content.Path = "-1,1046"; content.Published = true; - var umbracoSettings = SettingsForTests.GenerateMockRequestHandlerSettings(); - var umbContext = GetUmbracoContext("http://localhost:8000"); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings, Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(_requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), + new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = new UrlProvider( umbracoContextAccessor, - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(_webRoutingSettings), new UrlProviderCollection(new []{urlProvider}), new MediaUrlProviderCollection(Enumerable.Empty()), Mock.Of() @@ -123,15 +134,16 @@ namespace Umbraco.Tests.Routing child.Path = "-1,1046,1173"; child.Published = true; - var umbracoSettings = SettingsForTests.GenerateMockRequestHandlerSettings(); - - var umbContext = GetUmbracoContext("http://localhost:8000"); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbContext); - var urlProvider = new DefaultUrlProvider(umbracoSettings, Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(_requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), + new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = new UrlProvider( umbracoContextAccessor, - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(_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 e55a22065b..b134934ee9 100644 --- a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs @@ -13,6 +13,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Services; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -34,12 +35,12 @@ namespace Umbraco.Tests.Routing var logger = Mock.Of(); var mediaFileSystemMock = Mock.Of(); - var contentSection = Mock.Of(); + var contentSettings = new ContentSettingsBuilder().Build(); var dataTypeService = Mock.Of(); var propertyEditors = new MediaUrlGeneratorCollection(new IMediaUrlGenerator[] { - new FileUploadPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), - new ImageCropperPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService), + new FileUploadPropertyEditor(logger, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), + new ImageCropperPropertyEditor(logger, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService), }); _mediaUrlProvider = new DefaultMediaUrlProvider(propertyEditors, UriUtility); } @@ -149,9 +150,10 @@ namespace Umbraco.Tests.Routing private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext) { + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(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 358a47f09b..5082919dc1 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -2,31 +2,35 @@ using System.Linq; using System.Web.Mvc; using System.Web.Routing; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Web; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using Umbraco.Core.Strings; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Runtime; using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.PublishedContent; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; +using Umbraco.Web; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; using Umbraco.Web.Runtime; +using Umbraco.Web.WebApi; +using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; using Current = Umbraco.Web.Composing.Current; using ILogger = Umbraco.Core.Logging.ILogger; -using Umbraco.Tests.Common; namespace Umbraco.Tests.Routing { @@ -49,8 +53,8 @@ namespace Umbraco.Tests.Routing public class TestRuntime : CoreRuntime { - public TestRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - : base(configs, umbracoVersion, ioHelper, Mock.Of(), Mock.Of(), new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), NoAppCache.Instance) + public TestRuntime(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) + : base(globalSettings, connectionStrings,umbracoVersion, ioHelper, Mock.Of(), Mock.Of(), new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), AppCaches.NoCache) { } @@ -69,7 +73,8 @@ namespace Umbraco.Tests.Routing var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(Composition.TypeLoader.GetUmbracoApiControllers()); Composition.RegisterUnique(umbracoApiControllerTypes); - Composition.RegisterUnique(_ => new DefaultShortStringHelper(TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings())); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); + Composition.RegisterUnique(_ => new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings))); } public override void TearDown() @@ -149,7 +154,7 @@ namespace Umbraco.Tests.Routing var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContextAccessor, Mock.Of(), context => { - return new CustomDocumentController(Factory.GetInstance(), + return new CustomDocumentController(Factory.GetInstance>(), umbracoContextAccessor, Factory.GetInstance(), Factory.GetInstance(), @@ -190,7 +195,7 @@ namespace Umbraco.Tests.Routing ///
public class CustomDocumentController : RenderMvcController { - public CustomDocumentController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) + public CustomDocumentController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger) { } diff --git a/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs b/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs index a78459fa39..c0b83b08cb 100644 --- a/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs +++ b/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs @@ -1,9 +1,8 @@ -using System.Web.Mvc; +using System; +using System.Web.Mvc; using System.Web.Routing; -using Moq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Web; @@ -51,12 +50,13 @@ namespace Umbraco.Tests.Routing public void Is_Reserved_By_Route(string url, bool shouldMatch) { //reset the app config, we only want to test routes not the hard coded paths - // TODO: Why are we using and modifying the global IGlobalSettings and not just a custom one? - var globalSettingsMock = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettingsMock.Setup(x => x.ReservedPaths).Returns(""); - globalSettingsMock.Setup(x => x.ReservedUrls).Returns(""); - var routableDocFilter = new RoutableDocumentFilter(globalSettingsMock.Object, IOHelper); + var globalSettings = new GlobalSettingsBuilder() + .WithReservedPaths(string.Empty) + .WithReservedUrls(String.Empty) + .Build(); + + var routableDocFilter = new RoutableDocumentFilter(globalSettings, IOHelper); var routes = new RouteCollection(); diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs index 0165e7714f..ceea358a42 100644 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs @@ -1,20 +1,13 @@ using System; -using System.IO; using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Logging; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Web; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Sync; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; -using Umbraco.Web.PublishedCache; -using Umbraco.Web.Routing; namespace Umbraco.Tests.Routing { @@ -31,8 +24,10 @@ namespace Umbraco.Tests.Routing // FIXME: be able to get the UmbracoModule from the container. any reason settings were from testobjects? //create the module var logger = Mock.Of(); - var globalSettings = TestObjects.GetGlobalSettings(); - var runtime = new RuntimeState(globalSettings, UmbracoVersion); + var globalSettings = new GlobalSettingsBuilder() + .WithReservedPaths((GlobalSettings.StaticReservedPaths + "~/umbraco")) + .Build(); + var runtime = Umbraco.Core.RuntimeState.Booting(); _module = new UmbracoInjectedModule ( diff --git a/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs new file mode 100644 index 0000000000..2c5bfc52e9 --- /dev/null +++ b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs @@ -0,0 +1,59 @@ +using NUnit.Framework; +using Umbraco.Core.Configuration.Models; +using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Testing; +using Umbraco.Web.Routing; + +namespace Umbraco.Tests.Routing +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] + public class UrlProviderWithHideTopLevelNodeFromPathTests : BaseUrlProviderTest + { + private GlobalSettings _globalSettings; + + public override void SetUp() + { + _globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(HideTopLevelNodeFromPath).Build(); + base.SetUp(); + PublishedSnapshotService = CreatePublishedSnapshotService(_globalSettings); + + + } + + protected override bool HideTopLevelNodeFromPath => true; + + protected override void ComposeSettings() + { + base.ComposeSettings(); + Composition.RegisterUnique(x => Microsoft.Extensions.Options.Options.Create(_globalSettings)); + } + + [TestCase(1046, "/")] + [TestCase(1173, "/sub1/")] + [TestCase(1174, "/sub1/sub2/")] + [TestCase(1176, "/sub1/sub-3/")] + [TestCase(1177, "/sub1/custom-sub-1/")] + [TestCase(1178, "/sub1/custom-sub-2/")] + [TestCase(1175, "/sub-2/")] + [TestCase(1172, "/test-page/")] // not hidden because not first root + public void Get_Url_Hiding_Top_Level(int nodeId, string niceUrlMatch) + { + + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); + + var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: _globalSettings, snapshotService:PublishedSnapshotService); + var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), + new SiteDomainHelper(), umbracoContextAccessor, UriUtility); + var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); + + var result = publishedUrlProvider.GetUrl(nodeId); + Assert.AreEqual(niceUrlMatch, result); + } + } +} diff --git a/src/Umbraco.Tests/Routing/UrlProviderTests.cs b/src/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs similarity index 66% rename from src/Umbraco.Tests/Routing/UrlProviderTests.cs rename to src/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs index 1ff0a2b33d..e8f3bf97fd 100644 --- a/src/Umbraco.Tests/Routing/UrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs @@ -4,38 +4,36 @@ using System.Globalization; using System.Linq; using Moq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Web.Composing; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.PublishedContent; -using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; -using Umbraco.Tests.Common; namespace Umbraco.Tests.Routing { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class UrlProviderTests : BaseWebTest + public class UrlProviderWithoutHideTopLevelNodeFromPathTests : BaseUrlProviderTest { - private IUmbracoContextAccessor UmbracoContextAccessor { get; } = new TestUmbracoContextAccessor(); + private readonly GlobalSettings _globalSettings; - protected override void Compose() + public UrlProviderWithoutHideTopLevelNodeFromPathTests() { - base.Compose(); - Composition.Register(); + _globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(HideTopLevelNodeFromPath).Build(); } + protected override bool HideTopLevelNodeFromPath => false; + protected override void ComposeSettings() { - Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); - Composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockGlobalSettings); + base.ComposeSettings(); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(_globalSettings)); } /// @@ -45,19 +43,17 @@ namespace Umbraco.Tests.Routing [Test] public void Ensure_Cache_Is_Correct() { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(false).Build(); - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); - - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: _globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - var requestHandlerMock = Mock.Get(requestHandlerSettings); - requestHandlerMock.Setup(x => x.AddTrailingSlash).Returns(false);// (cached routes have none) var samples = new Dictionary { { 1046, "/home" }, @@ -98,18 +94,6 @@ namespace Umbraco.Tests.Routing Assert.AreEqual(0, cachedIds.Count); } - private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) - { - return new UrlProvider( - new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSettings, - new UrlProviderCollection(new []{urlProvider}), - new MediaUrlProviderCollection(Enumerable.Empty()), - Mock.Of() - ); - } - - // test hideTopLevelNodeFromPath false [TestCase(1046, "/home/")] [TestCase(1173, "/home/sub1/")] [TestCase(1174, "/home/sub1/sub2/")] @@ -120,42 +104,14 @@ namespace Umbraco.Tests.Routing [TestCase(1172, "/test-page/")] public void Get_Url_Not_Hiding_Top_Level(int nodeId, string niceUrlMatch) { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); - - - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: _globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, - new SiteDomainHelper(), umbracoContextAccessor, UriUtility); - var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); - - var result = publishedUrlProvider.GetUrl(nodeId); - Assert.AreEqual(niceUrlMatch, result); - } - - // no need for umbracoUseDirectoryUrls test = should be handled by UriUtilityTests - - // test hideTopLevelNodeFromPath true - [TestCase(1046, "/")] - [TestCase(1173, "/sub1/")] - [TestCase(1174, "/sub1/sub2/")] - [TestCase(1176, "/sub1/sub-3/")] - [TestCase(1177, "/sub1/custom-sub-1/")] - [TestCase(1178, "/sub1/custom-sub-2/")] - [TestCase(1175, "/sub-2/")] - [TestCase(1172, "/test-page/")] // not hidden because not first root - public void Get_Url_Hiding_Top_Level(int nodeId, string niceUrlMatch) - { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); - - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings.Object); - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -168,11 +124,7 @@ namespace Umbraco.Tests.Routing { const string currentUri = "http://example.us/test"; - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); - + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); var contentType = new PublishedContentType(Guid.NewGuid(), 666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); var publishedContent = new SolidPublishedContent(contentType) { Id = 1234 }; @@ -193,12 +145,14 @@ namespace Umbraco.Tests.Routing snapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())) .Returns(snapshot); - var umbracoContext = GetUmbracoContext(currentUri, - globalSettings: globalSettings.Object, + globalSettings: _globalSettings, snapshotService: snapshotService.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -216,10 +170,7 @@ namespace Umbraco.Tests.Routing { const string currentUri = "http://example.fr/test"; - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); var contentType = new PublishedContentType(Guid.NewGuid(), 666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); var publishedContent = new SolidPublishedContent(contentType) { Id = 1234 }; @@ -249,12 +200,14 @@ namespace Umbraco.Tests.Routing snapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())) .Returns(snapshot); - var umbracoContext = GetUmbracoContext(currentUri, - globalSettings: globalSettings.Object, + globalSettings: _globalSettings, snapshotService: snapshotService.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -272,10 +225,7 @@ namespace Umbraco.Tests.Routing { const string currentUri = "http://example.us/test"; - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); - - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); var contentType = new PublishedContentType(Guid.NewGuid(), 666, "alias", PublishedItemType.Content, Enumerable.Empty(), Enumerable.Empty(), ContentVariation.Culture); var publishedContent = new SolidPublishedContent(contentType) { Id = 1234 }; @@ -306,10 +256,13 @@ namespace Umbraco.Tests.Routing .Returns(snapshot); var umbracoContext = GetUmbracoContext(currentUri, - globalSettings: globalSettings.Object, + globalSettings: _globalSettings, snapshotService: snapshotService.Object); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); @@ -323,15 +276,14 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_Relative_Or_Absolute() { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); - - - var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, globalSettings: globalSettings.Object); + var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, globalSettings: _globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -344,14 +296,13 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_Unpublished() { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); - - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(_globalSettings), new SiteDomainHelper(), UmbracoContextAccessor, UriUtility); - var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, globalSettings: globalSettings.Object); + var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, globalSettings: _globalSettings); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); //mock the Umbraco settings that we need diff --git a/src/Umbraco.Tests/Routing/UrlRoutesTests.cs b/src/Umbraco.Tests/Routing/UrlRoutesTests.cs index 0c608d3e94..d0dd708561 100644 --- a/src/Umbraco.Tests/Routing/UrlRoutesTests.cs +++ b/src/Umbraco.Tests/Routing/UrlRoutesTests.cs @@ -5,6 +5,7 @@ using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -196,10 +197,9 @@ DetermineRouteById(id): [TestCase(2006, false, "/x/b/e")] public void GetRouteByIdNoHide(int id, bool hide, string expected) { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(hide); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(hide).Build(); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings: globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings: globalSettings); var cache = umbracoContext.Content as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); @@ -220,10 +220,10 @@ DetermineRouteById(id): [TestCase(2006, true, "/b/e")] // risky! public void GetRouteByIdHide(int id, bool hide, string expected) { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(hide); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(hide).Build(); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings: globalSettings.Object); + var snapshotService = CreatePublishedSnapshotService(globalSettings); + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings: globalSettings, snapshotService: snapshotService); var cache = umbracoContext.Content as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); @@ -234,10 +234,10 @@ DetermineRouteById(id): [Test] public void GetRouteByIdCache() { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings.Object); + var snapshotService = CreatePublishedSnapshotService(globalSettings); + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings, snapshotService: snapshotService); var cache = umbracoContext.Content as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); @@ -265,10 +265,10 @@ DetermineRouteById(id): [TestCase("/x", false, 2000)] public void GetByRouteNoHide(string route, bool hide, int expected) { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(hide); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(hide).Build(); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings.Object); + var snapshotService = CreatePublishedSnapshotService(globalSettings); + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings, snapshotService: snapshotService); var cache = umbracoContext.Content as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); @@ -296,10 +296,10 @@ DetermineRouteById(id): [TestCase("/b/c", true, 1002)] // (hence the 2005 collision) public void GetByRouteHide(string route, bool hide, int expected) { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(hide); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(hide).Build(); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings.Object); + var snapshotService = CreatePublishedSnapshotService(globalSettings); + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings, snapshotService: snapshotService); var cache = umbracoContext.Content as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); @@ -319,10 +319,10 @@ DetermineRouteById(id): [Test] public void GetByRouteCache() { - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings.Object); + var snapshotService = CreatePublishedSnapshotService(globalSettings); + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings, snapshotService:snapshotService); var cache = umbracoContext.Content as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); diff --git a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs index d8e373b428..a960cdba53 100644 --- a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs @@ -4,13 +4,12 @@ using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Routing; @@ -178,14 +177,15 @@ 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 = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); - 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 globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(globalSettings), 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 = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - 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 umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -238,14 +238,15 @@ 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 = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); - 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 globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -270,14 +271,16 @@ 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 = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); - 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 globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -292,14 +295,16 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_DomainsAndCache() { - var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); - 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 globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -356,14 +361,16 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_Relative_Or_Absolute() { - var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); - 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 globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext("http://domain1.com/test", 1111, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext("http://domain1.com/test", 1111, globalSettings: globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -381,14 +388,16 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_Alternate() { - var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); - 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 globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); - var umbracoContext = GetUmbracoContext("http://domain1.com/en/test", 1111, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext("http://domain1.com/en/test", 1111, globalSettings: globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -408,9 +417,10 @@ namespace Umbraco.Tests.Routing private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) { + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(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 13ee5afa3e..03faa70d8c 100644 --- a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs +++ b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs @@ -3,15 +3,14 @@ using System.Linq; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using Umbraco.Core.Services; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Web; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Routing { @@ -33,19 +32,20 @@ namespace Umbraco.Tests.Routing [Test] public void DoNotPolluteCache() { - 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 = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var globalSettings = new GlobalSettingsBuilder().WithHideTopLevelNodeFromPath(false).Build(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().WithAddTrailingSlash(true).Build(); SetDomains1(); const string url = "http://domain1.com/1001-1/1001-1-1"; // get the nice url for 100111 - var umbracoContext = GetUmbracoContext(url, 9999, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext(url, 9999, globalSettings: globalSettings); var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var urlProvider = new DefaultUrlProvider(settings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + Logger, + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -97,9 +97,10 @@ namespace Umbraco.Tests.Routing private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) { + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(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 f63c56b64e..045ed2e3e8 100644 --- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs +++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs @@ -1,28 +1,27 @@ using System; using System.Collections.Generic; -using System.Data; using Examine; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Events; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Exceptions; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Runtime; -using Umbraco.Core.Scoping; using Umbraco.Net; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web; using Umbraco.Web.Hosting; using Umbraco.Web.Runtime; +using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Runtimes @@ -84,48 +83,39 @@ namespace Umbraco.Tests.Runtimes // test application public class TestUmbracoApplication : UmbracoApplicationBase { - public TestUmbracoApplication() : base(_logger, _configs, _ioHelper, _profiler, new AspNetHostingEnvironment(_hostingSettings), new AspNetBackOfficeInfo(_globalSettings, _ioHelper, _logger, _settings)) + public TestUmbracoApplication() : base(_logger, + new SecuritySettings(), + new GlobalSettings(), + new ConnectionStrings(), + _ioHelper, _profiler, new AspNetHostingEnvironment(Options.Create(new HostingSettings())), new AspNetBackOfficeInfo(_globalSettings, _ioHelper, _logger, Options.Create(new WebRoutingSettings()))) { } private static readonly DebugDiagnosticsLogger _logger = new DebugDiagnosticsLogger(new MessageTemplates()); 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 = SettingsForTests.DefaultGlobalSettings; - private static readonly IHostingSettings _hostingSettings = SettingsForTests.DefaultHostingSettings; - private static readonly IContentSettings _contentSettings = SettingsForTests.GenerateMockContentSettings(); - private static readonly IWebRoutingSettings _settings = _configs.WebRouting(); - - private static Configs GetConfigs() - { - var configs = new ConfigsFactory().Create(); - configs.Add(() => _globalSettings); - configs.Add(() => _contentSettings); - configs.Add(() => _hostingSettings); - return configs; - } + private static readonly GlobalSettings _globalSettings = new GlobalSettings(); public IRuntime Runtime { get; private set; } - protected override IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) + protected override IRuntime GetRuntime(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) { - return Runtime = new TestRuntime(configs, umbracoVersion, ioHelper, logger, profiler, hostingEnvironment, backOfficeInfo); + return Runtime = new TestRuntime(globalSettings, connectionStrings, umbracoVersion, ioHelper, logger, profiler, hostingEnvironment, backOfficeInfo); } } // test runtime 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, TestHelper.GetTypeFinder(), NoAppCache.Instance) + public TestRuntime(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) + :base(globalSettings, connectionStrings,umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), AppCaches.NoCache) { } // must override the database factory // else BootFailedException because U cannot connect to the configured db - protected internal override IUmbracoDatabaseFactory GetDatabaseFactory() + protected internal override IUmbracoDatabaseFactory CreateDatabaseFactory() { var mock = new Mock(); mock.Setup(x => x.Configured).Returns(true); @@ -170,7 +160,6 @@ namespace Umbraco.Tests.Runtimes public void Compose(Composition composition) { - 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 ac0ff3f9f9..7c834d7cf3 100644 --- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs +++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs @@ -37,6 +37,8 @@ using Current = Umbraco.Web.Composing.Current; using Umbraco.Tests.Common; using Umbraco.Tests.Common.Composing; using Umbraco.Core.Media; +using Umbraco.Tests.Common.Builders; +using Microsoft.Extensions.Options; namespace Umbraco.Tests.Runtimes { @@ -63,31 +65,29 @@ namespace Umbraco.Tests.Runtimes var profiler = new LogProfiler(logger); var profilingLogger = new ProfilingLogger(logger, profiler); var appCaches = AppCaches.Disabled; - var globalSettings = TestHelper.GetConfigs().Global(); - var connectionStrings = TestHelper.GetConfigs().ConnectionStrings(); + var globalSettings = new GlobalSettingsBuilder().Build(); + var connectionStrings = new ConnectionStringsBuilder().Build(); var typeFinder = TestHelper.GetTypeFinder(); - var databaseFactory = new UmbracoDatabaseFactory(logger,globalSettings, connectionStrings, new Lazy(() => factory.GetInstance()), TestHelper.DbProviderFactoryCreator); + var databaseFactory = new UmbracoDatabaseFactory(logger, Options.Create(globalSettings), Options.Create(connectionStrings), new Lazy(() => factory.GetInstance()), TestHelper.DbProviderFactoryCreator); var ioHelper = TestHelper.IOHelper; var hostingEnvironment = Mock.Of(); var typeLoader = new TypeLoader(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(null, umbracoVersion); - var configs = TestHelper.GetConfigs(); + var runtimeState = new RuntimeState(globalSettings, umbracoVersion, databaseFactory, logger); 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); + var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, ioHelper, appCaches); 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, typeFinder, NoAppCache.Instance); + var coreRuntime = new CoreRuntime(globalSettings, connectionStrings, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder, AppCaches.NoCache); // determine actual runtime level - runtimeState.DetermineRuntimeLevel(databaseFactory, logger); + runtimeState.DetermineRuntimeLevel(); Console.WriteLine(runtimeState.Level); // going to be Install BUT we want to force components to be there (nucache etc) runtimeState.Level = RuntimeLevel.Run; @@ -118,14 +118,29 @@ namespace Umbraco.Tests.Runtimes composition.RegisterUnique(); composition.RegisterUnique(_ => new MediaUrlProviderCollection(Enumerable.Empty())); + // TODO: found these registration were necessary here as dependencies for ComponentCollection + // are not resolved. Need to check this if these explicit registrations are the best way to handle this. + var contentSettings = new ContentSettingsBuilder().Build(); + var coreDebugSettings = new CoreDebugSettingsBuilder().Build(); + var nuCacheSettings = new NuCacheSettingsBuilder().Build(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettingsBuilder().Build(); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + + composition.Register(x => Options.Create(globalSettings)); + composition.Register(x => Options.Create(contentSettings)); + composition.Register(x => Options.Create(coreDebugSettings)); + composition.Register(x => Options.Create(nuCacheSettings)); + composition.Register(x => Options.Create(requestHandlerSettings)); + composition.Register(x => Options.Create(userPasswordConfigurationSettings)); + composition.Register(x => Options.Create(webRoutingSettings)); + // initialize some components only/individually composition.WithCollectionBuilder() .Clear() .Append(); // configure - composition.Configs.Add(() => TestHelpers.SettingsForTests.DefaultGlobalSettings); - composition.Configs.Add(TestHelpers.SettingsForTests.GenerateMockContentSettings); // create and register the factory Current.Factory = factory = composition.CreateFactory(); @@ -163,7 +178,7 @@ namespace Umbraco.Tests.Runtimes var scopeProvider = factory.GetInstance(); using (var scope = scopeProvider.CreateScope()) { - var creator = new DatabaseSchemaCreator(scope.Database, logger, umbracoVersion, TestHelpers.SettingsForTests.DefaultGlobalSettings); + var creator = new DatabaseSchemaCreator(scope.Database, logger, umbracoVersion); creator.InitializeDatabaseSchema(); scope.Complete(); } @@ -269,16 +284,18 @@ namespace Umbraco.Tests.Runtimes Mock.Get(runtimeState).Setup(x => x.Level).Returns(RuntimeLevel.Run); var mainDom = Mock.Of(); Mock.Get(mainDom).Setup(x => x.IsMainDom).Returns(true); - var configs = TestHelper.GetConfigs(); // create the register and the composition var register = TestHelper.GetRegister(); - var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, configs, ioHelper, appCaches); + var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, ioHelper, appCaches); var umbracoVersion = TestHelper.GetUmbracoVersion(); 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, typeFinder, NoAppCache.Instance); + var globalSettings = new GlobalSettingsBuilder().Build(); + var connectionStrings = new ConnectionStringsBuilder().Build(); + + var coreRuntime = new CoreRuntime(globalSettings, connectionStrings, umbracoVersion, ioHelper, logger, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder, AppCaches.NoCache); // get the components // all of them? diff --git a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs index be609f9a83..5ca6308bcd 100644 --- a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Services; using Umbraco.Tests.Components; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Scoping { @@ -34,28 +35,22 @@ namespace Umbraco.Tests.Scoping var register = TestHelper.GetRegister(); - var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(register, TestHelper.GetMockedTypeLoader(), Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); _testObjects = new TestObjects(register); - composition.RegisterUnique(factory => new FileSystems(factory, factory.TryGetInstance(), TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings(), TestHelper.GetHostingEnvironment())); + var globalSettings = new GlobalSettingsBuilder().Build(); + composition.RegisterUnique(factory => new FileSystems(factory, factory.TryGetInstance(), TestHelper.IOHelper, Microsoft.Extensions.Options.Options.Create(globalSettings), TestHelper.GetHostingEnvironment())); composition.WithCollectionBuilder(); - composition.Configs.Add(() => SettingsForTests.DefaultGlobalSettings); - composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); - Current.Reset(); Current.Factory = composition.CreateFactory(); - - SettingsForTests.Reset(); // ensure we have configuration } [TearDown] public void TearDown() { Current.Reset(); - - SettingsForTests.Reset(); } [TestCase(false, true, true)] diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 49bca378c7..a669e543f2 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -1,16 +1,11 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Web.Routing; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; -using Umbraco.Core.Install; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -20,16 +15,14 @@ using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Sync; using Umbraco.Tests.Common; -using Umbraco.Tests.Strings; +using Umbraco.Tests.Common.Builders; 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; using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.PublishedCache.NuCache.DataSource; -using Umbraco.Web.Routing; using Umbraco.Web.Security; using Current = Umbraco.Web.Composing.Current; @@ -73,7 +66,7 @@ namespace Umbraco.Tests.Scoping private Action _onPublishedAssertAction; - protected override IPublishedSnapshotService CreatePublishedSnapshotService() + protected override IPublishedSnapshotService CreatePublishedSnapshotService(GlobalSettings globalSettings = null) { var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor); @@ -87,7 +80,8 @@ namespace Umbraco.Tests.Scoping var hostingEnvironment = TestHelper.GetHostingEnvironment(); var typeFinder = TestHelper.GetTypeFinder(); - var settings = Mock.Of(); + + var nuCacheSettings = new NuCacheSettingsBuilder().Build(); return new PublishedSnapshotService( options, @@ -102,14 +96,14 @@ namespace Umbraco.Tests.Scoping documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, new DatabaseDataSource(Mock.Of()), - Factory.GetInstance(), + Microsoft.Extensions.Options.Options.Create(globalSettings ?? new GlobalSettingsBuilder().Build()), Factory.GetInstance(), new NoopPublishedModelFactory(), new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }), hostingEnvironment, - new MockShortStringHelper(), + Mock.Of(), IOHelper, - settings); + Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); } protected IUmbracoContext GetUmbracoContextNu(string url, RouteData routeData = null, bool setSingleton = false) @@ -123,7 +117,7 @@ namespace Umbraco.Tests.Scoping var umbracoContext = new UmbracoContext( httpContextAccessor, service, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs index 4c3bb288e4..da90d7fefa 100644 --- a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs @@ -1,21 +1,23 @@ using System; using System.Collections.Generic; using System.Linq; +using Moq; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Web.Composing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Events; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Scoping; +using Umbraco.Core.Sync; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Web.Cache; -using Moq; -using Umbraco.Core; -using Umbraco.Core.Events; -using Umbraco.Core.Logging; -using Umbraco.Core.Sync; using Umbraco.Web; +using Umbraco.Web.Cache; +using Umbraco.Web.Composing; namespace Umbraco.Tests.Scoping { @@ -25,6 +27,15 @@ namespace Umbraco.Tests.Scoping { private DistributedCacheBinder _distributedCacheBinder; + private GlobalSettings _globalSettings; + + public override void SetUp() + { + base.SetUp(); + + _globalSettings = new GlobalSettingsBuilder().Build(); + } + protected override void Compose() { base.Compose(); @@ -63,7 +74,7 @@ namespace Umbraco.Tests.Scoping var service = ServiceContext.UserService; var globalCache = Current.AppCaches.IsolatedCaches.GetOrCreate(typeof(IUser)); - var user = (IUser)new User(TestObjects.GetGlobalSettings(), "name", "email", "username", "rawPassword"); + var user = (IUser)new User(_globalSettings, "name", "email", "username", "rawPassword"); service.Save(user); // global cache contains the entity @@ -140,7 +151,7 @@ namespace Umbraco.Tests.Scoping var service = ServiceContext.LocalizationService; var globalCache = Current.AppCaches.IsolatedCaches.GetOrCreate(typeof (ILanguage)); - var lang = (ILanguage) new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var lang = (ILanguage) new Language(_globalSettings, "fr-FR"); service.Save(lang); // global cache has been flushed, reload @@ -232,7 +243,7 @@ namespace Umbraco.Tests.Scoping var service = ServiceContext.LocalizationService; var globalCache = Current.AppCaches.IsolatedCaches.GetOrCreate(typeof (IDictionaryItem)); - var lang = (ILanguage)new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var lang = (ILanguage)new Language(_globalSettings, "fr-FR"); service.Save(lang); var item = (IDictionaryItem) new DictionaryItem("item-key"); diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index 852872fca0..59610e43bd 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -5,19 +5,19 @@ using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Web.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Sync; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.Cache; +using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; namespace Umbraco.Tests.Scoping @@ -44,8 +44,13 @@ namespace Umbraco.Tests.Scoping protected override void ComposeSettings() { - Composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); - Composition.Configs.Add(SettingsForTests.GenerateMockGlobalSettings); + var contentSettings = new ContentSettingsBuilder().Build(); + var globalSettings = new GlobalSettingsBuilder().Build(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettingsBuilder().Build(); + + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); } [TearDown] diff --git a/src/Umbraco.Tests/Security/BackOfficeOwinUserManagerTests.cs b/src/Umbraco.Tests/Security/BackOfficeOwinUserManagerTests.cs index 8958eabd42..32c85121d2 100644 --- a/src/Umbraco.Tests/Security/BackOfficeOwinUserManagerTests.cs +++ b/src/Umbraco.Tests/Security/BackOfficeOwinUserManagerTests.cs @@ -3,12 +3,14 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; using Microsoft.Owin.Security.DataProtection; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; using Umbraco.Net; using Umbraco.Web.Security; @@ -23,28 +25,32 @@ namespace Umbraco.Tests.Security const string v7Hash = "7Uob6fMTTxDIhWGebYiSxg==P+hgvWlXLbDd4cFLADn811KOaVI/9pg1PNvTuG5NklY="; const string plaintext = "4XxzH3s3&J"; - var mockPasswordConfiguration = new Mock(); + var userPasswordConfiguration = new UserPasswordConfigurationSettings() + { + HashAlgorithmType = Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName + }; var mockIpResolver = new Mock(); var mockUserStore = new Mock>(); var mockDataProtectionProvider = new Mock(); mockDataProtectionProvider.Setup(x => x.Create(It.IsAny())) .Returns(new Mock().Object); - mockPasswordConfiguration.Setup(x => x.HashAlgorithmType) - .Returns(Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); + var userManager = BackOfficeOwinUserManager.Create( - mockPasswordConfiguration.Object, + Options.Create(userPasswordConfiguration), mockIpResolver.Object, mockUserStore.Object, null, mockDataProtectionProvider.Object, new NullLogger>()); - var mockGlobalSettings = new Mock(); - mockGlobalSettings.Setup(x => x.DefaultUILanguage).Returns("test"); + var globalSettings = new GlobalSettings() + { + DefaultUILanguage = "test" + }; - var user = new BackOfficeIdentityUser(mockGlobalSettings.Object, 2, new List()) + var user = new BackOfficeIdentityUser(globalSettings, 2, new List()) { UserName = "alice", Name = "Alice", diff --git a/src/Umbraco.Tests/Security/OwinDataProtectorTokenProviderTests.cs b/src/Umbraco.Tests/Security/OwinDataProtectorTokenProviderTests.cs index 7b1ca53104..4874545571 100644 --- a/src/Umbraco.Tests/Security/OwinDataProtectorTokenProviderTests.cs +++ b/src/Umbraco.Tests/Security/OwinDataProtectorTokenProviderTests.cs @@ -8,7 +8,9 @@ using Moq; using NUnit.Framework; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Tests.Common.Builders; using Umbraco.Web.Security; namespace Umbraco.Tests.Security @@ -81,7 +83,7 @@ namespace Umbraco.Tests.Security reader.ReadInt64(); // creation time reader.ReadString(); // user ID var purpose = reader.ReadString(); - + Assert.AreEqual(expectedPurpose, purpose); } } @@ -227,14 +229,13 @@ namespace Umbraco.Tests.Security _mockDataProtector.Setup(x => x.Protect(It.IsAny())).Returns((byte[] originalBytes) => originalBytes); _mockDataProtector.Setup(x => x.Unprotect(It.IsAny())).Returns((byte[] originalBytes) => originalBytes); - var mockGlobalSettings = new Mock(); - mockGlobalSettings.Setup(x => x.DefaultUILanguage).Returns("test"); + var globalSettings = new GlobalSettingsBuilder().Build(); _mockUserManager = new Mock>(new Mock>().Object, null, null, null, null, null, null, null, null); _mockUserManager.Setup(x => x.SupportsUserSecurityStamp).Returns(false); - _testUser = new BackOfficeIdentityUser(mockGlobalSettings.Object, 2, new List()) + _testUser = new BackOfficeIdentityUser(globalSettings, 2, new List()) { UserName = "alice", Name = "Alice", diff --git a/src/Umbraco.Tests/Services/ContentServiceEventTests.cs b/src/Umbraco.Tests/Services/ContentServiceEventTests.cs index 26f6d37456..208afe5b4b 100644 --- a/src/Umbraco.Tests/Services/ContentServiceEventTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceEventTests.cs @@ -1,11 +1,13 @@ using System.Linq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -18,10 +20,13 @@ namespace Umbraco.Tests.Services Logger = UmbracoTestOptions.Logger.Console)] public class ContentServiceEventTests : TestWithSomeContentBase { + private GlobalSettings _globalSettings; + public override void SetUp() { base.SetUp(); ContentRepositoryBase.ThrowOnWarning = true; + _globalSettings = new GlobalSettingsBuilder().Build(); } public override void TearDown() @@ -35,7 +40,7 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); + languageService.Save(new Language(_globalSettings, "fr-FR")); var contentTypeService = ServiceContext.ContentTypeService; @@ -146,7 +151,7 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); + languageService.Save(new Language(_globalSettings, "fr-FR")); var contentTypeService = ServiceContext.ContentTypeService; @@ -312,7 +317,7 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); + languageService.Save(new Language(_globalSettings, "fr-FR")); var contentTypeService = ServiceContext.ContentTypeService; diff --git a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs index d5afde6477..02f6ad330f 100644 --- a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs +++ b/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.TestHelpers.Stubs; @@ -43,10 +44,11 @@ namespace Umbraco.Tests.Services private DocumentRepository CreateDocumentRepository(IScopeProvider provider) { var accessor = (IScopeAccessor)provider; + var globalSettings = new GlobalSettingsBuilder().Build(); var tRepository = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepo = new TagRepository(accessor, AppCaches.Disabled, Logger); var commonRepository = new ContentTypeCommonRepository(accessor, tRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, Microsoft.Extensions.Options.Options.Create(globalSettings)); var ctRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(accessor); diff --git a/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs b/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs index d856f3bd82..35bbaa5f68 100644 --- a/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs +++ b/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -425,11 +426,13 @@ namespace Umbraco.Tests.Services private void CreateTypes(out IContentType iContentType, out IContentType vContentType) { - var langDe = new Language(TestObjects.GetGlobalSettings(), "de") { IsDefault = true }; + var globalSettings = new GlobalSettingsBuilder().Build(); + + var langDe = new Language(globalSettings, "de") { IsDefault = true }; ServiceContext.LocalizationService.Save(langDe); - var langRu = new Language(TestObjects.GetGlobalSettings(), "ru"); + var langRu = new Language(globalSettings, "ru"); ServiceContext.LocalizationService.Save(langRu); - var langEs = new Language(TestObjects.GetGlobalSettings(), "es"); + var langEs = new Language(globalSettings, "es"); ServiceContext.LocalizationService.Save(langEs); iContentType = new ContentType(ShortStringHelper, -1) diff --git a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs index 5e2c3823af..10bd82cbde 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs @@ -9,6 +9,8 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Services { @@ -19,12 +21,15 @@ namespace Umbraco.Tests.Services Logger = UmbracoTestOptions.Logger.Console)] public class ContentServiceTagsTests : TestWithSomeContentBase { + private GlobalSettings _globalSettings; + public PropertyEditorCollection PropertyEditorCollection => Factory.GetInstance(); public override void SetUp() { base.SetUp(); ContentRepositoryBase.ThrowOnWarning = true; + _globalSettings = new GlobalSettingsBuilder().Build(); } public override void TearDown() @@ -81,7 +86,7 @@ namespace Umbraco.Tests.Services public void TagsCanBeVariant() { var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + languageService.Save(new Language(_globalSettings, "fr-FR")); // en-US is already there var contentService = ServiceContext.ContentService; var contentTypeService = ServiceContext.ContentTypeService; @@ -205,7 +210,7 @@ namespace Umbraco.Tests.Services public void TagsCanBecomeInvariant() { var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + languageService.Save(new Language(_globalSettings, "fr-FR")); // en-US is already there var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; @@ -262,7 +267,7 @@ namespace Umbraco.Tests.Services public void TagsCanBecomeInvariant2() { var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + languageService.Save(new Language(_globalSettings, "fr-FR")); // en-US is already there var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; @@ -309,7 +314,7 @@ namespace Umbraco.Tests.Services public void TagsCanBecomeInvariantByPropertyType() { var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + languageService.Save(new Language(_globalSettings, "fr-FR")); // en-US is already there var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; @@ -366,7 +371,7 @@ namespace Umbraco.Tests.Services public void TagsCanBecomeInvariantByPropertyTypeAndBackToVariant() { var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + languageService.Save(new Language(_globalSettings, "fr-FR")); // en-US is already there var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 81f8a5bcad..82d7235388 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -6,21 +6,21 @@ using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; -using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Core.Events; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories.Implement; -using Umbraco.Core.Scoping; -using Umbraco.Core.Services.Implement; -using Umbraco.Tests.Testing; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using Umbraco.Core.Cache; using Umbraco.Core.PropertyEditors; -using Umbraco.Tests.Common.TestHelpers.Entities; +using Umbraco.Core.Scoping; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; +using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Testing; namespace Umbraco.Tests.Services { @@ -40,10 +40,13 @@ namespace Umbraco.Tests.Services // TODO: Add test to verify there is only ONE newest document/content in {Constants.DatabaseSchema.Tables.Document} table after updating. // TODO: Add test to delete specific version (with and without deleting prior versions) and versions by date. + private GlobalSettings _globalSettings; + public override void SetUp() { base.SetUp(); ContentRepositoryBase.ThrowOnWarning = true; + _globalSettings = new GlobalSettingsBuilder().Build(); } public override void TearDown() @@ -173,8 +176,8 @@ namespace Umbraco.Tests.Services [Test] public void Perform_Scheduled_Publishing() { - var langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var langUk = new Language(_globalSettings, "en-GB") { IsDefault = true }; + var langFr = new Language(_globalSettings, "fr-FR"); ServiceContext.LocalizationService.Save(langFr); ServiceContext.LocalizationService.Save(langUk); @@ -508,7 +511,7 @@ namespace Umbraco.Tests.Services [Test] public void Can_Save_New_Content_With_Explicit_User() { - var user = new User(TestObjects.GetGlobalSettings()) + var user = new User(_globalSettings) { Name = "Test", Email = "test@test.com", @@ -877,8 +880,8 @@ namespace Umbraco.Tests.Services [Test] public void Unpublishing_Mandatory_Language_Unpublishes_Document() { - var langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true, IsMandatory = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var langUk = new Language(_globalSettings, "en-GB") { IsDefault = true, IsMandatory = true }; + var langFr = new Language(_globalSettings, "fr-FR"); ServiceContext.LocalizationService.Save(langFr); ServiceContext.LocalizationService.Save(langUk); @@ -974,8 +977,8 @@ namespace Umbraco.Tests.Services { // Arrange - var langGB = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var langGB = new Language(_globalSettings, "en-GB") { IsDefault = true }; + var langFr = new Language(_globalSettings, "fr-FR"); ServiceContext.LocalizationService.Save(langFr); ServiceContext.LocalizationService.Save(langGB); @@ -1042,8 +1045,8 @@ namespace Umbraco.Tests.Services { // Arrange - var langGB = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true, IsMandatory = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var langGB = new Language(_globalSettings, "en-GB") { IsDefault = true, IsMandatory = true }; + var langFr = new Language(_globalSettings, "fr-FR"); ServiceContext.LocalizationService.Save(langFr); ServiceContext.LocalizationService.Save(langGB); @@ -1221,8 +1224,8 @@ namespace Umbraco.Tests.Services { //TODO: This is using an internal API - we aren't exposing this publicly (at least for now) but we'll keep the test around - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr"); - var langDa = new Language(TestObjects.GetGlobalSettings(), "da"); + var langFr = new Language(_globalSettings, "fr"); + var langDa = new Language(_globalSettings, "da"); ServiceContext.LocalizationService.Save(langFr); ServiceContext.LocalizationService.Save(langDa); @@ -2157,8 +2160,8 @@ namespace Umbraco.Tests.Services [Test] public void Can_Rollback_Version_On_Multilingual() { - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr"); - var langDa = new Language(TestObjects.GetGlobalSettings(), "da"); + var langFr = new Language(_globalSettings, "fr"); + var langDa = new Language(_globalSettings, "da"); ServiceContext.LocalizationService.Save(langFr); ServiceContext.LocalizationService.Save(langDa); @@ -2684,8 +2687,8 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - var langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var langUk = new Language(_globalSettings, "en-GB") { IsDefault = true }; + var langFr = new Language(_globalSettings, "fr-FR"); languageService.Save(langFr); languageService.Save(langUk); @@ -2719,8 +2722,8 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - var langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var langUk = new Language(_globalSettings, "en-GB") { IsDefault = true }; + var langFr = new Language(_globalSettings, "fr-FR"); languageService.Save(langFr); languageService.Save(langUk); @@ -2756,9 +2759,9 @@ namespace Umbraco.Tests.Services { var languageService = ServiceContext.LocalizationService; - var langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); - var langDa = new Language(TestObjects.GetGlobalSettings(), "da-DK"); + var langUk = new Language(_globalSettings, "en-GB") { IsDefault = true }; + var langFr = new Language(_globalSettings, "fr-FR"); + var langDa = new Language(_globalSettings, "da-DK"); languageService.Save(langFr); languageService.Save(langUk); @@ -2858,10 +2861,10 @@ namespace Umbraco.Tests.Services var languageService = ServiceContext.LocalizationService; //var langFr = new Language("fr-FR") { IsDefaultVariantLanguage = true }; - var langXx = new Language(TestObjects.GetGlobalSettings(), "pt-PT") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); - var langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB"); - var langDe = new Language(TestObjects.GetGlobalSettings(), "de-DE"); + var langXx = new Language(_globalSettings, "pt-PT") { IsDefault = true }; + var langFr = new Language(_globalSettings, "fr-FR"); + var langUk = new Language(_globalSettings, "en-GB"); + var langDe = new Language(_globalSettings, "de-DE"); languageService.Save(langFr); languageService.Save(langUk); @@ -3247,7 +3250,7 @@ namespace Umbraco.Tests.Services var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, Microsoft.Extensions.Options.Options.Create(_globalSettings)); contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); var entityRepository = new EntityRepository(accessor); @@ -3260,8 +3263,8 @@ namespace Umbraco.Tests.Services private void CreateEnglishAndFrenchDocumentType(out Language langUk, out Language langFr, out ContentType contentType) { - langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + langUk = new Language(_globalSettings, "en-GB") { IsDefault = true }; + langFr = new Language(_globalSettings, "fr-FR"); ServiceContext.LocalizationService.Save(langFr); ServiceContext.LocalizationService.Save(langUk); diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs index ab9f85aa3c..7e88e85360 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs @@ -8,8 +8,8 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.Install; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -19,7 +19,7 @@ using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Sync; -using Umbraco.Tests.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -45,7 +45,7 @@ namespace Umbraco.Tests.Services .Add(() => Composition.TypeLoader.GetCacheRefreshers()); } - protected override IPublishedSnapshotService CreatePublishedSnapshotService() + protected override IPublishedSnapshotService CreatePublishedSnapshotService(GlobalSettings globalSettings = null) { var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor); @@ -59,7 +59,8 @@ namespace Umbraco.Tests.Services var hostingEnvironment = Mock.Of(); var typeFinder = TestHelper.GetTypeFinder(); - var settings = Mock.Of(); + + var nuCacheSettings = new NuCacheSettingsBuilder().Build(); return new PublishedSnapshotService( options, @@ -74,14 +75,14 @@ namespace Umbraco.Tests.Services documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, new DatabaseDataSource(Mock.Of()), - Factory.GetInstance(), + Microsoft.Extensions.Options.Options.Create(globalSettings ?? new GlobalSettingsBuilder().Build()), Factory.GetInstance(), Mock.Of(), new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }), hostingEnvironment, - new MockShortStringHelper(), + Mock.Of(), IOHelper, - settings); + Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); } public class LocalServerMessenger : ServerMessengerBase @@ -310,7 +311,9 @@ namespace Umbraco.Tests.Services var nlContentName = "Content nl-NL"; var nlCulture = "nl-NL"; - ServiceContext.LocalizationService.Save(new Language(TestObjects.GetGlobalSettings(), nlCulture)); + var globalSettings = new GlobalSettingsBuilder().Build(); + + ServiceContext.LocalizationService.Save(new Language(globalSettings, nlCulture)); var includeCultureNames = contentType.Variations.HasFlag(ContentVariation.Culture); @@ -666,9 +669,11 @@ namespace Umbraco.Tests.Services // can change it to variant and back // can then switch one property to variant - var languageEn = new Language(TestObjects.GetGlobalSettings(), "en") { IsDefault = true }; + var globalSettings = new GlobalSettingsBuilder().Build(); + + var languageEn = new Language(globalSettings, "en") { IsDefault = true }; ServiceContext.LocalizationService.Save(languageEn); - var languageFr = new Language(TestObjects.GetGlobalSettings(), "fr"); + var languageFr = new Language(globalSettings, "fr"); ServiceContext.LocalizationService.Save(languageFr); var contentType = CreateContentType(ContentVariation.Nothing); @@ -1259,9 +1264,10 @@ namespace Umbraco.Tests.Services private void CreateFrenchAndEnglishLangs() { - var languageEn = new Language(TestObjects.GetGlobalSettings(), "en") { IsDefault = true }; + var globalSettings = new GlobalSettingsBuilder().Build(); + var languageEn = new Language(globalSettings, "en") { IsDefault = true }; ServiceContext.LocalizationService.Save(languageEn); - var languageFr = new Language(TestObjects.GetGlobalSettings(), "fr"); + var languageFr = new Language(globalSettings, "fr"); ServiceContext.LocalizationService.Save(languageFr); } diff --git a/src/Umbraco.Tests/Services/EntityServiceTests.cs b/src/Umbraco.Tests/Services/EntityServiceTests.cs index fb802420d5..8be2dcc962 100644 --- a/src/Umbraco.Tests/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests/Services/EntityServiceTests.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -31,8 +32,9 @@ namespace Umbraco.Tests.Services if (_langFr == null && _langEs == null) { - _langFr = new Language(SettingsForTests.GenerateMockGlobalSettings(), "fr-FR"); - _langEs = new Language(SettingsForTests.GenerateMockGlobalSettings(), "es-ES"); + var globalSettings = new GlobalSettingsBuilder().Build(); + _langFr = new Language(globalSettings, "fr-FR"); + _langEs = new Language(globalSettings, "es-ES"); ServiceContext.LocalizationService.Save(_langFr); ServiceContext.LocalizationService.Save(_langEs); } diff --git a/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs b/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs index e10dd99482..8497208d93 100644 --- a/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs +++ b/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs @@ -4,9 +4,10 @@ using System.Linq; using System.Xml.Linq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Services.Importing; using Umbraco.Tests.Testing; @@ -17,6 +18,13 @@ namespace Umbraco.Tests.Services public class EntityXmlSerializerTests : TestWithSomeContentBase { private IEntityXmlSerializer Serializer => Factory.GetInstance(); + private GlobalSettings _globalSettings; + + public override void SetUp() + { + base.SetUp(); + _globalSettings = new GlobalSettingsBuilder().Build(); + } [Test] public void Can_Export_Macro() @@ -56,10 +64,10 @@ namespace Umbraco.Tests.Services public void Can_Export_Languages() { // Arrange - var languageNbNo = new Language(TestObjects.GetGlobalSettings(), "nb-NO") { CultureName = "Norwegian" }; + var languageNbNo = new Language(_globalSettings, "nb-NO") { CultureName = "Norwegian" }; ServiceContext.LocalizationService.Save(languageNbNo); - var languageEnGb = new Language(TestObjects.GetGlobalSettings(), "en-GB") { CultureName = "English (United Kingdom)" }; + var languageEnGb = new Language(_globalSettings, "en-GB") { CultureName = "English (United Kingdom)" }; ServiceContext.LocalizationService.Save(languageEnGb); var newPackageXml = XElement.Parse(ImportResources.Dictionary_Package); @@ -74,10 +82,10 @@ namespace Umbraco.Tests.Services private void CreateDictionaryData() { - var languageNbNo = new Language(TestObjects.GetGlobalSettings(), "nb-NO") { CultureName = "nb-NO" }; + var languageNbNo = new Language(_globalSettings, "nb-NO") { CultureName = "nb-NO" }; ServiceContext.LocalizationService.Save(languageNbNo); - var languageEnGb = new Language(TestObjects.GetGlobalSettings(), "en-GB") { CultureName = "en-GB" }; + var languageEnGb = new Language(_globalSettings, "en-GB") { CultureName = "en-GB" }; ServiceContext.LocalizationService.Save(languageEnGb); var parentItem = new DictionaryItem("Parent"); diff --git a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs b/src/Umbraco.Tests/Services/LocalizationServiceTests.cs index c5ff549ee3..2785cdea27 100644 --- a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs +++ b/src/Umbraco.Tests/Services/LocalizationServiceTests.cs @@ -9,6 +9,8 @@ using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Core.Persistence; +using Umbraco.Core.Configuration.Models; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Services { @@ -29,6 +31,14 @@ namespace Umbraco.Tests.Services private int _danishLangId; private int _englishLangId; + private GlobalSettings _globalSettings; + + public override void SetUp() + { + base.SetUp(); + _globalSettings = new GlobalSettingsBuilder().Build(); + } + [Test] public void Can_Get_Root_Dictionary_Items() { @@ -181,7 +191,7 @@ namespace Umbraco.Tests.Services [Test] public void Can_Delete_Language() { - var norwegian = new Language(TestObjects.GetGlobalSettings(), "nb-NO") { CultureName = "Norwegian" }; + var norwegian = new Language(_globalSettings, "nb-NO") { CultureName = "Norwegian" }; ServiceContext.LocalizationService.Save(norwegian, 0); Assert.That(norwegian.HasIdentity, Is.True); var languageId = norwegian.Id; @@ -196,7 +206,7 @@ namespace Umbraco.Tests.Services public void Can_Delete_Language_Used_As_Fallback() { var danish = ServiceContext.LocalizationService.GetLanguageByIsoCode("da-DK"); - var norwegian = new Language(TestObjects.GetGlobalSettings(), "nb-NO") { CultureName = "Norwegian", FallbackLanguageId = danish.Id }; + var norwegian = new Language(_globalSettings, "nb-NO") { CultureName = "Norwegian", FallbackLanguageId = danish.Id }; ServiceContext.LocalizationService.Save(norwegian, 0); var languageId = danish.Id; @@ -346,7 +356,7 @@ namespace Umbraco.Tests.Services // Arrange var localizationService = ServiceContext.LocalizationService; var isoCode = "en-AU"; - var language = new Core.Models.Language(TestObjects.GetGlobalSettings(), isoCode); + var language = new Core.Models.Language(_globalSettings, isoCode); // Act localizationService.Save(language); @@ -361,7 +371,7 @@ namespace Umbraco.Tests.Services { var localizationService = ServiceContext.LocalizationService; var isoCode = "en-AU"; - var language = new Core.Models.Language(TestObjects.GetGlobalSettings(), isoCode); + var language = new Core.Models.Language(_globalSettings, isoCode); // Act localizationService.Save(language); @@ -375,14 +385,14 @@ namespace Umbraco.Tests.Services public void Set_Default_Language() { var localizationService = ServiceContext.LocalizationService; - var language = new Core.Models.Language(TestObjects.GetGlobalSettings(), "en-AU"); + var language = new Core.Models.Language(_globalSettings, "en-AU"); language.IsDefault = true; localizationService.Save(language); var result = localizationService.GetLanguageById(language.Id); Assert.IsTrue(result.IsDefault); - var language2 = new Core.Models.Language(TestObjects.GetGlobalSettings(), "en-NZ"); + var language2 = new Core.Models.Language(_globalSettings, "en-NZ"); language2.IsDefault = true; localizationService.Save(language2); var result2 = localizationService.GetLanguageById(language2.Id); @@ -398,7 +408,7 @@ namespace Umbraco.Tests.Services { var localizationService = ServiceContext.LocalizationService; var isoCode = "en-AU"; - var language = new Core.Models.Language(TestObjects.GetGlobalSettings(), isoCode); + var language = new Core.Models.Language(_globalSettings, isoCode); localizationService.Save(language); // Act @@ -411,8 +421,8 @@ namespace Umbraco.Tests.Services public override void CreateTestData() { - var danish = new Language(TestObjects.GetGlobalSettings(), "da-DK") { CultureName = "Danish" }; - var english = new Language(TestObjects.GetGlobalSettings(), "en-GB") { CultureName = "English" }; + var danish = new Language(_globalSettings, "da-DK") { CultureName = "Danish" }; + var english = new Language(_globalSettings, "en-GB") { CultureName = "English" }; ServiceContext.LocalizationService.Save(danish, 0); ServiceContext.LocalizationService.Save(english, 0); _danishLangId = danish.Id; diff --git a/src/Umbraco.Tests/Services/SectionServiceTests.cs b/src/Umbraco.Tests/Services/SectionServiceTests.cs index 80a4de4bfe..82fda67003 100644 --- a/src/Umbraco.Tests/Services/SectionServiceTests.cs +++ b/src/Umbraco.Tests/Services/SectionServiceTests.cs @@ -4,6 +4,7 @@ using System.Threading; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Models.Membership; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Testing; using Umbraco.Web.Services; @@ -34,7 +35,8 @@ namespace Umbraco.Tests.Services private IUser CreateTestUser() { - var user = new User(TestObjects.GetGlobalSettings()) + var globalSettings = new GlobalSettingsBuilder().Build(); + var user = new User(globalSettings) { Name = "Test user", Username = "testUser", diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests/Services/UserServiceTests.cs index cedb329f13..fef2fa30af 100644 --- a/src/Umbraco.Tests/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests/Services/UserServiceTests.cs @@ -6,20 +6,17 @@ using System.Text; using System.Threading; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Exceptions; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Tests.Common.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; using Umbraco.Web.Actions; using MockedUser = Umbraco.Tests.TestHelpers.Entities.MockedUser; - namespace Umbraco.Tests.Services { /// @@ -724,7 +721,8 @@ namespace Umbraco.Tests.Services var hash = new HMACSHA1(); hash.Key = Encoding.Unicode.GetBytes(password); var encodedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password))); - var membershipUser = new User(TestObjects.GetGlobalSettings(), "JohnDoe", "john@umbraco.io", encodedPassword, encodedPassword); + var globalSettings = new GlobalSettingsBuilder().Build(); + var membershipUser = new User(globalSettings, "JohnDoe", "john@umbraco.io", encodedPassword, encodedPassword); userService.Save(membershipUser); // Assert diff --git a/src/Umbraco.Tests/Strings/StringValidationTests.cs b/src/Umbraco.Tests/Strings/StringValidationTests.cs deleted file mode 100644 index b76783080b..0000000000 --- a/src/Umbraco.Tests/Strings/StringValidationTests.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using NUnit.Framework; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Strings -{ - [TestFixture] - public class StringValidationTests : UmbracoTestBase - { - [Test] - public void Validate_Email_Address() - { - var foo = new EmailAddressAttribute(); - - Assert.IsTrue(foo.IsValid("someone@somewhere.com")); - Assert.IsTrue(foo.IsValid("someone@somewhere.co.uk")); - Assert.IsTrue(foo.IsValid("someone+tag@somewhere.net")); - Assert.IsTrue(foo.IsValid("futureTLD@somewhere.fooo")); - - Assert.IsTrue(foo.IsValid("abc@xyz.financial")); - Assert.IsTrue(foo.IsValid("admin+gmail-syntax@c.pizza")); - Assert.IsTrue(foo.IsValid("admin@c.pizza")); - - Assert.IsFalse(foo.IsValid("fdsa")); - Assert.IsFalse(foo.IsValid("fdsa@")); - - // IsValid can be either a powerful regex OR a dummy test, - // and by default it depends on System.ComponentModel.DataAnnotations.AppSettings.DisableRegEx - // which ends up using BinaryCompatibility.Current.TargetsAtLeastFramework472 so for some reason - // in 472 we are not using the regex anymore - // - // it can be forced, though with an app settings - // dataAnnotations:dataTypeAttribute:disableRegEx = false - // - // since Umbraco is now 4.7.2+, the setting is required for the following tests to pass - - Assert.IsFalse(foo.IsValid("fdsa@fdsa")); - Assert.IsFalse(foo.IsValid("fdsa@fdsa.")); - - } - } -} diff --git a/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs b/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs index 14e45d976c..4dc7ad0278 100644 --- a/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs +++ b/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs @@ -14,6 +14,7 @@ using Umbraco.Core; using System.Diagnostics; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Templates { @@ -76,9 +77,9 @@ namespace Umbraco.Tests.Templates var umbracoContextFactory = TestUmbracoContextFactory.Create( umbracoContextAccessor: umbracoContextAccessor); - + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); var publishedUrlProvider = new UrlProvider(umbracoContextAccessor, - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(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 20677468c6..375dc91d19 100644 --- a/src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs +++ b/src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; @@ -72,8 +73,9 @@ namespace Umbraco.Tests.Templates var umbracoContextFactory = TestUmbracoContextFactory.Create( umbracoContextAccessor: umbracoContextAccessor); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); var publishedUrlProvider = new UrlProvider(umbracoContextAccessor, - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(webRoutingSettings), new UrlProviderCollection(new []{contentUrlProvider.Object}), new MediaUrlProviderCollection(new []{mediaUrlProvider.Object}), Mock.Of() diff --git a/src/Umbraco.Tests/Templates/ViewHelperTests.cs b/src/Umbraco.Tests/Templates/ViewHelperTests.cs index ca304d5cda..9f6da6c34a 100644 --- a/src/Umbraco.Tests/Templates/ViewHelperTests.cs +++ b/src/Umbraco.Tests/Templates/ViewHelperTests.cs @@ -10,7 +10,8 @@ namespace Umbraco.Tests.Templates public void NoOptions() { var view = ViewHelper.GetDefaultFileContent(); - Assert.AreEqual(FixView(@"@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage + Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = null; }"), FixView(view)); @@ -20,7 +21,8 @@ namespace Umbraco.Tests.Templates public void Layout() { var view = ViewHelper.GetDefaultFileContent(layoutPageAlias: "Dharznoik"); - Assert.AreEqual(FixView(@"@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage + Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = ""Dharznoik.cshtml""; }"), FixView(view)); @@ -30,7 +32,8 @@ namespace Umbraco.Tests.Templates public void ClassName() { var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName"); - Assert.AreEqual(FixView(@"@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage + Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = null; }"), FixView(view)); @@ -40,7 +43,8 @@ namespace Umbraco.Tests.Templates public void Namespace() { var view = ViewHelper.GetDefaultFileContent(modelNamespace: "Models"); - Assert.AreEqual(FixView(@"@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage + Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @{ Layout = null; }"), FixView(view)); @@ -50,7 +54,8 @@ namespace Umbraco.Tests.Templates public void ClassNameAndNamespace() { var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models"); - Assert.AreEqual(FixView(@"@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage + Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @using ContentModels = My.Models; @{ Layout = null; @@ -61,7 +66,8 @@ namespace Umbraco.Tests.Templates public void ClassNameAndNamespaceAndAlias() { var view = ViewHelper.GetDefaultFileContent(modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels"); - Assert.AreEqual(FixView(@"@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage + Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @using MyModels = My.Models; @{ Layout = null; @@ -72,7 +78,8 @@ namespace Umbraco.Tests.Templates public void Combined() { var view = ViewHelper.GetDefaultFileContent(layoutPageAlias: "Dharznoik", modelClassName: "ClassName", modelNamespace: "My.Models", modelNamespaceAlias: "MyModels"); - Assert.AreEqual(FixView(@"@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage + Assert.AreEqual(FixView(@"@using Umbraco.Web.PublishedModels; +@inherits Umbraco.Web.Common.AspNetCore.UmbracoViewPage @using MyModels = My.Models; @{ Layout = ""Dharznoik.cshtml""; diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs index 6bc228bf83..3faea42f01 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs @@ -45,7 +45,7 @@ namespace Umbraco.Tests.TestHelpers logger, false); - var composition = new Composition(container, typeLoader, Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + var composition = new Composition(container, typeLoader, Mock.Of(), ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); composition.RegisterUnique(_ => Mock.Of()); composition.RegisterUnique(_ => Mock.Of()); diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 8926c02182..e51a10da50 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -5,6 +5,7 @@ using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -13,6 +14,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.PublishedContent; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web; @@ -91,13 +93,14 @@ namespace Umbraco.Tests.TestHelpers internal PublishedRouter CreatePublishedRouter(IFactory container = null, ContentFinderCollection contentFinders = null) { - return CreatePublishedRouter(SettingsForTests.GenerateMockWebRoutingSettings(), container ?? Factory, contentFinders); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + return CreatePublishedRouter(webRoutingSettings, container ?? Factory, contentFinders); } - internal static PublishedRouter CreatePublishedRouter(IWebRoutingSettings webRoutingSettings, IFactory container = null, ContentFinderCollection contentFinders = null) + internal static PublishedRouter CreatePublishedRouter(WebRoutingSettings webRoutingSettings, IFactory container = null, ContentFinderCollection contentFinders = null) { return new PublishedRouter( - webRoutingSettings, + Microsoft.Extensions.Options.Options.Create(webRoutingSettings), contentFinders ?? new ContentFinderCollection(Enumerable.Empty()), new TestLastChanceFinder(), new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 641691e853..379c176099 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -1,31 +1,21 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net.Http; using System.Web; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Dispatcher; -using System.Web.Security; using Moq; using Umbraco.Core.BackOffice; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Dictionary; -using Umbraco.Core.IO; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Security; using Umbraco.Web.WebApi; -using Umbraco.Core.Logging; -using Umbraco.Tests.Testing.Objects.Accessors; -using Umbraco.Web.Security.Providers; -using Umbraco.Tests.Strings; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers.Entities; @@ -67,7 +57,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting contentTypeService: mockedContentTypeService, localizedTextService:Mock.Of()); - var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettings(); // FIXME: v8? ////new app context @@ -105,7 +95,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting var backofficeIdentity = (UmbracoBackOfficeIdentity) owinContext.Authentication.User.Identity; - var webSecurity = new Mock(); + var backofficeSecurity = new Mock(); //mock CurrentUser var groups = new List(); @@ -126,13 +116,13 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting mockUser.Setup(x => x.StartContentIds).Returns(backofficeIdentity.StartContentNodes); mockUser.Setup(x => x.StartMediaIds).Returns(backofficeIdentity.StartMediaNodes); mockUser.Setup(x => x.Username).Returns(backofficeIdentity.Username); - webSecurity.Setup(x => x.CurrentUser) + backofficeSecurity.Setup(x => x.CurrentUser) .Returns(mockUser.Object); //mock Validate - webSecurity.Setup(x => x.ValidateCurrentUser()) + backofficeSecurity.Setup(x => x.ValidateCurrentUser()) .Returns(() => true); - webSecurity.Setup(x => x.UserHasSectionAccess(It.IsAny(), It.IsAny())) + backofficeSecurity.Setup(x => x.UserHasSectionAccess(It.IsAny(), It.IsAny())) .Returns(() => true); var publishedSnapshot = new Mock(); @@ -145,7 +135,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting var httpContextAccessor = TestHelper.GetHttpContextAccessor(httpContext); var umbCtx = new UmbracoContext(httpContextAccessor, publishedSnapshotService.Object, - webSecurity.Object, + backofficeSecurity.Object, globalSettings, TestHelper.GetHostingEnvironment(), new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs index 531d87f76f..4977b5d81a 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Umbraco.Core.Models.Membership; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.TestHelpers.Entities { @@ -23,7 +24,8 @@ namespace Umbraco.Tests.TestHelpers.Entities internal static User CreateUser(string suffix = "") { - var user = new User(SettingsForTests.GenerateMockGlobalSettings()) + var globalSettings = new GlobalSettingsBuilder().Build(); + var user = new User(globalSettings) { Language = "en", IsApproved = true, @@ -41,10 +43,11 @@ namespace Umbraco.Tests.TestHelpers.Entities { var list = new List(); + var globalSettings = new GlobalSettingsBuilder().Build(); for (int i = 0; i < amount; i++) { var name = "Member No-" + i; - var user = new User(SettingsForTests.GenerateMockGlobalSettings(), name, "test" + i + "@test.com", "test" + i, "test" + i); + var user = new User(globalSettings, name, "test" + i + "@test.com", "test" + i, "test" + i); onCreating?.Invoke(i, user); diff --git a/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs b/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs deleted file mode 100644 index b58301287b..0000000000 --- a/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; - -namespace Umbraco.Tests.TestHelpers -{ - public class SettingsForTests - { - private static Common.SettingsForTests _settingsForTests = new Common.SettingsForTests(); - - public static IGlobalSettings GenerateMockGlobalSettings() => _settingsForTests.GenerateMockGlobalSettings(TestHelper.GetUmbracoVersion()); - - /// - /// Returns generated settings which can be stubbed to return whatever values necessary - /// - /// - public static IContentSettings GenerateMockContentSettings() => _settingsForTests.GenerateMockContentSettings(); - - //// from appSettings - - //private static 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 static void Reset() => _settingsForTests.Reset(); - - internal static IGlobalSettings DefaultGlobalSettings => _settingsForTests.GetDefaultGlobalSettings(TestHelper.GetUmbracoVersion()); - - internal static IHostingSettings DefaultHostingSettings => _settingsForTests.DefaultHostingSettings; - - public static IHostingSettings GenerateMockHostingSettings() => _settingsForTests.GenerateMockHostingSettings(); - - public static IWebRoutingSettings GenerateMockWebRoutingSettings() => _settingsForTests.GenerateMockWebRoutingSettings(); - - public static IRequestHandlerSettings GenerateMockRequestHandlerSettings() => _settingsForTests.GenerateMockRequestHandlerSettings(); - - public static ISecuritySettings GenerateMockSecuritySettings() => _settingsForTests.GenerateMockSecuritySettings(); - - public static IUserPasswordConfiguration GenerateMockUserPasswordConfiguration() => _settingsForTests.GenerateMockUserPasswordConfiguration(); - - public static IMemberPasswordConfiguration GenerateMockMemberPasswordConfiguration() => _settingsForTests.GenerateMockMemberPasswordConfiguration(); - } -} diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index 9aeb668518..041c9d0c21 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -33,6 +33,9 @@ using Umbraco.Web; using Umbraco.Web.Hosting; using Umbraco.Web.Routing; using File = System.IO.File; +using Umbraco.Tests.Common.Builders; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Tests.TestHelpers { @@ -59,11 +62,11 @@ namespace Umbraco.Tests.TestHelpers public override IBackOfficeInfo GetBackOfficeInfo() => new AspNetBackOfficeInfo( - SettingsForTests.GenerateMockGlobalSettings(GetUmbracoVersion()), - TestHelper.IOHelper, Mock.Of(), SettingsForTests.GenerateMockWebRoutingSettings()); + new GlobalSettings(), + TestHelper.IOHelper, Mock.Of(), Options.Create(new WebRoutingSettings())); public override IHostingEnvironment GetHostingEnvironment() - => new AspNetHostingEnvironment(SettingsForTests.DefaultHostingSettings); + => new AspNetHostingEnvironment(Options.Create(new HostingSettings())); public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => new AspNetApplicationShutdownRegistry(); @@ -76,13 +79,11 @@ namespace Umbraco.Tests.TestHelpers public static TypeLoader GetMockedTypeLoader() => _testHelperInternal.GetMockedTypeLoader(); - public static Configs GetConfigs() => _testHelperInternal.GetConfigs(); - - public static IRuntimeState GetRuntimeState() => _testHelperInternal.GetRuntimeState(); + //public static Configs GetConfigs() => _testHelperInternal.GetConfigs(); public static IBackOfficeInfo GetBackOfficeInfo() => _testHelperInternal.GetBackOfficeInfo(); - public static IConfigsFactory GetConfigsFactory() => _testHelperInternal.GetConfigsFactory(); + // public static IConfigsFactory GetConfigsFactory() => _testHelperInternal.GetConfigsFactory(); /// /// Gets the working directory of the test project. @@ -96,16 +97,14 @@ namespace Umbraco.Tests.TestHelpers 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 CoreDebugSettings CoreDebugSettings => _testHelperInternal.CoreDebugSettings; public static IIOHelper IOHelper => _testHelperInternal.IOHelper; public static IMainDom MainDom => _testHelperInternal.MainDom; public static UriUtility UriUtility => _testHelperInternal.UriUtility; - public static IWebRoutingSettings WebRoutingSettings => _testHelperInternal.WebRoutingSettings; - - public static IEmailSender EmailSender { get; } = new EmailSender(SettingsForTests.GenerateMockGlobalSettings()); + public static IEmailSender EmailSender { get; } = new EmailSender(Options.Create(new GlobalSettingsBuilder().Build())); /// @@ -117,12 +116,12 @@ namespace Umbraco.Tests.TestHelpers public static void InitializeContentDirectories() { - CreateDirectories(new[] { Constants.SystemDirectories.MvcViews, SettingsForTests.GenerateMockGlobalSettings().UmbracoMediaPath, Constants.SystemDirectories.AppPlugins }); + CreateDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath, Constants.SystemDirectories.AppPlugins }); } public static void CleanContentDirectories() { - CleanDirectories(new[] { Constants.SystemDirectories.MvcViews, SettingsForTests.GenerateMockGlobalSettings().UmbracoMediaPath }); + CleanDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath }); } public static void CreateDirectories(string[] directories) @@ -304,25 +303,6 @@ namespace Umbraco.Tests.TestHelpers } } - // TODO: Move to MockedValueEditors.cs - public static DataValueEditor CreateDataValueEditor(string name) - { - var valueType = (ValueTypes.IsValue(name)) ? name : ValueTypes.String; - - return new DataValueEditor( - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - new DataEditorAttribute(name, name, name) - { - ValueType = valueType - } - - ); - } - - public static IUmbracoVersion GetUmbracoVersion() => _testHelperInternal.GetUmbracoVersion(); public static IRegister GetRegister() => _testHelperInternal.GetRegister(); diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs index 1b63bcc98d..7037961e7d 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -7,12 +7,11 @@ using System.Linq.Expressions; using Moq; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Services; using Umbraco.Persistance.SqlCe; using Umbraco.Tests.Common; @@ -136,9 +135,9 @@ namespace Umbraco.Tests.TestHelpers return umbracoContextFactory.EnsureUmbracoContext().UmbracoContext; } - public IGlobalSettings GetGlobalSettings() + public GlobalSettings GetGlobalSettings() { - return SettingsForTests.DefaultGlobalSettings; + return new GlobalSettings(); } public IFileSystems GetFileSystemsMock() { diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 7356018c58..e101bb33a3 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -1,28 +1,26 @@ using System; +using System.Configuration; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; using Moq; using NPoco; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; -using Umbraco.Core.Packaging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; -using Umbraco.Core.Strings; using Umbraco.Persistance.SqlCe; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers.Stubs; using Current = Umbraco.Web.Composing.Current; @@ -70,163 +68,6 @@ namespace Umbraco.Tests.TestHelpers return new UmbracoDatabase(connection, sqlContext, logger, TestHelper.BulkSqlInsertProvider); } - public void RegisterServices(IRegister register) - { } - - /// - /// Gets a ServiceContext. - /// - /// - /// - /// A cache. - /// A logger. - /// An io helper. - /// - /// - /// An event messages factory. - /// Some url segment providers. - /// An Umbraco Version. - /// A container. - /// A ServiceContext. - /// Should be used sparingly for integration tests only - for unit tests - /// just mock the services to be passed to the ctor of the ServiceContext. - public ServiceContext GetServiceContext(IScopeProvider scopeProvider, IScopeAccessor scopeAccessor, - AppCaches cache, - ILogger logger, - IIOHelper ioHelper, - IGlobalSettings globalSettings, - IContentSettings contentSettings, - IEventMessagesFactory eventMessagesFactory, - UrlSegmentProviderCollection urlSegmentProviders, - IUmbracoVersion umbracoVersion, - IHostingEnvironment hostingEnvironment, - IFactory factory = null) - { - if (scopeProvider == null) throw new ArgumentNullException(nameof(scopeProvider)); - if (scopeAccessor == null) throw new ArgumentNullException(nameof(scopeAccessor)); - if (cache == null) throw new ArgumentNullException(nameof(cache)); - if (logger == null) throw new ArgumentNullException(nameof(logger)); - if (eventMessagesFactory == null) throw new ArgumentNullException(nameof(eventMessagesFactory)); - - var scheme = Mock.Of(); - - var shortStringHelper = Mock.Of(); - - var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, logger, shortStringHelper); - - var externalLoginService = GetLazyService(factory, c => new ExternalLoginService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); - var publicAccessService = GetLazyService(factory, c => new PublicAccessService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); - var domainService = GetLazyService(factory, c => new DomainService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); - var auditService = GetLazyService(factory, c => new AuditService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c))); - - var localizedTextService = GetLazyService(factory, c => new LocalizedTextService( - new Lazy(() => - { - var mainLangFolder = new DirectoryInfo(ioHelper.MapPath(Current.Configs.Global().UmbracoPath + "/config/lang/")); - var appPlugins = new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.AppPlugins)); - var configLangFolder = new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.Config + "/lang/")); - - var pluginLangFolders = appPlugins.Exists == false - ? Enumerable.Empty() - : appPlugins.GetDirectories() - .SelectMany(x => x.GetDirectories("Lang")) - .SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly)) - .Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 5) - .Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false)); - - //user defined langs that overwrite the default, these should not be used by plugin creators - var userLangFolders = configLangFolder.Exists == false - ? Enumerable.Empty() - : configLangFolder - .GetFiles("*.user.xml", SearchOption.TopDirectoryOnly) - .Where(x => Path.GetFileNameWithoutExtension(x.FullName).Length == 10) - .Select(x => new LocalizedTextServiceSupplementaryFileSource(x, true)); - - return new LocalizedTextServiceFileSources( - logger, - cache, - mainLangFolder, - pluginLangFolders.Concat(userLangFolders)); - - }), - logger)); - - var runtimeState = Mock.Of(); - var idkMap = new IdKeyMap(scopeProvider); - - var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - - var localizationService = GetLazyService(factory, c => new LocalizationService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c))); - var userService = GetLazyService(factory, c => new UserService(scopeProvider, logger, eventMessagesFactory, runtimeState, GetRepo(c), GetRepo(c),globalSettings)); - 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, localizedTextService.Value)); - var contentService = GetLazyService(factory, c => new ContentService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), propertyValidationService, TestHelper.ShortStringHelper)); - var notificationService = GetLazyService(factory, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, localizationService.Value, logger, ioHelper, GetRepo(c), globalSettings, contentSettings, TestHelper.EmailSender)); - 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))); - var mediaService = GetLazyService(factory, c => new MediaService(scopeProvider, mediaFileSystem, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), TestHelper.ShortStringHelper)); - var contentTypeService = GetLazyService(factory, c => new ContentTypeService(scopeProvider, logger, eventMessagesFactory, contentService.Value, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); - var mediaTypeService = GetLazyService(factory, c => new MediaTypeService(scopeProvider, logger, eventMessagesFactory, mediaService.Value, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); - var fileService = GetLazyService(factory, c => new FileService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), TestHelper.ShortStringHelper, globalSettings, hostingEnvironment)); - - var memberTypeService = GetLazyService(factory, c => new MemberTypeService(scopeProvider, logger, eventMessagesFactory, memberService.Value, GetRepo(c), GetRepo(c), GetRepo(c))); - var entityService = GetLazyService(factory, c => new EntityService(scopeProvider, logger, eventMessagesFactory, idkMap, GetRepo(c))); - - var macroService = GetLazyService(factory, c => new MacroService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c))); - var packagingService = GetLazyService(factory, c => - { - var compiledPackageXmlParser = new CompiledPackageXmlParser(new ConflictingPackageData(macroService.Value, fileService.Value), globalSettings); - return new PackagingService( - auditService.Value, - new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, hostingEnvironment, - new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders, TestHelper.ShortStringHelper, propertyEditorCollection), logger, umbracoVersion, globalSettings, "createdPackages.config"), - new PackagesRepository(contentService.Value, contentTypeService.Value, dataTypeService.Value, fileService.Value, macroService.Value, localizationService.Value, hostingEnvironment, - new EntityXmlSerializer(contentService.Value, mediaService.Value, dataTypeService.Value, userService.Value, localizationService.Value, contentTypeService.Value, urlSegmentProviders, TestHelper.ShortStringHelper, propertyEditorCollection), logger, umbracoVersion, globalSettings, "installedPackages.config"), - new PackageInstallation( - new PackageDataInstallation(logger, fileService.Value, macroService.Value, localizationService.Value, dataTypeService.Value, entityService.Value, contentTypeService.Value, contentService.Value, propertyEditorCollection, scopeProvider, shortStringHelper, GetGlobalSettings(), localizedTextService.Value), - new PackageFileInstallation(compiledPackageXmlParser, ioHelper, new ProfilingLogger(logger, new TestProfiler())), - compiledPackageXmlParser, Mock.Of(), - Mock.Of(x => x.ApplicationPhysicalPath == ioHelper.MapPath("~"))), - ioHelper); - }); - var relationService = GetLazyService(factory, c => new RelationService(scopeProvider, logger, eventMessagesFactory, entityService.Value, GetRepo(c), GetRepo(c), GetRepo(c))); - var tagService = GetLazyService(factory, c => new TagService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); - var redirectUrlService = GetLazyService(factory, c => new RedirectUrlService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); - var consentService = GetLazyService(factory, c => new ConsentService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); - var keyValueService = GetLazyService(factory, c => new KeyValueService(scopeProvider, GetRepo(c))); - var contentTypeServiceBaseFactory = GetLazyService(factory, c => new ContentTypeBaseServiceProvider(factory.GetInstance(),factory.GetInstance(),factory.GetInstance())); - - return new ServiceContext( - publicAccessService, - domainService, - auditService, - localizedTextService, - tagService, - contentService, - userService, - memberService, - mediaService, - contentTypeService, - mediaTypeService, - dataTypeService, - fileService, - localizationService, - packagingService, - serverRegistrationService, - entityService, - relationService, - macroService, - memberTypeService, - memberGroupService, - notificationService, - externalLoginService, - redirectUrlService, - consentService, - keyValueService, - contentTypeServiceBaseFactory); - } - private Lazy GetLazyService(IFactory container, Func ctor) where T : class { @@ -241,6 +82,11 @@ namespace Umbraco.Tests.TestHelpers public IScopeProvider GetScopeProvider(ILogger logger, ITypeFinder typeFinder = null, FileSystems fileSystems = null, IUmbracoDatabaseFactory databaseFactory = null) { + var globalSettings = new GlobalSettingsBuilder().Build(); + var connectionString = ConfigurationManager.ConnectionStrings[Constants.System.UmbracoConnectionName].ConnectionString; + var connectionStrings = new ConnectionStringsBuilder().WithUmbracoConnectionString(connectionString).Build(); + var coreDebugSettings = new CoreDebugSettingsBuilder().Build(); + if (databaseFactory == null) { // var mappersBuilder = new MapperCollectionBuilder(Current.Container); // FIXME: @@ -248,19 +94,17 @@ namespace Umbraco.Tests.TestHelpers // var mappers = mappersBuilder.CreateCollection(); var mappers = Current.Factory.GetInstance(); databaseFactory = new UmbracoDatabaseFactory(logger, - SettingsForTests.DefaultGlobalSettings, - new ConnectionStrings(), - Constants.System.UmbracoConnectionName, + globalSettings, + connectionStrings, new Lazy(() => mappers), TestHelper.DbProviderFactoryCreator); } typeFinder ??= new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); - fileSystems ??= new FileSystems(Current.Factory, logger, TestHelper.IOHelper, SettingsForTests.GenerateMockGlobalSettings(), TestHelper.GetHostingEnvironment()); + fileSystems ??= new FileSystems(Current.Factory, logger, TestHelper.IOHelper, Options.Create(globalSettings), TestHelper.GetHostingEnvironment()); var coreDebug = TestHelper.CoreDebugSettings; var mediaFileSystem = Mock.Of(); - var scopeProvider = new ScopeProvider(databaseFactory, fileSystems, coreDebug, mediaFileSystem, logger, typeFinder, NoAppCache.Instance); - return scopeProvider; + return new ScopeProvider(databaseFactory, fileSystems, Microsoft.Extensions.Options.Options.Create(coreDebugSettings), mediaFileSystem, logger, typeFinder, NoAppCache.Instance); } } diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index cfcdacdadf..fe41ac2d9c 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -1,8 +1,6 @@ using System; -using System.Collections.Generic; using System.Configuration; using System.Data.SqlServerCe; -using System.Linq; using System.Threading; using System.Web.Routing; using System.Xml; @@ -10,8 +8,7 @@ using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; @@ -33,6 +30,7 @@ using Umbraco.Persistance.SqlCe; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Web.WebApi; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.TestHelpers { @@ -237,11 +235,11 @@ namespace Umbraco.Tests.TestHelpers } } - protected virtual IPublishedSnapshotService CreatePublishedSnapshotService() + protected virtual IPublishedSnapshotService CreatePublishedSnapshotService(GlobalSettings globalSettings = null) { var cache = NoAppCache.Instance; - ContentTypesCache = new PublishedContentTypeCache( + ContentTypesCache ??= new PublishedContentTypeCache( Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), @@ -261,7 +259,7 @@ namespace Umbraco.Tests.TestHelpers Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), DefaultCultureAccessor, Logger, - Factory.GetInstance(), + globalSettings ?? TestObjects.GetGlobalSettings(), HostingEnvironment, HostingLifetime, ShortStringHelper, @@ -301,7 +299,7 @@ namespace Umbraco.Tests.TestHelpers { using (var scope = ScopeProvider.CreateScope()) { - var schemaHelper = new DatabaseSchemaCreator(scope.Database, Logger, UmbracoVersion, TestObjects.GetGlobalSettings()); + var schemaHelper = new DatabaseSchemaCreator(scope.Database, Logger, UmbracoVersion); //Create the umbraco database and its base data schemaHelper.InitializeDatabaseSchema(); @@ -351,7 +349,7 @@ namespace Umbraco.Tests.TestHelpers } } - protected IUmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IGlobalSettings globalSettings = null, IPublishedSnapshotService snapshotService = null) + protected IUmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, GlobalSettings globalSettings = null, IPublishedSnapshotService snapshotService = null) { // ensure we have a PublishedCachesService var service = snapshotService ?? PublishedSnapshotService as XmlPublishedSnapshotService; @@ -374,8 +372,8 @@ namespace Umbraco.Tests.TestHelpers var umbracoContext = new UmbracoContext( httpContextAccessor, service, - Mock.Of(), - globalSettings ?? Factory.GetInstance(), + Mock.Of(), + globalSettings ?? new GlobalSettingsBuilder().Build(), HostingEnvironment, new TestVariationContextAccessor(), UriUtility, diff --git a/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs b/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs index cb20c56d6d..544e60d721 100644 --- a/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs +++ b/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs @@ -1,7 +1,5 @@ using Moq; -using NUnit.Framework.Internal; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Services; using Umbraco.Tests.Common; using Umbraco.Tests.TestHelpers; @@ -16,12 +14,12 @@ namespace Umbraco.Tests.Testing.Objects /// public class TestUmbracoContextFactory { - public static IUmbracoContextFactory Create(IGlobalSettings globalSettings = null, + public static IUmbracoContextFactory Create(GlobalSettings globalSettings = null, IUmbracoContextAccessor umbracoContextAccessor = null, IHttpContextAccessor httpContextAccessor = null, IPublishedUrlProvider publishedUrlProvider = null) { - if (globalSettings == null) globalSettings = TestHelpers.SettingsForTests.GenerateMockGlobalSettings(); + if (globalSettings == null) globalSettings = new GlobalSettings(); 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 6f5739eb02..8a08e2be07 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Dictionary; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; @@ -27,6 +28,7 @@ using Umbraco.Web.Security; using Umbraco.Web.Security.Providers; using Umbraco.Web.WebApi; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Testing.TestingTests { @@ -84,9 +86,10 @@ namespace Umbraco.Tests.Testing.TestingTests .Returns(UrlInfo.Url("/hello/world/1234")); var urlProvider = urlProviderMock.Object; + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); var theUrlProvider = new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(webRoutingSettings), new UrlProviderCollection(new [] { urlProvider }), new MediaUrlProviderCollection( Enumerable.Empty()) , umbracoContext.VariationContextAccessor); @@ -108,7 +111,7 @@ namespace Umbraco.Tests.Testing.TestingTests var membershipHelper = new MembershipHelper(Mock.Of(), Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, logger, ShortStringHelper, Mock.Of()); var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of() })); - var umbracoApiController = new FakeUmbracoApiController(Mock.Of(), Mock.Of(), Mock.Of(), ServiceContext.CreatePartial(), AppCaches.NoCache, logger, Mock.Of(), umbracoMapper, Mock.Of()); + var umbracoApiController = new FakeUmbracoApiController(new GlobalSettings(), Mock.Of(), Mock.Of(), ServiceContext.CreatePartial(), AppCaches.NoCache, logger, Mock.Of(), umbracoMapper, Mock.Of()); Assert.Pass(); } @@ -116,7 +119,7 @@ namespace Umbraco.Tests.Testing.TestingTests internal class FakeUmbracoApiController : UmbracoApiController { - public FakeUmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) + public FakeUmbracoApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { } } } diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 94c52e8d96..08a1297cda 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -13,13 +13,19 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Dictionary; using Umbraco.Core.Events; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Manifest; +using Umbraco.Core.Mapping; +using Umbraco.Core.Media; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; @@ -27,39 +33,34 @@ using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Security; +using Umbraco.Core.Serialization; +using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; +using Umbraco.Net; +using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Components; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Web; -using Umbraco.Web.Services; using Umbraco.Web.Actions; +using Umbraco.Web.AspNet; using Umbraco.Web.ContentApps; +using Umbraco.Web.Hosting; +using Umbraco.Web.Install; +using Umbraco.Web.PropertyEditors; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; -using Umbraco.Core.Composing.CompositionExtensions; -using Umbraco.Core.Hosting; -using Umbraco.Core.Mapping; -using Umbraco.Core.Serialization; -using Umbraco.Web.Composing.CompositionExtensions; -using Umbraco.Web.Hosting; using Umbraco.Web.Sections; -using FileSystems = Umbraco.Core.IO.FileSystems; -using Umbraco.Web.Templates; -using Umbraco.Web.PropertyEditors; -using Umbraco.Core.Dictionary; -using Umbraco.Net; -using Umbraco.Core.Security; -using Umbraco.Core.Services; -using Umbraco.Web.AspNet; -using Umbraco.Web.Install; using Umbraco.Web.Security; using Umbraco.Web.Security.Providers; +using Umbraco.Web.Services; +using Umbraco.Web.Templates; using Umbraco.Web.Trees; using Current = Umbraco.Web.Composing.Current; -using Umbraco.Tests.Common; -using Umbraco.Core.Media; +using FileSystems = Umbraco.Core.IO.FileSystems; namespace Umbraco.Tests.Testing { @@ -136,7 +137,7 @@ namespace Umbraco.Tests.Testing protected virtual IProfilingLogger ProfilingLogger => Factory.GetInstance(); - protected IHostingEnvironment HostingEnvironment { get; } = new AspNetHostingEnvironment(TestHelpers.SettingsForTests.DefaultHostingSettings); + protected IHostingEnvironment HostingEnvironment { get; } = new AspNetHostingEnvironment(Microsoft.Extensions.Options.Options.Create(new HostingSettings())); protected IApplicationShutdownRegistry HostingLifetime { get; } = new AspNetApplicationShutdownRegistry(); protected IIpResolver IpResolver => Factory.GetInstance(); protected IBackOfficeInfo BackOfficeInfo => Factory.GetInstance(); @@ -172,12 +173,12 @@ namespace Umbraco.Tests.Testing TypeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); var appCaches = GetAppCaches(); - var globalSettings = TestHelpers.SettingsForTests.DefaultGlobalSettings; - var settings = TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings(); + var globalSettings = new GlobalSettingsBuilder().Build(); + var settings = new WebRoutingSettings(); - IBackOfficeInfo backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, IOHelper, logger, settings); + IBackOfficeInfo backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, IOHelper, logger, Microsoft.Extensions.Options.Options.Create(settings)); IIpResolver ipResolver = new AspNetIpResolver(); - UmbracoVersion = new UmbracoVersion(globalSettings); + UmbracoVersion = new UmbracoVersion(); LocalizedTextService = new LocalizedTextService(new Dictionary>(), logger); @@ -187,9 +188,11 @@ namespace Umbraco.Tests.Testing - Composition = new Composition(register, typeLoader, proflogger, ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); + Composition = new Composition(register, typeLoader, proflogger, ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); + //TestHelper.GetConfigs().RegisterWith(register); + Composition.RegisterUnique(IOHelper); Composition.RegisterUnique(UriUtility); @@ -313,21 +316,21 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(); Composition.RegisterUnique(); - Composition.RegisterUnique(); + Composition.RegisterUnique(); Composition.RegisterUnique(); Composition.RegisterUnique(); Composition.RegisterUnique(); Composition.RegisterUnique(); Composition.RegisterUnique(); + + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); Composition.RegisterUnique(factory => new UrlProvider( factory.GetInstance(), - TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings(), + Microsoft.Extensions.Options.Options.Create(webRoutingSettings), new UrlProviderCollection(Enumerable.Empty()), new MediaUrlProviderCollection(Enumerable.Empty()), - factory.GetInstance() - - )); + factory.GetInstance())); @@ -411,16 +414,21 @@ namespace Umbraco.Tests.Testing protected virtual void ComposeSettings() { - Composition.Configs.Add(() => TestHelpers.SettingsForTests.DefaultGlobalSettings); - Composition.Configs.Add(() => TestHelpers.SettingsForTests.DefaultHostingSettings); - 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); + var contentSettings = new ContentSettingsBuilder().Build(); + var coreDebugSettings = new CoreDebugSettingsBuilder().Build(); + var globalSettings = new GlobalSettingsBuilder().Build(); + var nuCacheSettings = new NuCacheSettingsBuilder().Build(); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettingsBuilder().Build(); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); - //Composition.Configs.Add(() => new DefaultUserPasswordConfig()); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(contentSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(coreDebugSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(requestHandlerSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(userPasswordConfigurationSettings)); + Composition.Register(x => Microsoft.Extensions.Options.Options.Create(webRoutingSettings)); } protected virtual void ComposeApplication(bool withApplication) @@ -457,13 +465,12 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(_ => new TransientEventMessagesFactory()); - var globalSettings = TestHelper.GetConfigs().Global(); - var connectionStrings = TestHelper.GetConfigs().ConnectionStrings(); + var globalSettings = new GlobalSettingsBuilder().Build(); + var connectionStrings = new ConnectionStringsBuilder().Build(); Composition.RegisterUnique(f => new UmbracoDatabaseFactory(Logger, globalSettings, connectionStrings, - Constants.System.UmbracoConnectionName, new Lazy(f.GetInstance), TestHelper.DbProviderFactoryCreator)); @@ -553,7 +560,6 @@ namespace Umbraco.Tests.Testing // reset all other static things that should not be static ;( UriUtility.ResetAppDomainAppVirtualPath(HostingEnvironment); - 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 debdfd3c6b..8e69230799 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 + 1.11.24 - + @@ -95,22 +95,22 @@ - - - - + + + + - - + + - + - + @@ -121,24 +121,23 @@ - - - - - - + + + + + @@ -147,13 +146,9 @@ - - - - @@ -173,10 +168,6 @@ - - - - @@ -184,11 +175,10 @@ - - + @@ -222,10 +212,8 @@ - - @@ -254,9 +242,6 @@ - - - @@ -279,7 +264,6 @@ - @@ -290,10 +274,6 @@ - - - - @@ -312,11 +292,7 @@ - - - - True @@ -342,7 +318,6 @@ - @@ -368,7 +343,6 @@ - @@ -392,7 +366,6 @@ - @@ -423,7 +396,6 @@ - @@ -458,10 +430,6 @@ - - {fbe7c065-dac0-4025-a78b-63b24d3ab00b} - Umbraco.Configuration - {29aa69d9-b597-4395-8d42-43b1263c240a} Umbraco.Core @@ -474,10 +442,6 @@ {3ae7bf57-966b-45a5-910a-954d7c554441} Umbraco.Infrastructure - - {52ac0ba8-a60e-4e36-897b-e8b97a54ed1c} - Umbraco.ModelsBuilder.Embedded - {33085570-9bf2-4065-a9b0-a29d920d13ba} Umbraco.Persistance.SqlCe diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index 0d55fd99d7..eac16e457f 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Components; using Umbraco.Tests.TestHelpers; @@ -33,8 +34,8 @@ namespace Umbraco.Tests.UmbracoExamine protected override void Compose() { base.Compose(); - - Composition.RegisterUnique(_ => new DefaultShortStringHelper(SettingsForTests.GenerateMockRequestHandlerSettings())); + var requestHandlerSettings = new RequestHandlerSettingsBuilder().Build(); + Composition.RegisterUnique(_ => new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings))); } } } diff --git a/src/Umbraco.Tests/Web/Mvc/RenderNoContentControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderNoContentControllerTests.cs index d33ce3bfcc..3f66dcb86c 100644 --- a/src/Umbraco.Tests/Web/Mvc/RenderNoContentControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/RenderNoContentControllerTests.cs @@ -2,6 +2,7 @@ using Moq; using NUnit.Framework; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Tests.Common; using Umbraco.Web; @@ -20,8 +21,7 @@ namespace Umbraco.Tests.Web.Mvc var mockUmbracoContext = new Mock(); mockUmbracoContext.Setup(x => x.Content.HasContent()).Returns(true); var mockIOHelper = new Mock(); - var mockGlobalSettings = new Mock(); - var controller = new RenderNoContentController(new TestUmbracoContextAccessor(mockUmbracoContext.Object), mockIOHelper.Object, mockGlobalSettings.Object); + var controller = new RenderNoContentController(new TestUmbracoContextAccessor(mockUmbracoContext.Object), mockIOHelper.Object, new GlobalSettings()); var result = controller.Index() as RedirectResult; @@ -39,10 +39,12 @@ namespace Umbraco.Tests.Web.Mvc 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(new TestUmbracoContextAccessor(mockUmbracoContext.Object), mockIOHelper.Object, mockGlobalSettings.Object); + var globalSettings = new GlobalSettings() + { + UmbracoPath = UmbracoPathSetting, + NoNodesViewPath = ViewPath, + }; + var controller = new RenderNoContentController(new TestUmbracoContextAccessor(mockUmbracoContext.Object), mockIOHelper.Object, globalSettings); var result = controller.Index() as ViewResult; Assert.IsNotNull(result); diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index 4c222b9116..8e0c534550 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Web; @@ -155,8 +156,8 @@ namespace Umbraco.Tests.Web.Mvc var content = Mock.Of(publishedContent => publishedContent.Id == 12345); - - var publishedRouter = BaseWebTest.CreatePublishedRouter(TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings()); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + var publishedRouter = BaseWebTest.CreatePublishedRouter(webRoutingSettings); 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 6f1a073eca..bcaf1ceccf 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -22,6 +22,7 @@ using Umbraco.Web.Models; using Umbraco.Web.Mvc; using Umbraco.Web.Routing; using Umbraco.Web.Security; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.Web.Mvc { @@ -387,7 +388,8 @@ namespace Umbraco.Tests.Web.Mvc { var umbracoContext = GetUmbracoContext("/dang", 0); - var publishedRouter = BaseWebTest.CreatePublishedRouter(TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings()); + var webRoutingSettings = new WebRoutingSettingsBuilder().Build(); + var publishedRouter = BaseWebTest.CreatePublishedRouter(webRoutingSettings); var frequest = publishedRouter.CreateRequest(umbracoContext, new Uri("http://localhost/dang")); frequest.Culture = CultureInfo.InvariantCulture; @@ -438,7 +440,7 @@ namespace Umbraco.Tests.Web.Mvc var ctx = new UmbracoContext( httpContextAccessor, _service, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs index 32d8e0917b..0e5b963d9f 100644 --- a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs +++ b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs @@ -32,7 +32,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( httpContextAccessor, Mock.Of(), - Mock.Of(), + Mock.Of(), TestObjects.GetGlobalSettings(), HostingEnvironment, new TestVariationContextAccessor(), @@ -53,7 +53,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( httpContextAccessor, Mock.Of(), - Mock.Of(), + Mock.Of(), TestObjects.GetGlobalSettings(), HostingEnvironment, new TestVariationContextAccessor(), @@ -84,7 +84,7 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( httpContextAccessor, Mock.Of(), - Mock.Of(), + Mock.Of(), TestObjects.GetGlobalSettings(), HostingEnvironment, new TestVariationContextAccessor(), diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index 643c0e7e99..3669911841 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -1,22 +1,21 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Routing; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Mail; using System.Threading.Tasks; using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Extensions; using Umbraco.Net; @@ -40,17 +39,17 @@ namespace Umbraco.Web.BackOffice.Controllers [IsBackOffice] // TODO: This could be applied with our Application Model conventions public class AuthenticationController : UmbracoApiControllerBase { - private readonly IWebSecurity _webSecurity; - private readonly BackOfficeUserManager _userManager; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly IBackOfficeUserManager _userManager; private readonly BackOfficeSignInManager _signInManager; private readonly IUserService _userService; private readonly ILocalizedTextService _textService; private readonly UmbracoMapper _umbracoMapper; - private readonly IGlobalSettings _globalSettings; - private readonly ISecuritySettings _securitySettings; + private readonly GlobalSettings _globalSettings; + private readonly SecuritySettings _securitySettings; private readonly ILogger _logger; private readonly IIpResolver _ipResolver; - private readonly IUserPasswordConfiguration _passwordConfiguration; + private readonly UserPasswordConfigurationSettings _passwordConfiguration; private readonly IEmailSender _emailSender; private readonly Core.Hosting.IHostingEnvironment _hostingEnvironment; private readonly IRequestAccessor _requestAccessor; @@ -60,33 +59,33 @@ namespace Umbraco.Web.BackOffice.Controllers // TODO: We need to review all _userManager.Raise calls since many/most should be on the usermanager or signinmanager, very few should be here public AuthenticationController( - IWebSecurity webSecurity, - BackOfficeUserManager backOfficeUserManager, + IBackofficeSecurityAccessor backofficeSecurityAccessor, + IBackOfficeUserManager backOfficeUserManager, BackOfficeSignInManager signInManager, IUserService userService, ILocalizedTextService textService, UmbracoMapper umbracoMapper, - IGlobalSettings globalSettings, - ISecuritySettings securitySettings, + IOptions globalSettings, + IOptions securitySettings, ILogger logger, IIpResolver ipResolver, - IUserPasswordConfiguration passwordConfiguration, + IOptions passwordConfiguration, IEmailSender emailSender, Core.Hosting.IHostingEnvironment hostingEnvironment, IRequestAccessor requestAccessor, LinkGenerator linkGenerator) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _userManager = backOfficeUserManager; _signInManager = signInManager; _userService = userService; _textService = textService; _umbracoMapper = umbracoMapper; - _globalSettings = globalSettings; - _securitySettings = securitySettings; + _globalSettings = globalSettings.Value; + _securitySettings = securitySettings.Value; _logger = logger; _ipResolver = ipResolver; - _passwordConfiguration = passwordConfiguration; + _passwordConfiguration = passwordConfiguration.Value; _emailSender = emailSender; _hostingEnvironment = hostingEnvironment; _requestAccessor = requestAccessor; @@ -100,7 +99,7 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoAuthorize] public IDictionary GetPasswordConfig(int userId) { - return _passwordConfiguration.GetConfiguration(userId != _webSecurity.CurrentUser.Id); + return _passwordConfiguration.GetConfiguration(userId != _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); } /// @@ -168,7 +167,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpGet] public bool IsAuthenticated() { - var attempt = _webSecurity.AuthorizeRequest(); + var attempt = _backofficeSecurityAccessor.BackofficeSecurity.AuthorizeRequest(); if (attempt == ValidateRequestAttempt.Success) { return true; @@ -190,7 +189,7 @@ namespace Umbraco.Web.BackOffice.Controllers //[CheckIfUserTicketDataIsStale] // TODO: Migrate this, though it will need to be done differently at the cookie auth level public UserDetail GetCurrentUser() { - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; var result = _umbracoMapper.Map(user); //set their remaining seconds @@ -211,7 +210,7 @@ namespace Umbraco.Web.BackOffice.Controllers [SetAngularAntiForgeryTokens] public ActionResult GetCurrentInvitedUser() { - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user.IsApproved) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs index 7cbeb8e86e..5ee7cf31cf 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs @@ -3,8 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -17,9 +19,9 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly IFileSystem _jsLibFileSystem; - public BackOfficeAssetsController(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILogger logger, IGlobalSettings globalSettings) + public BackOfficeAssetsController(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILogger logger, IOptions globalSettings) { - _jsLibFileSystem = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, globalSettings.UmbracoPath + Path.DirectorySeparatorChar + "lib"); + _jsLibFileSystem = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, globalSettings.Value.UmbracoPath + Path.DirectorySeparatorChar + "lib"); } [HttpGet] diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index ef1243daf0..27932f79c7 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -5,15 +5,17 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Grid; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.WebAssets; @@ -30,51 +32,49 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.BackOffice.Controllers { - + //[UmbracoRequireHttps] //TODO Reintroduce + [DisableBrowserCache] [PluginController(Constants.Web.Mvc.BackOfficeArea)] public class BackOfficeController : Controller { - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; private readonly IRuntimeMinifier _runtimeMinifier; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly ILocalizedTextService _textService; private readonly IGridConfig _gridConfig; private readonly BackOfficeServerVariables _backOfficeServerVariables; private readonly AppCaches _appCaches; private readonly BackOfficeSignInManager _signInManager; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILogger _logger; private readonly IJsonSerializer _jsonSerializer; public BackOfficeController( - BackOfficeUserManager userManager, + IBackOfficeUserManager userManager, IRuntimeMinifier runtimeMinifier, - IGlobalSettings globalSettings, + IOptions globalSettings, IHostingEnvironment hostingEnvironment, - IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IGridConfig gridConfig, BackOfficeServerVariables backOfficeServerVariables, AppCaches appCaches, BackOfficeSignInManager signInManager, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, IJsonSerializer jsonSerializer) { _userManager = userManager; _runtimeMinifier = runtimeMinifier; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; - _umbracoContextAccessor = umbracoContextAccessor; _textService = textService; _gridConfig = gridConfig ?? throw new ArgumentNullException(nameof(gridConfig)); _backOfficeServerVariables = backOfficeServerVariables; _appCaches = appCaches; _signInManager = signInManager; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _logger = logger; _jsonSerializer = jsonSerializer; } @@ -96,7 +96,7 @@ namespace Umbraco.Web.BackOffice.Controllers //if you are hitting VerifyInvite, you're already signed in as a different user, and the token is invalid //you'll exit on one of the return RedirectToAction(nameof(Default)) but you're still logged in so you just get //dumped at the default admin view with no detail - if (_webSecurity.IsAuthenticated()) + if (_backofficeSecurityAccessor.BackofficeSecurity.IsAuthenticated()) { await _signInManager.SignOutAsync(); } @@ -189,7 +189,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpGet] public Dictionary> LocalizedText(string culture = null) { - var isAuthenticated = _webSecurity.IsAuthenticated(); + var isAuthenticated = _backofficeSecurityAccessor.BackofficeSecurity.IsAuthenticated(); var cultureInfo = string.IsNullOrWhiteSpace(culture) //if the user is logged in, get their culture, otherwise default to 'en' diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs index 34494e1492..755c0b3a3f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs @@ -1,16 +1,15 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Routing; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using System.Text; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.WebAssets; using Umbraco.Extensions; @@ -19,10 +18,8 @@ using Umbraco.Web.BackOffice.PropertyEditors; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Editors; using Umbraco.Web.Features; -using Umbraco.Web.HealthCheck; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Trees; -using Umbraco.Web.WebApi; namespace Umbraco.Web.BackOffice.Controllers { @@ -34,14 +31,14 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly LinkGenerator _linkGenerator; private readonly IRuntimeState _runtimeState; private readonly UmbracoFeatures _features; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IUmbracoVersion _umbracoVersion; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly TreeCollection _treeCollection; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IRuntimeSettings _settings; - private readonly ISecuritySettings _securitySettings; + private readonly RuntimeSettings _runtimeSettings; + private readonly SecuritySettings _securitySettings; private readonly IRuntimeMinifier _runtimeMinifier; private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider; @@ -49,28 +46,28 @@ namespace Umbraco.Web.BackOffice.Controllers LinkGenerator linkGenerator, IRuntimeState runtimeState, UmbracoFeatures features, - IGlobalSettings globalSettings, + IOptions globalSettings, IUmbracoVersion umbracoVersion, - IContentSettings contentSettings, + IOptions contentSettings, IHttpContextAccessor httpContextAccessor, TreeCollection treeCollection, IHostingEnvironment hostingEnvironment, - IRuntimeSettings settings, - ISecuritySettings securitySettings, + IOptions runtimeSettings, + IOptions securitySettings, IRuntimeMinifier runtimeMinifier, IAuthenticationSchemeProvider authenticationSchemeProvider) { _linkGenerator = linkGenerator; _runtimeState = runtimeState; _features = features; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _umbracoVersion = umbracoVersion; - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _httpContextAccessor = httpContextAccessor; _treeCollection = treeCollection ?? throw new ArgumentNullException(nameof(treeCollection)); _hostingEnvironment = hostingEnvironment; - _settings = settings; - _securitySettings = securitySettings; + _runtimeSettings = runtimeSettings.Value; + _securitySettings = securitySettings.Value; _runtimeMinifier = runtimeMinifier; _authenticationSchemeProvider = authenticationSchemeProvider; } @@ -366,7 +363,7 @@ namespace Umbraco.Web.BackOffice.Controllers {"appPluginsPath", _hostingEnvironment.ToAbsolute(Constants.SystemDirectories.AppPlugins).TrimEnd('/')}, { "imageFileTypes", - string.Join(",", _contentSettings.ImageFileTypes) + string.Join(",", _contentSettings.Imaging.ImageFileTypes) }, { "disallowedUploadFiles", @@ -513,7 +510,7 @@ namespace Umbraco.Web.BackOffice.Controllers private string GetMaxRequestLength() { - return _settings.MaxRequestLength.HasValue ? _settings.MaxRequestLength.Value.ToString() : string.Empty; + return _runtimeSettings.MaxRequestLength.HasValue ? _runtimeSettings.MaxRequestLength.Value.ToString() : string.Empty; } } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs index 621f3a0e78..4bf76a108a 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Net.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Legacy; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Mapping; using Umbraco.Core.Models; @@ -15,15 +14,13 @@ using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Strings.Css; using Umbraco.Extensions; -using Umbraco.Web.Models.ContentEditing; -using Stylesheet = Umbraco.Core.Models.Stylesheet; -using StylesheetRule = Umbraco.Web.Models.ContentEditing.StylesheetRule; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.ActionsResults; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; -using Umbraco.Web.Editors; -using Umbraco.Web.BackOffice.Trees; +using Umbraco.Web.Models.ContentEditing; +using Stylesheet = Umbraco.Core.Models.Stylesheet; +using StylesheetRule = Umbraco.Web.Models.ContentEditing.StylesheetRule; namespace Umbraco.Web.BackOffice.Controllers { @@ -41,7 +38,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly ILocalizedTextService _localizedTextService; private readonly UmbracoMapper _umbracoMapper; private readonly IShortStringHelper _shortStringHelper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; public CodeFileController( IIOHelper ioHelper, @@ -51,9 +48,8 @@ namespace Umbraco.Web.BackOffice.Controllers ILocalizedTextService localizedTextService, UmbracoMapper umbracoMapper, IShortStringHelper shortStringHelper, - IGlobalSettings globalSettings) + IOptions globalSettings) { - _ioHelper = ioHelper; _fileSystems = fileSystems; _fileService = fileService; @@ -61,7 +57,7 @@ namespace Umbraco.Web.BackOffice.Controllers _localizedTextService = localizedTextService; _umbracoMapper = umbracoMapper; _shortStringHelper = shortStringHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } /// diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs index 7704b198ae..66ece55162 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web.Editors private readonly IContentService _contentService; private readonly ILocalizedTextService _localizedTextService; private readonly IUserService _userService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IEntityService _entityService; private readonly IContentTypeService _contentTypeService; private readonly UmbracoMapper _umbracoMapper; @@ -84,7 +84,7 @@ namespace Umbraco.Web.Editors PropertyEditorCollection propertyEditors, IContentService contentService, IUserService userService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IContentTypeService contentTypeService, UmbracoMapper umbracoMapper, @@ -105,7 +105,7 @@ namespace Umbraco.Web.Editors _contentService = contentService; _localizedTextService = localizedTextService; _userService = userService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _entityService = entityService; _contentTypeService = contentTypeService; _umbracoMapper = umbracoMapper; @@ -428,7 +428,7 @@ namespace Umbraco.Web.Editors private ContentItemDisplay GetEmpty(IContentType contentType, int parentId) { - var emptyContent = _contentService.Create("", parentId, contentType.Alias, _webSecurity.GetUserId().ResultOr(0)); + var emptyContent = _contentService.Create("", parentId, contentType.Alias, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); var mapped = MapToDisplay(emptyContent); // translate the content type name if applicable mapped.ContentTypeName = _localizedTextService.UmbracoDictionaryTranslate(CultureDictionary, mapped.ContentTypeName); @@ -597,9 +597,9 @@ namespace Umbraco.Web.Editors EnsureUniqueName(name, content, nameof(name)); - var blueprint = _contentService.CreateContentFromBlueprint(content, name, _webSecurity.GetUserId().ResultOr(0)); + var blueprint = _contentService.CreateContentFromBlueprint(content, name, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); - _contentService.SaveBlueprint(blueprint, _webSecurity.GetUserId().ResultOr(0)); + _contentService.SaveBlueprint(blueprint, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); var notificationModel = new SimpleNotificationModel(); notificationModel.AddSuccessNotification( @@ -633,7 +633,7 @@ namespace Umbraco.Web.Editors { EnsureUniqueName(content.Name, content, "Name"); - _contentService.SaveBlueprint(contentItem.PersistedContent, _webSecurity.CurrentUser.Id); + _contentService.SaveBlueprint(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); //we need to reuse the underlying logic so return the result that it wants return OperationResult.Succeed(new EventMessages()); }, @@ -658,7 +658,7 @@ namespace Umbraco.Web.Editors { var contentItemDisplay = PostSaveInternal( contentItem, - content => _contentService.Save(contentItem.PersistedContent, _webSecurity.CurrentUser.Id), + content => _contentService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id), MapToDisplay); return contentItemDisplay; @@ -760,7 +760,7 @@ namespace Umbraco.Web.Editors case ContentSaveAction.SendPublish: case ContentSaveAction.SendPublishNew: - var sendResult = _contentService.SendToPublication(contentItem.PersistedContent, _webSecurity.CurrentUser.Id); + var sendResult = _contentService.SendToPublication(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); wasCancelled = sendResult == false; if (sendResult) { @@ -1204,7 +1204,7 @@ namespace Umbraco.Web.Editors //if this item's path has already been denied or if the user doesn't have access to it, add to the deny list if (denied.Any(x => c.Path.StartsWith($"{x.Path},")) || (ContentPermissionsHelper.CheckPermissions(c, - _webSecurity.CurrentUser, _userService, _entityService, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _userService, _entityService, ActionPublish.ActionLetter) == ContentPermissionsHelper.ContentAccess.Denied)) { denied.Add(c); @@ -1221,7 +1221,7 @@ namespace Umbraco.Web.Editors if (!contentItem.PersistedContent.ContentType.VariesByCulture()) { //its invariant, proceed normally - var publishStatus = _contentService.SaveAndPublishBranch(contentItem.PersistedContent, force, userId: _webSecurity.CurrentUser.Id); + var publishStatus = _contentService.SaveAndPublishBranch(contentItem.PersistedContent, force, userId: _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); // TODO: Deal with multiple cancellations wasCancelled = publishStatus.Any(x => x.Result == PublishResultType.FailedPublishCancelledByEvent); successfulCultures = null; //must be null! this implies invariant @@ -1256,7 +1256,7 @@ namespace Umbraco.Web.Editors if (canPublish) { //proceed to publish if all validation still succeeds - var publishStatus = _contentService.SaveAndPublishBranch(contentItem.PersistedContent, force, culturesToPublish, _webSecurity.CurrentUser.Id); + var publishStatus = _contentService.SaveAndPublishBranch(contentItem.PersistedContent, force, culturesToPublish, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); // TODO: Deal with multiple cancellations wasCancelled = publishStatus.Any(x => x.Result == PublishResultType.FailedPublishCancelledByEvent); successfulCultures = contentItem.Variants.Where(x => x.Publish).Select(x => x.Culture).ToArray(); @@ -1265,7 +1265,7 @@ namespace Umbraco.Web.Editors else { //can only save - var saveResult = _contentService.Save(contentItem.PersistedContent, _webSecurity.CurrentUser.Id); + var saveResult = _contentService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); var publishStatus = new[] { new PublishResult(PublishResultType.FailedPublishMandatoryCultureMissing, null, contentItem.PersistedContent) @@ -1293,7 +1293,7 @@ namespace Umbraco.Web.Editors if (!contentItem.PersistedContent.ContentType.VariesByCulture()) { //its invariant, proceed normally - var publishStatus = _contentService.SaveAndPublish(contentItem.PersistedContent, userId: _webSecurity.CurrentUser.Id); + var publishStatus = _contentService.SaveAndPublish(contentItem.PersistedContent, userId: _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); wasCancelled = publishStatus.Result == PublishResultType.FailedPublishCancelledByEvent; successfulCultures = null; //must be null! this implies invariant return publishStatus; @@ -1338,7 +1338,7 @@ namespace Umbraco.Web.Editors if (canPublish) { //proceed to publish if all validation still succeeds - var publishStatus = _contentService.SaveAndPublish(contentItem.PersistedContent, culturesToPublish, _webSecurity.CurrentUser.Id); + var publishStatus = _contentService.SaveAndPublish(contentItem.PersistedContent, culturesToPublish, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); wasCancelled = publishStatus.Result == PublishResultType.FailedPublishCancelledByEvent; successfulCultures = culturesToPublish; return publishStatus; @@ -1346,7 +1346,7 @@ namespace Umbraco.Web.Editors else { //can only save - var saveResult = _contentService.Save(contentItem.PersistedContent, _webSecurity.CurrentUser.Id); + var saveResult = _contentService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); var publishStatus = new PublishResult(PublishResultType.FailedPublishMandatoryCultureMissing, null, contentItem.PersistedContent); wasCancelled = saveResult.Result == OperationResultType.FailedCancelledByEvent; successfulCultures = Array.Empty(); @@ -1501,7 +1501,7 @@ namespace Umbraco.Web.Editors return HandleContentNotFound(id, false); } - var publishResult = _contentService.SaveAndPublish(foundContent, userId: _webSecurity.GetUserId().ResultOr(0)); + var publishResult = _contentService.SaveAndPublish(foundContent, userId: _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (publishResult.Success == false) { var notificationModel = new SimpleNotificationModel(); @@ -1553,7 +1553,7 @@ namespace Umbraco.Web.Editors //if the current item is in the recycle bin if (foundContent.Trashed == false) { - var moveResult = _contentService.MoveToRecycleBin(foundContent, _webSecurity.GetUserId().ResultOr(0)); + var moveResult = _contentService.MoveToRecycleBin(foundContent, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (moveResult.Success == false) { //returning an object of INotificationModel will ensure that any pending @@ -1563,7 +1563,7 @@ namespace Umbraco.Web.Editors } else { - var deleteResult = _contentService.Delete(foundContent, _webSecurity.GetUserId().ResultOr(0)); + var deleteResult = _contentService.Delete(foundContent, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (deleteResult.Success == false) { //returning an object of INotificationModel will ensure that any pending @@ -1587,7 +1587,7 @@ namespace Umbraco.Web.Editors [EnsureUserPermissionForContent(Constants.System.RecycleBinContent, ActionDelete.ActionLetter)] public IActionResult EmptyRecycleBin() { - _contentService.EmptyRecycleBin(_webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + _contentService.EmptyRecycleBin(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); return new UmbracoNotificationSuccessResponse(_localizedTextService.Localize("defaultdialogs/recycleBinIsEmpty")); } @@ -1616,7 +1616,7 @@ namespace Umbraco.Web.Editors var contentService = _contentService; // Save content with new sort order and update content xml in db accordingly - var sortResult = contentService.Sort(sorted.IdSortOrder, _webSecurity.CurrentUser.Id); + var sortResult = contentService.Sort(sorted.IdSortOrder, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); if (!sortResult.Success) { Logger.Warn("Content sorting failed, this was probably caused by an event being cancelled"); @@ -1643,7 +1643,7 @@ namespace Umbraco.Web.Editors { var toMove = ValidateMoveOrCopy(move); - _contentService.Move(toMove, move.ParentId, _webSecurity.GetUserId().ResultOr(0)); + _contentService.Move(toMove, move.ParentId, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); return Content(toMove.Path, MediaTypeNames.Text.Plain, Encoding.UTF8); } @@ -1658,7 +1658,7 @@ namespace Umbraco.Web.Editors { var toCopy = ValidateMoveOrCopy(copy); - var c = _contentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal, copy.Recursive, _webSecurity.GetUserId().ResultOr(0)); + var c = _contentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal, copy.Recursive, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); return Content(c.Path, MediaTypeNames.Text.Plain, Encoding.UTF8); } @@ -1681,7 +1681,7 @@ namespace Umbraco.Web.Editors if (model.Cultures.Length == 0 || model.Cultures.Length == languageCount) { //this means that the entire content item will be unpublished - var unpublishResult = _contentService.Unpublish(foundContent, userId: _webSecurity.GetUserId().ResultOr(0)); + var unpublishResult = _contentService.Unpublish(foundContent, userId: _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); var content = MapToDisplay(foundContent); @@ -1704,7 +1704,7 @@ namespace Umbraco.Web.Editors var results = new Dictionary(); foreach (var c in model.Cultures) { - var result = _contentService.Unpublish(foundContent, culture: c, userId: _webSecurity.GetUserId().ResultOr(0)); + var result = _contentService.Unpublish(foundContent, culture: c, userId: _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); results[c] = result; if (result.Result == PublishResultType.SuccessUnpublishMandatoryCulture) { @@ -1772,7 +1772,7 @@ namespace Umbraco.Web.Editors return NotFound("There is no content node with id {model.NodeId}."); } - var permission = _userService.GetPermissions(_webSecurity.CurrentUser, node.Path); + var permission = _userService.GetPermissions(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, node.Path); if (permission.AssignedPermissions.Contains(ActionAssignDomain.ActionLetter.ToString(), StringComparer.Ordinal) == false) @@ -2260,7 +2260,7 @@ namespace Umbraco.Web.Editors { var display = _umbracoMapper.Map(content, context => { - context.Items["CurrentUser"] = _webSecurity.CurrentUser; + context.Items["CurrentUser"] = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; }); display.AllowPreview = display.AllowPreview && content.Trashed == false && content.ContentType.IsElement == false; return display; @@ -2275,7 +2275,7 @@ namespace Umbraco.Web.Editors var content = _contentService.GetById(contentId); if (content == null) return NotFound(); - var userNotifications = _notificationService.GetUserNotifications(_webSecurity.CurrentUser, content.Path).ToList(); + var userNotifications = _notificationService.GetUserNotifications(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, content.Path).ToList(); foreach (var a in _actionCollection.Where(x => x.ShowInNotifier)) { @@ -2297,7 +2297,7 @@ namespace Umbraco.Web.Editors var content = _contentService.GetById(contentId); if (content == null) return NotFound(); - _notificationService.SetNotifications(_webSecurity.CurrentUser, content, notifyOptions); + _notificationService.SetNotifications(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, content, notifyOptions); return NoContent(); } @@ -2362,7 +2362,7 @@ namespace Umbraco.Web.Editors [HttpPost] public IActionResult PostRollbackContent(int contentId, int versionId, string culture = "*") { - var rollbackResult = _contentService.Rollback(contentId, versionId, culture, _webSecurity.GetUserId().ResultOr(0)); + var rollbackResult = _contentService.Rollback(contentId, versionId, culture, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); if (rollbackResult.Success) return Ok(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs index 146f2c32b7..7955b82eeb 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs @@ -26,12 +26,15 @@ using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; using Constants = Umbraco.Core.Constants; using Umbraco.Core.Mapping; +using Umbraco.Core.Security; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Editors; using Umbraco.Web.Security; using ContentType = Umbraco.Core.Models.ContentType; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.BackOffice.Controllers { @@ -48,13 +51,13 @@ namespace Umbraco.Web.BackOffice.Controllers public class ContentTypeController : ContentTypeControllerBase { private readonly IEntityXmlSerializer _serializer; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly PropertyEditorCollection _propertyEditors; private readonly IScopeProvider _scopeProvider; private readonly IIOHelper _ioHelper; private readonly IContentTypeService _contentTypeService; private readonly UmbracoMapper _umbracoMapper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IDataTypeService _dataTypeService; private readonly IShortStringHelper _shortStringHelper; private readonly ILocalizedTextService _localizedTextService; @@ -67,21 +70,19 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IEntityService _entityService; private readonly IHostingEnvironment _hostingEnvironment; - public ContentTypeController( ICultureDictionary cultureDictionary, - EditorValidatorCollection editorValidatorCollection, IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, UmbracoMapper umbracoMapper, ILocalizedTextService localizedTextService, IEntityXmlSerializer serializer, - IGlobalSettings globalSettings, + IOptions globalSettings, PropertyEditorCollection propertyEditors, IScopeProvider scopeProvider, IIOHelper ioHelper, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IDataTypeService dataTypeService, IShortStringHelper shortStringHelper, IFileService fileService, @@ -91,7 +92,8 @@ namespace Umbraco.Web.BackOffice.Controllers ILocalizationService localizationService, IMacroService macroService, IEntityService entityService, - IHostingEnvironment hostingEnvironment) + IHostingEnvironment hostingEnvironment, + EditorValidatorCollection editorValidatorCollection) : base(cultureDictionary, editorValidatorCollection, contentTypeService, @@ -101,13 +103,13 @@ namespace Umbraco.Web.BackOffice.Controllers localizedTextService) { _serializer = serializer; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _propertyEditors = propertyEditors; _scopeProvider = scopeProvider; _ioHelper = ioHelper; _contentTypeService = contentTypeService; _umbracoMapper = umbracoMapper; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _dataTypeService = dataTypeService; _shortStringHelper = shortStringHelper; _localizedTextService = localizedTextService; @@ -206,7 +208,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new HttpResponseException(HttpStatusCode.NotFound); } - _contentTypeService.Delete(foundType, _webSecurity.CurrentUser.Id); + _contentTypeService.Delete(foundType, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } @@ -305,14 +307,14 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpPost] public IActionResult DeleteContainer(int id) { - _contentTypeService.DeleteContainer(id, _webSecurity.CurrentUser.Id); + _contentTypeService.DeleteContainer(id, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } public IActionResult PostCreateContainer(int parentId, string name) { - var result = _contentTypeService.CreateContainer(parentId, name, _webSecurity.CurrentUser.Id); + var result = _contentTypeService.CreateContainer(parentId, name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return result ? Ok(result.Result) //return the id @@ -321,7 +323,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult PostRenameContainer(int id, string name) { - var result = _contentTypeService.RenameContainer(id, name, _webSecurity.CurrentUser.Id); + var result = _contentTypeService.RenameContainer(id, name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return result ? Ok(result.Result) //return the id @@ -616,12 +618,12 @@ namespace Umbraco.Web.BackOffice.Controllers } var dataInstaller = new PackageDataInstallation(_logger, _fileService, _macroService, _LocalizationService, - _dataTypeService, _entityService, _contentTypeService, _contentService, _propertyEditors, _scopeProvider, _shortStringHelper, _globalSettings, _localizedTextService); + _dataTypeService, _entityService, _contentTypeService, _contentService, _propertyEditors, _scopeProvider, _shortStringHelper, Options.Create(_globalSettings), _localizedTextService); var xd = new XmlDocument {XmlResolver = null}; xd.Load(filePath); - var userId = _webSecurity.GetUserId().ResultOr(0); + var userId = _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0); var element = XElement.Parse(xd.InnerXml); dataInstaller.ImportDocumentType(element, userId); diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 3bf44f4e9c..abd9e6ab1d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -1,31 +1,31 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Net.Http; -using System.Threading.Tasks; -using Umbraco.Core.Services; -using Umbraco.Web.Models; -using Umbraco.Web.Models.ContentEditing; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Cache; -using Umbraco.Core.IO; -using Umbraco.Web.WebApi.Filters; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Media; +using Umbraco.Core.Security; +using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Security; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; +using Umbraco.Web.Models; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Security; namespace Umbraco.Web.BackOffice.Controllers @@ -37,13 +37,13 @@ namespace Umbraco.Web.BackOffice.Controllers public class CurrentUserController : UmbracoAuthorizedJsonController { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IImageUrlGenerator _imageUrlGenerator; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IUserService _userService; private readonly UmbracoMapper _umbracoMapper; - private readonly BackOfficeUserManager _backOfficeUserManager; + private readonly IBackOfficeUserManager _backOfficeUserManager; private readonly ILogger _logger; private readonly ILocalizedTextService _localizedTextService; private readonly AppCaches _appCaches; @@ -51,23 +51,23 @@ namespace Umbraco.Web.BackOffice.Controllers public CurrentUserController( IMediaFileSystem mediaFileSystem, - IContentSettings contentSettings, + IOptions contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IUserService userService, UmbracoMapper umbracoMapper, - BackOfficeUserManager backOfficeUserManager, + IBackOfficeUserManager backOfficeUserManager, ILogger logger, ILocalizedTextService localizedTextService, AppCaches appCaches, IShortStringHelper shortStringHelper) { _mediaFileSystem = mediaFileSystem; - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _hostingEnvironment = hostingEnvironment; _imageUrlGenerator = imageUrlGenerator; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _userService = userService; _umbracoMapper = umbracoMapper; _backOfficeUserManager = backOfficeUserManager; @@ -87,7 +87,7 @@ namespace Umbraco.Web.BackOffice.Controllers public Dictionary GetPermissions(int[] nodeIds) { var permissions = _userService - .GetPermissions(_webSecurity.CurrentUser, nodeIds); + .GetPermissions(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, nodeIds); var permissionsDictionary = new Dictionary(); foreach (var nodeId in nodeIds) @@ -108,7 +108,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpGet] public bool HasPermission(string permissionToCheck, int nodeId) { - var p = _userService.GetPermissions(_webSecurity.CurrentUser, nodeId).GetAllPermissions(); + var p = _userService.GetPermissions(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, nodeId).GetAllPermissions(); if (p.Contains(permissionToCheck.ToString(CultureInfo.InvariantCulture))) { return true; @@ -127,15 +127,15 @@ namespace Umbraco.Web.BackOffice.Controllers if (status == null) throw new ArgumentNullException(nameof(status)); List userTours; - if (_webSecurity.CurrentUser.TourData.IsNullOrWhiteSpace()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData.IsNullOrWhiteSpace()) { userTours = new List { status }; - _webSecurity.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); - _userService.Save(_webSecurity.CurrentUser); + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); + _userService.Save(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); return userTours; } - userTours = JsonConvert.DeserializeObject>(_webSecurity.CurrentUser.TourData).ToList(); + userTours = JsonConvert.DeserializeObject>(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData).ToList(); var found = userTours.FirstOrDefault(x => x.Alias == status.Alias); if (found != null) { @@ -143,8 +143,8 @@ namespace Umbraco.Web.BackOffice.Controllers userTours.Remove(found); } userTours.Add(status); - _webSecurity.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); - _userService.Save(_webSecurity.CurrentUser); + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); + _userService.Save(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); return userTours; } @@ -154,10 +154,10 @@ namespace Umbraco.Web.BackOffice.Controllers /// public IEnumerable GetUserTours() { - if (_webSecurity.CurrentUser.TourData.IsNullOrWhiteSpace()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData.IsNullOrWhiteSpace()) return Enumerable.Empty(); - var userTours = JsonConvert.DeserializeObject>(_webSecurity.CurrentUser.TourData); + var userTours = JsonConvert.DeserializeObject>(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.TourData); return userTours; } @@ -173,7 +173,7 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoAuthorize(redirectToUmbracoLogin: false, requireApproval : true)] public async Task PostSetInvitedUserPassword([FromBody]string newPassword) { - var user = await _backOfficeUserManager.FindByIdAsync(_webSecurity.GetUserId().ResultOr(0).ToString()); + var user = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0).ToString()); if (user == null) throw new InvalidOperationException("Could not find user"); var result = await _backOfficeUserManager.AddPasswordAsync(user, newPassword); @@ -188,13 +188,13 @@ namespace Umbraco.Web.BackOffice.Controllers } //They've successfully set their password, we can now update their user account to be approved - _webSecurity.CurrentUser.IsApproved = true; + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsApproved = true; //They've successfully set their password, and will now get fully logged into the back office, so the lastlogindate is set so the backoffice shows they have logged in - _webSecurity.CurrentUser.LastLoginDate = DateTime.UtcNow; - _userService.Save(_webSecurity.CurrentUser); + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.LastLoginDate = DateTime.UtcNow; + _userService.Save(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); //now we can return their full object since they are now really logged into the back office - var userDisplay = _umbracoMapper.Map(_webSecurity.CurrentUser); + var userDisplay = _umbracoMapper.Map(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); userDisplay.SecondsUntilTimeout = HttpContext.User.GetRemainingAuthSeconds(); return userDisplay; @@ -204,7 +204,7 @@ namespace Umbraco.Web.BackOffice.Controllers public async Task PostSetAvatar(IList files) { //borrow the logic from the user controller - return await UsersController.PostSetAvatarInternal(files, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, _webSecurity.GetUserId().ResultOr(0)); + return await UsersController.PostSetAvatarInternal(files, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); } /// @@ -217,7 +217,7 @@ namespace Umbraco.Web.BackOffice.Controllers public async Task> PostChangePassword(ChangingPasswordModel data) { var passwordChanger = new PasswordChanger(_logger); - var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_webSecurity.CurrentUser, _webSecurity.CurrentUser, data, _backOfficeUserManager); + var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, data, _backOfficeUserManager); if (passwordChangeResult.Success) { @@ -239,7 +239,7 @@ namespace Umbraco.Web.BackOffice.Controllers [ValidateAngularAntiForgeryToken] public async Task> GetCurrentUserLinkedLogins() { - var identityUser = await _backOfficeUserManager.FindByIdAsync(_webSecurity.GetUserId().ResultOr(0).ToString()); + var identityUser = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0).ToString()); return identityUser.Logins.ToDictionary(x => x.LoginProvider, x => x.ProviderKey); } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs index 03bbe132f3..8970a70b34 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs @@ -43,7 +43,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// Initializes a new instance of the with all its dependencies. /// public DashboardController( - IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, diff --git a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs index 194029db4b..3ffcd5cec3 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs @@ -4,20 +4,21 @@ using System.Data; using System.Linq; using System.Net; using System.Net.Mime; +using System.Text; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using Umbraco.Web.Models.ContentEditing; -using System.Text; -using Constants = Umbraco.Core.Constants; -using Umbraco.Core.Mapping; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Editors; +using Umbraco.Web.Models.ContentEditing; +using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.BackOffice.Controllers { @@ -34,7 +35,7 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly PropertyEditorCollection _propertyEditors; private readonly IDataTypeService _dataTypeService; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly UmbracoMapper _umbracoMapper; private readonly PropertyEditorCollection _propertyEditorCollection; private readonly IContentTypeService _contentTypeService; @@ -46,7 +47,7 @@ namespace Umbraco.Web.BackOffice.Controllers public DataTypeController( PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, - IContentSettings contentSettings, + IOptions contentSettings, UmbracoMapper umbracoMapper, PropertyEditorCollection propertyEditorCollection, IContentTypeService contentTypeService, @@ -57,7 +58,7 @@ namespace Umbraco.Web.BackOffice.Controllers { _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); _dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _propertyEditorCollection = propertyEditorCollection ?? throw new ArgumentNullException(nameof(propertyEditorCollection)); _contentTypeService = contentTypeService ?? throw new ArgumentNullException(nameof(contentTypeService)); diff --git a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs index 26cccb9141..207dee60f4 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -15,6 +16,8 @@ using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Security; using Constants = Umbraco.Core.Constants; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.BackOffice.Controllers { @@ -32,24 +35,24 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly ILogger _logger; private readonly ILocalizationService _localizationService; - private readonly IWebSecurity _webSecurity; - private readonly IGlobalSettings _globalSettings; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly GlobalSettings _globalSettings; private readonly ILocalizedTextService _localizedTextService; private readonly UmbracoMapper _umbracoMapper; public DictionaryController( ILogger logger, ILocalizationService localizationService, - IWebSecurity webSecurity, - IGlobalSettings globalSettings, + IBackofficeSecurityAccessor backofficeSecurityAccessor, + IOptions globalSettings, ILocalizedTextService localizedTextService, UmbracoMapper umbracoMapper ) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); - _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); + _globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); } @@ -72,10 +75,10 @@ namespace Umbraco.Web.BackOffice.Controllers foreach (var dictionaryItem in foundDictionaryDescendants) { - _localizationService.Delete(dictionaryItem, _webSecurity.CurrentUser.Id); + _localizationService.Delete(dictionaryItem, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); } - _localizationService.Delete(foundDictionary, _webSecurity.CurrentUser.Id); + _localizationService.Delete(foundDictionary, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } @@ -102,7 +105,7 @@ namespace Umbraco.Web.BackOffice.Controllers { var message = _localizedTextService.Localize( "dictionaryItem/changeKeyError", - _webSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings), + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings), new Dictionary { { "0", key } }); throw HttpResponseException.CreateNotificationValidationErrorResponse(message); } @@ -141,7 +144,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// Returns a not found response when dictionary item does not exist /// - [DetermineAmbiguousActionByPassingParameters] + [DetermineAmbiguousActionByPassingParameters] public ActionResult GetById(int id) { var dictionary = _localizationService.GetDictionaryItemById(id); @@ -216,7 +219,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (dictionaryItem == null) throw HttpResponseException.CreateNotificationValidationErrorResponse("Dictionary item does not exist"); - var userCulture = _webSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings); + var userCulture = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings); if (dictionary.NameIsDirty) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 1afe9bccf4..35d9c51cd4 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Core.Mapping; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Xml; @@ -53,7 +54,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IPublishedContentQuery _publishedContentQuery; private readonly IShortStringHelper _shortStringHelper; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IContentService _contentService; private readonly UmbracoMapper _umbracoMapper; @@ -74,7 +75,7 @@ namespace Umbraco.Web.BackOffice.Controllers IPublishedContentQuery publishedContentQuery, IShortStringHelper shortStringHelper, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IPublishedUrlProvider publishedUrlProvider, IContentService contentService, UmbracoMapper umbracoMapper, @@ -96,7 +97,7 @@ namespace Umbraco.Web.BackOffice.Controllers publishedContentQuery ?? throw new ArgumentNullException(nameof(publishedContentQuery)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _publishedUrlProvider = publishedUrlProvider ?? throw new ArgumentNullException(nameof(publishedUrlProvider)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); @@ -175,7 +176,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (string.IsNullOrEmpty(query)) return result; - var allowedSections = _webSecurity.CurrentUser.AllowedSections.ToArray(); + var allowedSections = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.AllowedSections.ToArray(); foreach (var searchableTree in _searchableTreeCollection.SearchableApplicationTrees.OrderBy(t => t.Value.SortOrder)) { @@ -721,9 +722,9 @@ namespace Umbraco.Web.BackOffice.Controllers switch (type) { case UmbracoEntityTypes.Document: - return _webSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); + return _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); case UmbracoEntityTypes.Media: - return _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); + return _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); default: return Array.Empty(); } @@ -862,10 +863,10 @@ namespace Umbraco.Web.BackOffice.Controllers switch (entityType) { case UmbracoEntityTypes.Document: - aids = _webSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); + aids = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); break; case UmbracoEntityTypes.Media: - aids = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); + aids = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); break; } diff --git a/src/Umbraco.Web.BackOffice/Controllers/IconController.cs b/src/Umbraco.Web.BackOffice/Controllers/IconController.cs index bbefa82bd9..28509e2425 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/IconController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/IconController.cs @@ -1,29 +1,19 @@ using System.Collections.Generic; -using System.Linq; -using Umbraco.Web.Models; -using System.IO; -using Umbraco.Core; -using Ganss.XSS; -using Umbraco.Core.Configuration; -using Umbraco.Core.Hosting; +using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Attributes; -using Umbraco.Web.Common.Filters; namespace Umbraco.Web.Editors { [PluginController("UmbracoApi")] public class IconController : UmbracoAuthorizedApiController { - private readonly IHostingEnvironment _hostingEnvironment; - private readonly IGlobalSettings _globalSettings; + private readonly IIconService _iconService; - public IconController( - IHostingEnvironment hostingEnvironment, - IGlobalSettings globalSettings) + public IconController(IIconService iconService) { - _hostingEnvironment = hostingEnvironment; - _globalSettings = globalSettings; + _iconService = iconService; } /// @@ -34,78 +24,16 @@ namespace Umbraco.Web.Editors [DetermineAmbiguousActionByPassingParameters] public IconModel GetIcon(string iconName) { - return string.IsNullOrWhiteSpace(iconName) - ? null - : CreateIconModel(iconName.StripFileExtension(), - _hostingEnvironment.MapPathWebRoot($"{_globalSettings.IconsPath}/{iconName}.svg")); - } - - /// - /// Gets an IconModel using values from a FileInfo model - /// - /// - /// - [DetermineAmbiguousActionByPassingParameters] - public IconModel GetIcon(FileInfo fileInfo) - { - return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name) - ? null - : CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName); + return _iconService.GetIcon(iconName); } /// /// Gets a list of all svg icons found at at the global icons path. /// /// - public List GetAllIcons() + public IList GetAllIcons() { - var icons = new List(); - var directory = new DirectoryInfo(_hostingEnvironment.MapPathWebRoot($"{_globalSettings.IconsPath}/")); - var iconNames = directory.GetFiles("*.svg"); - - iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo => - { - var icon = GetIcon(iconInfo); - - if (icon != null) - { - icons.Add(icon); - } - }); - - return icons; - } - - /// - /// Gets an IconModel containing the icon name and SvgString - /// - /// - /// - /// - private IconModel CreateIconModel(string iconName, string iconPath) - { - var sanitizer = new HtmlSanitizer(); - sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes); - sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes); - sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags); - - try - { - var svgContent = System.IO.File.ReadAllText(iconPath); - var sanitizedString = sanitizer.Sanitize(svgContent); - - var svg = new IconModel - { - Name = iconName, - SvgString = sanitizedString - }; - - return svg; - } - catch - { - return null; - } + return _iconService.GetAllIcons(); } } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs index b264fd987b..6f1b7fb037 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs @@ -1,8 +1,10 @@ using System; using System.IO; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Media; using Umbraco.Core.Models; @@ -18,14 +20,16 @@ namespace Umbraco.Web.BackOffice.Controllers public class ImagesController : UmbracoAuthorizedApiController { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly IImageUrlGenerator _imageUrlGenerator; - public ImagesController(IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, + public ImagesController( + IMediaFileSystem mediaFileSystem, + IOptions contentSettings, IImageUrlGenerator imageUrlGenerator) { _mediaFileSystem = mediaFileSystem; - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _imageUrlGenerator = imageUrlGenerator; } @@ -99,9 +103,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// /// - /// - /// - /// /// /// /// If there is no media, image property or image file is found then this will return not found. @@ -112,7 +113,7 @@ namespace Umbraco.Web.BackOffice.Controllers decimal? focalPointLeft = null, decimal? focalPointTop = null, string animationProcessMode = "first", - ImageCropMode mode = ImageCropMode.Max, + ImageCropMode mode = ImageCropMode.Max, bool upscale = false, string cacheBusterValue = "", decimal? cropX1 = null, diff --git a/src/Umbraco.Web.BackOffice/Controllers/LanguageController.cs b/src/Umbraco.Web.BackOffice/Controllers/LanguageController.cs index 14667c1fe5..66f8b6d7e0 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/LanguageController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/LanguageController.cs @@ -3,8 +3,10 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Services; @@ -25,15 +27,15 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly ILocalizationService _localizationService; private readonly UmbracoMapper _umbracoMapper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; public LanguageController(ILocalizationService localizationService, UmbracoMapper umbracoMapper, - IGlobalSettings globalSettings) + IOptions globalSettings) { _localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); - _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); + _globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings)); } /// diff --git a/src/Umbraco.Web.BackOffice/Controllers/LogController.cs b/src/Umbraco.Web.BackOffice/Controllers/LogController.cs index e99ea890d7..7dd2b1af44 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/LogController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/LogController.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Mapping; using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -26,7 +27,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IImageUrlGenerator _imageUrlGenerator; private readonly IAuditService _auditService; private readonly UmbracoMapper _umbracoMapper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IUserService _userService; private readonly AppCaches _appCaches; private readonly ISqlContext _sqlContext; @@ -36,7 +37,7 @@ namespace Umbraco.Web.BackOffice.Controllers IImageUrlGenerator imageUrlGenerator, IAuditService auditService, UmbracoMapper umbracoMapper, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IUserService userService, AppCaches appCaches, ISqlContext sqlContext) @@ -45,7 +46,7 @@ namespace Umbraco.Web.BackOffice.Controllers _imageUrlGenerator = imageUrlGenerator ?? throw new ArgumentNullException(nameof(imageUrlGenerator)); _auditService = auditService ?? throw new ArgumentNullException(nameof(auditService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _appCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); _sqlContext = sqlContext ?? throw new ArgumentNullException(nameof(sqlContext)); @@ -89,7 +90,7 @@ namespace Umbraco.Web.BackOffice.Controllers long totalRecords; var dateQuery = sinceDate.HasValue ? _sqlContext.Query().Where(x => x.CreateDate >= sinceDate) : null; - var userId = _webSecurity.GetUserId().ResultOr(0); + var userId = _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0); var result = _auditService.GetPagedItemsByUser(userId, pageNumber - 1, pageSize, out totalRecords, orderDirection, customFilter:dateQuery); var mapped = _umbracoMapper.MapEnumerable(result); return new PagedResult(totalRecords, pageNumber, pageSize) diff --git a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs index cf951a57c3..b64a4753bb 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs @@ -18,6 +18,7 @@ using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Security; using Umbraco.Core; using Umbraco.Core.Mapping; +using Umbraco.Core.Security; namespace Umbraco.Web.BackOffice.Controllers { @@ -32,7 +33,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly ParameterEditorCollection _parameterEditorCollection; private readonly IMacroService _macroService; private readonly IShortStringHelper _shortStringHelper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILogger _logger; private readonly IHostingEnvironment _hostingEnvironment; private readonly UmbracoMapper _umbracoMapper; @@ -41,7 +42,7 @@ namespace Umbraco.Web.BackOffice.Controllers ParameterEditorCollection parameterEditorCollection, IMacroService macroService, IShortStringHelper shortStringHelper, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, IHostingEnvironment hostingEnvironment, UmbracoMapper umbracoMapper @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Controllers _parameterEditorCollection = parameterEditorCollection ?? throw new ArgumentNullException(nameof(parameterEditorCollection)); _macroService = macroService ?? throw new ArgumentNullException(nameof(macroService)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); @@ -95,7 +96,7 @@ namespace Umbraco.Web.BackOffice.Controllers MacroSource = string.Empty }; - _macroService.Save(macro, _webSecurity.CurrentUser.Id); + _macroService.Save(macro, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return macro.Id; } @@ -215,7 +216,7 @@ namespace Umbraco.Web.BackOffice.Controllers try { - _macroService.Save(macro, _webSecurity.CurrentUser.Id); + _macroService.Save(macro, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); macroDisplay.Notifications.Clear(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index ba19f7c2b4..34f0f0afd7 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -3,35 +3,33 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Net.Http; using System.Net.Mime; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Services; -using Umbraco.Web.Models.ContentEditing; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Mapping; +using Umbraco.Core.Models; using Umbraco.Core.Models.ContentEditing; -using Umbraco.Core.Models.Editors; using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Validation; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; using Umbraco.Web.ContentApps; using Umbraco.Web.WebApi.Filters; -using Constants = Umbraco.Core.Constants; -using Umbraco.Core.Mapping; +using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Filters; @@ -39,7 +37,11 @@ using Umbraco.Web.BackOffice.ModelBinders; using Umbraco.Web.Common.ActionResults; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; +using Umbraco.Web.ContentApps; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Security; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.BackOffice.Controllers { @@ -52,11 +54,11 @@ namespace Umbraco.Web.BackOffice.Controllers public class MediaController : ContentControllerBase { private readonly IShortStringHelper _shortStringHelper; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly IMediaTypeService _mediaTypeService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly UmbracoMapper _umbracoMapper; private readonly IDataTypeService _dataTypeService; private readonly ILocalizedTextService _localizedTextService; @@ -69,11 +71,11 @@ namespace Umbraco.Web.BackOffice.Controllers IShortStringHelper shortStringHelper, IEventMessagesFactory eventMessages, ILocalizedTextService localizedTextService, - IContentSettings contentSettings, + IOptions contentSettings, IMediaTypeService mediaTypeService, IMediaService mediaService, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, UmbracoMapper umbracoMapper, IDataTypeService dataTypeService, ISqlContext sqlContext, @@ -85,11 +87,11 @@ namespace Umbraco.Web.BackOffice.Controllers : base(cultureDictionary, logger, shortStringHelper, eventMessages, localizedTextService) { _shortStringHelper = shortStringHelper; - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _mediaTypeService = mediaTypeService; _mediaService = mediaService; _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _umbracoMapper = umbracoMapper; _dataTypeService = dataTypeService; _localizedTextService = localizedTextService; @@ -116,7 +118,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new HttpResponseException(HttpStatusCode.NotFound); } - var emptyContent = _mediaService.CreateMedia("", parentId, contentType.Alias, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var emptyContent = _mediaService.CreateMedia("", parentId, contentType.Alias, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); var mapped = _umbracoMapper.Map(emptyContent); //remove the listview app if it exists @@ -278,7 +280,7 @@ namespace Umbraco.Web.BackOffice.Controllers protected int[] UserStartNodes { - get { return _userStartNodes ?? (_userStartNodes = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); } + get { return _userStartNodes ?? (_userStartNodes = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); } } /// @@ -435,7 +437,7 @@ namespace Umbraco.Web.BackOffice.Controllers //if the current item is in the recycle bin if (foundMedia.Trashed == false) { - var moveResult = _mediaService.MoveToRecycleBin(foundMedia, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var moveResult = _mediaService.MoveToRecycleBin(foundMedia, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); if (moveResult == false) { //returning an object of INotificationModel will ensure that any pending @@ -445,7 +447,7 @@ namespace Umbraco.Web.BackOffice.Controllers } else { - var deleteResult = _mediaService.Delete(foundMedia, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var deleteResult = _mediaService.Delete(foundMedia, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); if (deleteResult == false) { //returning an object of INotificationModel will ensure that any pending @@ -469,7 +471,7 @@ namespace Umbraco.Web.BackOffice.Controllers var destinationParentID = move.ParentId; var sourceParentID = toMove.ParentId; - var moveResult = _mediaService.Move(toMove, move.ParentId, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var moveResult = _mediaService.Move(toMove, move.ParentId, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); if (sourceParentID == destinationParentID) { @@ -543,7 +545,7 @@ namespace Umbraco.Web.BackOffice.Controllers } //save the item - var saveStatus = _mediaService.Save(contentItem.PersistedContent, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + var saveStatus = _mediaService.Save(contentItem.PersistedContent, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); //return the updated model var display = _umbracoMapper.Map(contentItem.PersistedContent); @@ -589,7 +591,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpPost] public IActionResult EmptyRecycleBin() { - _mediaService.EmptyRecycleBin(_webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); + _mediaService.EmptyRecycleBin(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId)); return new UmbracoNotificationSuccessResponse(_localizedTextService.Localize("defaultdialogs/recycleBinIsEmpty")); } @@ -646,7 +648,7 @@ namespace Umbraco.Web.BackOffice.Controllers var mediaService = _mediaService; var f = mediaService.CreateMedia(folder.Name, parentId.Value, Constants.Conventions.MediaTypes.Folder); - mediaService.Save(f, _webSecurity.CurrentUser.Id); + mediaService.Save(f, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return _umbracoMapper.Map(f); } @@ -742,7 +744,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (contentTypeAlias == Constants.Conventions.MediaTypes.AutoSelect) { - if (_contentSettings.ImageFileTypes.Contains(ext)) + if (_contentSettings.Imaging.ImageFileTypes.Contains(ext)) { mediaType = Constants.Conventions.MediaTypes.Image; } @@ -754,7 +756,7 @@ namespace Umbraco.Web.BackOffice.Controllers var mediaItemName = fileName.ToFriendlyName(); - var f = mediaService.CreateMedia(mediaItemName, parentId.Value, mediaType, _webSecurity.CurrentUser.Id); + var f = mediaService.CreateMedia(mediaItemName, parentId.Value, mediaType, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); await using (var stream = formFile.OpenReadStream()) @@ -763,7 +765,7 @@ namespace Umbraco.Web.BackOffice.Controllers } - var saveResult = mediaService.Save(f, _webSecurity.CurrentUser.Id); + var saveResult = mediaService.Save(f, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); if (saveResult == false) { AddCancelMessage(tempFiles, @@ -856,7 +858,7 @@ namespace Umbraco.Web.BackOffice.Controllers //ensure the user has access to this folder by parent id! if (validatePermissions && CheckPermissions( new Dictionary(), - _webSecurity.CurrentUser, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _mediaService, _entityService, intParentId) == false) diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaTypeController.cs index 617d3f1538..31cc5d63cd 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaTypeController.cs @@ -7,6 +7,7 @@ using Umbraco.Core; using Umbraco.Core.Dictionary; using Umbraco.Core.Mapping; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.BackOffice.Filters; @@ -36,7 +37,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMediaTypeService _mediaTypeService; private readonly IShortStringHelper _shortStringHelper; private readonly UmbracoMapper _umbracoMapper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MediaTypeController(ICultureDictionary cultureDictionary, EditorValidatorCollection editorValidatorCollection, @@ -48,7 +49,7 @@ namespace Umbraco.Web.BackOffice.Controllers IShortStringHelper shortStringHelper, IEntityService entityService, IMediaService mediaService, - IWebSecurity webSecurity) + IBackofficeSecurityAccessor backofficeSecurityAccessor) : base( cultureDictionary, editorValidatorCollection, @@ -64,7 +65,7 @@ namespace Umbraco.Web.BackOffice.Controllers _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _contentTypeService = contentTypeService ?? throw new ArgumentNullException(nameof(contentTypeService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); } @@ -147,7 +148,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new HttpResponseException(HttpStatusCode.NotFound); } - _mediaTypeService.Delete(foundType, _webSecurity.CurrentUser.Id); + _mediaTypeService.Delete(foundType, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } @@ -241,14 +242,14 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpPost] public IActionResult DeleteContainer(int id) { - _mediaTypeService.DeleteContainer(id, _webSecurity.CurrentUser.Id); + _mediaTypeService.DeleteContainer(id, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } public IActionResult PostCreateContainer(int parentId, string name) { - var result = _mediaTypeService.CreateContainer(parentId, name, _webSecurity.CurrentUser.Id); + var result = _mediaTypeService.CreateContainer(parentId, name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return result ? Ok(result.Result) //return the id @@ -257,7 +258,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult PostRenameContainer(int id, string name) { - var result = _mediaTypeService.RenameContainer(id, name, _webSecurity.CurrentUser.Id); + var result = _mediaTypeService.RenameContainer(id, name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return result ? Ok(result.Result) //return the id diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs index 9627c96e24..6d60da0910 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs @@ -8,23 +8,20 @@ using System.Net.Mime; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; using Umbraco.Core.Logging; +using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Web.ContentApps; -using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.WebApi.Filters; -using Constants = Umbraco.Core.Constants; -using Umbraco.Core.Mapping; -using Umbraco.Core.Serialization; using Umbraco.Core.Strings; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Filters; @@ -32,7 +29,11 @@ using Umbraco.Web.BackOffice.ModelBinders; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Common.Filters; +using Umbraco.Web.ContentApps; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Security; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.BackOffice.Controllers { @@ -45,8 +46,7 @@ namespace Umbraco.Web.BackOffice.Controllers [OutgoingNoHyphenGuidFormat] public class MemberController : ContentControllerBase { - - private readonly IMemberPasswordConfiguration _passwordConfig; + private readonly MemberPasswordConfigurationSettings _passwordConfig; private readonly PropertyEditorCollection _propertyEditors; private readonly LegacyPasswordSecurity _passwordSecurity; private readonly UmbracoMapper _umbracoMapper; @@ -54,7 +54,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMemberTypeService _memberTypeService; private readonly IDataTypeService _dataTypeService; private readonly ILocalizedTextService _localizedTextService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IJsonSerializer _jsonSerializer; public MemberController( @@ -63,18 +63,18 @@ namespace Umbraco.Web.BackOffice.Controllers IShortStringHelper shortStringHelper, IEventMessagesFactory eventMessages, ILocalizedTextService localizedTextService, - IMemberPasswordConfiguration passwordConfig, + IOptions passwordConfig, PropertyEditorCollection propertyEditors, LegacyPasswordSecurity passwordSecurity, UmbracoMapper umbracoMapper, IMemberService memberService, IMemberTypeService memberTypeService, IDataTypeService dataTypeService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IJsonSerializer jsonSerializer) : base(cultureDictionary, logger, shortStringHelper, eventMessages, localizedTextService) { - _passwordConfig = passwordConfig; + _passwordConfig = passwordConfig.Value; _propertyEditors = propertyEditors; _passwordSecurity = passwordSecurity; _umbracoMapper = umbracoMapper; @@ -82,7 +82,7 @@ namespace Umbraco.Web.BackOffice.Controllers _memberTypeService = memberTypeService; _dataTypeService = dataTypeService; _localizedTextService = localizedTextService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _jsonSerializer = jsonSerializer; } @@ -310,7 +310,7 @@ namespace Umbraco.Web.BackOffice.Controllers throw new InvalidOperationException($"No member type found with alias {contentItem.ContentTypeAlias}"); var member = new Member(contentItem.Name, contentItem.Email, contentItem.Username, memberType, true) { - CreatorId = _webSecurity.CurrentUser.Id, + CreatorId = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id, RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword), Comments = contentItem.Comments, IsApproved = contentItem.IsApproved @@ -328,13 +328,13 @@ namespace Umbraco.Web.BackOffice.Controllers /// private void UpdateMemberData(MemberSave contentItem) { - contentItem.PersistedContent.WriterId = _webSecurity.CurrentUser.Id; + contentItem.PersistedContent.WriterId = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id; // If the user doesn't have access to sensitive values, then we need to check if any of the built in member property types // have been marked as sensitive. If that is the case we cannot change these persisted values no matter what value has been posted. // There's only 3 special ones we need to deal with that are part of the MemberSave instance: Comments, IsApproved, IsLockedOut // but we will take care of this in a generic way below so that it works for all props. - if (!_webSecurity.CurrentUser.HasAccessToSensitiveData()) + if (!_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasAccessToSensitiveData()) { var memberType = _memberTypeService.Get(contentItem.PersistedContent.ContentTypeId); var sensitiveProperties = memberType @@ -458,7 +458,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpGet] public IActionResult ExportMemberData(Guid key) { - var currentUser = _webSecurity.CurrentUser; + var currentUser = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (currentUser.HasAccessToSensitiveData() == false) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs index 8ef8749c2d..e4d616cc43 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Strings; using Umbraco.Web.Models.ContentEditing; using Constants = Umbraco.Core.Constants; using Umbraco.Core.Mapping; +using Umbraco.Core.Security; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -33,7 +34,7 @@ namespace Umbraco.Web.Editors public class MemberTypeController : ContentTypeControllerBase { private readonly IMemberTypeService _memberTypeService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IShortStringHelper _shortStringHelper; private readonly UmbracoMapper _umbracoMapper; private readonly ILocalizedTextService _localizedTextService; @@ -46,7 +47,7 @@ namespace Umbraco.Web.Editors IMemberTypeService memberTypeService, UmbracoMapper umbracoMapper, ILocalizedTextService localizedTextService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IShortStringHelper shortStringHelper) : base(cultureDictionary, editorValidatorCollection, @@ -57,7 +58,7 @@ namespace Umbraco.Web.Editors localizedTextService) { _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _localizedTextService = @@ -141,7 +142,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - _memberTypeService.Delete(foundType, _webSecurity.CurrentUser.Id); + _memberTypeService.Delete(foundType, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return Ok(); } @@ -201,7 +202,7 @@ namespace Umbraco.Web.Editors var ctId = Convert.ToInt32(contentTypeSave.Id); var ct = ctId > 0 ? _memberTypeService.Get(ctId) : null; - if (_webSecurity.CurrentUser.HasAccessToSensitiveData() == false) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasAccessToSensitiveData() == false) { //We need to validate if any properties on the contentTypeSave have had their IsSensitiveValue changed, //and if so, we need to check if the current user has access to sensitive values. If not, we have to return an error diff --git a/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs b/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs index d8df34748d..fa16288fb5 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageController.cs @@ -10,6 +10,7 @@ using Semver; using Umbraco.Core; using Umbraco.Core.Hosting; using Umbraco.Core.Models.Packaging; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -27,16 +28,16 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly IHostingEnvironment _hostingEnvironment; private readonly IPackagingService _packagingService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public PackageController( IHostingEnvironment hostingEnvironment, IPackagingService packagingService, - IWebSecurity webSecurity) + IBackofficeSecurityAccessor backofficeSecurityAccessor) { _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); _packagingService = packagingService ?? throw new ArgumentNullException(nameof(packagingService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); } public IEnumerable GetCreatedPackages() @@ -90,7 +91,7 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpDelete] public IActionResult DeleteCreatedPackage(int packageId) { - _packagingService.DeleteCreatedPackage(packageId, _webSecurity.GetUserId().ResultOr(0)); + _packagingService.DeleteCreatedPackage(packageId, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); return Ok(); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs index b61e86746a..fe9523f410 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models.Packaging; using Umbraco.Net; using Umbraco.Core.Packaging; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.WebAssets; using Umbraco.Web.BackOffice.Filters; @@ -38,7 +39,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IRuntimeMinifier _runtimeMinifier; private readonly IPackagingService _packagingService; private readonly ILogger _logger; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILocalizedTextService _localizedTextService; public PackageInstallController( @@ -48,7 +49,7 @@ namespace Umbraco.Web.BackOffice.Controllers IRuntimeMinifier runtimeMinifier, IPackagingService packagingService, ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService localizedTextService) { _umbracoVersion = umbracoVersion ?? throw new ArgumentNullException(nameof(umbracoVersion)); @@ -57,7 +58,7 @@ namespace Umbraco.Web.BackOffice.Controllers _runtimeMinifier = runtimeMinifier ?? throw new ArgumentNullException(nameof(runtimeMinifier)); _packagingService = packagingService ?? throw new ArgumentNullException(nameof(packagingService)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); } @@ -87,14 +88,14 @@ namespace Umbraco.Web.BackOffice.Controllers var package = _packagingService.GetInstalledPackageById(packageId); if (package == null) return NotFound(); - var summary = _packagingService.UninstallPackage(package.Name, _webSecurity.GetUserId().ResultOr(0)); + var summary = _packagingService.UninstallPackage(package.Name, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); //now get all other packages by this name since we'll uninstall all versions foreach (var installed in _packagingService.GetAllInstalledPackages() .Where(x => x.Name == package.Name && x.Id != package.Id)) { //remove from the xml - _packagingService.DeleteInstalledPackage(installed.Id, _webSecurity.GetUserId().ResultOr(0)); + _packagingService.DeleteInstalledPackage(installed.Id, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); } } catch (Exception ex) @@ -223,7 +224,7 @@ namespace Umbraco.Web.BackOffice.Controllers var packageFile = await _packagingService.FetchPackageFileAsync( Guid.Parse(packageGuid), _umbracoVersion.Current, - _webSecurity.GetUserId().ResultOr(0)); + _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); fileName = packageFile.Name; } @@ -310,7 +311,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); var zipFile = new FileInfo(definition.PackagePath); - var installedFiles = _packagingService.InstallCompiledPackageFiles(definition, zipFile, _webSecurity.GetUserId().ResultOr(0)); + var installedFiles = _packagingService.InstallCompiledPackageFiles(definition, zipFile, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); //set a restarting marker and reset the app pool _umbracoApplicationLifetime.Restart(); @@ -342,7 +343,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (definition == null) throw new InvalidOperationException("Not package definition found with id " + model.Id); var zipFile = new FileInfo(definition.PackagePath); - var installSummary = _packagingService.InstallCompiledPackageData(definition, zipFile, _webSecurity.GetUserId().ResultOr(0)); + var installSummary = _packagingService.InstallCompiledPackageData(definition, zipFile, _backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); return model; } diff --git a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs index fec9d23f19..fb6d597d9e 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PreviewController.cs @@ -1,13 +1,16 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.Extensions.Options; using System; using System.IO; using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Hosting; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.WebAssets; using Umbraco.Extensions; @@ -18,6 +21,8 @@ using Umbraco.Web.Editors; using Umbraco.Web.Features; using Umbraco.Web.PublishedCache; using Umbraco.Web.Security; +using Umbraco.Web.Services; +using Umbraco.Web.Trees; using Umbraco.Web.WebAssets; using Constants = Umbraco.Core.Constants; @@ -28,10 +33,10 @@ namespace Umbraco.Web.BackOffice.Controllers public class PreviewController : Controller { private readonly UmbracoFeatures _features; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IPublishedSnapshotService _publishedSnapshotService; - private readonly IWebSecurity _webSecurity; - private readonly ILocalizationService _localizationService; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly ILocalizationService _localizationService; private readonly IHostingEnvironment _hostingEnvironment; private readonly ICookieManager _cookieManager; private readonly IRuntimeMinifier _runtimeMinifier; @@ -39,9 +44,9 @@ namespace Umbraco.Web.BackOffice.Controllers public PreviewController( UmbracoFeatures features, - IGlobalSettings globalSettings, + IOptions globalSettings, IPublishedSnapshotService publishedSnapshotService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizationService localizationService, IHostingEnvironment hostingEnvironment, ICookieManager cookieManager, @@ -49,9 +54,9 @@ namespace Umbraco.Web.BackOffice.Controllers ICompositeViewEngine viewEngines) { _features = features; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _publishedSnapshotService = publishedSnapshotService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _localizationService = localizationService; _hostingEnvironment = hostingEnvironment; _cookieManager = cookieManager; @@ -105,7 +110,7 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoAuthorize] public ActionResult Frame(int id, string culture) { - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; var previewToken = _publishedSnapshotService.EnterPreview(user, id); diff --git a/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs b/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs index 5086919b83..c5a2108ced 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs @@ -12,6 +12,10 @@ using Umbraco.Core.Mapping; using Umbraco.Core.Services; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Security; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; +using Umbraco.Core.Security; namespace Umbraco.Web.BackOffice.Controllers { @@ -19,25 +23,29 @@ namespace Umbraco.Web.BackOffice.Controllers public class RedirectUrlManagementController : UmbracoAuthorizedApiController { private readonly ILogger _logger; - private readonly IWebRoutingSettings _webRoutingSettings; - private readonly IWebSecurity _webSecurity; + private readonly WebRoutingSettings _webRoutingSettings; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IRedirectUrlService _redirectUrlService; private readonly UmbracoMapper _umbracoMapper; private readonly IHostingEnvironment _hostingEnvironment; + private readonly IConfigManipulator _configManipulator; - public RedirectUrlManagementController(ILogger logger, - IWebRoutingSettings webRoutingSettings, - IWebSecurity webSecurity, + public RedirectUrlManagementController( + ILogger logger, + IOptions webRoutingSettings, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IRedirectUrlService redirectUrlService, UmbracoMapper umbracoMapper, - IHostingEnvironment hostingEnvironment) + IHostingEnvironment hostingEnvironment, + IConfigManipulator configManipulator) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webRoutingSettings = webRoutingSettings ?? throw new ArgumentNullException(nameof(webRoutingSettings)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _webRoutingSettings = webRoutingSettings.Value ?? throw new ArgumentNullException(nameof(webRoutingSettings)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _redirectUrlService = redirectUrlService ?? throw new ArgumentNullException(nameof(redirectUrlService)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); + _configManipulator = configManipulator ?? throw new ArgumentNullException(nameof(configManipulator)); } /// @@ -48,7 +56,7 @@ namespace Umbraco.Web.BackOffice.Controllers public IActionResult GetEnableState() { var enabled = _webRoutingSettings.DisableRedirectUrlTracking == false; - var userIsAdmin = _webSecurity.CurrentUser.IsAdmin(); + var userIsAdmin = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin(); return Ok(new { enabled, userIsAdmin }); } @@ -104,30 +112,17 @@ namespace Umbraco.Web.BackOffice.Controllers [HttpPost] public IActionResult ToggleUrlTracker(bool disable) { - var userIsAdmin = _webSecurity.CurrentUser.IsAdmin(); + var userIsAdmin = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin(); if (userIsAdmin == false) { var errorMessage = "User is not a member of the administrators group and so is not allowed to toggle the URL tracker"; _logger.Debug(errorMessage); throw new SecurityException(errorMessage); } - var configFilePath =_hostingEnvironment.MapPathContentRoot("~/config/umbracoSettings.config"); var action = disable ? "disable" : "enable"; - if (System.IO.File.Exists(configFilePath) == false) - return BadRequest($"Couldn't {action} URL Tracker, the umbracoSettings.config file does not exist."); - - var umbracoConfig = new XmlDocument { PreserveWhitespace = true }; - umbracoConfig.Load(configFilePath); - - var webRoutingElement = umbracoConfig.SelectSingleNode("//web.routing") as XmlElement; - if (webRoutingElement == null) - return BadRequest($"Couldn't {action} URL Tracker, the web.routing element was not found in umbracoSettings.config."); - - // note: this adds the attribute if it does not exist - webRoutingElement.SetAttribute("disableRedirectUrlTracking", disable.ToString().ToLowerInvariant()); - umbracoConfig.Save(configFilePath); + _configManipulator.SaveDisableRedirectUrlTracking(disable); return Ok($"URL tracker is now {action}d."); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/RelationTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/RelationTypeController.cs index 0991dca09f..54fc3352d3 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/RelationTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/RelationTypeController.cs @@ -15,7 +15,6 @@ using Umbraco.Core.Mapping; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; -using Umbraco.Web.Editors; namespace Umbraco.Web.BackOffice.Controllers { @@ -43,9 +42,8 @@ namespace Umbraco.Web.BackOffice.Controllers _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); } - /// - /// Gets a relation type by ID. + /// Gets a relation type by id /// /// The relation type ID. /// Returns the . @@ -63,7 +61,6 @@ namespace Umbraco.Web.BackOffice.Controllers return display; } - /// /// Gets a relation type by guid /// diff --git a/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs b/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs index 5239994e04..c579a3ec1d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; using Umbraco.Core; using Umbraco.Core.Mapping; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Attributes; @@ -22,43 +24,46 @@ namespace Umbraco.Web.Editors public class SectionController : UmbracoAuthorizedJsonController { private readonly IControllerFactory _controllerFactory; + private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; private readonly IDashboardService _dashboardService; private readonly ILocalizedTextService _localizedTextService; private readonly ISectionService _sectionService; private readonly ITreeService _treeService; private readonly UmbracoMapper _umbracoMapper; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public SectionController( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService localizedTextService, IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService, - UmbracoMapper umbracoMapper, IControllerFactory controllerFactory) + UmbracoMapper umbracoMapper, IControllerFactory controllerFactory, + IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _localizedTextService = localizedTextService; _dashboardService = dashboardService; _sectionService = sectionService; _treeService = treeService; _umbracoMapper = umbracoMapper; _controllerFactory = controllerFactory; + _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider; } public IEnumerable
GetSections() { - var sections = _sectionService.GetAllowedSections(_webSecurity.GetUserId().ResultOr(0)); + var sections = _sectionService.GetAllowedSections(_backofficeSecurityAccessor.BackofficeSecurity.GetUserId().ResultOr(0)); var sectionModels = sections.Select(_umbracoMapper.Map
).ToArray(); // this is a bit nasty since we'll be proxying via the app tree controller but we sort of have to do that // since tree's by nature are controllers and require request contextual data var appTreeController = - new ApplicationTreeController(_treeService, _sectionService, _localizedTextService, _controllerFactory) + new ApplicationTreeController(_treeService, _sectionService, _localizedTextService, _controllerFactory, _actionDescriptorCollectionProvider) { ControllerContext = ControllerContext }; - var dashboards = _dashboardService.GetDashboards(_webSecurity.CurrentUser); + var dashboards = _dashboardService.GetDashboards(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser); //now we can add metadata for each section so that the UI knows if there's actually anything at all to render for //a dashboard for a given section, then the UI can deal with it accordingly (i.e. redirect to the first tree) @@ -104,10 +109,10 @@ namespace Umbraco.Web.Editors { var sections = _sectionService.GetSections(); var mapped = sections.Select(_umbracoMapper.Map
); - if (_webSecurity.CurrentUser.IsAdmin()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin()) return mapped; - return mapped.Where(x => _webSecurity.CurrentUser.AllowedSections.Contains(x.Alias)).ToArray(); + return mapped.Where(x => _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.AllowedSections.Contains(x.Alias)).ToArray(); } } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs b/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs index dd7c539922..b62d6b6080 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs @@ -6,8 +6,10 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Strings; @@ -28,19 +30,19 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly IHostingEnvironment _hostingEnvironment; private readonly IShortStringHelper _shortStringHelper; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly IIOHelper _ioHelper; public TinyMceController( IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper, - IContentSettings contentSettings, + IOptions contentSettings, IIOHelper ioHelper ) { _hostingEnvironment = hostingEnvironment; _shortStringHelper = shortStringHelper; - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _ioHelper = ioHelper; } @@ -76,7 +78,7 @@ namespace Umbraco.Web.BackOffice.Controllers var safeFileName = fileName.ToSafeFileName(_shortStringHelper); var ext = safeFileName.Substring(safeFileName.LastIndexOf('.') + 1).ToLower(); - if (_contentSettings.IsFileAllowedForUpload(ext) == false || _contentSettings.ImageFileTypes.Contains(ext) == false) + if (_contentSettings.IsFileAllowedForUpload(ext) == false || _contentSettings.Imaging.ImageFileTypes.Contains(ext) == false) { // Throw some error - to say can't upload this IMG type return new UmbracoProblemResult("This is not an image filetype extension that is approved", HttpStatusCode.BadRequest); diff --git a/src/Umbraco.Web.BackOffice/Controllers/TourController.cs b/src/Umbraco.Web.BackOffice/Controllers/TourController.cs index f85bdb1bd5..818b4edf66 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TourController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TourController.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; using Newtonsoft.Json; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Models; @@ -19,22 +21,22 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly TourFilterCollection _filters; private readonly IHostingEnvironment _hostingEnvironment; - private readonly ITourSettings _tourSettings; - private readonly IWebSecurity _webSecurity; + private readonly TourSettings _tourSettings; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IContentTypeService _contentTypeService; public TourController( TourFilterCollection filters, IHostingEnvironment hostingEnvironment, - ITourSettings tourSettings, - IWebSecurity webSecurity, + IOptions tourSettings, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IContentTypeService contentTypeService) { _filters = filters; _hostingEnvironment = hostingEnvironment; - _tourSettings = tourSettings; - _webSecurity = webSecurity; + _tourSettings = tourSettings.Value; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _contentTypeService = contentTypeService; } @@ -45,7 +47,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (_tourSettings.EnableTours == false) return result; - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user == null) return result; @@ -187,7 +189,7 @@ namespace Umbraco.Web.BackOffice.Controllers var backOfficeTours = tours.Where(x => aliasFilters.Count == 0 || aliasFilters.All(filter => filter.IsMatch(x.Alias)) == false); - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; var localizedTours = backOfficeTours.Where(x => string.IsNullOrWhiteSpace(x.Culture) || x.Culture.Equals(user.Language, diff --git a/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs index c3e1a71b86..85c92d1139 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs @@ -18,7 +18,7 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoAuthorize] [DisableBrowserCache] [UmbracoWebApiRequireHttps] - //[CheckIfUserTicketDataIsStale] //TODO reintroduce + [CheckIfUserTicketDataIsStale] //[UnhandedExceptionLoggerConfiguration] //TODO reintroduce //[EnableDetailedErrors] //TODO reintroduce public abstract class UmbracoAuthorizedApiController : UmbracoApiController diff --git a/src/Umbraco.Web.BackOffice/Controllers/UpdateCheckController.cs b/src/Umbraco.Web.BackOffice/Controllers/UpdateCheckController.cs index 4212bace72..71dc97c835 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UpdateCheckController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UpdateCheckController.cs @@ -3,11 +3,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Options; using Semver; using Umbraco.Composing; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Models; @@ -21,21 +24,21 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IUpgradeService _upgradeService; private readonly IUmbracoVersion _umbracoVersion; private readonly ICookieManager _cookieManager; - private readonly IWebSecurity _webSecurity; - private readonly IGlobalSettings _globalSettings; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly GlobalSettings _globalSettings; public UpdateCheckController( IUpgradeService upgradeService, IUmbracoVersion umbracoVersion, ICookieManager cookieManager, - IWebSecurity webSecurity, - IGlobalSettings globalSettings) + IBackofficeSecurityAccessor backofficeSecurityAccessor, + IOptions globalSettings) { _upgradeService = upgradeService ?? throw new ArgumentNullException(nameof(upgradeService)); _umbracoVersion = umbracoVersion ?? throw new ArgumentNullException(nameof(umbracoVersion)); _cookieManager = cookieManager ?? throw new ArgumentNullException(nameof(cookieManager)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); - _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); + _globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings)); } [UpdateCheckResponseFilter] @@ -43,7 +46,7 @@ namespace Umbraco.Web.BackOffice.Controllers { var updChkCookie = _cookieManager.GetCookieValue("UMB_UPDCHK"); var updateCheckCookie = updChkCookie ?? string.Empty; - if (_globalSettings.VersionCheckPeriod > 0 && string.IsNullOrEmpty(updateCheckCookie) && _webSecurity.CurrentUser.IsAdmin()) + if (_globalSettings.VersionCheckPeriod > 0 && string.IsNullOrEmpty(updateCheckCookie) && _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin()) { try { @@ -77,11 +80,11 @@ namespace Umbraco.Web.BackOffice.Controllers private class UpdateCheckResponseFilter : IActionFilter { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public UpdateCheckResponseFilter(IGlobalSettings globalSettings) + public UpdateCheckResponseFilter(IOptions globalSettings) { - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } public void OnActionExecuted(ActionExecutedContext context) diff --git a/src/Umbraco.Web.BackOffice/Controllers/UserGroupsController.cs b/src/Umbraco.Web.BackOffice/Controllers/UserGroupsController.cs index 44b675771b..6d641c9cf9 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UserGroupsController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UserGroupsController.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.BackOffice.Filters; @@ -27,13 +28,13 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IContentService _contentService; private readonly IEntityService _entityService; private readonly IMediaService _mediaService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly UmbracoMapper _umbracoMapper; private readonly ILocalizedTextService _localizedTextService; private readonly IShortStringHelper _shortStringHelper; public UserGroupsController(IUserService userService, IContentService contentService, - IEntityService entityService, IMediaService mediaService, IWebSecurity webSecurity, + IEntityService entityService, IMediaService mediaService, IBackofficeSecurityAccessor backofficeSecurityAccessor, UmbracoMapper umbracoMapper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) { @@ -41,7 +42,7 @@ namespace Umbraco.Web.BackOffice.Controllers _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); @@ -57,19 +58,19 @@ namespace Umbraco.Web.BackOffice.Controllers var authHelper = new UserGroupEditorAuthorizationHelper( _userService, _contentService, _mediaService, _entityService); - var isAuthorized = authHelper.AuthorizeGroupAccess(_webSecurity.CurrentUser, userGroupSave.Alias); + var isAuthorized = authHelper.AuthorizeGroupAccess(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, userGroupSave.Alias); if (isAuthorized == false) throw new HttpResponseException(HttpStatusCode.Unauthorized, isAuthorized.Result); //if sections were added we need to check that the current user has access to that section - isAuthorized = authHelper.AuthorizeSectionChanges(_webSecurity.CurrentUser, + isAuthorized = authHelper.AuthorizeSectionChanges(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, userGroupSave.PersistedUserGroup.AllowedSections, userGroupSave.Sections); if (isAuthorized == false) throw new HttpResponseException(HttpStatusCode.Unauthorized, isAuthorized.Result); //if start nodes were changed we need to check that the current user has access to them - isAuthorized = authHelper.AuthorizeStartNodeChanges(_webSecurity.CurrentUser, + isAuthorized = authHelper.AuthorizeStartNodeChanges(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, userGroupSave.PersistedUserGroup.StartContentId, userGroupSave.StartContentId, userGroupSave.PersistedUserGroup.StartMediaId, @@ -111,18 +112,18 @@ namespace Umbraco.Web.BackOffice.Controllers private void EnsureNonAdminUserIsInSavedUserGroup(UserGroupSave userGroupSave) { - if (_webSecurity.CurrentUser.IsAdmin()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin()) { return; } var userIds = userGroupSave.Users.ToList(); - if (userIds.Contains(_webSecurity.CurrentUser.Id)) + if (userIds.Contains(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id)) { return; } - userIds.Add(_webSecurity.CurrentUser.Id); + userIds.Add(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); userGroupSave.Users = userIds; } @@ -144,7 +145,7 @@ namespace Umbraco.Web.BackOffice.Controllers var allGroups = _umbracoMapper.MapEnumerable(_userService.GetAllUserGroups()) .ToList(); - var isAdmin = _webSecurity.CurrentUser.IsAdmin(); + var isAdmin = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin(); if (isAdmin) return allGroups; if (onlyCurrentUserGroups == false) @@ -155,7 +156,7 @@ namespace Umbraco.Web.BackOffice.Controllers } //we cannot return user groups that this user does not have access to - var currentUserGroups = _webSecurity.CurrentUser.Groups.Select(x => x.Alias).ToArray(); + var currentUserGroups = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Groups.Select(x => x.Alias).ToArray(); return allGroups.Where(x => currentUserGroups.Contains(x.Alias)).ToArray(); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs index 75f7a6e512..3e7216e497 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Net.Http; using System.Net.Mail; using System.Runtime.Serialization; using System.Security.Cryptography; @@ -11,27 +10,26 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Mapping; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.WebApi.Filters; -using Constants = Umbraco.Core.Constants; -using IUser = Umbraco.Core.Models.Membership.IUser; -using Task = System.Threading.Tasks.Task; -using Umbraco.Core.Mapping; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Hosting; -using Umbraco.Core.Media; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.ModelBinders; @@ -40,7 +38,13 @@ using Umbraco.Web.Common.ActionResults; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Editors; +using Umbraco.Web.Models; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Security; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; +using IUser = Umbraco.Core.Models.Membership.IUser; +using Task = System.Threading.Tasks.Task; namespace Umbraco.Web.BackOffice.Controllers { @@ -51,14 +55,14 @@ namespace Umbraco.Web.BackOffice.Controllers public class UsersController : UmbracoAuthorizedJsonController { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly ISqlContext _sqlContext; private readonly IImageUrlGenerator _imageUrlGenerator; - private readonly ISecuritySettings _securitySettings; + private readonly SecuritySettings _securitySettings; private readonly IRequestAccessor _requestAccessor; private readonly IEmailSender _emailSender; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly AppCaches _appCaches; private readonly IShortStringHelper _shortStringHelper; private readonly IUserService _userService; @@ -67,21 +71,21 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IEntityService _entityService; private readonly IMediaService _mediaService; private readonly IContentService _contentService; - private readonly IGlobalSettings _globalSettings; - private readonly BackOfficeUserManager _backOfficeUserManager; + private readonly GlobalSettings _globalSettings; + private readonly IBackOfficeUserManager _backOfficeUserManager; private readonly ILogger _logger; private readonly LinkGenerator _linkGenerator; public UsersController( IMediaFileSystem mediaFileSystem, - IContentSettings contentSettings, + IOptions contentSettings, IHostingEnvironment hostingEnvironment, ISqlContext sqlContext, IImageUrlGenerator imageUrlGenerator, - ISecuritySettings securitySettings, + IOptions securitySettings, IRequestAccessor requestAccessor, IEmailSender emailSender, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, AppCaches appCaches, IShortStringHelper shortStringHelper, IUserService userService, @@ -90,20 +94,20 @@ namespace Umbraco.Web.BackOffice.Controllers IEntityService entityService, IMediaService mediaService, IContentService contentService, - IGlobalSettings globalSettings, - BackOfficeUserManager backOfficeUserManager, + IOptions globalSettings, + IBackOfficeUserManager backOfficeUserManager, ILogger logger, LinkGenerator linkGenerator) { _mediaFileSystem = mediaFileSystem; - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _hostingEnvironment = hostingEnvironment; _sqlContext = sqlContext; _imageUrlGenerator = imageUrlGenerator; - _securitySettings = securitySettings; + _securitySettings = securitySettings.Value; _requestAccessor = requestAccessor; _emailSender = emailSender; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _appCaches = appCaches; _shortStringHelper = shortStringHelper; _userService = userService; @@ -112,7 +116,7 @@ namespace Umbraco.Web.BackOffice.Controllers _entityService = entityService; _mediaService = mediaService; _contentService = contentService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _backOfficeUserManager = backOfficeUserManager; _logger = logger; _linkGenerator = linkGenerator; @@ -124,7 +128,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// public string[] GetCurrentUserAvatarUrls() { - var urls = _webSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); + var urls = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator); if (urls == null) throw new HttpResponseException(HttpStatusCode.BadRequest, "Could not access Gravatar endpoint"); @@ -138,7 +142,7 @@ namespace Umbraco.Web.BackOffice.Controllers return await PostSetAvatarInternal(files, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, id); } - internal static async Task PostSetAvatarInternal(IList files, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IContentSettings contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, int id) + internal static async Task PostSetAvatarInternal(IList files, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, ContentSettings contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, int id) { if (files is null) { @@ -290,7 +294,7 @@ namespace Umbraco.Web.BackOffice.Controllers var hideDisabledUsers = _securitySettings.HideDisabledUsersInBackoffice; var excludeUserGroups = new string[0]; - var isAdmin = _webSecurity.CurrentUser.IsAdmin(); + var isAdmin = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsAdmin(); if (isAdmin == false) { //this user is not an admin so in that case we need to exclude all admin users @@ -299,7 +303,7 @@ namespace Umbraco.Web.BackOffice.Controllers var filterQuery = _sqlContext.Query(); - if (!_webSecurity.CurrentUser.IsSuper()) + if (!_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.IsSuper()) { // only super can see super - but don't use IsSuper, cannot be mapped to SQL //filterQuery.Where(x => !x.IsSuper()); @@ -360,7 +364,7 @@ namespace Umbraco.Web.BackOffice.Controllers //Perform authorization here to see if the current user can actually save this user with the info being requested var authHelper = new UserEditorAuthorizationHelper(_contentService,_mediaService, _userService, _entityService); - var canSaveUser = authHelper.IsAuthorized(_webSecurity.CurrentUser, null, null, null, userSave.UserGroups); + var canSaveUser = authHelper.IsAuthorized(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, null, null, null, userSave.UserGroups); if (canSaveUser == false) { throw new HttpResponseException(HttpStatusCode.Unauthorized, canSaveUser.Result); @@ -444,7 +448,7 @@ namespace Umbraco.Web.BackOffice.Controllers //Perform authorization here to see if the current user can actually save this user with the info being requested var authHelper = new UserEditorAuthorizationHelper(_contentService,_mediaService, _userService, _entityService); - var canSaveUser = authHelper.IsAuthorized(_webSecurity.CurrentUser, user, null, null, userSave.UserGroups); + var canSaveUser = authHelper.IsAuthorized(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, user, null, null, userSave.UserGroups); if (canSaveUser == false) { throw new HttpResponseException(HttpStatusCode.Unauthorized, canSaveUser.Result); @@ -479,7 +483,7 @@ namespace Umbraco.Web.BackOffice.Controllers //send the email - await SendUserInviteEmailAsync(display, _webSecurity.CurrentUser.Name, _webSecurity.CurrentUser.Email, user, userSave.Message); + await SendUserInviteEmailAsync(display, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Name, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Email, user, userSave.Message); display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles/resendInviteHeader"), _localizedTextService.Localize("speechBubbles/resendInviteSuccess", new[] { user.Name })); @@ -575,7 +579,7 @@ namespace Umbraco.Web.BackOffice.Controllers //Perform authorization here to see if the current user can actually save this user with the info being requested var authHelper = new UserEditorAuthorizationHelper(_contentService,_mediaService, _userService, _entityService); - var canSaveUser = authHelper.IsAuthorized(_webSecurity.CurrentUser, found, userSave.StartContentIds, userSave.StartMediaIds, userSave.UserGroups); + var canSaveUser = authHelper.IsAuthorized(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, found, userSave.StartContentIds, userSave.StartMediaIds, userSave.UserGroups); if (canSaveUser == false) { throw new HttpResponseException(HttpStatusCode.Unauthorized, canSaveUser.Result); @@ -658,7 +662,7 @@ namespace Umbraco.Web.BackOffice.Controllers } var passwordChanger = new PasswordChanger(_logger); - var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_webSecurity.CurrentUser, found, changingPasswordModel, _backOfficeUserManager); + var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, found, changingPasswordModel, _backOfficeUserManager); if (passwordChangeResult.Success) { @@ -683,7 +687,7 @@ namespace Umbraco.Web.BackOffice.Controllers [AdminUsersAuthorize("userIds")] public IActionResult PostDisableUsers([FromQuery]int[] userIds) { - var tryGetCurrentUserId = _webSecurity.GetUserId(); + var tryGetCurrentUserId = _backofficeSecurityAccessor.BackofficeSecurity.GetUserId(); if (tryGetCurrentUserId && userIds.Contains(tryGetCurrentUserId.Result)) { throw HttpResponseException.CreateNotificationValidationErrorResponse("The current user cannot disable itself"); @@ -739,11 +743,16 @@ namespace Umbraco.Web.BackOffice.Controllers public async Task PostUnlockUsers([FromQuery]int[] userIds) { if (userIds.Length <= 0) return Ok(); + var notFound = new List(); foreach (var u in userIds) { var user = await _backOfficeUserManager.FindByIdAsync(u.ToString()); - if (user == null) throw new InvalidOperationException(); + if (user == null) + { + notFound.Add(u); + continue; + } var unlockResult = await _backOfficeUserManager.SetLockoutEndDateAsync(user, DateTimeOffset.Now); if (unlockResult.Succeeded == false) @@ -760,7 +769,7 @@ namespace Umbraco.Web.BackOffice.Controllers } return new UmbracoNotificationSuccessResponse( - _localizedTextService.Localize("speechBubbles/unlockUsersSuccess", new[] {userIds.Length.ToString()})); + _localizedTextService.Localize("speechBubbles/unlockUsersSuccess", new[] {(userIds.Length - notFound.Count).ToString()})); } [AdminUsersAuthorize("userIds")] diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs similarity index 79% rename from src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs rename to src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs index 282668e4e6..3cba66812e 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs @@ -7,7 +7,7 @@ using Umbraco.Web.BackOffice.Security; namespace Umbraco.Extensions { - public static class UmbracoBackOfficeApplicationBuilderExtensions + public static class BackOfficeApplicationBuilderExtensions { public static IApplicationBuilder UseUmbraco(this IApplicationBuilder app) { @@ -44,11 +44,6 @@ namespace Umbraco.Extensions app.UseUmbracoRuntimeMinification(); - // Important we handle image manipulations before the static files, otherwise the querystring is just ignored. - // TODO: Since we are dependent on these we need to register them but what happens when we call this multiple times since we are dependent on this for UseUmbracoWebsite too? - app.UseImageSharp(); - app.UseStaticFiles(); - app.UseMiddleware(); return app; diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs similarity index 62% rename from src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeServiceCollectionExtensions.cs rename to src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs index fc3efab5e0..4e00525c2a 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; @@ -7,9 +8,10 @@ using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Security; using Umbraco.Core.Serialization; using Umbraco.Net; @@ -20,51 +22,9 @@ using Umbraco.Web.Common.Security; namespace Umbraco.Extensions { - public static class UmbracoBackOfficeServiceCollectionExtensions + + public static class BackOfficeServiceCollectionExtensions { - public static IServiceCollection AddUmbraco(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration config) - { - if (services == null) throw new ArgumentNullException(nameof(services)); - - // TODO: We will need to decide on if we want to use the ServiceBasedControllerActivator to create our controllers - // or use the default IControllerActivator: DefaultControllerActivator (which doesn't directly use the container to resolve controllers) - // This will affect whether we need to explicitly register controllers in the container like we do today in v8. - // What we absolutely must do though is make sure we explicitly opt-in to using one or the other *always* for our controllers instead of - // relying on a global configuration set by a user since if a custom IControllerActivator is used for our own controllers we may not - // guarantee it will work. And then... is that even possible? - - // TODO: we will need to simplify this and prob just have a one or 2 main method that devs call which call all other required methods, - // but for now we'll just be explicit with all of them - services.AddUmbracoConfiguration(config); - services.AddUmbracoCore(webHostEnvironment, out var factory); - services.AddUmbracoWebComponents(); - services.AddUmbracoRuntimeMinifier(config); - services.AddUmbracoBackOffice(); - services.AddUmbracoBackOfficeIdentity(); - services.AddMiniProfiler(options => - { - options.ShouldProfile = request => false; // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile - }); - - //We need to have runtime compilation of views when using umbraco. We could consider having only this when a specific config is set. - //But as far as I can see, there are still precompiled views, even when this is activated, so maybe it is okay. - services.AddControllersWithViews().AddRazorRuntimeCompilation(); - - - // If using Kestrel: https://stackoverflow.com/a/55196057 - services.Configure(options => - { - options.AllowSynchronousIO = true; - }); - - services.Configure(options => - { - options.AllowSynchronousIO = true; - }); - - return services; - } - /// /// Adds the services required for running the Umbraco back office /// @@ -98,14 +58,14 @@ namespace Umbraco.Extensions services.BuildUmbracoBackOfficeIdentity() .AddDefaultTokenProviders() .AddUserStore() - .AddUserManager() + .AddUserManager() .AddSignInManager() .AddClaimsPrincipalFactory>(); // Configure the options specifically for the UmbracoBackOfficeIdentityOptions instance services.ConfigureOptions(); services.ConfigureOptions(); - } + } private static IdentityBuilder BuildUmbracoBackOfficeIdentity(this IServiceCollection services) { @@ -121,7 +81,7 @@ namespace Umbraco.Extensions services.TryAddScoped, PasswordValidator>(); services.TryAddScoped>( services => new BackOfficePasswordHasher( - new LegacyPasswordSecurity(services.GetRequiredService()), + new LegacyPasswordSecurity(services.GetRequiredService>().Value), services.GetRequiredService())); services.TryAddScoped, DefaultUserConfirmation>(); services.TryAddScoped, UserClaimsPrincipalFactory>(); diff --git a/src/Umbraco.Web.BackOffice/Extensions/ControllerContextExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/ControllerContextExtensions.cs new file mode 100644 index 0000000000..ca17d97fc7 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Extensions/ControllerContextExtensions.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; + +namespace Umbraco.Extensions +{ + internal static class ControllerContextExtensions + { + /// + /// Invokes the authorization filters for the controller action. + /// + /// Whether the user is authenticated or not. + internal static async Task InvokeAuthorizationFiltersForRequest(this ControllerContext controllerContext, ActionContext actionContext) + { + var actionDescriptor = controllerContext.ActionDescriptor; + + var filters = actionDescriptor.FilterDescriptors; + var filterGrouping = new FilterGrouping(filters, controllerContext.HttpContext.RequestServices); + + // because the continuation gets built from the inside out we need to reverse the filter list + // so that least specific filters (Global) get run first and the most specific filters (Action) get run last. + var authorizationFilters = filterGrouping.AuthorizationFilters.Reverse().ToList(); + var asyncAuthorizationFilters = filterGrouping.AsyncAuthorizationFilters.Reverse().ToList(); + + if (authorizationFilters.Count == 0 && asyncAuthorizationFilters.Count == 0) + return true; + + // if the authorization filter returns a result, it means it failed to authorize + var authorizationFilterContext = new AuthorizationFilterContext(actionContext, filters.Select(x=>x.Filter).ToArray()); + return await ExecuteAuthorizationFiltersAsync(authorizationFilterContext, authorizationFilters, asyncAuthorizationFilters); + } + + /// + /// Executes a chain of filters. + /// + /// + /// Recursively calls in to itself as its continuation for the next filter in the chain. + /// + private static async Task ExecuteAuthorizationFiltersAsync( + AuthorizationFilterContext authorizationFilterContext, + IList authorizationFilters, + IList asyncAuthorizationFilters) + { + + foreach (var authorizationFilter in authorizationFilters) + { + authorizationFilter.OnAuthorization(authorizationFilterContext); + if (!(authorizationFilterContext.Result is null)) + { + return false; + } + + } + + foreach (var asyncAuthorizationFilter in asyncAuthorizationFilters) + { + await asyncAuthorizationFilter.OnAuthorizationAsync(authorizationFilterContext); + if (!(authorizationFilterContext.Result is null)) + { + return false; + } + } + + return true; + } + + /// + /// Quickly split filters into different types + /// + private class FilterGrouping + { + private readonly List _actionFilters = new List(); + private readonly List _asyncActionFilters = new List(); + private readonly List _authorizationFilters = new List(); + private readonly List _asyncAuthorizationFilters = new List(); + private readonly List _exceptionFilters = new List(); + private readonly List _asyncExceptionFilters = new List(); + + public FilterGrouping(IEnumerable filters, IServiceProvider serviceProvider) + { + if (filters == null) throw new ArgumentNullException("filters"); + + foreach (FilterDescriptor f in filters) + { + var filter = f.Filter; + Categorize(filter, _actionFilters, serviceProvider); + Categorize(filter, _authorizationFilters, serviceProvider); + Categorize(filter, _exceptionFilters, serviceProvider); + Categorize(filter, _asyncActionFilters, serviceProvider); + Categorize(filter, _asyncAuthorizationFilters, serviceProvider); + } + } + + public IEnumerable ActionFilters => _actionFilters; + public IEnumerable AsyncActionFilters => _asyncActionFilters; + public IEnumerable AuthorizationFilters => _authorizationFilters; + + public IEnumerable AsyncAuthorizationFilters => _asyncAuthorizationFilters; + + public IEnumerable ExceptionFilters => _exceptionFilters; + + public IEnumerable AsyncExceptionFilters => _asyncExceptionFilters; + + private static void Categorize(IFilterMetadata filter, List list, IServiceProvider serviceProvider) where T : class + { + if(filter is TypeFilterAttribute typeFilterAttribute) + { + filter = typeFilterAttribute.CreateInstance(serviceProvider); + } + + T match = filter as T; + if (match != null) + { + list.Add(match); + } + } + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs new file mode 100644 index 0000000000..eab7142665 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Extensions/IdentityBuilderExtensions.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.BackOffice; + +namespace Umbraco.Extensions +{ + public static class IdentityBuilderExtensions + { + /// + /// Adds a for the . + /// + /// The type of the user manager to add. + /// + /// The current instance. + public static IdentityBuilder AddUserManager(this IdentityBuilder identityBuilder) where TUserManager : UserManager, TInterface + { + identityBuilder.AddUserManager(); + identityBuilder.Services.AddScoped(typeof(TInterface), typeof(TUserManager)); + return identityBuilder; + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs new file mode 100644 index 0000000000..71325d70d4 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs @@ -0,0 +1,28 @@ +using Umbraco.Web.Common.Builder; + +namespace Umbraco.Extensions +{ + public static class UmbracoBuilderExtensions + { + public static void BuildWithAllBackOfficeComponents(this IUmbracoBuilder builder) + { + builder + .WithConfiguration() + .WithCore() + .WithWebComponents() + .WithRuntimeMinifier() + .WithBackOffice() + .WithBackOfficeIdentity() + .WithMiniProfiler() + .WithMvcAndRazor() + .WithWebServer() + .Build(); + } + + public static IUmbracoBuilder WithBackOffice(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithBackOffice), () => builder.Services.AddUmbracoBackOffice()); + + public static IUmbracoBuilder WithBackOfficeIdentity(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithBackOfficeIdentity), () => builder.Services.AddUmbracoBackOfficeIdentity()); + } +} diff --git a/src/Umbraco.Web.BackOffice/Filters/AdminUsersAuthorizeAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/AdminUsersAuthorizeAttribute.cs index 526504b04d..4920b6351a 100644 --- a/src/Umbraco.Web.BackOffice/Filters/AdminUsersAuthorizeAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/AdminUsersAuthorizeAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Editors; using Umbraco.Web.Security; @@ -34,7 +35,7 @@ namespace Umbraco.Web.BackOffice.Filters private readonly IContentService _contentService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public AdminUsersAuthorizeFilter( IRequestAccessor requestAccessor, @@ -42,7 +43,7 @@ namespace Umbraco.Web.BackOffice.Filters IContentService contentService, IMediaService mediaService, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, string parameterName) { _requestAccessor = requestAccessor; @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Filters _contentService = contentService; _mediaService = mediaService; _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _parameterName = parameterName; } @@ -86,7 +87,7 @@ namespace Umbraco.Web.BackOffice.Filters var users = _userService.GetUsersById(userIds); var authHelper = new UserEditorAuthorizationHelper(_contentService, _mediaService, _userService, _entityService); - return users.All(user => authHelper.IsAuthorized(_webSecurity.CurrentUser, user, null, null, null) != false); + return users.All(user => authHelper.IsAuthorized(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, user, null, null, null) != false); } } diff --git a/src/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttribute.cs index 6541d122ab..c484de3bfb 100644 --- a/src/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/AppendUserModifiedHeaderAttribute.cs @@ -43,8 +43,8 @@ namespace Umbraco.Web.BackOffice.Filters throw new InvalidOperationException($"No argument found for the current action with the name: {_userIdParameter}"); } - var webSecurity = context.HttpContext.RequestServices.GetService(); - var user = webSecurity.CurrentUser; + var backofficeSecurity = context.HttpContext.RequestServices.GetService(); + var user = backofficeSecurity.CurrentUser; if (user == null) { return; diff --git a/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs new file mode 100644 index 0000000000..cde2f77bf7 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.BackOffice; +using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Mapping; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Services; +using Umbraco.Extensions; +using Umbraco.Web.BackOffice.Security; +using Umbraco.Web.Common.Security; + +namespace Umbraco.Web.BackOffice.Filters +{ + internal sealed class CheckIfUserTicketDataIsStaleAttribute : TypeFilterAttribute + { + public CheckIfUserTicketDataIsStaleAttribute() : base(typeof(CheckIfUserTicketDataIsStaleFilter)) + { + } + + private class CheckIfUserTicketDataIsStaleFilter : IAsyncActionFilter + { + private readonly IRequestCache _requestCache; + private readonly UmbracoMapper _umbracoMapper; + private readonly IUserService _userService; + private readonly IEntityService _entityService; + private readonly ILocalizedTextService _localizedTextService; + private readonly IOptions _globalSettings; + private readonly BackOfficeSignInManager _backOfficeSignInManager; + private readonly IBackOfficeAntiforgery _backOfficeAntiforgery; + + public CheckIfUserTicketDataIsStaleFilter( + IRequestCache requestCache, + UmbracoMapper umbracoMapper, + IUserService userService, + IEntityService entityService, + ILocalizedTextService localizedTextService, + IOptions globalSettings, + BackOfficeSignInManager backOfficeSignInManager, + IBackOfficeAntiforgery backOfficeAntiforgery) + { + _requestCache = requestCache; + _umbracoMapper = umbracoMapper; + _userService = userService; + _entityService = entityService; + _localizedTextService = localizedTextService; + _globalSettings = globalSettings; + _backOfficeSignInManager = backOfficeSignInManager; + _backOfficeAntiforgery = backOfficeAntiforgery; + } + + + public async Task OnActionExecutionAsync(ActionExecutingContext actionContext, ActionExecutionDelegate next) + { + await CheckStaleData(actionContext); + + await next(); + + await CheckStaleData(actionContext); + + //return if nothing is updated + if (_requestCache.Get(nameof(CheckIfUserTicketDataIsStaleFilter)) is null) + return; + + await UpdateTokensAndAppendCustomHeaders(actionContext); + } + + private async Task UpdateTokensAndAppendCustomHeaders(ActionExecutingContext actionContext) + { + var tokenFilter = + new SetAngularAntiForgeryTokensAttribute.SetAngularAntiForgeryTokensFilter(_backOfficeAntiforgery, + _globalSettings); + await tokenFilter.OnActionExecutionAsync(actionContext, + () => Task.FromResult(new ActionExecutedContext(actionContext, new List(), null))); + + //add the header + AppendUserModifiedHeaderAttribute.AppendHeader(actionContext); + } + + + private async Task CheckStaleData(ActionExecutingContext actionContext) + { + if (actionContext?.HttpContext.Request == null || actionContext.HttpContext.User?.Identity == null) + { + return; + } + + //don't execute if it's already been done + if (!(_requestCache.Get(nameof(CheckIfUserTicketDataIsStaleFilter)) is null)) + return; + + var identity = actionContext.HttpContext.User.Identity as UmbracoBackOfficeIdentity; + if (identity == null) return; + + var userId = identity.Id.TryConvertTo(); + if (userId == false) return; + + var user = _userService.GetUserById(userId.Result); + if (user == null) return; + + //a list of checks to execute, if any of them pass then we resync + var checks = new Func[] + { + () => user.Username != identity.Username, + () => + { + var culture = user.GetUserCulture(_localizedTextService, _globalSettings.Value); + return culture != null && culture.ToString() != identity.Culture; + }, + () => user.AllowedSections.UnsortedSequenceEqual(identity.AllowedApplications) == false, + () => user.Groups.Select(x => x.Alias).UnsortedSequenceEqual(identity.Roles) == false, + () => + { + var startContentIds = user.CalculateContentStartNodeIds(_entityService); + return startContentIds.UnsortedSequenceEqual(identity.StartContentNodes) == false; + }, + () => + { + var startMediaIds = user.CalculateMediaStartNodeIds(_entityService); + return startMediaIds.UnsortedSequenceEqual(identity.StartMediaNodes) == false; + } + }; + + if (checks.Any(check => check())) + { + await ReSync(user, actionContext); + } + } + + /// + /// This will update the current request IPrincipal to be correct and re-create the auth ticket + /// + /// + /// + /// + private async Task ReSync(IUser user, ActionExecutingContext actionContext) + { + var backOfficeIdentityUser = _umbracoMapper.Map(user); + await _backOfficeSignInManager.SignInAsync(backOfficeIdentityUser, isPersistent: true); + + //ensure the remainder of the request has the correct principal set + actionContext.HttpContext.SetPrincipalForRequest(ClaimsPrincipal.Current); + + //flag that we've made changes + _requestCache.Set(nameof(CheckIfUserTicketDataIsStaleFilter), true); + } + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs index 71323b1659..eee5cb6d30 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs @@ -22,14 +22,14 @@ namespace Umbraco.Web.BackOffice.Filters internal abstract class ContentModelValidator { - protected IWebSecurity WebSecurity { get; } + protected IBackofficeSecurity BackofficeSecurity { get; } public IPropertyValidationService PropertyValidationService { get; } protected ILogger Logger { get; } - protected ContentModelValidator(ILogger logger, IWebSecurity webSecurity, IPropertyValidationService propertyValidationService) + protected ContentModelValidator(ILogger logger, IBackofficeSecurity backofficeSecurity, IPropertyValidationService propertyValidationService) { Logger = logger ?? throw new ArgumentNullException(nameof(logger)); - WebSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + BackofficeSecurity = backofficeSecurity ?? throw new ArgumentNullException(nameof(backofficeSecurity)); PropertyValidationService = propertyValidationService ?? throw new ArgumentNullException(nameof(propertyValidationService)); } } @@ -53,10 +53,10 @@ namespace Umbraco.Web.BackOffice.Filters protected ContentModelValidator( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, propertyValidationService) + : base(logger, backofficeSecurity, propertyValidationService) { _textService = textService ?? throw new ArgumentNullException(nameof(textService)); } diff --git a/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs index 493b2e04ea..a73b20dca5 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs @@ -13,10 +13,10 @@ namespace Umbraco.Web.BackOffice.Filters { public ContentSaveModelValidator( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, textService, propertyValidationService) + : base(logger, backofficeSecurity, textService, propertyValidationService) { } diff --git a/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs index 216f94499b..457929690f 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs @@ -35,12 +35,12 @@ namespace Umbraco.Web.BackOffice.Filters private readonly ILogger _logger; private readonly ILocalizedTextService _textService; private readonly IUserService _userService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public ContentSaveValidationFilter( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IContentService contentService, IUserService userService, @@ -48,7 +48,7 @@ namespace Umbraco.Web.BackOffice.Filters IPropertyValidationService propertyValidationService) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); @@ -59,11 +59,11 @@ namespace Umbraco.Web.BackOffice.Filters public void OnActionExecuting(ActionExecutingContext context) { var model = (ContentItemSave) context.ActionArguments["contentItem"]; - var contentItemValidator = new ContentSaveModelValidator(_logger, _webSecurity, _textService, _propertyValidationService); + var contentItemValidator = new ContentSaveModelValidator(_logger, _backofficeSecurityAccessor.BackofficeSecurity, _textService, _propertyValidationService); if (!ValidateAtLeastOneVariantIsBeingSaved(model, context)) return; if (!contentItemValidator.ValidateExistingContent(model, context)) return; - if (!ValidateUserAccess(model, context, _webSecurity)) return; + if (!ValidateUserAccess(model, context, _backofficeSecurityAccessor.BackofficeSecurity)) return; //validate for each variant that is being updated foreach (var variant in model.Variants.Where(x => x.Save)) @@ -101,9 +101,9 @@ namespace Umbraco.Web.BackOffice.Filters ///
/// /// - /// + /// private bool ValidateUserAccess(ContentItemSave contentItem, ActionExecutingContext actionContext, - IWebSecurity webSecurity) + IBackofficeSecurity backofficeSecurity) { // We now need to validate that the user is allowed to be doing what they are doing. // Based on the action we need to check different permissions. @@ -217,13 +217,13 @@ namespace Umbraco.Web.BackOffice.Filters actionContext.HttpContext.Items[typeof(IContent).ToString()] = contentItem; accessResult = ContentPermissionsHelper.CheckPermissions( - contentToCheck, webSecurity.CurrentUser, + contentToCheck, backofficeSecurity.CurrentUser, _userService, _entityService, permissionToCheck.ToArray()); } else { accessResult = ContentPermissionsHelper.CheckPermissions( - contentIdToCheck, webSecurity.CurrentUser, + contentIdToCheck, backofficeSecurity.CurrentUser, _userService, _contentService, _entityService, out contentToCheck, permissionToCheck.ToArray()); diff --git a/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForContentAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForContentAttribute.cs index 131854808e..1c271d93e6 100644 --- a/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForContentAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForContentAttribute.cs @@ -75,7 +75,7 @@ namespace Umbraco.Web.BackOffice.Filters private sealed class EnsureUserPermissionForContentFilter : IActionFilter { private readonly int? _nodeId; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IEntityService _entityService; private readonly IUserService _userService; private readonly IContentService _contentService; @@ -83,58 +83,58 @@ namespace Umbraco.Web.BackOffice.Filters private readonly char? _permissionToCheck; public EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, string paramName) - :this(webSecurity, entityService, userService, contentService, null, paramName, ActionBrowse.ActionLetter) + :this(backofficeSecurityAccessor, entityService, userService, contentService, null, paramName, ActionBrowse.ActionLetter) { } public EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, int nodeId, char permissionToCheck) - :this(webSecurity, entityService, userService, contentService, nodeId, null, permissionToCheck) + :this(backofficeSecurityAccessor, entityService, userService, contentService, nodeId, null, permissionToCheck) { } public EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, int nodeId) - :this(webSecurity, entityService, userService, contentService, nodeId, null, null) + :this(backofficeSecurityAccessor, entityService, userService, contentService, nodeId, null, null) { } public EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, string paramName, char permissionToCheck) - :this(webSecurity, entityService, userService, contentService, null, paramName, permissionToCheck) + :this(backofficeSecurityAccessor, entityService, userService, contentService, null, paramName, permissionToCheck) { } private EnsureUserPermissionForContentFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IUserService userService, IContentService contentService, int? nodeId, string paramName, char? permissionToCheck) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); @@ -156,7 +156,7 @@ namespace Umbraco.Web.BackOffice.Filters public void OnActionExecuting(ActionExecutingContext context) { - if (_webSecurity.CurrentUser == null) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser == null) { //not logged in throw new HttpResponseException(HttpStatusCode.Unauthorized); @@ -213,7 +213,7 @@ namespace Umbraco.Web.BackOffice.Filters } var permissionResult = ContentPermissionsHelper.CheckPermissions(nodeId, - _webSecurity.CurrentUser, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _userService, _contentService, _entityService, diff --git a/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForMediaAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForMediaAttribute.cs index 526e95cf96..3bf3bd8730 100644 --- a/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForMediaAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/EnsureUserPermissionForMediaAttribute.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Exceptions; @@ -40,7 +41,7 @@ namespace Umbraco.Web.WebApi.Filters { private readonly int? _nodeId; private readonly string _paramName; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IEntityService _entityService; private readonly IMediaService _mediaService; @@ -48,21 +49,21 @@ namespace Umbraco.Web.WebApi.Filters /// This constructor will only be able to test the start node access ///
public EnsureUserPermissionForMediaFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IMediaService mediaService, int nodeId) - :this(webSecurity, entityService, mediaService, nodeId, null) + :this(backofficeSecurityAccessor, entityService, mediaService, nodeId, null) { _nodeId = nodeId; } public EnsureUserPermissionForMediaFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IMediaService mediaService, string paramName) - :this(webSecurity, entityService, mediaService,null, paramName) + :this(backofficeSecurityAccessor, entityService, mediaService,null, paramName) { if (paramName == null) throw new ArgumentNullException(nameof(paramName)); if (string.IsNullOrEmpty(paramName)) @@ -70,12 +71,12 @@ namespace Umbraco.Web.WebApi.Filters } private EnsureUserPermissionForMediaFilter( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IMediaService mediaService, int? nodeId, string paramName) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); @@ -117,7 +118,7 @@ namespace Umbraco.Web.WebApi.Filters public void OnActionExecuting(ActionExecutingContext context) { - if (_webSecurity.CurrentUser == null) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser == null) { throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized); } @@ -158,7 +159,7 @@ namespace Umbraco.Web.WebApi.Filters if (MediaController.CheckPermissions( context.HttpContext.Items, - _webSecurity.CurrentUser, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _mediaService, _entityService, nodeId)) diff --git a/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs index 855cd05829..c67bbefd89 100644 --- a/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Actions; using Umbraco.Web.Security; @@ -60,8 +61,8 @@ namespace Umbraco.Web.BackOffice.Filters - public FilterAllowedOutgoingContentFilter(Type outgoingType, string propertyName, char permissionToCheck, IUserService userService, IEntityService entityService, IWebSecurity webSecurity) - : base(entityService, webSecurity, outgoingType, propertyName) + public FilterAllowedOutgoingContentFilter(Type outgoingType, string propertyName, char permissionToCheck, IUserService userService, IEntityService entityService, IBackofficeSecurityAccessor backofficeSecurityAccessor) + : base(entityService, backofficeSecurityAccessor, outgoingType, propertyName) { _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); diff --git a/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs index a600f5a928..a6325e0650 100644 --- a/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs @@ -34,13 +34,13 @@ namespace Umbraco.Web.WebApi.Filters { private readonly Type _outgoingType; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly string _propertyName; - public FilterAllowedOutgoingMediaFilter(IEntityService entityService, IWebSecurity webSecurity, Type outgoingType, string propertyName) + public FilterAllowedOutgoingMediaFilter(IEntityService entityService, IBackofficeSecurityAccessor backofficeSecurityAccessor, Type outgoingType, string propertyName) { _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _propertyName = propertyName; _outgoingType = outgoingType; @@ -57,7 +57,7 @@ namespace Umbraco.Web.WebApi.Filters { if (context.Result == null) return; - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user == null) return; var objectContent = context.Result as ObjectResult; diff --git a/src/Umbraco.Web.BackOffice/Filters/IsCurrentUserModelFilterAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/IsCurrentUserModelFilterAttribute.cs index 521dd34d77..380995db4d 100644 --- a/src/Umbraco.Web.BackOffice/Filters/IsCurrentUserModelFilterAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/IsCurrentUserModelFilterAttribute.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Umbraco.Core.Security; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Security; @@ -15,11 +16,11 @@ namespace Umbraco.Web.BackOffice.Filters private class IsCurrentUserModelFilter : IActionFilter { - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; - public IsCurrentUserModelFilter(IWebSecurity webSecurity) + public IsCurrentUserModelFilter(IBackofficeSecurityAccessor backofficeSecurityAccessor) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; } @@ -27,7 +28,7 @@ namespace Umbraco.Web.BackOffice.Filters { if (context.Result == null) return; - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user == null) return; var objectContent = context.Result as ObjectResult; diff --git a/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs index a81f4d329a..ee89a8e2fd 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Models.ContentEditing; @@ -29,18 +30,18 @@ namespace Umbraco.Web.BackOffice.Filters private readonly ILogger _logger; private readonly IMediaService _mediaService; private readonly ILocalizedTextService _textService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MediaItemSaveValidationFilter( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IMediaService mediaService, IEntityService entityService, IPropertyValidationService propertyValidationService) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Filters public void OnActionExecuting(ActionExecutingContext context) { var model = (MediaItemSave) context.ActionArguments["contentItem"]; - var contentItemValidator = new MediaSaveModelValidator(_logger, _webSecurity, _textService, _propertyValidationService); + var contentItemValidator = new MediaSaveModelValidator(_logger, _backofficeSecurityAccessor.BackofficeSecurity, _textService, _propertyValidationService); if (ValidateUserAccess(model, context)) { @@ -101,7 +102,7 @@ namespace Umbraco.Web.BackOffice.Filters if (MediaController.CheckPermissions( actionContext.HttpContext.Items, - _webSecurity.CurrentUser, + _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, _mediaService, _entityService, contentIdToCheck, contentToCheck) == false) { diff --git a/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs index 4dd9e6592c..7eaf0cb60f 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs @@ -13,10 +13,10 @@ namespace Umbraco.Web.BackOffice.Filters { public MediaSaveModelValidator( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, textService, propertyValidationService) + : base(logger, backofficeSecurity, textService, propertyValidationService) { } } diff --git a/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs index 208f0eeb07..9ca7cc4f31 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs @@ -26,13 +26,13 @@ namespace Umbraco.Web.BackOffice.Filters public MemberSaveModelValidator( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IMemberTypeService memberTypeService, IMemberService memberService, IShortStringHelper shortStringHelper, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, textService, propertyValidationService) + : base(logger, backofficeSecurity, textService, propertyValidationService) { _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); _memberService = memberService ?? throw new ArgumentNullException(nameof(memberService)); @@ -96,7 +96,7 @@ namespace Umbraco.Web.BackOffice.Filters //if the user doesn't have access to sensitive values, then we need to validate the incoming properties to check //if a sensitive value is being submitted. - if (WebSecurity.CurrentUser.HasAccessToSensitiveData() == false) + if (BackofficeSecurity.CurrentUser.HasAccessToSensitiveData() == false) { var contentType = _memberTypeService.Get(model.PersistedContent.ContentTypeId); var sensitiveProperties = contentType diff --git a/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs index e6f6edb2e3..bfa03264c3 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Models.ContentEditing; @@ -22,7 +23,7 @@ namespace Umbraco.Web.BackOffice.Filters private sealed class MemberSaveValidationFilter : IActionFilter { private readonly ILogger _logger; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILocalizedTextService _textService; private readonly IMemberTypeService _memberTypeService; private readonly IMemberService _memberService; @@ -31,7 +32,7 @@ namespace Umbraco.Web.BackOffice.Filters public MemberSaveValidationFilter( ILogger logger, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IMemberTypeService memberTypeService, IMemberService memberService, @@ -39,7 +40,7 @@ namespace Umbraco.Web.BackOffice.Filters IPropertyValidationService propertyValidationService) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); _memberService = memberService ?? throw new ArgumentNullException(nameof(memberService)); @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Filters public void OnActionExecuting(ActionExecutingContext context) { var model = (MemberSave)context.ActionArguments["contentItem"]; - var contentItemValidator = new MemberSaveModelValidator(_logger, _webSecurity, _textService, _memberTypeService, _memberService, _shortStringHelper, _propertyValidationService); + var contentItemValidator = new MemberSaveModelValidator(_logger, _backofficeSecurityAccessor.BackofficeSecurity, _textService, _memberTypeService, _memberService, _shortStringHelper, _propertyValidationService); //now do each validation step if (contentItemValidator.ValidateExistingContent(model, context)) if (contentItemValidator.ValidateProperties(model, model, context)) diff --git a/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs index d433ba9886..9952eb52f9 100644 --- a/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/OutgoingEditorModelEventAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Web.Editors; using Umbraco.Web.Security; @@ -13,12 +14,12 @@ namespace Umbraco.Web.WebApi.Filters internal sealed class OutgoingEditorModelEventAttribute : ActionFilterAttribute { private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; - public OutgoingEditorModelEventAttribute(IUmbracoContextAccessor umbracoContextAccessor, IWebSecurity webSecurity) + public OutgoingEditorModelEventAttribute(IUmbracoContextAccessor umbracoContextAccessor, IBackofficeSecurityAccessor backofficeSecurityAccessor) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); } public override void OnActionExecuted(ActionExecutedContext context) @@ -26,7 +27,7 @@ namespace Umbraco.Web.WebApi.Filters if (context.Result == null) return; var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user == null) return; if (context.Result is ObjectResult objectContent) diff --git a/src/Umbraco.Web.BackOffice/Filters/SetAngularAntiForgeryTokensAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/SetAngularAntiForgeryTokensAttribute.cs index e52287b57e..aaf23d1799 100644 --- a/src/Umbraco.Web.BackOffice/Filters/SetAngularAntiForgeryTokensAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/SetAngularAntiForgeryTokensAttribute.cs @@ -2,8 +2,9 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.BackOffice.Security; namespace Umbraco.Extensions @@ -17,15 +18,15 @@ namespace Umbraco.Extensions { } - private class SetAngularAntiForgeryTokensFilter : IAsyncActionFilter + internal class SetAngularAntiForgeryTokensFilter : IAsyncActionFilter { private readonly IBackOfficeAntiforgery _antiforgery; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public SetAngularAntiForgeryTokensFilter(IBackOfficeAntiforgery antiforgery, IGlobalSettings globalSettings) + public SetAngularAntiForgeryTokensFilter(IBackOfficeAntiforgery antiforgery, IOptions globalSettings) { _antiforgery = antiforgery; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) @@ -54,24 +55,31 @@ namespace Umbraco.Extensions //We need to set 2 cookies: one is the cookie value that angular will use to set a header value on each request, // the 2nd is the validation value generated by the anti-forgery helper that we use to validate the header token against. - context.HttpContext.Response.Cookies.Append( - Constants.Web.AngularCookieName, headerToken, - new Microsoft.AspNetCore.Http.CookieOptions - { - Path = "/", - //must be js readable - HttpOnly = false, - Secure = _globalSettings.UseHttps - }); + if (!(headerToken is null)) + { + context.HttpContext.Response.Cookies.Append( + Constants.Web.AngularCookieName, headerToken, + new Microsoft.AspNetCore.Http.CookieOptions + { + Path = "/", + //must be js readable + HttpOnly = false, + Secure = _globalSettings.UseHttps + }); + } + + if (!(cookieToken is null)) + { + context.HttpContext.Response.Cookies.Append( + Constants.Web.CsrfValidationCookieName, cookieToken, + new Microsoft.AspNetCore.Http.CookieOptions + { + Path = "/", + HttpOnly = true, + Secure = _globalSettings.UseHttps + }); + } - context.HttpContext.Response.Cookies.Append( - Constants.Web.CsrfValidationCookieName, cookieToken, - new Microsoft.AspNetCore.Http.CookieOptions - { - Path = "/", - HttpOnly = true, - Secure = _globalSettings.UseHttps - }); } } diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoApplicationAuthorizeAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/UmbracoApplicationAuthorizeAttribute.cs index 4465436e77..3850682cf2 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoApplicationAuthorizeAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/UmbracoApplicationAuthorizeAttribute.cs @@ -1,6 +1,7 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Umbraco.Core.Security; using Umbraco.Web.Security; namespace Umbraco.Web.BackOffice.Filters @@ -22,19 +23,19 @@ namespace Umbraco.Web.BackOffice.Filters ///
internal static bool Enable = true; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly string[] _appNames; /// /// Constructor to set any number of applications that the user needs access to be authorized /// - /// + /// /// /// If the user has access to any of the specified apps, they will be authorized. /// - public UmbracoApplicationAuthorizeFilter(IWebSecurity webSecurity, params string[] appName) + public UmbracoApplicationAuthorizeFilter(IBackofficeSecurityAccessor backofficeSecurityAccessor, params string[] appName) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _appNames = appName; } @@ -54,9 +55,9 @@ namespace Umbraco.Web.BackOffice.Filters return true; } - var authorized = _webSecurity.CurrentUser != null - && _appNames.Any(app => _webSecurity.UserHasSectionAccess( - app, _webSecurity.CurrentUser)); + var authorized = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser != null + && _appNames.Any(app => _backofficeSecurityAccessor.BackofficeSecurity.UserHasSectionAccess( + app, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser)); return authorized; } diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoTreeAuthorizeAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/UmbracoTreeAuthorizeAttribute.cs index d4ec1b45e1..5f6e00e82e 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoTreeAuthorizeAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/UmbracoTreeAuthorizeAttribute.cs @@ -3,6 +3,7 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Web.Security; using Umbraco.Web.Services; @@ -34,22 +35,22 @@ namespace Umbraco.Web.BackOffice.Filters private readonly string[] _treeAliases; private readonly ITreeService _treeService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; /// /// Constructor to set authorization to be based on a tree alias for which application security will be applied /// - /// + /// + /// /// /// If the user has access to the application that the treeAlias is specified in, they will be authorized. /// Multiple trees may be specified. /// - /// - public UmbracoTreeAuthorizeFilter(ITreeService treeService, IWebSecurity webSecurity, + public UmbracoTreeAuthorizeFilter(ITreeService treeService, IBackofficeSecurityAccessor backofficeSecurityAccessor, params string[] treeAliases) { _treeService = treeService ?? throw new ArgumentNullException(nameof(treeService)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _treeAliases = treeAliases; } @@ -75,9 +76,9 @@ namespace Umbraco.Web.BackOffice.Filters .Distinct() .ToArray(); - return _webSecurity.CurrentUser != null - && apps.Any(app => _webSecurity.UserHasSectionAccess( - app, _webSecurity.CurrentUser)); + return _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser != null + && apps.Any(app => _backofficeSecurityAccessor.BackofficeSecurity.UserHasSectionAccess( + app, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser)); } } } diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoWebApiRequireHttpsAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/UmbracoWebApiRequireHttpsAttribute.cs index 7c7652c532..e2a1d942d9 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoWebApiRequireHttpsAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/UmbracoWebApiRequireHttpsAttribute.cs @@ -3,7 +3,8 @@ using System.Net; using System.Net.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.BackOffice.Filters { @@ -27,11 +28,11 @@ namespace Umbraco.Web.BackOffice.Filters public class UmbracoWebApiRequireHttpsFilter: IAuthorizationFilter { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public UmbracoWebApiRequireHttpsFilter(IGlobalSettings globalSettings) + public UmbracoWebApiRequireHttpsFilter(IOptions globalSettings) { - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; } public void OnAuthorization(AuthorizationFilterContext context) diff --git a/src/Umbraco.Web.BackOffice/Filters/UserGroupAuthorizationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/UserGroupAuthorizationAttribute.cs index b0175fe6ec..d867cc90bc 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UserGroupAuthorizationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/UserGroupAuthorizationAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Security; @@ -34,7 +35,7 @@ namespace Umbraco.Web.BackOffice.Filters private readonly IContentService _contentService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public UserGroupAuthorizationFilter( IRequestAccessor requestAccessor, @@ -42,7 +43,7 @@ namespace Umbraco.Web.BackOffice.Filters IContentService contentService, IMediaService mediaService, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, string parameterName) { _requestAccessor = requestAccessor; @@ -50,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Filters _contentService = contentService; _mediaService = mediaService; _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _parameterName = parameterName; } @@ -64,7 +65,7 @@ namespace Umbraco.Web.BackOffice.Filters private bool IsAuthorized(AuthorizationFilterContext actionContext) { - var currentUser = _webSecurity.CurrentUser; + var currentUser = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; var queryString = actionContext.HttpContext.Request.Query; diff --git a/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs b/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs index 6b8eada506..fc5ea85dfa 100644 --- a/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs +++ b/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs @@ -8,6 +8,8 @@ using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.HealthCheck; using Umbraco.Web.Common.Attributes; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.BackOffice.Controllers { @@ -22,12 +24,12 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IList _disabledCheckIds; private readonly ILogger _logger; - public HealthCheckController(HealthCheckCollection checks, ILogger logger, IHealthChecksSettings healthChecksSettings) + public HealthCheckController(HealthCheckCollection checks, ILogger logger, IOptions healthChecksSettings) { _checks = checks ?? throw new ArgumentNullException(nameof(checks)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - var healthCheckConfig = healthChecksSettings ?? throw new ArgumentNullException(nameof(healthChecksSettings)); + var healthCheckConfig = healthChecksSettings.Value ?? throw new ArgumentNullException(nameof(healthChecksSettings)); _disabledCheckIds = healthCheckConfig.DisabledChecks .Select(x => x.Id) .ToList(); diff --git a/src/Umbraco.Web.BackOffice/Mapping/MediaMapDefinition.cs b/src/Umbraco.Web.BackOffice/Mapping/MediaMapDefinition.cs index 0a7bdb0026..4076f01aab 100644 --- a/src/Umbraco.Web.BackOffice/Mapping/MediaMapDefinition.cs +++ b/src/Umbraco.Web.BackOffice/Mapping/MediaMapDefinition.cs @@ -1,14 +1,14 @@ -using Umbraco.Core; +using System; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Dictionary; -using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Trees; -using Umbraco.Core.Configuration.UmbracoSettings; -using System; namespace Umbraco.Web.Models.Mapping { @@ -23,17 +23,17 @@ namespace Umbraco.Web.Models.Mapping private readonly IMediaTypeService _mediaTypeService; private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly TabsAndPropertiesMapper _tabsAndPropertiesMapper; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; public MediaMapDefinition(ICultureDictionary cultureDictionary, CommonMapper commonMapper, CommonTreeNodeMapper commonTreeNodeMapper, IMediaService mediaService, IMediaTypeService mediaTypeService, - ILocalizedTextService localizedTextService, MediaUrlGeneratorCollection mediaUrlGenerators, IContentSettings contentSettings, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) + ILocalizedTextService localizedTextService, MediaUrlGeneratorCollection mediaUrlGenerators, IOptions contentSettings, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) { _commonMapper = commonMapper; _commonTreeNodeMapper = commonTreeNodeMapper; _mediaService = mediaService; _mediaTypeService = mediaTypeService; _mediaUrlGenerators = mediaUrlGenerators; - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _tabsAndPropertiesMapper = new TabsAndPropertiesMapper(cultureDictionary, localizedTextService, contentTypeBaseServiceProvider); } diff --git a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs index ec0a75fe11..dd3b3988c9 100644 --- a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs +++ b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs @@ -1,6 +1,8 @@ using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Controllers; @@ -14,19 +16,19 @@ namespace Umbraco.Web.BackOffice.Routing ///
public class BackOfficeAreaRoutes : IAreaRoutes { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IRuntimeState _runtimeState; private readonly UmbracoApiControllerTypeCollection _apiControllers; private readonly string _umbracoPathSegment; public BackOfficeAreaRoutes( - IGlobalSettings globalSettings, + IOptions globalSettings, IHostingEnvironment hostingEnvironment, IRuntimeState runtimeState, UmbracoApiControllerTypeCollection apiControllers) { - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; _runtimeState = runtimeState; _apiControllers = apiControllers; diff --git a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs index 600602f5b5..aed4cbdbb5 100644 --- a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs +++ b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs @@ -4,10 +4,12 @@ using Umbraco.Core.Composing; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Services; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Routing; using Umbraco.Web.BackOffice.Security; +using Umbraco.Web.BackOffice.Services; using Umbraco.Web.BackOffice.Trees; using Umbraco.Web.Common.Runtime; using Umbraco.Web.Trees; @@ -45,6 +47,8 @@ namespace Umbraco.Web.BackOffice.Runtime factory.GetInstance(), factory.GetInstance(), "~/")); + + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Web.BackOffice/Security/BackOfficeCookieManager.cs b/src/Umbraco.Web.BackOffice/Security/BackOfficeCookieManager.cs index 75112e9a22..60bdc9c8ff 100644 --- a/src/Umbraco.Web.BackOffice/Security/BackOfficeCookieManager.cs +++ b/src/Umbraco.Web.BackOffice/Security/BackOfficeCookieManager.cs @@ -1,16 +1,15 @@ -using Microsoft.AspNetCore.Authentication.Cookies; +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Routing; -using System; -using System.Collections.Generic; -using System.Linq; using Umbraco.Core; -using Umbraco.Extensions; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Extensions; namespace Umbraco.Web.BackOffice.Security { @@ -28,7 +27,7 @@ namespace Umbraco.Web.BackOffice.Security private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IRuntimeState _runtime; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IRequestCache _requestCache; private readonly string[] _explicitPaths; @@ -36,7 +35,7 @@ namespace Umbraco.Web.BackOffice.Security IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtime, IHostingEnvironment hostingEnvironment, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IRequestCache requestCache, LinkGenerator linkGenerator) : this(umbracoContextAccessor, runtime, hostingEnvironment, globalSettings, requestCache, linkGenerator, null) @@ -46,7 +45,7 @@ namespace Umbraco.Web.BackOffice.Security IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtime, IHostingEnvironment hostingEnvironment, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IRequestCache requestCache, LinkGenerator linkGenerator, IEnumerable explicitPaths) diff --git a/src/Umbraco.Web.BackOffice/Security/BackOfficeSessionIdValidator.cs b/src/Umbraco.Web.BackOffice/Security/BackOfficeSessionIdValidator.cs index fdf630e01c..b5974c870a 100644 --- a/src/Umbraco.Web.BackOffice/Security/BackOfficeSessionIdValidator.cs +++ b/src/Umbraco.Web.BackOffice/Security/BackOfficeSessionIdValidator.cs @@ -1,16 +1,14 @@  +using System; +using System.Security.Claims; +using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; -using System; -using System.Collections.Generic; -using System.Security.Claims; -using System.Text; -using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Extensions; @@ -37,14 +35,14 @@ namespace Umbraco.Web.BackOffice.Security { public const string CookieName = "UMB_UCONTEXT_C"; private readonly ISystemClock _systemClock; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; - public BackOfficeSessionIdValidator(ISystemClock systemClock, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, BackOfficeUserManager userManager) + public BackOfficeSessionIdValidator(ISystemClock systemClock, IOptions globalSettings, IHostingEnvironment hostingEnvironment, IBackOfficeUserManager userManager) { _systemClock = systemClock; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; _userManager = userManager; } diff --git a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs index d51db33a55..3b8421ce6a 100644 --- a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs +++ b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs @@ -5,20 +5,20 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.Services; -using Umbraco.Net; using Umbraco.Core.Security; +using Umbraco.Core.Services; using Umbraco.Extensions; -using Microsoft.Extensions.DependencyInjection; +using Umbraco.Net; using Umbraco.Web.Common.Security; -using Microsoft.AspNetCore.Routing; namespace Umbraco.Web.BackOffice.Security { @@ -28,8 +28,8 @@ namespace Umbraco.Web.BackOffice.Security public class ConfigureBackOfficeCookieOptions : IConfigureNamedOptions { private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly ISecuritySettings _securitySettings; - private readonly IGlobalSettings _globalSettings; + private readonly SecuritySettings _securitySettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IRuntimeState _runtimeState; private readonly IDataProtectionProvider _dataProtection; @@ -42,8 +42,8 @@ namespace Umbraco.Web.BackOffice.Security public ConfigureBackOfficeCookieOptions( IUmbracoContextAccessor umbracoContextAccessor, - ISecuritySettings securitySettings, - IGlobalSettings globalSettings, + IOptions securitySettings, + IOptions globalSettings, IHostingEnvironment hostingEnvironment, IRuntimeState runtimeState, IDataProtectionProvider dataProtection, @@ -55,8 +55,8 @@ namespace Umbraco.Web.BackOffice.Security LinkGenerator linkGenerator) { _umbracoContextAccessor = umbracoContextAccessor; - _securitySettings = securitySettings; - _globalSettings = globalSettings; + _securitySettings = securitySettings.Value; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; _runtimeState = runtimeState; _dataProtection = dataProtection; @@ -230,7 +230,7 @@ namespace Umbraco.Web.BackOffice.Security } /// - /// Ensures the ticket is renewed if the is set to true + /// Ensures the ticket is renewed if the is set to true /// and the current request is for the get user seconds endpoint /// /// diff --git a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeIdentityOptions.cs b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeIdentityOptions.cs index 13d608bd9b..31b5de2e43 100644 --- a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeIdentityOptions.cs +++ b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeIdentityOptions.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.BackOffice.Security { @@ -13,11 +14,11 @@ namespace Umbraco.Web.BackOffice.Security ///
public class ConfigureBackOfficeIdentityOptions : IConfigureOptions { - private readonly IUserPasswordConfiguration _userPasswordConfiguration; + private readonly UserPasswordConfigurationSettings _userPasswordConfiguration; - public ConfigureBackOfficeIdentityOptions(IUserPasswordConfiguration userPasswordConfiguration) + public ConfigureBackOfficeIdentityOptions(IOptions userPasswordConfiguration) { - _userPasswordConfiguration = userPasswordConfiguration; + _userPasswordConfiguration = userPasswordConfiguration.Value; } public void Configure(BackOfficeIdentityOptions options) diff --git a/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs b/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs index 2ee74aad01..76ecaa32e3 100644 --- a/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs +++ b/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.BackOffice.Security IUser currentUser, IUser savingUser, ChangingPasswordModel passwordModel, - BackOfficeUserManager userMgr) + IBackOfficeUserManager userMgr) { if (passwordModel == null) throw new ArgumentNullException(nameof(passwordModel)); if (userMgr == null) throw new ArgumentNullException(nameof(userMgr)); diff --git a/src/Umbraco.Web.BackOffice/Security/PreviewAuthenticationMiddleware.cs b/src/Umbraco.Web.BackOffice/Security/PreviewAuthenticationMiddleware.cs index ff182b9f7b..1854187a2a 100644 --- a/src/Umbraco.Web.BackOffice/Security/PreviewAuthenticationMiddleware.cs +++ b/src/Umbraco.Web.BackOffice/Security/PreviewAuthenticationMiddleware.cs @@ -6,6 +6,7 @@ using System; using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Extensions; @@ -16,14 +17,14 @@ namespace Umbraco.Web.BackOffice.Security ///
public class PreviewAuthenticationMiddleware : IMiddleware { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; public PreviewAuthenticationMiddleware( - IGlobalSettings globalSettings, + IOptions globalSettings, IHostingEnvironment hostingEnvironment) { - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; } diff --git a/src/Umbraco.Web.BackOffice/Services/IconService.cs b/src/Umbraco.Web.BackOffice/Services/IconService.cs new file mode 100644 index 0000000000..84bd98a459 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Services/IconService.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Ganss.XSS; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using File = System.IO.File; + +namespace Umbraco.Web.BackOffice.Services +{ + public class IconService : IIconService + { + private readonly IOptions _globalSettings; + private readonly IHostingEnvironment _hostingEnvironment; + + public IconService(IOptions globalSettings, IHostingEnvironment hostingEnvironment) + { + _globalSettings = globalSettings; + _hostingEnvironment = hostingEnvironment; + } + + + /// + public IList GetAllIcons() + { + var icons = new List(); + var directory = new DirectoryInfo(_hostingEnvironment.MapPathWebRoot($"{_globalSettings.Value.IconsPath}/")); + var iconNames = directory.GetFiles("*.svg"); + + iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo => + { + var icon = GetIcon(iconInfo); + + if (icon != null) + { + icons.Add(icon); + } + }); + + return icons; + } + + /// + public IconModel GetIcon(string iconName) + { + return string.IsNullOrWhiteSpace(iconName) + ? null + : CreateIconModel(iconName.StripFileExtension(), _hostingEnvironment.MapPathWebRoot($"{_globalSettings.Value.IconsPath}/{iconName}.svg")); + } + + /// + /// Gets an IconModel using values from a FileInfo model + /// + /// + /// + private IconModel GetIcon(FileInfo fileInfo) + { + return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name) + ? null + : CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName); + } + + /// + /// Gets an IconModel containing the icon name and SvgString + /// + /// + /// + /// + private IconModel CreateIconModel(string iconName, string iconPath) + { + var sanitizer = new HtmlSanitizer(); + sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes); + sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes); + sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags); + + try + { + var svgContent = File.ReadAllText(iconPath); + var sanitizedString = sanitizer.Sanitize(svgContent); + + var svg = new IconModel + { + Name = iconName, + SvgString = sanitizedString + }; + + return svg; + } + catch + { + return null; + } + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs index c9bcf01fad..92cb5b1b93 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs @@ -1,4 +1,5 @@ -using System; + +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -7,10 +8,12 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Primitives; using Umbraco.Core; using Umbraco.Core.Services; +using Umbraco.Extensions; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Trees; using Umbraco.Web.Common.Attributes; @@ -34,18 +37,22 @@ namespace Umbraco.Web.Trees private readonly ISectionService _sectionService; private readonly ILocalizedTextService _localizedTextService; private readonly IControllerFactory _controllerFactory; + private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; + public ApplicationTreeController( ITreeService treeService, ISectionService sectionService, ILocalizedTextService localizedTextService, - IControllerFactory controllerFactory + IControllerFactory controllerFactory, + IActionDescriptorCollectionProvider actionDescriptorCollectionProvider ) { _treeService = treeService; _sectionService = sectionService; _localizedTextService = localizedTextService; _controllerFactory = controllerFactory; + _actionDescriptorCollectionProvider = actionDescriptorCollectionProvider; } /// @@ -250,67 +257,36 @@ namespace Umbraco.Web.Trees private async Task GetApiControllerProxy(Type controllerType, string action, FormCollection querystring) { // note: this is all required in order to execute the auth-filters for the sub request, we - // need to "trick" web-api into thinking that it is actually executing the proxied controller. - + // need to "trick" mvc into thinking that it is actually executing the proxied controller. + var controllerName = controllerType.Name.Substring(0, controllerType.Name.Length - 10); // remove controller part of name; // create proxy route data specifying the action & controller to execute var routeData = new RouteData(new RouteValueDictionary() { ["action"] = action, - ["controller"] = controllerType.Name.Substring(0,controllerType.Name.Length-10) // remove controller part of name; - + ["controller"] = controllerName }); + if (!(querystring is null)) + { + foreach (var (key,value) in querystring) + { + routeData.Values[key] = value; + } + } + var actionDescriptor = _actionDescriptorCollectionProvider.ActionDescriptors.Items + .Cast() + .First(x => + x.ControllerName.Equals(controllerName) && + x.ActionName == action); - var controllerContext = new ControllerContext( - new ActionContext( - HttpContext, - routeData, - new ControllerActionDescriptor() - { - ControllerTypeInfo = controllerType.GetTypeInfo() - } - )); + var actionContext = new ActionContext(HttpContext, routeData, actionDescriptor); + var proxyControllerContext = new ControllerContext(actionContext); + var controller = (TreeController) _controllerFactory.CreateController(proxyControllerContext); - var controller = (TreeController) _controllerFactory.CreateController(controllerContext); - - - //TODO Refactor trees or reimplement this hacks to check authentication. - //https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/3694 - - // var context = ControllerContext; - // - // // get the controller - // var controller = (TreeController) DependencyResolver.Current.GetService(controllerType) - // ?? throw new Exception($"Failed to create controller of type {controllerType.FullName}."); - // - // // create the proxy URL for the controller action - // var proxyUrl = HttpContext.Request.RequestUri.GetLeftPart(UriPartial.Authority) - // + HttpContext.Request.GetUrlHelper().GetUmbracoApiService(action, controllerType) - // + "?" + querystring.ToQueryString(); - // - // - // - // // create a proxy request - // var proxyRequest = new HttpRequestMessage(HttpMethod.Get, proxyUrl); - // - // // create a proxy controller context - // var proxyContext = new HttpControllerContext(context.Configuration, proxyRoute, proxyRequest) - // { - // ControllerDescriptor = new HttpControllerDescriptor(context.ControllerDescriptor.Configuration, ControllerExtensions.GetControllerName(controllerType), controllerType), - // RequestContext = context.RequestContext, - // Controller = controller - // }; - // - // // wire everything - // controller.ControllerContext = proxyContext; - // controller.Request = proxyContext.Request; - // controller.RequestContext.RouteData = proxyRoute; - // - // // auth - // var authResult = await controller.ControllerContext.InvokeAuthorizationFiltersForRequest(); - // if (authResult != null) - // throw new HttpResponseException(authResult); + var isAllowed = await controller.ControllerContext.InvokeAuthorizationFiltersForRequest(actionContext); + if (!isAllowed) + throw new HttpResponseException(HttpStatusCode.Forbidden); return controller; } diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs index 0cc73af315..10fbdea0b6 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs @@ -13,6 +13,7 @@ using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Search; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Constants = Umbraco.Core.Constants; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Trees; @@ -20,6 +21,8 @@ using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Security; using Umbraco.Web.WebApi; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Trees { @@ -40,39 +43,38 @@ namespace Umbraco.Web.Trees { private readonly UmbracoTreeSearcher _treeSearcher; private readonly ActionCollection _actions; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IMenuItemCollectionFactory _menuItemCollectionFactory; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IContentService _contentService; private readonly IEntityService _entityService; private readonly IPublicAccessService _publicAccessService; private readonly IUserService _userService; private readonly ILocalizationService _localizationService; - public ContentTreeController( ILocalizedTextService localizedTextService, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, ActionCollection actionCollection, IUserService userService, IDataTypeService dataTypeService, UmbracoTreeSearcher treeSearcher, ActionCollection actions, - IGlobalSettings globalSettings, + IOptions globalSettings, IContentService contentService, IPublicAccessService publicAccessService, ILocalizationService localizationService) - : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, entityService, webSecurity, logger, actionCollection, userService, dataTypeService) + : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, entityService, backofficeSecurityAccessor, logger, actionCollection, userService, dataTypeService) { _treeSearcher = treeSearcher; _actions = actions; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _menuItemCollectionFactory = menuItemCollectionFactory; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _contentService = contentService; _entityService = entityService; _publicAccessService = publicAccessService; @@ -87,7 +89,7 @@ namespace Umbraco.Web.Trees private int[] _userStartNodes; protected override int[] UserStartNodes - => _userStartNodes ?? (_userStartNodes = _webSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService)); + => _userStartNodes ?? (_userStartNodes = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService)); @@ -165,7 +167,7 @@ namespace Umbraco.Web.Trees menu.DefaultMenuAlias = ActionNew.ActionAlias; // we need to get the default permissions as you can't set permissions on the very root node - var permission = _userService.GetPermissions(_webSecurity.CurrentUser, Constants.System.Root).First(); + var permission = _userService.GetPermissions(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, Constants.System.Root).First(); var nodeActions = _actions.FromEntityPermission(permission) .Select(x => new MenuItem(x)); @@ -201,7 +203,7 @@ namespace Umbraco.Web.Trees } //if the user has no path access for this node, all they can do is refresh - if (!_webSecurity.CurrentUser.HasContentPathAccess(item, _entityService)) + if (!_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasContentPathAccess(item, _entityService)) { var menu = _menuItemCollectionFactory.Create(); menu.Items.Add(new RefreshNode(LocalizedTextService, true)); diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs index e458e8754b..ef2f4c2899 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs @@ -25,7 +25,7 @@ namespace Umbraco.Web.Trees public abstract class ContentTreeControllerBase : TreeController, ITreeNodeController { private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILogger _logger; private readonly ActionCollection _actionCollection; private readonly IUserService _userService; @@ -38,7 +38,7 @@ namespace Umbraco.Web.Trees UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, ActionCollection actionCollection, IUserService userService, @@ -47,7 +47,7 @@ namespace Umbraco.Web.Trees : base(localizedTextService, umbracoApiControllerTypeCollection) { _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _logger = logger; _actionCollection = actionCollection; _userService = userService; @@ -64,7 +64,7 @@ namespace Umbraco.Web.Trees /// /// /// - public ActionResult GetTreeNode(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormCollection queryStrings) + public ActionResult GetTreeNode([FromRoute] string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]FormCollection queryStrings) { int asInt; Guid asGuid = Guid.Empty; @@ -147,12 +147,12 @@ namespace Umbraco.Web.Trees switch (RecycleBinId) { case Constants.System.RecycleBinMedia: - startNodeIds = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); - startNodePaths = _webSecurity.CurrentUser.GetMediaStartNodePaths(_entityService); + startNodeIds = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService); + startNodePaths = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetMediaStartNodePaths(_entityService); break; case Constants.System.RecycleBinContent: - startNodeIds = _webSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); - startNodePaths = _webSecurity.CurrentUser.GetContentStartNodePaths(_entityService); + startNodeIds = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateContentStartNodeIds(_entityService); + startNodePaths = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetContentStartNodePaths(_entityService); break; default: throw new NotSupportedException("Path access is only determined on content or media"); @@ -196,7 +196,7 @@ namespace Umbraco.Web.Trees // TODO: in the future we could return a validation statement so we can have some UI to notify the user they don't have access if (ignoreUserStartNodes == false && HasPathAccess(id, queryStrings) == false) { - _logger.Warn("User {Username} does not have access to node with id {Id}", _webSecurity.CurrentUser.Username, id); + _logger.Warn("User {Username} does not have access to node with id {Id}", _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Username, id); return nodes; } @@ -312,8 +312,8 @@ namespace Umbraco.Web.Trees { if (entity == null) return false; return RecycleBinId == Constants.System.RecycleBinContent - ? _webSecurity.CurrentUser.HasContentPathAccess(entity, _entityService) - : _webSecurity.CurrentUser.HasMediaPathAccess(entity, _entityService); + ? _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasContentPathAccess(entity, _entityService) + : _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasMediaPathAccess(entity, _entityService); } /// @@ -441,7 +441,7 @@ namespace Umbraco.Web.Trees var deleteAction = _actionCollection.FirstOrDefault(y => y.Letter == ActionDelete.ActionLetter); if (deleteAction != null) { - var perms = _webSecurity.CurrentUser.GetPermissions(Constants.System.RecycleBinContentString, _userService); + var perms = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.GetPermissions(Constants.System.RecycleBinContentString, _userService); deleteAllowed = perms.FirstOrDefault(x => x.Contains(deleteAction.Letter)) != null; } @@ -492,7 +492,7 @@ namespace Umbraco.Web.Trees internal IEnumerable GetAllowedUserMenuItemsForNode(IUmbracoEntity dd) { - var permissionsForPath = _userService.GetPermissionsForPath(_webSecurity.CurrentUser, dd.Path).GetAllPermissions(); + var permissionsForPath = _userService.GetPermissionsForPath(_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser, dd.Path).GetAllPermissions(); return _actionCollection.GetByLetters(permissionsForPath).Select(x => new MenuItem(x)); } diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs index 46ef45e85d..2a7f769c7b 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs @@ -12,6 +12,7 @@ using Umbraco.Web.Models.Trees; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Search; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Constants = Umbraco.Core.Constants; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Trees; @@ -39,26 +40,26 @@ namespace Umbraco.Web.Trees private readonly UmbracoTreeSearcher _treeSearcher; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MediaTreeController( ILocalizedTextService localizedTextService, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, IEntityService entityService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILogger logger, ActionCollection actionCollection, IUserService userService, IDataTypeService dataTypeService, UmbracoTreeSearcher treeSearcher, IMediaService mediaService) - : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, entityService, webSecurity, logger, actionCollection, userService, dataTypeService) + : base(localizedTextService, umbracoApiControllerTypeCollection, menuItemCollectionFactory, entityService, backofficeSecurityAccessor, logger, actionCollection, userService, dataTypeService) { _treeSearcher = treeSearcher; _mediaService = mediaService; _entityService = entityService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; } protected override int RecycleBinId => Constants.System.RecycleBinMedia; @@ -67,7 +68,7 @@ namespace Umbraco.Web.Trees private int[] _userStartNodes; protected override int[] UserStartNodes - => _userStartNodes ?? (_userStartNodes = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); + => _userStartNodes ?? (_userStartNodes = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); /// /// Creates a tree node for a content item based on an UmbracoEntity @@ -134,7 +135,7 @@ namespace Umbraco.Web.Trees } //if the user has no path access for this node, all they can do is refresh - if (!_webSecurity.CurrentUser.HasMediaPathAccess(item, _entityService)) + if (!_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasMediaPathAccess(item, _entityService)) { menu.Items.Add(new RefreshNode(LocalizedTextService, true)); return menu; diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs index 967e4f22fc..859ee2f846 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Extensions; using Umbraco.Web.Actions; @@ -37,7 +38,7 @@ namespace Umbraco.Web.Trees private readonly IMenuItemCollectionFactory _menuItemCollectionFactory; private readonly IMemberService _memberService; private readonly IMemberTypeService _memberTypeService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MemberTreeController( ILocalizedTextService localizedTextService, @@ -46,14 +47,14 @@ namespace Umbraco.Web.Trees IMenuItemCollectionFactory menuItemCollectionFactory, IMemberService memberService, IMemberTypeService memberTypeService, - IWebSecurity webSecurity) + IBackofficeSecurityAccessor backofficeSecurityAccessor) : base(localizedTextService, umbracoApiControllerTypeCollection) { _treeSearcher = treeSearcher; _menuItemCollectionFactory = menuItemCollectionFactory; _memberService = memberService; _memberTypeService = memberTypeService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; } /// @@ -145,7 +146,7 @@ namespace Umbraco.Web.Trees //add delete option for all members menu.Items.Add(LocalizedTextService, opensDialog: true); - if (_webSecurity.CurrentUser.HasAccessToSensitiveData()) + if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.HasAccessToSensitiveData()) { menu.Items.Add(new ExportMember(LocalizedTextService)); } diff --git a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj index 2547117531..d9e4e05b0c 100644 --- a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj +++ b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj @@ -15,10 +15,10 @@ - - + + - + @@ -31,7 +31,6 @@ - diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreBackOfficeInfo.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreBackOfficeInfo.cs index 39b1d7ff4e..fe991275de 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreBackOfficeInfo.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreBackOfficeInfo.cs @@ -1,13 +1,14 @@ +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.Common.AspNetCore { public class AspNetCoreBackOfficeInfo : IBackOfficeInfo { - public AspNetCoreBackOfficeInfo(IGlobalSettings globalSettings) + public AspNetCoreBackOfficeInfo(IOptionsMonitor globalSettings) { - GetAbsoluteUrl = globalSettings.UmbracoPath; + GetAbsoluteUrl = globalSettings.CurrentValue.UmbracoPath; } public string GetAbsoluteUrl { get; } // TODO make absolute diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs index efa1a52ad4..ede121a9f7 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs @@ -1,19 +1,21 @@ using System; using System.IO; using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.Common.AspNetCore { - public class AspNetCoreHostingEnvironment : Umbraco.Core.Hosting.IHostingEnvironment + public class AspNetCoreHostingEnvironment : Core.Hosting.IHostingEnvironment { - private readonly IHostingSettings _hostingSettings; + private IOptionsMonitor _hostingSettings; private readonly IWebHostEnvironment _webHostEnvironment; private string _localTempPath; - public AspNetCoreHostingEnvironment(IHostingSettings hostingSettings, IWebHostEnvironment webHostEnvironment) + public AspNetCoreHostingEnvironment(IOptionsMonitor hostingSettings, IWebHostEnvironment webHostEnvironment) { _hostingSettings = hostingSettings ?? throw new ArgumentNullException(nameof(hostingSettings)); _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment)); @@ -22,12 +24,7 @@ namespace Umbraco.Web.Common.AspNetCore ApplicationId = AppDomain.CurrentDomain.Id.ToString(); ApplicationPhysicalPath = webHostEnvironment.ContentRootPath; - //TODO how to find this, This is a server thing, not application thing. - ApplicationVirtualPath = hostingSettings.ApplicationVirtualPath?.EnsureStartsWith('/') - ?? "/"; - IISVersion = new Version(0, 0); // TODO not necessary IIS - } public bool IsHosted { get; } = true; @@ -36,8 +33,9 @@ namespace Umbraco.Web.Common.AspNetCore public string ApplicationPhysicalPath { get; } public string ApplicationServerAddress { get; } - public string ApplicationVirtualPath { get; } - public bool IsDebugMode => _hostingSettings.DebugMode; + //TODO how to find this, This is a server thing, not application thing. + public string ApplicationVirtualPath => _hostingSettings.CurrentValue.ApplicationVirtualPath?.EnsureStartsWith('/') ?? "/"; + public bool IsDebugMode => _hostingSettings.CurrentValue.Debug; public Version IISVersion { get; } public string LocalTempPath @@ -47,7 +45,7 @@ namespace Umbraco.Web.Common.AspNetCore if (_localTempPath != null) return _localTempPath; - switch (_hostingSettings.LocalTempStorageLocation) + switch (_hostingSettings.CurrentValue.LocalTempStorageLocation) { case LocalTempStorage.AspNetTemp: diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs index d29e58a2bf..985c568a08 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreRequestAccessor.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Extensions; using Umbraco.Web.Common.Lifetime; @@ -13,18 +15,18 @@ namespace Umbraco.Web.Common.AspNetCore { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IWebRoutingSettings _webRoutingSettings; + private readonly WebRoutingSettings _webRoutingSettings; private readonly ISet _applicationUrls = new HashSet(); private Uri _currentApplicationUrl; public AspNetCoreRequestAccessor(IHttpContextAccessor httpContextAccessor, IUmbracoRequestLifetime umbracoRequestLifetime, IUmbracoContextAccessor umbracoContextAccessor, - IWebRoutingSettings webRoutingSettings) + IOptions webRoutingSettings) { _httpContextAccessor = httpContextAccessor; _umbracoContextAccessor = umbracoContextAccessor; - _webRoutingSettings = webRoutingSettings; + _webRoutingSettings = webRoutingSettings.Value; umbracoRequestLifetime.RequestStart += RequestStart; umbracoRequestLifetime.RequestEnd += RequestEnd; diff --git a/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs b/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs index e72b62b006..fde3d095fe 100644 --- a/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs +++ b/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs @@ -3,9 +3,10 @@ using System.Text; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; @@ -24,8 +25,8 @@ namespace Umbraco.Web.Common.AspNetCore private IUmbracoContext _umbracoContext; private IUmbracoContextAccessor UmbracoContextAccessor => Context.RequestServices.GetRequiredService(); - private IGlobalSettings GlobalSettings => Context.RequestServices.GetRequiredService(); - private IContentSettings ContentSettings => Context.RequestServices.GetRequiredService(); + private GlobalSettings GlobalSettings => Context.RequestServices.GetRequiredService>().Value; + private ContentSettings ContentSettings => Context.RequestServices.GetRequiredService>().Value; private IProfilerHtml ProfilerHtml => Context.RequestServices.GetRequiredService(); private IIOHelper IOHelper => Context.RequestServices.GetRequiredService(); diff --git a/src/Umbraco.Web.Common/Builder/IUmbracoBuilder.cs b/src/Umbraco.Web.Common/Builder/IUmbracoBuilder.cs new file mode 100644 index 0000000000..2de7d2d285 --- /dev/null +++ b/src/Umbraco.Web.Common/Builder/IUmbracoBuilder.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Text; + +namespace Umbraco.Web.Common.Builder +{ + + public interface IUmbracoBuilder + { + IServiceCollection Services { get; } + IWebHostEnvironment WebHostEnvironment { get; } + IConfiguration Config { get; } + IUmbracoBuilder AddWith(string key, Action add); + void Build(); + } +} diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilder.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilder.cs new file mode 100644 index 0000000000..3efb1e74f5 --- /dev/null +++ b/src/Umbraco.Web.Common/Builder/UmbracoBuilder.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; + +namespace Umbraco.Web.Common.Builder +{ + public class UmbracoBuilder : IUmbracoBuilder + { + private readonly Dictionary _registrations = new Dictionary(); + + public UmbracoBuilder(IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration config) + { + Services = services; + WebHostEnvironment = webHostEnvironment; + Config = config; + } + + public IServiceCollection Services { get; } + public IWebHostEnvironment WebHostEnvironment { get; } + public IConfiguration Config { get; } + + public IUmbracoBuilder AddWith(string key, Action add) + { + if (_registrations.ContainsKey(key)) return this; + _registrations[key] = add; + return this; + } + + public void Build() + { + foreach (var a in _registrations) + a.Value(); + } + } +} diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs new file mode 100644 index 0000000000..08b7670522 --- /dev/null +++ b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs @@ -0,0 +1,70 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; +using Umbraco.Extensions; + +namespace Umbraco.Web.Common.Builder +{ + // TODO: We could add parameters to configure each of these for flexibility + public static class UmbracoBuilderExtensions + { + public static IUmbracoBuilder AddUmbraco(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration config) + { + if (services is null) throw new ArgumentNullException(nameof(services)); + if (webHostEnvironment is null) throw new ArgumentNullException(nameof(webHostEnvironment)); + if (config is null) throw new ArgumentNullException(nameof(config)); + + var builder = new UmbracoBuilder(services, webHostEnvironment, config); + return builder; + } + + public static IUmbracoBuilder WithConfiguration(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithConfiguration), () => builder.Services.AddUmbracoConfiguration(builder.Config)); + + public static IUmbracoBuilder WithCore(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithCore), () => builder.Services.AddUmbracoCore(builder.WebHostEnvironment, out _)); + + public static IUmbracoBuilder WithMiniProfiler(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithMiniProfiler), () => + builder.Services.AddMiniProfiler(options => + { + options.ShouldProfile = request => false; // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile + })); + + public static IUmbracoBuilder WithMvcAndRazor(this IUmbracoBuilder builder, Action mvcOptions = null, Action mvcBuilding = null) + => builder.AddWith(nameof(WithMvcAndRazor), () => + { + // TODO: We need to figure out if we can work around this because calling AddControllersWithViews modifies the global app and order is very important + // this will directly affect developers who need to call that themselves. + //We need to have runtime compilation of views when using umbraco. We could consider having only this when a specific config is set. + //But as far as I can see, there are still precompiled views, even when this is activated, so maybe it is okay. + var mvcBuilder = builder.Services.AddControllersWithViews(mvcOptions).AddRazorRuntimeCompilation(); + mvcBuilding?.Invoke(mvcBuilder); + }); + + public static IUmbracoBuilder WithRuntimeMinifier(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithRuntimeMinifier), () => builder.Services.AddUmbracoRuntimeMinifier(builder.Config)); + + public static IUmbracoBuilder WithWebComponents(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithWebComponents), () => builder.Services.AddUmbracoWebComponents()); + + public static IUmbracoBuilder WithWebServer(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithWebServer), () => + { + // TODO: We need to figure out why thsi is needed and fix those endpoints to not need them, we don't want to change global things + // If using Kestrel: https://stackoverflow.com/a/55196057 + builder.Services.Configure(options => + { + options.AllowSynchronousIO = true; + }); + builder.Services.Configure(options => + { + options.AllowSynchronousIO = true; + }); + }); + } +} diff --git a/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs b/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs index 5baedf3ded..0369717b9b 100644 --- a/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/HttpRequestExtensions.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; namespace Umbraco.Extensions @@ -24,7 +25,7 @@ namespace Umbraco.Extensions return request.Cookies.TryGetValue(Constants.Web.PreviewCookieName, out var cookieVal) && !cookieVal.IsNullOrWhiteSpace(); } - public static bool IsBackOfficeRequest(this HttpRequest request, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + public static bool IsBackOfficeRequest(this HttpRequest request, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { return new Uri(request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsBackOfficeRequest(globalSettings, hostingEnvironment); } diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index d18275ca7f..e6808ea4e7 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -1,25 +1,23 @@ using System; using System.Data.Common; using System.Data.SqlClient; -using System.Globalization; using System.IO; -using System.Linq; using System.Reflection; using System.Runtime.InteropServices; -using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Serilog; using Serilog.Extensions.Hosting; using Serilog.Extensions.Logging; -using Umbraco.Configuration; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; @@ -27,13 +25,14 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Runtime; using Umbraco.Web.Common.AspNetCore; -using Umbraco.Web.Common.Extensions; using Umbraco.Web.Common.Profiler; +using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; +using CoreDebugSettings = Umbraco.Core.Configuration.Models.CoreDebugSettings; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; +using ILogger = Umbraco.Core.Logging.ILogger; namespace Umbraco.Extensions { - - public static class UmbracoCoreServiceCollectionExtensions { /// @@ -95,6 +94,28 @@ namespace Umbraco.Extensions return services; } + /// + /// Adds the Umbraco Back Core requirements + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static IServiceCollection AddUmbracoCore( + this IServiceCollection services, + IWebHostEnvironment webHostEnvironment, + IRegister umbContainer, + Assembly entryAssembly, + AppCaches appCaches, + ILoggingConfiguration loggingConfiguration, + out IFactory factory) + => services.AddUmbracoCore(webHostEnvironment, umbContainer, entryAssembly, appCaches, loggingConfiguration, GetCoreRuntime, out factory); + /// /// Adds the Umbraco Configuration requirements /// @@ -105,11 +126,29 @@ namespace Umbraco.Extensions { if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - var configsFactory = new AspNetCoreConfigsFactory(configuration); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "ActiveDirectory")); + services.Configure(configuration.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Content")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Core:Debug")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "ExceptionFilter")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Global")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "HealthChecks")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Hosting")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Imaging")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Examine")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "KeepAlive")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Logging")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigSecurityPrefix + "MemberPassword")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "ModelsBuilder")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "NuCache")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "RequestHandler")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Runtime")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Security")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "Tours")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "TypeFinder")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigSecurityPrefix + "UserPassword")); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigPrefix + "WebRouting")); - var configs = configsFactory.Create(); - - services.AddSingleton(configs); return services; } @@ -146,13 +185,19 @@ namespace Umbraco.Extensions IHttpContextAccessor httpContextAccessor = new HttpContextAccessor(); services.AddSingleton(httpContextAccessor); + var requestCache = new GenericDictionaryRequestAppCache(() => httpContextAccessor.HttpContext?.Items); + var appCaches = new AppCaches( + new DeepCloneAppCache(new ObjectCacheAppCache()), + requestCache, + new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); services.AddUmbracoCore(webHostEnvironment, umbContainer, Assembly.GetEntryAssembly(), - requestCache, + appCaches, loggingConfig, + GetCoreRuntime, out factory); return services; @@ -168,6 +213,7 @@ namespace Umbraco.Extensions /// /// /// + /// Delegate to create an /// /// public static IServiceCollection AddUmbracoCore( @@ -175,8 +221,10 @@ namespace Umbraco.Extensions IWebHostEnvironment webHostEnvironment, IRegister umbContainer, Assembly entryAssembly, - IRequestCache requestCache, + AppCaches appCaches, ILoggingConfiguration loggingConfiguration, + //TODO: Yep that's extremely ugly + Func getRuntime, out IFactory factory) { if (services is null) throw new ArgumentNullException(nameof(services)); @@ -203,21 +251,27 @@ namespace Umbraco.Extensions // into the container. This is not true for `Configs` but we should do that too, see comments in // `RegisterEssentials`. var serviceProvider = services.BuildServiceProvider(); - var configs = serviceProvider.GetService(); + + var globalSettings = serviceProvider.GetService>(); + var connectionStrings = serviceProvider.GetService>(); + var hostingSettings = serviceProvider.GetService>(); + var typeFinderSettings = serviceProvider.GetService>(); + var dbProviderFactoryCreator = serviceProvider.GetRequiredService(); CreateCompositionRoot(services, - configs, + globalSettings, + hostingSettings, webHostEnvironment, loggingConfiguration, out var logger, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler); - var globalSettings = configs.Global(); - var umbracoVersion = new UmbracoVersion(globalSettings); - var typeFinder = CreateTypeFinder(logger, profiler, webHostEnvironment, entryAssembly, configs.TypeFinder()); + var umbracoVersion = new UmbracoVersion(); + var typeFinder = CreateTypeFinder(logger, profiler, webHostEnvironment, entryAssembly, typeFinderSettings); - var coreRuntime = GetCoreRuntime( - configs, + var coreRuntime = getRuntime( + globalSettings.CurrentValue, + connectionStrings.Value, umbracoVersion, ioHelper, logger, @@ -225,7 +279,7 @@ namespace Umbraco.Extensions hostingEnvironment, backOfficeInfo, typeFinder, - requestCache, + appCaches, dbProviderFactoryCreator); factory = coreRuntime.Configure(container); @@ -233,7 +287,7 @@ namespace Umbraco.Extensions return services; } - private static ITypeFinder CreateTypeFinder(Core.Logging.ILogger logger, IProfiler profiler, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, ITypeFinderSettings typeFinderSettings) + private static ITypeFinder CreateTypeFinder(Core.Logging.ILogger logger, IProfiler profiler, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, IOptionsMonitor typeFinderSettings) { var runtimeHashPaths = new RuntimeHashPaths(); runtimeHashPaths.AddFolder(new DirectoryInfo(Path.Combine(webHostEnvironment.ContentRootPath, "bin"))); @@ -242,25 +296,23 @@ namespace Umbraco.Extensions } private static IRuntime GetCoreRuntime( - Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, Core.Logging.ILogger logger, - IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, - ITypeFinder typeFinder, IRequestCache requestCache, IDbProviderFactoryCreator dbProviderFactoryCreator) + GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, + IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, + ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator) { - // 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 isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); var mainDomLock = appSettingMainDomLock == "SqlMainDomLock" || isWindows == false - ? (IMainDomLock)new SqlMainDomLock(logger, globalSettings, connStrings, dbProviderFactoryCreator, hostingEnvironment) + ? (IMainDomLock)new SqlMainDomLock(logger, globalSettings, connectionStrings, dbProviderFactoryCreator, hostingEnvironment) : new MainDomSemaphoreLock(logger, hostingEnvironment); var mainDom = new MainDom(logger, mainDomLock); var coreRuntime = new CoreRuntime( - configs, + globalSettings, + connectionStrings, umbracoVersion, ioHelper, logger, @@ -271,14 +323,15 @@ namespace Umbraco.Extensions dbProviderFactoryCreator, mainDom, typeFinder, - requestCache); + appCaches); return coreRuntime; } private static IServiceCollection CreateCompositionRoot( IServiceCollection services, - Configs configs, + IOptionsMonitor globalSettings, + IOptionsMonitor hostingSettings, IWebHostEnvironment webHostEnvironment, ILoggingConfiguration loggingConfiguration, out Core.Logging.ILogger logger, @@ -287,14 +340,11 @@ namespace Umbraco.Extensions out IBackOfficeInfo backOfficeInfo, out IProfiler profiler) { - 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 globalSettings = configs.Global(); + if (globalSettings == null) + throw new InvalidOperationException($"Could not resolve type {typeof(GlobalSettings)} from the container, ensure {nameof(AddUmbracoConfiguration)} is called before calling {nameof(AddUmbracoCore)}"); hostingEnvironment = new AspNetCoreHostingEnvironment(hostingSettings, webHostEnvironment); - ioHelper = new IOHelper(hostingEnvironment, globalSettings); + ioHelper = new IOHelper(hostingEnvironment); logger = AddLogger(services, hostingEnvironment, loggingConfiguration); backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings); diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs index a795edf6cf..394a15e1d4 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs @@ -19,6 +19,7 @@ using Smidge; using Smidge.Nuglify; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.Common.ApplicationModels; using Umbraco.Web.Common.Middleware; using Umbraco.Web.Common.ModelBinding; @@ -40,8 +41,7 @@ namespace Umbraco.Extensions // 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(); + var imagingSettings = serviceProvider.GetService>().Value; services.AddUmbracoImageSharp(imagingSettings); return services; @@ -53,19 +53,19 @@ namespace Umbraco.Extensions /// /// /// - public static IServiceCollection AddUmbracoImageSharp(this IServiceCollection services, IImagingSettings imagingSettings) + public static IServiceCollection AddUmbracoImageSharp(this IServiceCollection services, ImagingSettings imagingSettings) { services.AddImageSharpCore( options => { options.Configuration = SixLabors.ImageSharp.Configuration.Default; - options.MaxBrowserCacheDays = imagingSettings.MaxBrowserCacheDays; - options.MaxCacheDays = imagingSettings.MaxCacheDays; - options.CachedNameLength = imagingSettings.CachedNameLength; + options.MaxBrowserCacheDays = imagingSettings.Cache.MaxBrowserCacheDays; + options.MaxCacheDays = imagingSettings.Cache.MaxCacheDays; + options.CachedNameLength = imagingSettings.Cache.CachedNameLength; options.OnParseCommands = context => { - RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Width, imagingSettings.MaxResizeWidth); - RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Height, imagingSettings.MaxResizeHeight); + RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Width, imagingSettings.Resize.MaxWidth); + RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Height, imagingSettings.Resize.MaxHeight); }; options.OnBeforeSave = _ => { }; options.OnProcessed = _ => { }; @@ -75,7 +75,7 @@ namespace Umbraco.Extensions .SetMemoryAllocator(provider => ArrayPoolMemoryAllocator.CreateWithMinimalPooling()) .Configure(options => { - options.CacheFolder = imagingSettings.CacheFolder; + options.CacheFolder = imagingSettings.Cache.CacheFolder; }) .SetCache() .SetCacheHash() diff --git a/src/Umbraco.Web.Common/Filters/HttpResponseExceptionFilter.cs b/src/Umbraco.Web.Common/Filters/HttpResponseExceptionFilter.cs index 46bfd6cdfa..6a5f6eaa47 100644 --- a/src/Umbraco.Web.Common/Filters/HttpResponseExceptionFilter.cs +++ b/src/Umbraco.Web.Common/Filters/HttpResponseExceptionFilter.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; -using Umbraco.Core.Exceptions; using Umbraco.Web.Common.Exceptions; namespace Umbraco.Web.Common.Filters diff --git a/src/Umbraco.Web.Common/Filters/JsonExceptionFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/JsonExceptionFilterAttribute.cs index 1ff8ede0ab..3d25016c15 100644 --- a/src/Umbraco.Web.Common/Filters/JsonExceptionFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/JsonExceptionFilterAttribute.cs @@ -25,7 +25,7 @@ namespace Umbraco.Web.Common.Filters public void OnException(ExceptionContext filterContext) { - if (filterContext.Exception != null) + if (filterContext.Exception != null && !filterContext.ExceptionHandled) { filterContext.HttpContext.Response.StatusCode = (int) HttpStatusCode.InternalServerError; diff --git a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs index 559a02e149..3c1de1e138 100644 --- a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs +++ b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs @@ -4,8 +4,9 @@ using System.Text.RegularExpressions; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Common.ModelBinders; @@ -22,12 +23,12 @@ namespace Umbraco.Web.Common.Filters { private static readonly Regex _getPublishedModelsTypesRegex = new Regex("Umbraco.Web.PublishedModels.(\\w+)", RegexOptions.Compiled); - private readonly IExceptionFilterSettings _exceptionFilterSettings; + private readonly ExceptionFilterSettings _exceptionFilterSettings; private readonly IPublishedModelFactory _publishedModelFactory; - public ModelBindingExceptionFilter(IExceptionFilterSettings exceptionFilterSettings, IPublishedModelFactory publishedModelFactory) + public ModelBindingExceptionFilter(IOptions exceptionFilterSettings, IPublishedModelFactory publishedModelFactory) { - _exceptionFilterSettings = exceptionFilterSettings; + _exceptionFilterSettings = exceptionFilterSettings.Value; _publishedModelFactory = publishedModelFactory ?? throw new ArgumentNullException(nameof(publishedModelFactory)); } diff --git a/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs b/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs index 8f3fcf3a95..fe941e89d5 100644 --- a/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/StatusCodeResultAttribute.cs @@ -2,6 +2,8 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; namespace Umbraco.Web.Common.Filters @@ -26,7 +28,7 @@ namespace Umbraco.Web.Common.Filters httpContext.Response.StatusCode = (int)_statusCode; - var disableIisCustomErrors = httpContext.RequestServices.GetService().TrySkipIisCustomErrors; + var disableIisCustomErrors = httpContext.RequestServices.GetService>().Value.TrySkipIisCustomErrors; var statusCodePagesFeature = httpContext.Features.Get(); if (statusCodePagesFeature != null) diff --git a/src/Umbraco.Web.Common/Install/InstallApiController.cs b/src/Umbraco.Web.Common/Install/InstallApiController.cs index edc73ef293..3470553c56 100644 --- a/src/Umbraco.Web.Common/Install/InstallApiController.cs +++ b/src/Umbraco.Web.Common/Install/InstallApiController.cs @@ -30,21 +30,19 @@ namespace Umbraco.Web.Common.Install private readonly DatabaseBuilder _databaseBuilder; private readonly InstallStatusTracker _installStatusTracker; private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; - private readonly BackOfficeSignInManager _backOfficeSignInManager; private readonly InstallStepCollection _installSteps; private readonly ILogger _logger; private readonly IProfilingLogger _proflog; public InstallApiController(DatabaseBuilder databaseBuilder, IProfilingLogger proflog, InstallHelper installHelper, InstallStepCollection installSteps, InstallStatusTracker installStatusTracker, - IUmbracoApplicationLifetime umbracoApplicationLifetime, BackOfficeSignInManager backOfficeSignInManager) + IUmbracoApplicationLifetime umbracoApplicationLifetime) { _databaseBuilder = databaseBuilder ?? throw new ArgumentNullException(nameof(databaseBuilder)); _proflog = proflog ?? throw new ArgumentNullException(nameof(proflog)); _installSteps = installSteps; _installStatusTracker = installStatusTracker; _umbracoApplicationLifetime = umbracoApplicationLifetime; - _backOfficeSignInManager = backOfficeSignInManager; InstallHelper = installHelper; _logger = _proflog; } @@ -90,14 +88,6 @@ namespace Umbraco.Web.Common.Install [HttpPost] public async Task CompleteInstall() { - // log the super user in if it's a new install - var installType = InstallHelper.GetInstallationType(); - if (installType == InstallationType.NewInstall) - { - var user = await _backOfficeSignInManager.UserManager.FindByIdAsync(Constants.Security.SuperUserId.ToString()); - await _backOfficeSignInManager.SignInAsync(user, false); - } - _umbracoApplicationLifetime.Restart(); return NoContent(); } diff --git a/src/Umbraco.Web.Common/Install/InstallController.cs b/src/Umbraco.Web.Common/Install/InstallController.cs index dbd0def5e9..026f604d50 100644 --- a/src/Umbraco.Web.Common/Install/InstallController.cs +++ b/src/Umbraco.Web.Common/Install/InstallController.cs @@ -7,11 +7,14 @@ using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Umbraco.Core.WebAssets; using Umbraco.Extensions; using Umbraco.Web.Common.Filters; using Umbraco.Web.Install; using Umbraco.Web.Security; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; namespace Umbraco.Web.Common.Install { @@ -23,10 +26,10 @@ namespace Umbraco.Web.Common.Install [Area(Umbraco.Core.Constants.Web.Mvc.InstallArea)] public class InstallController : Controller { - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly InstallHelper _installHelper; private readonly IRuntimeState _runtime; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IUmbracoVersion _umbracoVersion; private readonly ILogger _logger; @@ -34,20 +37,20 @@ namespace Umbraco.Web.Common.Install private readonly IRuntimeMinifier _runtimeMinifier; public InstallController( - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, InstallHelper installHelper, IRuntimeState runtime, - IGlobalSettings globalSettings, + IOptions globalSettings, IRuntimeMinifier runtimeMinifier, IHostingEnvironment hostingEnvironment, IUmbracoVersion umbracoVersion, ILogger logger, LinkGenerator linkGenerator) { - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _installHelper = installHelper; _runtime = runtime; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _runtimeMinifier = runtimeMinifier; _hostingEnvironment = hostingEnvironment; _umbracoVersion = umbracoVersion; @@ -70,7 +73,7 @@ namespace Umbraco.Web.Common.Install // Update ClientDependency version and delete its temp directories to make sure we get fresh caches _runtimeMinifier.Reset(); - var result = _webSecurity.ValidateCurrentUser(false); + var result = _backofficeSecurityAccessor.BackofficeSecurity.ValidateCurrentUser(false); switch (result) { diff --git a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs index 8685c0b8b1..58c1e59338 100644 --- a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs @@ -4,9 +4,10 @@ using System.IO; using System.Linq; using System.Text; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -22,7 +23,7 @@ namespace Umbraco.Web.Macros { private readonly IProfilingLogger _plogger; private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly ILocalizedTextService _textService; private readonly AppCaches _appCaches; private readonly IMacroService _macroService; @@ -33,11 +34,10 @@ namespace Umbraco.Web.Macros private readonly IRequestAccessor _requestAccessor; private readonly IHttpContextAccessor _httpContextAccessor; - public MacroRenderer( IProfilingLogger plogger, IUmbracoContextAccessor umbracoContextAccessor, - IContentSettings contentSettings, + IOptions contentSettings, ILocalizedTextService textService, AppCaches appCaches, IMacroService macroService, @@ -50,7 +50,7 @@ namespace Umbraco.Web.Macros { _plogger = plogger ?? throw new ArgumentNullException(nameof(plogger)); _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _textService = textService; _appCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); _macroService = macroService ?? throw new ArgumentNullException(nameof(macroService)); @@ -290,7 +290,7 @@ namespace Umbraco.Web.Macros Alias = macro.Alias, MacroSource = macro.MacroSource, Exception = e, - Behaviour = _contentSettings.MacroErrorBehaviour + Behaviour = _contentSettings.MacroErrors }; switch (macroErrorEventArgs.Behaviour) diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index 587a60caa9..f5b8d74402 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Logging; using System.Threading; using Umbraco.Core.Cache; using System.Collections.Generic; +using Umbraco.Core.Security; namespace Umbraco.Web.Common.Middleware { @@ -24,17 +25,20 @@ namespace Umbraco.Web.Common.Middleware private readonly IUmbracoRequestLifetimeManager _umbracoRequestLifetimeManager; private readonly IUmbracoContextFactory _umbracoContextFactory; private readonly IRequestCache _requestCache; + private readonly IBackofficeSecurityFactory _backofficeSecurityFactory; public UmbracoRequestMiddleware( ILogger logger, IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager, IUmbracoContextFactory umbracoContextFactory, - IRequestCache requestCache) + IRequestCache requestCache, + IBackofficeSecurityFactory backofficeSecurityFactory) { _logger = logger; _umbracoRequestLifetimeManager = umbracoRequestLifetimeManager; _umbracoContextFactory = umbracoContextFactory; _requestCache = requestCache; + _backofficeSecurityFactory = backofficeSecurityFactory; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) @@ -47,13 +51,14 @@ namespace Umbraco.Web.Common.Middleware await next(context); return; } - + _backofficeSecurityFactory.EnsureBackofficeSecurity(); // Needs to be before UmbracoContext var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); + try { if (umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest) - { + { LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); _logger.Verbose("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, requestUri); } diff --git a/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs index bc5cce9df1..dfd13ff101 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs @@ -1,4 +1,6 @@ -using System; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Net; @@ -13,6 +15,7 @@ namespace Umbraco.Web.Common.Profiler private readonly WebProfiler _profiler; private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; private readonly IUmbracoRequestLifetime _umbracoRequestLifetime; + private readonly List _terminate = new List(); public WebProfilerComponent(IProfiler profiler, ILogger logger, IUmbracoRequestLifetime umbracoRequestLifetime, IUmbracoApplicationLifetime umbracoApplicationLifetime) @@ -44,13 +47,19 @@ namespace Umbraco.Web.Common.Profiler public void Terminate() { + _umbracoApplicationLifetime.ApplicationInit -= InitializeApplication; + foreach (var t in _terminate) t(); } private void InitializeApplication(object sender, EventArgs args) { - _umbracoRequestLifetime.RequestStart += - (sender, context) => _profiler.UmbracoApplicationBeginRequest(context); - _umbracoRequestLifetime.RequestEnd += (sender, context) => _profiler.UmbracoApplicationEndRequest(context); + void requestStart(object sender, HttpContext context) => _profiler.UmbracoApplicationBeginRequest(context); + _umbracoRequestLifetime.RequestStart += requestStart; + _terminate.Add(() => _umbracoRequestLifetime.RequestStart -= requestStart); + + void requestEnd(object sender, HttpContext context) => _profiler.UmbracoApplicationEndRequest(context); + _umbracoRequestLifetime.RequestEnd += requestEnd; + _terminate.Add(() => _umbracoRequestLifetime.RequestEnd -= requestEnd); // Stop the profiling of the booting process _profiler.StopBoot(); diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index 959c4c27a2..45411b5e69 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs @@ -1,29 +1,31 @@ +using System.Linq; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Diagnostics; using Umbraco.Core.Hosting; -using Umbraco.Net; +using Umbraco.Core.Logging; using Umbraco.Core.Runtime; using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Extensions; +using Umbraco.Net; using Umbraco.Web.Common.AspNetCore; +using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.Formatters; +using Umbraco.Web.Common.Install; using Umbraco.Web.Common.Lifetime; using Umbraco.Web.Common.Macros; -using Umbraco.Web.Composing.CompositionExtensions; -using Umbraco.Web.Macros; -using Umbraco.Core.Diagnostics; -using Umbraco.Core.Logging; -using Umbraco.Web.Common.Profiler; -using Umbraco.Web.Common.Install; -using Umbraco.Extensions; -using System.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.Middleware; using Umbraco.Web.Common.ModelBinding; +using Umbraco.Web.Common.Profiler; using Umbraco.Web.Common.Routing; -using Umbraco.Web.Common.Templates; using Umbraco.Web.Common.Security; +using Umbraco.Web.Common.Templates; +using Umbraco.Web.Composing.CompositionExtensions; +using Umbraco.Web.Macros; using Umbraco.Web.Security; using Umbraco.Web.Templates; @@ -74,7 +76,8 @@ namespace Umbraco.Web.Common.Runtime // register the umbraco context factory composition.RegisterUnique(); - composition.RegisterUnique(); + composition.RegisterUnique(); + composition.RegisterUnique(); //register the install components //NOTE: i tried to not have these registered if we weren't installing or upgrading but post install when the site restarts @@ -96,9 +99,7 @@ namespace Umbraco.Web.Common.Runtime composition.RegisterUnique(); composition.RegisterUnique(); - composition.RegisterUnique(factory => new LegacyPasswordSecurity(factory.GetInstance())); - - + composition.RegisterUnique(factory => new LegacyPasswordSecurity(factory.GetInstance>().Value)); } } } diff --git a/src/Umbraco.Web.Common/Security/BackOfficeSignInManager.cs b/src/Umbraco.Web.Common/Security/BackOfficeSignInManager.cs index 07f7470243..6d4b2ddd4f 100644 --- a/src/Umbraco.Web.Common/Security/BackOfficeSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/BackOfficeSignInManager.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.Common.Security public class BackOfficeSignInManager : SignInManager { - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; public BackOfficeSignInManager( BackOfficeUserManager userManager, diff --git a/src/Umbraco.Web.Common/Security/WebSecurity.cs b/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs similarity index 91% rename from src/Umbraco.Web.Common/Security/WebSecurity.cs rename to src/Umbraco.Web.Common/Security/BackofficeSecurity.cs index c67d5a9b4f..6587501be7 100644 --- a/src/Umbraco.Web.Common/Security/WebSecurity.cs +++ b/src/Umbraco.Web.Common/Security/BackofficeSecurity.cs @@ -1,33 +1,34 @@ using System; using System.Security; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; +using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Extensions; using Umbraco.Web.Security; -using Umbraco.Core.Models; namespace Umbraco.Web.Common.Security { - public class WebSecurity : IWebSecurity + public class BackofficeSecurity : IBackofficeSecurity { private readonly IUserService _userService; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IHttpContextAccessor _httpContextAccessor; - public WebSecurity( + public BackofficeSecurity( IUserService userService, - IGlobalSettings globalSettings, + IOptions globalSettings, IHostingEnvironment hostingEnvironment, IHttpContextAccessor httpContextAccessor) { _userService = userService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; _httpContextAccessor = httpContextAccessor; } @@ -113,7 +114,7 @@ namespace Umbraco.Web.Common.Security return ValidateRequestAttempt.Success; } - private static bool RequestIsInUmbracoApplication(IHttpContextAccessor httpContextAccessor, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + private static bool RequestIsInUmbracoApplication(IHttpContextAccessor httpContextAccessor, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { return httpContextAccessor.GetRequiredHttpContext().Request.Path.ToString().IndexOf(hostingEnvironment.ToAbsolute(globalSettings.UmbracoPath), StringComparison.InvariantCultureIgnoreCase) > -1; } diff --git a/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs b/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs new file mode 100644 index 0000000000..7718981b27 --- /dev/null +++ b/src/Umbraco.Web.Common/Security/BackofficeSecurityFactory.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Core.Security; +using Umbraco.Core.Services; + +namespace Umbraco.Web.Common.Security +{ + public class BackofficeSecurityFactory: IBackofficeSecurityFactory + { + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly IUserService _userService; + private readonly IOptions _globalSettings; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IHttpContextAccessor _httpContextAccessor; + + public BackofficeSecurityFactory( + IBackofficeSecurityAccessor backofficeSecurityAccessor, + IUserService userService, + IOptions globalSettings, + IHostingEnvironment hostingEnvironment, + IHttpContextAccessor httpContextAccessor) + { + _backofficeSecurityAccessor = backofficeSecurityAccessor; + _userService = userService; + _globalSettings = globalSettings; + _hostingEnvironment = hostingEnvironment; + _httpContextAccessor = httpContextAccessor; + } + + public void EnsureBackofficeSecurity() + { + if (_backofficeSecurityAccessor.BackofficeSecurity is null) + { + _backofficeSecurityAccessor.BackofficeSecurity = new BackofficeSecurity(_userService, _globalSettings, _hostingEnvironment, _httpContextAccessor); + } + + } + } +} diff --git a/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs b/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs index d692303df5..1bec3cf41c 100644 --- a/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs @@ -11,7 +11,9 @@ using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -34,7 +36,7 @@ namespace Umbraco.Web.Common.Templates private readonly IPublishedRouter _publishedRouter; private readonly IFileService _fileService; private readonly ILocalizationService _languageService; - private readonly IWebRoutingSettings _webRoutingSettings; + private readonly WebRoutingSettings _webRoutingSettings; private readonly IShortStringHelper _shortStringHelper; private readonly IHttpContextAccessor _httpContextAccessor; private readonly ICompositeViewEngine _viewEngine; @@ -43,7 +45,7 @@ namespace Umbraco.Web.Common.Templates IPublishedRouter publishedRouter, IFileService fileService, ILocalizationService textService, - IWebRoutingSettings webRoutingSettings, + IOptions webRoutingSettings, IShortStringHelper shortStringHelper, IHttpContextAccessor httpContextAccessor, ICompositeViewEngine viewEngine) @@ -52,7 +54,7 @@ namespace Umbraco.Web.Common.Templates _publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter)); _fileService = fileService ?? throw new ArgumentNullException(nameof(fileService)); _languageService = textService ?? throw new ArgumentNullException(nameof(textService)); - _webRoutingSettings = webRoutingSettings ?? throw new ArgumentNullException(nameof(webRoutingSettings)); + _webRoutingSettings = webRoutingSettings.Value ?? throw new ArgumentNullException(nameof(webRoutingSettings)); _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); _viewEngine = viewEngine ?? throw new ArgumentNullException(nameof(viewEngine)); diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj index 2c8ce61d9a..81abd16ee5 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -15,16 +15,16 @@ - - - + + + - + @@ -35,5 +35,5 @@ <_Parameter1>Umbraco.Tests.UnitTests - + diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs index 4419015105..5e5b6f6910 100644 --- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs +++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContext.cs @@ -1,7 +1,9 @@ using System; +using Microsoft.Extensions.Options; using Umbraco.Composing; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.PublishedCache; @@ -15,7 +17,7 @@ namespace Umbraco.Web /// public class UmbracoContext : DisposableObjectSlim, IDisposeOnRequestEnd, IUmbracoContext { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly ICookieManager _cookieManager; private readonly IRequestAccessor _requestAccessor; @@ -29,8 +31,8 @@ namespace Umbraco.Web // warn: does *not* manage setting any IUmbracoContextAccessor internal UmbracoContext( IPublishedSnapshotService publishedSnapshotService, - IWebSecurity webSecurity, - IGlobalSettings globalSettings, + IBackofficeSecurity backofficeSecurity, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IVariationContextAccessor variationContextAccessor, UriUtility uriUtility, @@ -38,16 +40,16 @@ namespace Umbraco.Web IRequestAccessor requestAccessor) { if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService)); - if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity)); VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); + _hostingEnvironment = hostingEnvironment; _cookieManager = cookieManager; _requestAccessor = requestAccessor; ObjectCreated = DateTime.Now; UmbracoRequestId = Guid.NewGuid(); - Security = webSecurity; + Security = backofficeSecurity ?? throw new ArgumentNullException(nameof(backofficeSecurity)); // beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing _publishedSnapshot = new Lazy(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken)); @@ -76,9 +78,9 @@ namespace Umbraco.Web public Guid UmbracoRequestId { get; } /// - /// Gets the WebSecurity class + /// Gets the BackofficeSecurity class /// - public IWebSecurity Security { get; } + public IBackofficeSecurity Security { get; } /// /// Gets the uri that is handled by ASP.NET after server-side rewriting took place. diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs index 3c771a1668..a31ef614cf 100644 --- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs +++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs @@ -2,9 +2,12 @@ using System.IO; using System.Text; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Common.Security; using Umbraco.Web.PublishedCache; @@ -22,13 +25,13 @@ namespace Umbraco.Web private readonly IVariationContextAccessor _variationContextAccessor; private readonly IDefaultCultureAccessor _defaultCultureAccessor; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IUserService _userService; private readonly IHostingEnvironment _hostingEnvironment; private readonly IHttpContextAccessor _httpContextAccessor; private readonly ICookieManager _cookieManager; private readonly IRequestAccessor _requestAccessor; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly UriUtility _uriUtility; /// @@ -39,27 +42,27 @@ namespace Umbraco.Web IPublishedSnapshotService publishedSnapshotService, IVariationContextAccessor variationContextAccessor, IDefaultCultureAccessor defaultCultureAccessor, - IGlobalSettings globalSettings, + IOptions globalSettings, IUserService userService, IHostingEnvironment hostingEnvironment, UriUtility uriUtility, IHttpContextAccessor httpContextAccessor, ICookieManager cookieManager, IRequestAccessor requestAccessor, - IWebSecurity webSecurity) + IBackofficeSecurityAccessor backofficeSecurityAccessor) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService)); _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); _defaultCultureAccessor = defaultCultureAccessor ?? throw new ArgumentNullException(nameof(defaultCultureAccessor)); - _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); + _globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); _uriUtility = uriUtility ?? throw new ArgumentNullException(nameof(uriUtility)); _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); _cookieManager = cookieManager ?? throw new ArgumentNullException(nameof(cookieManager)); _requestAccessor = requestAccessor ?? throw new ArgumentNullException(nameof(requestAccessor)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); } private IUmbracoContext CreateUmbracoContext() @@ -77,7 +80,7 @@ namespace Umbraco.Web return new UmbracoContext( _publishedSnapshotService, - _webSecurity, + _backofficeSecurityAccessor.BackofficeSecurity, _globalSettings, _hostingEnvironment, _variationContextAccessor, diff --git a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js index fb03cbd1b1..93191dbaf5 100644 --- a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js +++ b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js @@ -218,10 +218,10 @@ function dependencies() { { "name": "spectrum", "src": [ - "./node_modules/spectrum-colorpicker/spectrum.js", - "./node_modules/spectrum-colorpicker/spectrum.css" + "./node_modules/spectrum-colorpicker2/dist/spectrum.js", + "./node_modules/spectrum-colorpicker2/dist/spectrum.css" ], - "base": "./node_modules/spectrum-colorpicker" + "base": "./node_modules/spectrum-colorpicker2/dist" }, { "name": "tinymce", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 100774f385..e0afe1c2a7 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -38,10 +38,10 @@ "lazyload-js": "1.0.0", "moment": "2.22.2", "ng-file-upload": "12.2.13", - "nouislider": "14.6.0", + "nouislider": "14.6.1", "npm": "^6.14.7", "signalr": "2.4.0", - "spectrum-colorpicker": "1.8.0", + "spectrum-colorpicker2": "2.0.3", "tinymce": "4.9.11", "typeahead.js": "0.11.1", "underscore": "1.9.1", @@ -72,11 +72,11 @@ "gulp-wrap": "0.15.0", "gulp-wrap-js": "0.4.1", "jasmine-core": "3.5.0", + "jsdom": "16.4.0", "karma": "4.4.1", - "karma-chrome-launcher": "^3.1.0", + "karma-jsdom-launcher": "^8.0.2", "karma-jasmine": "2.0.1", "karma-junit-reporter": "2.0.1", - "karma-phantomjs-launcher": "1.0.4", "karma-spec-reporter": "0.0.32", "less": "3.10.3", "lodash": "4.17.19", diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js index 76687dc0d6..6e4a388276 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js @@ -228,6 +228,9 @@ Use this directive to construct a header inside the main editor window. // to make it work for language edit/create setAccessibilityForEditorState(); scope.loading = false; + } else if (scope.name) { + setAccessibilityForName(); + scope.loading = false; } else { scope.loading = false; } @@ -266,6 +269,15 @@ Use this directive to construct a header inside the main editor window. editorService.iconPicker(iconPicker); }; + function setAccessibilityForName() { + var setTitle = false; + if (scope.setpagetitle !== undefined) { + setTitle = scope.setpagetitle; + } + if (setTitle) { + setAccessibilityHeaderDirective(false, scope.editorfor, scope.nameLocked, scope.name, "", true); + } + } function setAccessibilityForEditorState() { var isNew = editorState.current.id === 0 || editorState.current.id === "0" || diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/onOutsideClick.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/onOutsideClick.directive.js index a657fcbc55..07c8dc88fe 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/onOutsideClick.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/onOutsideClick.directive.js @@ -44,7 +44,7 @@ } // please to not use angularHelper.safeApply here, it won't work - scope.$apply(attrs.onOutsideClick); + scope.$evalAsync(attrs.onOutsideClick); } diff --git a/src/Umbraco.Web.UI.Client/src/views/components/property/property-actions/umbpropertyactions.component.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbpropertyactions.component.js similarity index 51% rename from src/Umbraco.Web.UI.Client/src/views/components/property/property-actions/umbpropertyactions.component.js rename to src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbpropertyactions.component.js index b0dc15d6cd..41dbd9f547 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/property/property-actions/umbpropertyactions.component.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbpropertyactions.component.js @@ -5,50 +5,77 @@ * A component to render the property action toggle */ - function umbPropertyActionsController(keyboardService) { + function umbPropertyActionsController(keyboardService, localizationService) { var vm = this; vm.isOpen = false; + vm.labels = { + openText: "Open Property Actions", + closeText: "Close Property Actions" + }; + + vm.open = open; + vm.close = close; + vm.toggle = toggle; + vm.executeAction = executeAction; + + vm.$onDestroy = onDestroy; + vm.$onInit = onInit; function initDropDown() { keyboardService.bind("esc", vm.close); } + function destroyDropDown() { keyboardService.unbind("esc"); } - vm.toggle = function() { + function toggle() { if (vm.isOpen === true) { vm.close(); } else { vm.open(); } } - vm.open = function() { + + function open() { vm.isOpen = true; initDropDown(); } - vm.close = function() { + + function close() { vm.isOpen = false; destroyDropDown(); } - vm.executeAction = function(action) { + function executeAction(action) { action.method(); vm.close(); } - vm.$onDestroy = function () { + function onDestroy() { if (vm.isOpen === true) { destroyDropDown(); } } - + + function onInit() { + + var labelKeys = [ + "propertyActions_tooltipForPropertyActionsMenu", + "propertyActions_tooltipForPropertyActionsMenuClose" + ] + + localizationService.localizeMany(labelKeys).then(values => { + vm.labels.openText = values[0]; + vm.labels.closeText = values[1]; + }); + } } var umbPropertyActionsComponent = { - templateUrl: 'views/components/property/property-actions/umb-property-actions.html', + templateUrl: 'views/components/property/umb-property-actions.html', bindings: { actions: "<" }, diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js index f2fc0d2dae..3ec1756e6c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreeitem.directive.js @@ -190,7 +190,7 @@ angular.module("umbraco.directives") var evts = []; - //listen for section changes + // Listen for section changes evts.push(eventsService.on("appState.sectionState.changed", function(e, args) { if (args.key === "currentSection") { //when the section changes disable all delete animations @@ -198,6 +198,13 @@ angular.module("umbraco.directives") } })); + // Update tree icon if changed + evts.push(eventsService.on("editors.tree.icon.changed", function (e, args) { + if (args.icon !== scope.node.icon && args.id === scope.node.id) { + scope.node.icon = args.icon; + } + })); + /** Depending on if any menu is shown and if the menu is shown for the current node, toggle delete animations */ function toggleDeleteAnimations() { //if both are false then remove animations diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbdropdown.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbdropdown.directive.js index d6006114a6..cfba5be2ce 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbdropdown.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbdropdown.directive.js @@ -22,7 +22,7 @@ - {{ item.name }} + @@ -110,7 +110,7 @@ // Stop listening when scope is destroyed. scope.$on('$destroy', stopListening); - + } var directive = { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-search/umbminisearch.component.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbminisearch.component.js similarity index 79% rename from src/Umbraco.Web.UI.Client/src/views/components/umb-mini-search/umbminisearch.component.js rename to src/Umbraco.Web.UI.Client/src/common/directives/components/umbminisearch.component.js index d7aee744e4..6c65cb6e23 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-search/umbminisearch.component.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbminisearch.component.js @@ -4,7 +4,7 @@ angular .module('umbraco') .component('umbMiniSearch', { - templateUrl: 'views/components/umb-mini-search/umb-mini-search.html', + templateUrl: 'views/components/umb-mini-search.html', controller: UmbMiniSearchController, controllerAs: 'vm', bindings: { @@ -18,6 +18,9 @@ function UmbMiniSearchController($scope) { var vm = this; + + vm.onKeyDown = onKeyDown; + vm.onChange = onChange; var searchDelay = _.debounce(function () { $scope.$apply(function () { @@ -27,23 +30,23 @@ }); }, 500); - vm.onKeyDown = function (ev) { + function onKeyDown(evt) { //13: enter - switch (ev.keyCode) { + switch (evt.keyCode) { case 13: if (vm.onSearch) { vm.onSearch(); } break; } - }; + } - vm.onChange = function () { + function onChange() { if (vm.onStartTyping) { vm.onStartTyping(); } searchDelay(); - }; + } } diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/util/umbkeyboardlist.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/util/umbkeyboardlist.directive.js index 20572fdf16..0b743d0f10 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/util/umbkeyboardlist.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/util/umbkeyboardlist.directive.js @@ -10,12 +10,12 @@
     
@@ -33,11 +33,11 @@ angular.module('umbraco.directives') return { restrict: 'A', link: function (scope, element, attr) { - + var listItems = []; var currentIndex = 0; var focusSet = false; - + $timeout(function(){ // get list of all links in the list listItems = element.find("li :tabbable"); @@ -82,7 +82,7 @@ angular.module('umbraco.directives') function arrowDown() { if (currentIndex < listItems.length - 1) { - // only bump the current index if the focus is already + // only bump the current index if the focus is already // set else we just want to focus the first element if (focusSet) { currentIndex++; @@ -112,4 +112,4 @@ angular.module('umbraco.directives') } }; - }]); \ No newline at end of file + }]); diff --git a/src/Umbraco.Web.UI.Client/src/common/filters/compareArrays.filter.js b/src/Umbraco.Web.UI.Client/src/common/filters/compareArrays.filter.js index 13f603260d..0cbf3077e6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/filters/compareArrays.filter.js +++ b/src/Umbraco.Web.UI.Client/src/common/filters/compareArrays.filter.js @@ -2,13 +2,17 @@ angular.module("umbraco.filters") .filter('compareArrays', function() { return function inArray(array, compareArray, compareProperty) { + if (!compareArray || !compareArray.length) { + return [...array]; + } + var result = []; - angular.forEach(array, function(arrayItem){ + array.forEach(function(arrayItem){ var exists = false; - angular.forEach(compareArray, function(compareItem){ + compareArray.forEach(function(compareItem){ if( arrayItem[compareProperty] === compareItem[compareProperty]) { exists = true; } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/angularhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/angularhelper.service.js index fd620bac18..7e7f804656 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/angularhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/angularhelper.service.js @@ -95,7 +95,7 @@ function angularHelper($q) { */ revalidateNgModel: function (scope, ngModel) { this.safeApply(scope, function() { - angular.forEach(ngModel.$parsers, function (parser) { + ngModel.$parsers.forEach(function (parser) { parser(ngModel.$viewValue); }); }); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditor.service.js index ffb1971169..dfa0eae297 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditor.service.js @@ -4,39 +4,113 @@ * * @description * Added in Umbraco 8.7. Service for dealing with Block Editors. - * + * * Block Editor Service provides the basic features for a block editor. * The main feature is the ability to create a Model Object which takes care of your data for your Block Editor. - * - * + * + * * ##Samples * * ####Instantiate a Model Object for your property editor: - * + * *
  *     modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, $scope);
  *     modelObject.load().then(onLoaded);
  * 
* - * + * * See {@link umbraco.services.blockEditorModelObject BlockEditorModelObject} for more samples. - * + * */ (function () { 'use strict'; + + /** + * When performing a runtime copy of Block Editors entries, we copy the ElementType Data Model and inner IDs are kept identical, to ensure new IDs are changed on paste we need to provide a resolver for the ClipboardService. + */ + angular.module('umbraco').run(['clipboardService', 'udiService', function (clipboardService, udiService) { + + function replaceUdi(obj, key, dataObject) { + var udi = obj[key]; + var newUdi = udiService.create("element"); + obj[key] = newUdi; + dataObject.forEach((data) => { + if (data.udi === udi) { + data.udi = newUdi; + } + }); + } + function replaceUdisOfObject(obj, propValue) { + for (var k in obj) { + if(k === "contentUdi") { + replaceUdi(obj, k, propValue.contentData); + } else if(k === "settingsUdi") { + replaceUdi(obj, k, propValue.settingsData); + } else { + // lets crawl through all properties of layout to make sure get captured all `contentUdi` and `settingsUdi` properties. + var propType = typeof obj[k]; + if(propType === "object" || propType === "array") { + replaceUdisOfObject(obj[k], propValue) + } + } + } + } + function replaceElementTypeBlockListUDIsResolver(obj, propClearingMethod) { + replaceRawBlockListUDIsResolver(obj.value, propClearingMethod); + } + + clipboardService.registerPastePropertyResolver(replaceElementTypeBlockListUDIsResolver, clipboardService.TYPES.ELEMENT_TYPE); + + + function replaceRawBlockListUDIsResolver(value, propClearingMethod) { + if (typeof value === "object") { + + // we got an object, and it has these three props then we are most likely dealing with a Block Editor. + if ((value.layout !== undefined && value.contentData !== undefined && value.settingsData !== undefined)) { + + replaceUdisOfObject(value.layout, value); + + // replace UDIs for inner properties of this Block Editors content data. + if(value.contentData.length > 0) { + value.contentData.forEach((item) => { + for (var k in item) { + propClearingMethod(item[k], clipboardService.TYPES.RAW); + } + }); + } + // replace UDIs for inner properties of this Block Editors settings data. + if(value.settingsData.length > 0) { + value.settingsData.forEach((item) => { + for (var k in item) { + propClearingMethod(item[k], clipboardService.TYPES.RAW); + } + }); + } + + } + } + } + + clipboardService.registerPastePropertyResolver(replaceRawBlockListUDIsResolver, clipboardService.TYPES.RAW); + + }]); + + + + function blockEditorService(blockEditorModelObject) { /** * @ngdocs function * @name createModelObject * @methodOf umbraco.services.blockEditorService - * + * * @description * Create a new Block Editor Model Object. * See {@link umbraco.services.blockEditorModelObject blockEditorModelObject} - * + * * @see umbraco.services.blockEditorModelObject * @param {object} propertyModelValue data object of the property editor, usually model.value. * @param {string} propertyEditorAlias alias of the property. diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js index 86b5bdd0d0..868b8baba7 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js @@ -13,8 +13,7 @@ (function () { 'use strict'; - - function blockEditorModelObjectFactory($interpolate, $q, udiService, contentResource, localizationService, umbRequestHelper) { + function blockEditorModelObjectFactory($interpolate, $q, udiService, contentResource, localizationService, umbRequestHelper, clipboardService) { /** * Simple mapping from property model content entry to editing model, @@ -231,7 +230,8 @@ var notSupportedProperties = [ "Umbraco.Tags", "Umbraco.UploadField", - "Umbraco.ImageCropper" + "Umbraco.ImageCropper", + "Umbraco.NestedContent" ]; @@ -524,12 +524,11 @@ } var blockConfiguration = this.getBlockConfiguration(dataModel.contentTypeKey); - var contentScaffold; + var contentScaffold = null; if (blockConfiguration === null) { - console.error("The block of " + contentUdi + " is not being initialized because its contentTypeKey('" + dataModel.contentTypeKey + "') is not allowed for this PropertyEditor"); - } - else { + console.warn("The block of " + contentUdi + " is not being initialized because its contentTypeKey('" + dataModel.contentTypeKey + "') is not allowed for this PropertyEditor"); + } else { contentScaffold = this.getScaffoldFromKey(blockConfiguration.contentElementTypeKey); if (contentScaffold === null) { console.error("The block of " + contentUdi + " is not begin initialized cause its Element Type was not loaded."); @@ -539,11 +538,9 @@ if (blockConfiguration === null || contentScaffold === null) { blockConfiguration = { - label: "Unsupported Block", + label: "Unsupported", unsupported: true }; - contentScaffold = {}; - } var blockObject = {}; @@ -568,10 +565,14 @@ , 10); // make basics from scaffold - blockObject.content = Utilities.copy(contentScaffold); - ensureUdiAndKey(blockObject.content, contentUdi); + if(contentScaffold !== null) {// We might not have contentScaffold + blockObject.content = Utilities.copy(contentScaffold); + ensureUdiAndKey(blockObject.content, contentUdi); - mapToElementModel(blockObject.content, dataModel); + mapToElementModel(blockObject.content, dataModel); + } else { + blockObject.content = null; + } blockObject.data = dataModel; blockObject.layout = layoutEntry; @@ -614,8 +615,7 @@ if (this.config.settingsElementTypeKey !== null) { mapElementValues(settings, this.settings); } - } - + }; blockObject.sync = function () { if (this.content !== null) { @@ -624,7 +624,7 @@ if (this.config.settingsElementTypeKey !== null) { mapToPropertyModel(this.settings, this.settingsData); } - } + }; // first time instant update of label. blockObject.label = getBlockLabel(blockObject); @@ -663,7 +663,6 @@ } return blockObject; - }, /** @@ -675,11 +674,8 @@ * @param {Object} blockObject The BlockObject to be removed and destroyed. */ removeDataAndDestroyModel: function (blockObject) { - var udi = blockObject.content.udi; - var settingsUdi = null; - if (blockObject.settings) { - settingsUdi = blockObject.settings.udi; - } + var udi = blockObject.layout.contentUdi; + var settingsUdi = blockObject.layout.settingsUdi || null; this.destroyBlockObject(blockObject); this.removeDataByUdi(udi); if (settingsUdi) { @@ -748,7 +744,7 @@ */ createFromElementType: function (elementTypeDataModel) { - elementTypeDataModel = Utilities.copy(elementTypeDataModel); + elementTypeDataModel = clipboardService.parseContentForPaste(elementTypeDataModel, clipboardService.TYPES.ELEMENT_TYPE); var contentElementTypeKey = elementTypeDataModel.contentTypeKey; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js b/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js index 0d2ca6623b..58ed07367e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js @@ -13,7 +13,28 @@ function clipboardService(notificationsService, eventsService, localStorageService, iconHelper) { - var clearPropertyResolvers = []; + const TYPES = {}; + TYPES.ELEMENT_TYPE = "elementType"; + TYPES.RAW = "raw"; + + var clearPropertyResolvers = {}; + var pastePropertyResolvers = {}; + var clipboardTypeResolvers = {}; + + clipboardTypeResolvers[TYPES.ELEMENT_TYPE] = function(data, propMethod) { + for (var t = 0; t < data.variants[0].tabs.length; t++) { + var tab = data.variants[0].tabs[t]; + for (var p = 0; p < tab.properties.length; p++) { + var prop = tab.properties[p]; + propMethod(prop, TYPES.ELEMENT_TYPE); + } + } + } + clipboardTypeResolvers[TYPES.RAW] = function(data, propMethod) { + for (var p = 0; p < data.length; p++) { + propMethod(data[p], TYPES.RAW); + } + } var STORAGE_KEY = "umbClipboardService"; @@ -57,28 +78,29 @@ function clipboardService(notificationsService, eventsService, localStorageServi } - function clearPropertyForStorage(prop) { + function resolvePropertyForStorage(prop, type) { - for (var i=0; i prepareEntryForStorage(data, firstLevelClearupMethod)); + var copiedDatas = datas.map(data => prepareEntryForStorage(type, data, firstLevelClearupMethod)); // remove previous copies of this entry: storage.entries = storage.entries.filter( diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index c27283d5ad..6d41ea087d 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -151,7 +151,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt // first check if tab is already added var foundInfoTab = false; - angular.forEach(tabs, function (tab) { + tabs.forEach(function (tab) { if (tab.id === infoTab.id && tab.alias === infoTab.alias) { foundInfoTab = true; } diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js index 1be66cc68f..9cec15d519 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenttypehelper.service.js @@ -11,7 +11,7 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje var newArray = []; - angular.forEach(array, function (arrayItem) { + array.forEach(function (arrayItem) { if (Utilities.isObject(arrayItem)) { newArray.push(arrayItem.id); @@ -116,13 +116,12 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje throw new Error("Cannot add this composition, these properties already exist on the content type: " + overlappingAliases.join()); } - angular.forEach(compositeContentType.groups, function (compositionGroup) { - + compositeContentType.groups.forEach(function (compositionGroup) { // order composition groups based on sort order compositionGroup.properties = $filter('orderBy')(compositionGroup.properties, 'sortOrder'); // get data type details - angular.forEach(compositionGroup.properties, function (property) { + compositionGroup.properties.forEach(function (property) { dataTypeResource.getById(property.dataTypeId) .then(function (dataType) { property.dataTypeIcon = dataType.icon; @@ -134,7 +133,7 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje compositionGroup.inherited = true; // set inherited state on properties - angular.forEach(compositionGroup.properties, function (compositionProperty) { + compositionGroup.properties.forEach(function (compositionProperty) { compositionProperty.inherited = true; }); @@ -142,7 +141,7 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje compositionGroup.tabState = "inActive"; // if groups are named the same - merge the groups - angular.forEach(contentType.groups, function (contentTypeGroup) { + contentType.groups.forEach(function (contentTypeGroup) { if (contentTypeGroup.name === compositionGroup.name) { @@ -224,7 +223,7 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje var groups = []; - angular.forEach(contentType.groups, function (contentTypeGroup) { + contentType.groups.forEach(function (contentTypeGroup) { if (contentTypeGroup.tabState !== "init") { @@ -238,7 +237,7 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje var properties = []; // remove all properties from composite content type - angular.forEach(contentTypeGroup.properties, function (property) { + contentTypeGroup.properties.forEach(function (property) { if (property.contentTypeId !== compositeContentType.id) { properties.push(property); } @@ -283,7 +282,7 @@ function contentTypeHelper(contentTypeResource, dataTypeResource, $filter, $inje var sortOrder = 0; - angular.forEach(properties, function (property) { + properties.forEach(function (property) { if (!property.inherited && property.propertyState !== "init") { property.sortOrder = sortOrder; } 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 0f4f04c6bf..381d09f62d 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 @@ -761,6 +761,23 @@ When building a custom infinite editor view you can use the same components as a open(editor); } + /** + * @ngdoc method + * @name umbraco.services.editorService#userGroupEditor + * @methodOf umbraco.services.editorService + * + * @description + * Opens the user group picker in infinite editing, the submit callback returns the saved user group + * @param {Object} editor rendering options + * @param {Callback} editor.submit Submits the editor + * @param {Callback} editor.close Closes the editor + * @returns {Object} editor object + */ + function userGroupEditor(editor) { + editor.view = "views/users/group.html"; + open(editor); + } + /** * @ngdoc method * @name umbraco.services.editorService#templateEditor @@ -1028,6 +1045,7 @@ When building a custom infinite editor view you can use the same components as a nodePermissions: nodePermissions, insertCodeSnippet: insertCodeSnippet, userGroupPicker: userGroupPicker, + userGroupEditor: userGroupEditor, templateEditor: templateEditor, sectionPicker: sectionPicker, insertField: insertField, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js index d9c11770cc..bd6bbcc5b3 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/formhelper.service.js @@ -17,10 +17,10 @@ function formHelper(angularHelper, serverValidationManager, notificationsService * @function * * @description - * Called by controllers when submitting a form - this ensures that all client validation is checked, + * Called by controllers when submitting a form - this ensures that all client validation is checked, * server validation is cleared, that the correct events execute and status messages are displayed. * This returns true if the form is valid, otherwise false if form submission cannot continue. - * + * * @param {object} args An object containing arguments for form submission */ submitForm: function (args) { @@ -46,7 +46,12 @@ function formHelper(angularHelper, serverValidationManager, notificationsService args.scope.$broadcast("formSubmitting", { scope: args.scope, action: args.action }); this.focusOnFirstError(currentForm); - args.scope.$broadcast("postFormSubmitting", { scope: args.scope, action: args.action }); + + // Some property editors need to perform an action after all property editors have reacted to the formSubmitting. + args.scope.$broadcast("formSubmittingFinalPhase", { scope: args.scope, action: args.action }); + + // Set the form state to submitted + currentForm.$setSubmitted(); //then check if the form is valid if (!args.skipValidation) { @@ -101,18 +106,32 @@ function formHelper(angularHelper, serverValidationManager, notificationsService * * @description * Called by controllers when a form has been successfully submitted, this ensures the correct events are raised. - * + * * @param {object} args An object containing arguments for form submission */ resetForm: function (args) { + + var currentForm; + if (!args) { throw "args cannot be null"; } if (!args.scope) { throw "args.scope cannot be null"; } + if (!args.formCtrl) { + //try to get the closest form controller + currentForm = angularHelper.getRequiredCurrentForm(args.scope); + } + else { + currentForm = args.formCtrl; + } - args.scope.$broadcast("formSubmitted", { scope: args.scope }); + // Set the form state to pristine + currentForm.$setPristine(); + currentForm.$setUntouched(); + + args.scope.$broadcast(args.hasErrors ? "formSubmittedValidationFailed" : "formSubmitted", { scope: args.scope }); }, showNotifications: function (args) { @@ -137,7 +156,7 @@ function formHelper(angularHelper, serverValidationManager, notificationsService * @description * Needs to be called when a form submission fails, this will wire up all server validation errors in ModelState and * add the correct messages to the notifications. If a server error has occurred this will show a ysod. - * + * * @param {object} err The error object returned from the http promise */ handleError: function (err) { @@ -176,7 +195,7 @@ function formHelper(angularHelper, serverValidationManager, notificationsService * * @description * This wires up all of the server validation model state so that valServer and valServerField directives work - * + * * @param {object} err The error object returned from the http promise */ handleServerValidation: function (modelState) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js index 0d0135fff8..5034de67eb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/iconhelper.service.js @@ -31,7 +31,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { { oldIcon: ".sprToPublish", newIcon: "mail-forward" }, { oldIcon: ".sprTranslate", newIcon: "comments" }, { oldIcon: ".sprUpdate", newIcon: "save" }, - + { oldIcon: ".sprTreeSettingDomain", newIcon: "icon-home" }, { oldIcon: ".sprTreeDoc", newIcon: "icon-document" }, { oldIcon: ".sprTreeDoc2", newIcon: "icon-diploma-alt" }, @@ -39,21 +39,21 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { { oldIcon: ".sprTreeDoc4", newIcon: "icon-newspaper-alt" }, { oldIcon: ".sprTreeDoc5", newIcon: "icon-notepad-alt" }, - { oldIcon: ".sprTreeDocPic", newIcon: "icon-picture" }, + { oldIcon: ".sprTreeDocPic", newIcon: "icon-picture" }, { oldIcon: ".sprTreeFolder", newIcon: "icon-folder" }, { oldIcon: ".sprTreeFolder_o", newIcon: "icon-folder" }, { oldIcon: ".sprTreeMediaFile", newIcon: "icon-music" }, { oldIcon: ".sprTreeMediaMovie", newIcon: "icon-movie" }, { oldIcon: ".sprTreeMediaPhoto", newIcon: "icon-picture" }, - + { oldIcon: ".sprTreeMember", newIcon: "icon-user" }, { oldIcon: ".sprTreeMemberGroup", newIcon: "icon-users" }, { oldIcon: ".sprTreeMemberType", newIcon: "icon-users" }, - + { oldIcon: ".sprTreeNewsletter", newIcon: "icon-file-text-alt" }, { oldIcon: ".sprTreePackage", newIcon: "icon-box" }, { oldIcon: ".sprTreeRepository", newIcon: "icon-server-alt" }, - + { oldIcon: ".sprTreeSettingDataType", newIcon: "icon-autofill" }, // TODO: Something needs to be done with the old tree icons that are commented out. @@ -61,7 +61,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { { oldIcon: ".sprTreeSettingAgent", newIcon: "" }, { oldIcon: ".sprTreeSettingCss", newIcon: "" }, { oldIcon: ".sprTreeSettingCssItem", newIcon: "" }, - + { oldIcon: ".sprTreeSettingDataTypeChild", newIcon: "" }, { oldIcon: ".sprTreeSettingDomain", newIcon: "" }, { oldIcon: ".sprTreeSettingLanguage", newIcon: "" }, @@ -94,9 +94,9 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { var iconCache = []; var liveRequests = []; var allIconsRequested = false; - + return { - + /** Used by the create dialogs for content/media types to format the data so that the thumbnails are styled properly */ formatContentTypeThumbnails: function (contentTypes) { for (var i = 0; i < contentTypes.length; i++) { @@ -209,15 +209,11 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { ,'Failed to retrieve icon: ' + iconName) .then(icon => { if(icon) { - var trustedIcon = { - name: icon.Name, - svgString: $sce.trustAsHtml(icon.SvgString) - }; - this._cacheIcon(trustedIcon); + var trustedIcon = this.defineIcon(icon.Name, icon.SvgString); - liveRequests = _.filter(liveRequests, iconRequestPath); + liveRequests = _.filter(liveRequests, iconRequestPath); - resolve(trustedIcon); + resolve(trustedIcon); } }) .catch(err => { @@ -240,15 +236,10 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { ,'Failed to retrieve icons') .then(icons => { icons.forEach(icon => { - var trustedIcon = { - name: icon.Name, - svgString: $sce.trustAsHtml(icon.SvgString) - }; - - this._cacheIcon(trustedIcon); + this.defineIcon(icon.Name, icon.SvgString); }); - resolve(iconCache); + resolve(iconCache); }) .catch(err => { console.warn(err); @@ -278,7 +269,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { console.warn("Can't read the css rules of: " + document.styleSheets[i].href, e); continue; } - + if (classes !== null) { for(var x=0;x x.name === name); + if(icon === undefined) { + icon = { + name: name, + svgString: $sce.trustAsHtml(svg) + }; + iconCache.push(icon); + } + return icon; }, /** Returns the cached icon or undefined */ diff --git a/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js index 28156e70c3..ee1e2a2311 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js @@ -419,7 +419,7 @@ if (isSelectedAll(items, selection)) { // unselect all items - angular.forEach(items, function (item) { + items.forEach(function (item) { item.selected = false; }); @@ -432,7 +432,7 @@ selection.length = 0; // select all items - angular.forEach(items, function (item) { + items.forEach(function (item) { var obj = { id: item.id }; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index 0907538b24..c1d84aa16b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -127,6 +127,13 @@ function navigationService($routeParams, $location, $q, $injector, eventsService } } + function showBackdrop() { + var backDropOptions = { + 'element': $('#leftcolumn')[0] + }; + backdropService.open(backDropOptions); + } + var service = { /** @@ -427,13 +434,9 @@ function navigationService($routeParams, $location, $q, $injector, eventsService showMenu: function (args) { var self = this; - var backDropOptions = { - 'element': $('#leftcolumn')[0] - }; - return treeService.getMenu({ treeNode: args.node }) .then(function (data) { - backdropService.open(backDropOptions); + showBackdrop(); //check for a default //NOTE: event will be undefined when a call to hideDialog is made so it won't re-load the default again. // but perhaps there's a better way to deal with with an additional parameter in the args ? it works though. @@ -544,6 +547,7 @@ function navigationService($routeParams, $location, $q, $injector, eventsService } } else { + showBackdrop(); service.showDialog({ node: node, action: action, diff --git a/src/Umbraco.Web.UI.Client/src/common/services/search.service.js b/src/Umbraco.Web.UI.Client/src/common/services/search.service.js index 803cd857b7..8e9525af84 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/search.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/search.service.js @@ -12,7 +12,7 @@ * *
  *      searchService.searchMembers({term: 'bob'}).then(function(results){
- *          angular.forEach(results, function(result){
+ *          results.forEach(function(result){
  *                  //returns:
  *                  {name: "name", id: 1234, menuUrl: "url", editorPath: "url", metaData: {}, subtitle: "/path/etc" }
  *           })
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
index 5d6b4646a3..6c0165ebfe 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
@@ -107,7 +107,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
 
         //queue rules loading
         if (configuredStylesheets) {
-            angular.forEach(configuredStylesheets, function (val, key) {
+            configuredStylesheets.forEach(function (val, key) {
 
                 if (val.indexOf(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/") === 0) {
                     // current format (full path to stylesheet)
@@ -119,7 +119,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
                 }
 
                 promises.push(stylesheetResource.getRulesByName(val).then(function (rules) {
-                    angular.forEach(rules, function (rule) {
+                    rules.forEach(function (rule) {
                         var r = {};
                         r.title = rule.name;
                         if (rule.selector[0] == ".") {
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/database.html b/src/Umbraco.Web.UI.Client/src/installer/steps/database.html
index cfe0940aa2..ebffc4cf97 100644
--- a/src/Umbraco.Web.UI.Client/src/installer/steps/database.html
+++ b/src/Umbraco.Web.UI.Client/src/installer/steps/database.html
@@ -40,7 +40,7 @@
                         
                         
Enter server domain or IP
diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/user.html b/src/Umbraco.Web.UI.Client/src/installer/steps/user.html index aea63869ba..4dd8afd512 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/steps/user.html +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/user.html @@ -1,7 +1,7 @@ 
-

Install Umbraco 9

+

Install Umbraco

-

Enter your name, email and password to install Umbraco 9 with its default settings, alternatively you can customize your installation

+

Enter your name, email and password to install Umbraco with its default settings, alternatively you can customize your installation

diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index d99573decb..ff834de837 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -77,7 +77,6 @@ @import "main.less"; @import "listview.less"; @import "gridview.less"; -@import "filter-toggle.less"; @import "forms/umb-validation-label.less"; @@ -173,6 +172,7 @@ @import "components/umb-textstring.less"; @import "components/umb-textarea.less"; @import "components/umb-dropdown.less"; +@import "components/umb-filter.less"; @import "components/umb-range-slider.less"; @import "components/umb-number.less"; @import "components/umb-tags-editor.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-language-picker.less b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-language-picker.less index 4e3741905f..34a339b4c9 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-language-picker.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-language-picker.less @@ -24,6 +24,7 @@ .umb-language-picker__expand { font-size: 14px; + pointer-events: none; } .umb-language-picker__toggle:hover { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less b/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less index 7036d60a63..6cdc5b1c99 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less @@ -6,7 +6,7 @@ width: 500px; } - p{ + p { margin: 7px 0; } } @@ -23,21 +23,18 @@ align-items: center; } -.umb-prevalues-multivalues__add { +.umb-prevalues-multivalues__add { display: flex; -} -.umb-prevalues-multivalues__add input { - width: 320px; -} + input { + display: flex; + width: 320px; + } -.umb-prevalues-multivalues__add input { - display: flex; -} - -.umb-prevalues-multivalues__add button { - margin: 0 6px 0 0; - margin-left: auto; + button { + margin: 0 6px 0 0; + margin-left: auto; + } } .umb-prevalues-multivalues__listitem { @@ -45,20 +42,26 @@ padding: 6px; margin: 10px 0px !important; background: @gray-10; - cursor: move; -} -.umb-prevalues-multivalues__listitem i { - display: flex; - align-items: center; - margin-right: 5px -} + &.ui-sortable-handle, + .ui-sortable-handle, + .handle + { + cursor: move; + } -.umb-prevalues-multivalues__listitem a { - cursor: pointer; - margin-left: auto; -} + i { + display: flex; + align-items: center; + margin-right: 5px + } -.umb-prevalues-multivalues__listitem input { - width: 295px; + a { + cursor: pointer; + margin-left: auto; + } + + input { + width: 295px; + } } 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 59d81eb3ea..d4599ea03d 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 @@ -96,7 +96,6 @@ body.touch .umb-tree { width: auto; height: auto; margin: 0 5px 0 auto; - padding: 7px 5px; overflow: visible; clip: auto; } @@ -185,12 +184,15 @@ body.touch .umb-tree { display: flex; flex: 0 0 auto; justify-content: flex-end; - padding: 7px 5px; text-align: center; margin: 0 5px 0 auto; cursor: pointer; border-radius: @baseBorderRadius; + .umb-button-ellipsis { + padding: 3px 5px; + } + i { height: 5px !important; width: 5px !important; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-checkmark.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-checkmark.less index f82e47bf88..6ab6169eec 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-checkmark.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-checkmark.less @@ -17,10 +17,21 @@ } } +.umb-checkmark__action { + &:hover, + &:focus { + .umb-checkmark { + border-color:@ui-action-discreet-border-hover; + color: @ui-selected-type-hover; + } + } +} + .umb-checkmark--checked { background: @ui-selected-border; border-color: @ui-selected-border; color: @white; + &:hover { background: @ui-selected-border-hover; border-color: @ui-selected-border-hover; @@ -28,6 +39,17 @@ } } +.umb-checkmark__action { + &:hover, + &:focus { + .umb-checkmark--checked { + background: @ui-selected-border-hover; + border-color: @ui-selected-border-hover; + color: @white; + } + } +} + .umb-checkmark--xs { width: 20px; height: 20px; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-filter.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-filter.less new file mode 100644 index 0000000000..7432555472 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-filter.less @@ -0,0 +1,13 @@ +.umb-filter { + position: relative; +} + +.umb-filter .umb-filter__toggle { + display: flex; +} + +.umb-filter .umb-filter__label { + margin-left: 5px; + margin-right: 3px; + max-width: 150px; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less index a8c428ba7a..0915f5f64f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less @@ -596,9 +596,10 @@ } .umb-grid .iconBox i { - font-size: 16px !important; - color: @gray-3 ; + color: @gray-3; display: block; + font-size: 16px; + line-height: inherit; } .umb-grid .help-text { @@ -609,8 +610,6 @@ clear: both; } - - // TINYMCE EDITOR // ------------------------- diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-insert-code-box.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-insert-code-box.less index f3b53f4def..006dae09dc 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-insert-code-box.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-insert-code-box.less @@ -8,20 +8,20 @@ padding: 15px 20px; margin-bottom: 10px; border-radius: 3px; - cursor: pointer; + text-align: left; } .umb-insert-code-box:hover, .umb-insert-code-box.-selected { background-color: @ui-option-hover; color: @ui-action-type-hover; - //border-color: @ui-action-border-hover; } .umb-insert-code-box__title { font-size: 15px; margin-bottom: 5px; font-weight: bold; + line-height: 1; } .umb-insert-code-box__description { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less index 56fa905310..32dcccb8da 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less @@ -122,6 +122,11 @@ .table { table-layout: fixed; + table { + display: table; + width: 100%; + } + thead th:first-child, thead th:nth-child(3) { width: 20%; } @@ -130,9 +135,16 @@ width: 15%; } + tr td:nth-child(3) { word-break: break-word; } + + button { + white-space: normal; + word-break: break-word; + text-align-last: left; + } } .exception { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less index abd1bfd047..09fea977c7 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less @@ -138,6 +138,7 @@ .umb-media-grid__item-overlay { display: flex; + align-items: center; width: 100%; opacity: 0; position: absolute; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less index 384d9b4ac1..7962981592 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less @@ -84,10 +84,8 @@ .umb-nested-content__heading { line-height: 20px; position: relative; - margin-top:1px; padding: 15px 5px; color:@ui-option-type; - border-radius: 3px 3px 0 0; &:hover { color:@ui-option-type-hover; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-property-actions.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-property-actions.less index f86b27af17..6b7d22d0b7 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-property-actions.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-property-actions.less @@ -1,9 +1,4 @@ -.umb-property-actions { - display: inline; -} - -.umb-property-actions__toggle, -.umb-property-actions__menu-open-toggle { +.umb-property-actions__toggle { position: relative; display: flex; flex: 0 0 auto; @@ -11,7 +6,6 @@ text-align: center; cursor: pointer; border-radius: 3px; - background-color: @ui-action-hover; i { @@ -32,27 +26,20 @@ } } } -.umb-property-actions__menu-open-toggle { - position: absolute; - z-index:1; - outline: none;// this is not acceccible by keyboard, since we use the .umb-property-actions__toggle for that. - top: -15px; - border-radius: 3px 3px 0 0; - - border-top-left-radius: 3px; - border-top-right-radius: 3px; - - border: 1px solid @dropdownBorder; - - border-bottom: 1px solid @gray-9; - - .box-shadow(0 5px 20px rgba(0,0,0,.3)); - - background-color: @white; +.umb-property-actions { + display: inline; + &.-open { + .umb-property-actions__toggle { + background-color: @white; + border-radius: 3px 3px 0 0; + border: 1px solid @dropdownBorder; + border-bottom: 1px solid @gray-9; + .box-shadow(0 5px 20px rgba(0,0,0,.3)); + } + } } - .umb-property .umb-property-actions { float: left; } @@ -66,32 +53,22 @@ .umb-property .umb-property-actions__toggle:focus { opacity: 1; } + // Revert-style-hack that ensures that we only show property-actions on properties that are directly begin hovered. .umb-property:hover .umb-property:not(:hover) .umb-property-actions__toggle { opacity: 0; } .umb-property-actions__menu { - position: absolute; z-index: 1000; - display: block; - float: left; min-width: 160px; list-style: none; .umb-contextmenu { - border-top-left-radius: 0; - margin-top:-2px; - - } - - .umb-contextmenu-item > button { - - z-index:2;// need to stay on top of menu-toggle-open shadow. - + margin-top: 0; } } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-picker-list.less b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-picker-list.less index 2e0d79e803..4a343f780a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-picker-list.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/users/umb-user-picker-list.less @@ -8,6 +8,8 @@ margin-bottom: 5px; padding: 10px; align-items: center; + width: 100%; + text-align: left; } .umb-user-picker-list-item:active, @@ -39,4 +41,4 @@ .umb-user-picker-list-item__name { font-size: 15px; font-weight: bold; -} \ No newline at end of file +} diff --git a/src/Umbraco.Web.UI.Client/src/less/filter-toggle.less b/src/Umbraco.Web.UI.Client/src/less/filter-toggle.less deleted file mode 100644 index 82f9f3f553..0000000000 --- a/src/Umbraco.Web.UI.Client/src/less/filter-toggle.less +++ /dev/null @@ -1,20 +0,0 @@ -.filter-toggle{ - margin: 0; - padding: 0 8px 0 0; - position: relative; -} - -.filter-toggle__level{ - display: inline-block; - font-weight: 700; - margin: 0 5px; - max-width: 150px; -} - -.filter-toggle__icon{ - position: absolute; - top: 0; - bottom: 0; - right: 0; - margin: auto 0; -} diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index ed5a2c0622..76c5af8819 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -118,6 +118,10 @@ label.control-label, .control-label { width: 100%; } +.macro-select .form-search { + margin: 0 0 10px; +} + // GENERAL STYLES // -------------- diff --git a/src/Umbraco.Web.UI.Client/src/less/gridview.less b/src/Umbraco.Web.UI.Client/src/less/gridview.less index 11ba7b2795..80f13fbf1f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/gridview.less +++ b/src/Umbraco.Web.UI.Client/src/less/gridview.less @@ -21,7 +21,7 @@ overflow: hidden; padding: 5px; border-radius:5px; - box-shadow: 3px 3px 12px 0px rgba(50, 50, 50, 0.45); + box-shadow: 3px 3px 12px 0 rgba(50, 50, 50, 0.45); } .usky-grid .ui-sortable-helper *{ @@ -150,7 +150,7 @@ .usky-grid .cell-tools-add { position: absolute; text-align: center; - bottom: 0px; + bottom: 0; left: 0; right: 0; margin: 0 45px 1px 0; @@ -160,14 +160,14 @@ } } -.usky-grid .usky-control:hover .cell-tools-add{ +.usky-grid .usky-control:hover .cell-tools-add{ opacity: 1; } -.usky-grid .cell-tools-remove { +.usky-grid .cell-tools-remove { display:inline-block; position: absolute; - top: 0px; + top: 0; right: 5px; text-align: right; z-index: 500; @@ -221,7 +221,7 @@ top: -22px; left: -1px; text-decoration: none; - padding: 0px 7px; + padding: 0 7px; display:none; font-size:0.8em; background-color: @white; @@ -234,7 +234,7 @@ .usky-grid .usky-row-inner > ins.item-label{ top: -20px; - left: 0px; + left: 0; } .usky-grid .usky-control-inner.selectedControl , .usky-grid .usky-row-inner.selectedRow{ @@ -408,7 +408,7 @@ .usky-grid ul li { display: inline-block; width: 120px; - margin: 8px 8px 0px 8px; + margin: 8px 8px 0 8px; } @@ -435,7 +435,7 @@ padding: -1px; position: absolute; margin: -1px -1px 0 -1px; - box-shadow: 2px 2px 10px 0px rgba(50, 50, 50, 0.14); + box-shadow: 2px 2px 10px 0 rgba(50, 50, 50, 0.14); z-index: 9999999; } @@ -558,7 +558,8 @@ margin: 20px; } - .usky-grid .uSky-templates-template a.tb:hover { + .usky-grid .uSky-templates-template button.tb:hover, + .usky-grid .uSky-templates-template button.tb:focus { border:5px solid @blueMid; } @@ -587,7 +588,9 @@ border-right: 1px dashed @gray-8 !important; } - .usky-grid a.uSky-templates-column:hover, .usky-grid a.uSky-templates-column.selected{ + .usky-grid button.uSky-templates-column:hover, + .usky-grid button.uSky-templates-column:focus, + .usky-grid button.uSky-templates-column.selected{ background-color: @blueMid; } @@ -628,13 +631,13 @@ transition: border 200ms linear; &.prevalues-rows { - margin: 0px 20px 20px 0px; + margin: 0 20px 20px 0; width: 80px; float:left; } &.prevalues-templates { - margin: 0px 20px 20px 0px; + margin: 0 20px 20px 0; float:left; } @@ -803,7 +806,7 @@ .usky-grid-configuration .uSky-templates .uSky-templates-template .tb{ max-height: 50px; border-width: 2px !important; - padding: 0px; + padding: 0; border-spacing:2px; overflow: hidden; } @@ -844,13 +847,13 @@ } .usky-grid-configuration .uSky-templates-rows .uSky-templates-row{ - margin: 0px 50px 20px 0px; + margin: 0 50px 20px 0; width: 60px; } .usky-grid-configuration .uSky-templates-rows .uSky-templates-row .tb{ border-width: 2px !important; - padding: 0px; + padding: 0; border-spacing:2px; } @@ -858,4 +861,6 @@ height: 10px !important; } -.usky-grid-configuration a.uSky-templates-column{height: 70px !important;} +.usky-grid-configuration button.uSky-templates-column { + height: 70px !important; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/listview.less b/src/Umbraco.Web.UI.Client/src/less/listview.less index 9d0ed002bb..582da12804 100644 --- a/src/Umbraco.Web.UI.Client/src/less/listview.less +++ b/src/Umbraco.Web.UI.Client/src/less/listview.less @@ -259,20 +259,21 @@ margin-right: 15px; } +.list-view-layout__icon-wrapper { + margin-right: 10px; +} + .list-view-layout__icon { font-size: 18px; - margin-right: 10px; vertical-align: middle; border: 1px solid @gray-8; background: @white; - padding: 6px 8px; - display: block; -} - -.list-view-layout__icon:hover, -.list-view-layout__icon:focus, -.list-view-layout__icon:active { - text-decoration: none; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; } .list-view-layout__remove { @@ -281,20 +282,9 @@ } .list-view-add-layout { - width:100%; - background:0 0; - margin-top: 10px; - color: @ui-action-discreet-type; - border: 1px dashed @ui-action-discreet-border; - display: flex; - align-items: center; - justify-content: center; - padding: 5px 0; - box-sizing: border-box; + &:extend(.umb-node-preview-add); } .list-view-add-layout:hover { - text-decoration: none; - color: @ui-action-discreet-type-hover; - border-color: @ui-action-discreet-border-hover; + &:extend(.umb-node-preview-add:hover); } diff --git a/src/Umbraco.Web.UI.Client/src/less/panel.less b/src/Umbraco.Web.UI.Client/src/less/panel.less index 115bdaed70..81326826f6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/panel.less +++ b/src/Umbraco.Web.UI.Client/src/less/panel.less @@ -413,6 +413,8 @@ input.umb-panel-header-name-input.name-is-empty { .umb-panel-header-name { font-size: 16px; font-weight: bold; + margin: 0; + line-height: 1.2; } diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 664be1dafc..3912d11161 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -163,6 +163,16 @@ .sp-replacer { display: inline-flex; margin-right: 18px; + height: auto; + + .sp-preview { + margin: 5px; + height: auto; + } + + .sp-dd { + line-height: 2rem; + } } label { diff --git a/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less b/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less index 787e50f204..d2968696dc 100644 --- a/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less +++ b/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less @@ -35,10 +35,13 @@ 7 = 7th step in spacing scale */ -.m-center { - margin-left: auto; +.m-center, +.mx-auto { + margin-left: auto; margin-right: auto; } +.ml-auto { margin-left: auto; } +.mr-auto { margin-right: auto; } .mt0 { margin-top: @spacing-none; } .mt1 { margin-top: @spacing-extra-small; } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js index a08a05b0f7..88cda027a8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.controller.js @@ -7,8 +7,8 @@ angular.module("umbraco") vm.tabs = []; localizationService.localizeMany([ - vm.model.liveEditing ? "prompt_discardChanges" : "general_close", - vm.model.liveEditing ? "buttons_confirmActionConfirm" : "buttons_submitChanges" + vm.model.createFlow ? "general_cancel" : (vm.model.liveEditing ? "prompt_discardChanges" : "general_close"), + vm.model.createFlow ? "general_create" : (vm.model.liveEditing ? "buttons_confirmActionConfirm" : "buttons_submitChanges") ]).then(function (data) { vm.closeLabel = data[0]; vm.submitLabel = data[1]; @@ -68,16 +68,16 @@ angular.module("umbraco") // * It would have a 'commit' method to commit the removed errors - which we would call in the formHelper.submitForm when it's successful // * It would have a 'rollback' method to reset the removed errors - which we would call here - - if (vm.blockForm.$dirty === true) { - localizationService.localizeMany(["prompt_discardChanges", "blockEditor_blockHasChanges"]).then(function (localizations) { + if (vm.model.createFlow === true || vm.blockForm.$dirty === true) { + var labels = vm.model.createFlow === true ? ["blockEditor_confirmCancelBlockCreationHeadline", "blockEditor_confirmCancelBlockCreationMessage"] : ["prompt_discardChanges", "blockEditor_blockHasChanges"]; + localizationService.localizeMany(labels).then(function (localizations) { const confirm = { title: localizations[0], view: "default", content: localizations[1], submitButtonLabelKey: "general_discard", submitButtonStyle: "danger", - closeButtonLabelKey: "general_cancel", + closeButtonLabelKey: "prompt_stay", submit: function () { overlayService.close(); vm.model.close(vm.model); @@ -88,11 +88,10 @@ angular.module("umbraco") }; overlayService.open(confirm); }); - - return; + } else { + vm.model.close(vm.model); } - // TODO: check if content/settings has changed and ask user if they are sure. - vm.model.close(vm.model); + } } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html index 285e554c68..2367771804 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html @@ -37,6 +37,7 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockpicker/blockpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockpicker/blockpicker.html index fb7e946ee7..6dea4debb6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockpicker/blockpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockpicker/blockpicker.html @@ -69,6 +69,7 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js index 515f54e3d7..c3d1312109 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.controller.js @@ -22,7 +22,7 @@ }; if ($scope.model.modify) { - angular.extend($scope.model.embed, $scope.model.modify); + Utilities.extend($scope.model.embed, $scope.model.modify); showPreview(); } @@ -34,7 +34,7 @@ vm.close = close; function onInit() { - if(!$scope.model.title) { + if (!$scope.model.title) { localizationService.localize("general_embed").then(function(value){ $scope.model.title = value; }); @@ -122,7 +122,6 @@ if ($scope.model.embed.url !== "") { showPreview(); } - } function toggleConstrain() { @@ -130,19 +129,18 @@ } function submit() { - if($scope.model && $scope.model.submit) { + if ($scope.model && $scope.model.submit) { $scope.model.submit($scope.model); } } function close() { - if($scope.model && $scope.model.close) { + if ($scope.model && $scope.model.close) { $scope.model.close(); } } onInit(); - } angular.module("umbraco").controller("Umbraco.Editors.EmbedController", EmbedController); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.html index 5862ca7059..19cf9b2278 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/embed/embed.html @@ -16,7 +16,7 @@ - + - +
-
-
...
-
-
-
-
...
-
- -
-
-
-
...
-
- -
-
-
-
...
-
-
+ + + +
@@ -54,5 +54,5 @@ - +
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/itempicker/itempicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/itempicker/itempicker.html index 5b121c172f..c563394ab3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/itempicker/itempicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/itempicker/itempicker.html @@ -25,14 +25,13 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macroparameterpicker/macroparameterpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macroparameterpicker/macroparameterpicker.html index e92ce65bde..151a8167e8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macroparameterpicker/macroparameterpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macroparameterpicker/macroparameterpicker.html @@ -34,15 +34,18 @@
{{key}}
@@ -55,15 +58,18 @@
{{result.group}}
- + Sorry, we can not find what you are looking for. diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html index fc1bec4ec1..c23aaa7cb9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/macropicker/macropicker.html @@ -15,7 +15,7 @@
-
+
/// - [SetAngularAntiForgeryTokens] + // [SetAngularAntiForgeryTokens] //TODO reintroduce when migrated to netcore public async Task> Get2FAProviders() { var userId = await SignInManager.GetVerifiedUserIdAsync(); @@ -127,7 +129,7 @@ namespace Umbraco.Web.Editors return userFactors; } - [SetAngularAntiForgeryTokens] + // [SetAngularAntiForgeryTokens] //TODO reintroduce when migrated to netcore public async Task PostSend2FACode([FromBody]string provider) { if (provider.IsNullOrWhiteSpace()) @@ -148,7 +150,7 @@ namespace Umbraco.Web.Editors return Ok(); } - [SetAngularAntiForgeryTokens] + // [SetAngularAntiForgeryTokens] //TODO reintroduce when migrated to netcore public async Task PostVerify2FACode(Verify2FACodeModel model) { if (ModelState.IsValid == false) diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index b963871a58..64bc2fd380 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -4,17 +4,19 @@ using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; using Microsoft.Owin.Security; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Web.Mvc; using Umbraco.Core.Services; using Umbraco.Web.Features; using Umbraco.Web.Security; using Constants = Umbraco.Core.Constants; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Hosting; using BackOfficeIdentityUser = Umbraco.Core.BackOffice.BackOfficeIdentityUser; @@ -32,32 +34,35 @@ namespace Umbraco.Web.Editors private BackOfficeOwinUserManager _userManager; private BackOfficeSignInManager _signInManager; private readonly IUmbracoVersion _umbracoVersion; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IRuntimeSettings _runtimeSettings; - private readonly ISecuritySettings _securitySettings; + private readonly RuntimeSettings _runtimeSettings; + private readonly SecuritySettings _securitySettings; + private readonly IIconService _iconService; public BackOfficeController( UmbracoFeatures features, - IGlobalSettings globalSettings, + IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IUmbracoVersion umbracoVersion, - IContentSettings contentSettings, + IOptions contentSettings, IHostingEnvironment hostingEnvironment, - IRuntimeSettings settings, - ISecuritySettings securitySettings) + IOptions settings, + IOptions securitySettings, + IIconService iconService) : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger) { _features = features; _umbracoVersion = umbracoVersion; - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value; _hostingEnvironment = hostingEnvironment; - _runtimeSettings = settings; - _securitySettings = securitySettings; + _runtimeSettings = settings.Value; + _securitySettings = securitySettings.Value; + _iconService = iconService; } protected BackOfficeSignInManager SignInManager => _signInManager ?? (_signInManager = OwinContext.GetBackOfficeSignInManager()); @@ -139,7 +144,7 @@ namespace Umbraco.Web.Editors if (defaultResponse == null) throw new ArgumentNullException("defaultResponse"); if (externalSignInResponse == null) throw new ArgumentNullException("externalSignInResponse"); - ViewData.SetUmbracoPath(GlobalSettings.GetUmbracoMvcArea(_hostingEnvironment)); + ViewData.SetUmbracoPath(GlobalSettings.Value.GetUmbracoMvcArea(_hostingEnvironment)); //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) || @@ -253,8 +258,7 @@ namespace Umbraco.Web.Editors var groups = Services.UserService.GetUserGroupsByAlias(autoLinkOptions.GetDefaultUserGroups(UmbracoContext, loginInfo)); - var autoLinkUser = BackOfficeIdentityUser.CreateNew( - GlobalSettings, + var autoLinkUser = BackOfficeIdentityUser.CreateNew(GlobalSettings.Value, loginInfo.Email, loginInfo.Email, autoLinkOptions.GetDefaultCulture(UmbracoContext, loginInfo)); diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index bdcb93099b..7b2cc04652 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -5,18 +5,17 @@ using System.Linq; using System.Runtime.Serialization; using System.Web; using System.Web.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Web.Features; -using Umbraco.Web.HealthCheck; -using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Mvc; -using Umbraco.Web.Trees; -using Constants = Umbraco.Core.Constants; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.WebAssets; +using Umbraco.Web.Features; +using Umbraco.Web.Mvc; using Umbraco.Web.Security; +using Umbraco.Web.Trees; +using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Editors { @@ -28,27 +27,27 @@ namespace Umbraco.Web.Editors private readonly UrlHelper _urlHelper; private readonly IRuntimeState _runtimeState; private readonly UmbracoFeatures _features; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IUmbracoVersion _umbracoVersion; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly TreeCollection _treeCollection; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IRuntimeSettings _settings; - private readonly ISecuritySettings _securitySettings; + private readonly RuntimeSettings _settings; + private readonly SecuritySettings _securitySettings; private readonly IRuntimeMinifier _runtimeMinifier; internal BackOfficeServerVariables( UrlHelper urlHelper, IRuntimeState runtimeState, UmbracoFeatures features, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IUmbracoVersion umbracoVersion, - IContentSettings contentSettings, + IOptions contentSettings, TreeCollection treeCollection, IHostingEnvironment hostingEnvironment, - IRuntimeSettings settings, - ISecuritySettings securitySettings, + IOptions settings, + IOptions securitySettings, IRuntimeMinifier runtimeMinifier) { _urlHelper = urlHelper; @@ -56,11 +55,11 @@ namespace Umbraco.Web.Editors _features = features; _globalSettings = globalSettings; _umbracoVersion = umbracoVersion; - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _treeCollection = treeCollection ?? throw new ArgumentNullException(nameof(treeCollection)); _hostingEnvironment = hostingEnvironment; - _settings = settings; - _securitySettings = securitySettings; + _settings = settings.Value; + _securitySettings = securitySettings.Value; _runtimeMinifier = runtimeMinifier; } @@ -148,7 +147,7 @@ namespace Umbraco.Web.Editors {"appPluginsPath", _hostingEnvironment.ToAbsolute(Constants.SystemDirectories.AppPlugins).TrimEnd('/')}, { "imageFileTypes", - string.Join(",", _contentSettings.ImageFileTypes) + string.Join(",", _contentSettings.Imaging.ImageFileTypes) }, { "disallowedUploadFiles", diff --git a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs index 64aba378f4..4cd5a76fa4 100644 --- a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs +++ b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs @@ -1,7 +1,9 @@ using System; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Persistence; @@ -31,7 +33,7 @@ namespace Umbraco.Web.Editors } protected UmbracoAuthorizedJsonController( - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index 5ddd34fbed..eccbe073cb 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -10,6 +10,7 @@ using System.Web.Mvc.Html; using System.Web.Routing; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Web.Mvc; @@ -60,7 +61,7 @@ namespace Umbraco.Web /// /// See: http://issues.umbraco.org/issue/U4-1614 /// - public static MvcHtmlString PreviewBadge(this HtmlHelper helper, IHttpContextAccessor httpContextAccessor, IGlobalSettings globalSettings, IIOHelper ioHelper, IContentSettings contentSettings) + public static MvcHtmlString PreviewBadge(this HtmlHelper helper, IHttpContextAccessor httpContextAccessor, GlobalSettings globalSettings, IIOHelper ioHelper, ContentSettings contentSettings) { if (Current.UmbracoContext.InPreviewMode) { diff --git a/src/Umbraco.Web/Logging/WebProfilerComponent.cs b/src/Umbraco.Web/Logging/WebProfilerComponent.cs index 2959e12ad7..2edeea6a1b 100755 --- a/src/Umbraco.Web/Logging/WebProfilerComponent.cs +++ b/src/Umbraco.Web/Logging/WebProfilerComponent.cs @@ -35,7 +35,9 @@ namespace Umbraco.Web.Logging } public void Terminate() - { } + { + UmbracoApplicationBase.ApplicationInit -= InitializeApplication; + } private void InitializeApplication(object sender, EventArgs args) { diff --git a/src/Umbraco.Web/Macros/MacroRenderer.cs b/src/Umbraco.Web/Macros/MacroRenderer.cs index 7f6a1cdbf3..8d13c03e8b 100644 --- a/src/Umbraco.Web/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web/Macros/MacroRenderer.cs @@ -3,8 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.IO; @@ -20,7 +22,7 @@ namespace Umbraco.Web.Macros { private readonly IProfilingLogger _plogger; private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; private readonly ILocalizedTextService _textService; private readonly AppCaches _appCaches; private readonly IMacroService _macroService; @@ -35,7 +37,7 @@ namespace Umbraco.Web.Macros public MacroRenderer( IProfilingLogger plogger, IUmbracoContextAccessor umbracoContextAccessor, - IContentSettings contentSettings, + IOptions contentSettings, ILocalizedTextService textService, AppCaches appCaches, IMacroService macroService, @@ -48,7 +50,7 @@ namespace Umbraco.Web.Macros { _plogger = plogger ?? throw new ArgumentNullException(nameof(plogger)); _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); _textService = textService; _appCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); _macroService = macroService ?? throw new ArgumentNullException(nameof(macroService)); @@ -288,7 +290,7 @@ namespace Umbraco.Web.Macros Alias = macro.Alias, MacroSource = macro.MacroSource, Exception = e, - Behaviour = _contentSettings.MacroErrorBehaviour + Behaviour = _contentSettings.MacroErrors }; switch (macroErrorEventArgs.Behaviour) diff --git a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs index 118c53a7f0..e25ab4a69e 100644 --- a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs +++ b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs @@ -6,10 +6,8 @@ using System.Web.Routing; using System.Web.SessionState; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Exceptions; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using Umbraco.Web.Composing; using Umbraco.Web.WebApi; namespace Umbraco.Web.Mvc @@ -44,7 +42,7 @@ namespace Umbraco.Web.Mvc /// /// internal static Route RouteControllerPlugin(this AreaRegistration area, - IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, string controllerName, Type controllerType, RouteCollection routes, string controllerSuffixName, string defaultAction, object defaultId, string umbracoTokenValue = "backoffice", diff --git a/src/Umbraco.Web/Mvc/BackOfficeArea.cs b/src/Umbraco.Web/Mvc/BackOfficeArea.cs index 156a896bb5..eeb48c3b38 100644 --- a/src/Umbraco.Web/Mvc/BackOfficeArea.cs +++ b/src/Umbraco.Web/Mvc/BackOfficeArea.cs @@ -1,8 +1,7 @@ using System.Web.Mvc; -using Umbraco.Web.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Web.Editors; namespace Umbraco.Web.Mvc @@ -10,10 +9,10 @@ namespace Umbraco.Web.Mvc // TODO: This has been ported to netcore, can be removed internal class BackOfficeArea : AreaRegistration { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - public BackOfficeArea(IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) + public BackOfficeArea(GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { _globalSettings = globalSettings; _hostingEnvironment = hostingEnvironment; diff --git a/src/Umbraco.Web/Mvc/ModelBindingExceptionFilter.cs b/src/Umbraco.Web/Mvc/ModelBindingExceptionFilter.cs index 60ca151ce6..b189867a89 100644 --- a/src/Umbraco.Web/Mvc/ModelBindingExceptionFilter.cs +++ b/src/Umbraco.Web/Mvc/ModelBindingExceptionFilter.cs @@ -3,8 +3,10 @@ using System.Configuration; using System.Net; using System.Text.RegularExpressions; using System.Web.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core.Configuration; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Web.Composing; namespace Umbraco.Web.Mvc @@ -23,7 +25,7 @@ namespace Umbraco.Web.Mvc public void OnException(ExceptionContext filterContext) { - var settings = Current.Factory.GetInstance(); + var settings = Current.Factory.GetInstance>().Value; var disabled = settings?.Disabled ?? false; if (Current.PublishedModelFactory.IsLiveFactory() && !disabled diff --git a/src/Umbraco.Web/Mvc/PluginControllerArea.cs b/src/Umbraco.Web/Mvc/PluginControllerArea.cs index 838e304847..a4440ec4a6 100644 --- a/src/Umbraco.Web/Mvc/PluginControllerArea.cs +++ b/src/Umbraco.Web/Mvc/PluginControllerArea.cs @@ -6,6 +6,7 @@ using System.Web.Routing; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Web.WebApi; @@ -17,7 +18,7 @@ namespace Umbraco.Web.Mvc ///
internal class PluginControllerArea : AreaRegistration { - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IEnumerable _surfaceControllers; private readonly IEnumerable _apiControllers; @@ -30,7 +31,7 @@ namespace Umbraco.Web.Mvc /// /// /// - public PluginControllerArea(IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IEnumerable pluginControllers) + public PluginControllerArea(GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IEnumerable pluginControllers) { _globalSettings = globalSettings; _hostingEnvironment = hostingEnvironment; diff --git a/src/Umbraco.Web/Mvc/RedirectToUmbracoPageResult.cs b/src/Umbraco.Web/Mvc/RedirectToUmbracoPageResult.cs index e379f569e0..4658910ab0 100644 --- a/src/Umbraco.Web/Mvc/RedirectToUmbracoPageResult.cs +++ b/src/Umbraco.Web/Mvc/RedirectToUmbracoPageResult.cs @@ -19,6 +19,7 @@ namespace Umbraco.Web.Mvc { private IPublishedContent _publishedContent; private readonly int _pageId; + private readonly Guid _key; private NameValueCollection _queryStringValues; private IPublishedUrlProvider _publishedUrlProvider; private string _url; @@ -51,14 +52,25 @@ namespace Umbraco.Web.Mvc get { return _pageId; } } + public Guid Key + { + get { return _key; } + } public IPublishedContent PublishedContent { get { if (_publishedContent != null) return _publishedContent; - //need to get the URL for the page - _publishedContent = Current.UmbracoContext.Content.GetById(_pageId); + if (_pageId != default(int)) + { + _publishedContent = Current.UmbracoContext.Content.GetById(_pageId); + } + + else if (_key != default(Guid)) + { + _publishedContent = Current.UmbracoContext.Content.GetById(_key); + } return _publishedContent; } @@ -159,6 +171,38 @@ namespace Umbraco.Web.Mvc _publishedUrlProvider = publishedUrlProvider; } + /// + /// Creates a new RedirectToUmbracoResult + /// + /// + /// + public RedirectToUmbracoPageResult(Guid key) + { + _key = key; + } + + /// + /// Creates a new RedirectToUmbracoResult + /// + /// + /// + public RedirectToUmbracoPageResult(Guid key, NameValueCollection queryStringValues) + { + _key = key; + _queryStringValues = queryStringValues; + } + + /// + /// Creates a new RedirectToUmbracoResult + /// + /// + /// + public RedirectToUmbracoPageResult(Guid key, string queryString) + { + _key = key; + _queryStringValues = ParseQueryString(queryString); + } + /// /// Creates a new RedirectToUmbracoResult /// diff --git a/src/Umbraco.Web/Mvc/RenderMvcController.cs b/src/Umbraco.Web/Mvc/RenderMvcController.cs index 7286f52c64..be17bf85c2 100644 --- a/src/Umbraco.Web/Mvc/RenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/RenderMvcController.cs @@ -1,7 +1,9 @@ using System; using System.Web.Mvc; +using Microsoft.Extensions.Options; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -25,7 +27,7 @@ namespace Umbraco.Web.Mvc ActionInvoker = new RenderActionInvoker(); } - public RenderMvcController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) + public RenderMvcController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger) { ActionInvoker = new RenderActionInvoker(); diff --git a/src/Umbraco.Web/Mvc/RenderNoContentController.cs b/src/Umbraco.Web/Mvc/RenderNoContentController.cs index 9334591fbb..52ee7cf44d 100644 --- a/src/Umbraco.Web/Mvc/RenderNoContentController.cs +++ b/src/Umbraco.Web/Mvc/RenderNoContentController.cs @@ -1,6 +1,7 @@ using System; using System.Web.Mvc; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Web.Models; @@ -10,9 +11,9 @@ namespace Umbraco.Web.Mvc { private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IIOHelper _ioHelper; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; - public RenderNoContentController(IUmbracoContextAccessor umbracoContextAccessor, IIOHelper ioHelper, IGlobalSettings globalSettings) + public RenderNoContentController(IUmbracoContextAccessor umbracoContextAccessor, IIOHelper ioHelper, GlobalSettings globalSettings) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); diff --git a/src/Umbraco.Web/Mvc/StatusCodeFilterAttribute.cs b/src/Umbraco.Web/Mvc/StatusCodeFilterAttribute.cs deleted file mode 100644 index 727c29b93c..0000000000 --- a/src/Umbraco.Web/Mvc/StatusCodeFilterAttribute.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Net; -using System.Web.Mvc; -using Umbraco.Core; -using Umbraco.Web.Composing; - -namespace Umbraco.Web.Mvc -{ - /// - /// Forces the response to have a specific http status code - /// - /// Migrated already to .Net Core - internal class StatusCodeResultAttribute : ActionFilterAttribute - { - private readonly HttpStatusCode _statusCode; - - public StatusCodeResultAttribute(HttpStatusCode statusCode) - { - _statusCode = statusCode; - } - - public override void OnActionExecuted(ActionExecutedContext filterContext) - { - base.OnActionExecuted(filterContext); - - filterContext.HttpContext.Response.StatusCode = (int)_statusCode; - filterContext.HttpContext.Response.TrySkipIisCustomErrors = Current.Configs.WebRouting().TrySkipIisCustomErrors; - } - } -} diff --git a/src/Umbraco.Web/Mvc/SurfaceController.cs b/src/Umbraco.Web/Mvc/SurfaceController.cs index b9c857a8b3..29f2f5c541 100644 --- a/src/Umbraco.Web/Mvc/SurfaceController.cs +++ b/src/Umbraco.Web/Mvc/SurfaceController.cs @@ -58,6 +58,38 @@ namespace Umbraco.Web.Mvc return new RedirectToUmbracoPageResult(pageId, queryString, Current.PublishedUrlProvider); } + /// + /// Redirects to the Umbraco page with the given id + /// + /// + /// + protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid key) + { + return new RedirectToUmbracoPageResult(key); + } + + /// + /// Redirects to the Umbraco page with the given id and passes provided querystring + /// + /// + /// + /// + protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid key, NameValueCollection queryStringValues) + { + return new RedirectToUmbracoPageResult(key, queryStringValues); + } + + /// + /// Redirects to the Umbraco page with the given id and passes provided querystring + /// + /// + /// + /// + protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid key, string queryString) + { + return new RedirectToUmbracoPageResult(key, queryString); + } + /// /// Redirects to the Umbraco page with the given id /// diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs index b5c6185069..6148535d46 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs @@ -2,8 +2,10 @@ using System.Web; using System.Web.Mvc; using Umbraco.Core; -using Umbraco.Web.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Security; +using Umbraco.Core.Configuration.Models; +using Umbraco.Web.Composing; using Umbraco.Web.Security; namespace Umbraco.Web.Mvc @@ -13,22 +15,22 @@ namespace Umbraco.Web.Mvc public sealed class UmbracoAuthorizeAttribute : AuthorizeAttribute { // see note in HttpInstallAuthorizeAttribute - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IRuntimeState _runtimeState; private readonly string _redirectUrl; private IRuntimeState RuntimeState => _runtimeState ?? Current.RuntimeState; - private IWebSecurity WebSecurity => _webSecurity ?? Current.UmbracoContext.Security; + private IBackofficeSecurity BackofficeSecurity => _backofficeSecurityAccessor.BackofficeSecurity ?? Current.UmbracoContext.Security; /// /// THIS SHOULD BE ONLY USED FOR UNIT TESTS /// - /// + /// /// - public UmbracoAuthorizeAttribute(IWebSecurity webSecurity, IRuntimeState runtimeState) + public UmbracoAuthorizeAttribute(IBackofficeSecurityAccessor backofficeSecurityAccessor, IRuntimeState runtimeState) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); } @@ -55,7 +57,7 @@ namespace Umbraco.Web.Mvc { if (redirectToUmbracoLogin) { - _redirectUrl = Current.Configs.Global().GetBackOfficePath(Current.HostingEnvironment).EnsureStartsWith("~"); + _redirectUrl = new GlobalSettings().GetBackOfficePath(Current.HostingEnvironment).EnsureStartsWith("~"); } } @@ -74,7 +76,7 @@ namespace Umbraco.Web.Mvc // otherwise we need to ensure that a user is logged in return RuntimeState.Level == RuntimeLevel.Install || RuntimeState.Level == RuntimeLevel.Upgrade - || WebSecurity.ValidateCurrentUser(); + || BackofficeSecurity.ValidateCurrentUser(); } catch (Exception) { diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs index 0724cd138d..6471656c42 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs @@ -1,5 +1,7 @@ -using Umbraco.Core.Cache; +using Microsoft.Extensions.Options; +using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Services; @@ -21,7 +23,7 @@ namespace Umbraco.Web.Mvc { } - protected UmbracoAuthorizedController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) + protected UmbracoAuthorizedController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger) { } diff --git a/src/Umbraco.Web/Mvc/UmbracoController.cs b/src/Umbraco.Web/Mvc/UmbracoController.cs index 9cfd93ba9d..29f0949473 100644 --- a/src/Umbraco.Web/Mvc/UmbracoController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoController.cs @@ -1,12 +1,14 @@ using System; using System.Web; using System.Web.Mvc; +using Microsoft.Extensions.Options; using Microsoft.Owin; using Umbraco.Core.Cache; using Umbraco.Web.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Services; using Umbraco.Web.Security; @@ -23,7 +25,7 @@ namespace Umbraco.Web.Mvc /// /// Gets or sets the Umbraco context. /// - public IGlobalSettings GlobalSettings { get; } + public IOptions GlobalSettings { get; } /// /// Gets the Umbraco context. @@ -65,11 +67,11 @@ namespace Umbraco.Web.Mvc /// /// Gets the web security helper. /// - public virtual IWebSecurity Security => UmbracoContext.Security; + public virtual IBackofficeSecurity Security => UmbracoContext.Security; protected UmbracoController() : this( - Current.Factory.GetInstance(), + Current.Factory.GetInstance>(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), @@ -78,7 +80,7 @@ namespace Umbraco.Web.Mvc { } - protected UmbracoController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) + protected UmbracoController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) { GlobalSettings = globalSettings; UmbracoContextAccessor = umbracoContextAccessor; diff --git a/src/Umbraco.Web/Mvc/UmbracoRequireHttpsAttribute.cs b/src/Umbraco.Web/Mvc/UmbracoRequireHttpsAttribute.cs index 9a0aa6b600..b88d1c0736 100644 --- a/src/Umbraco.Web/Mvc/UmbracoRequireHttpsAttribute.cs +++ b/src/Umbraco.Web/Mvc/UmbracoRequireHttpsAttribute.cs @@ -16,7 +16,7 @@ namespace Umbraco.Web.Mvc protected override void HandleNonHttpsRequest(AuthorizationContext filterContext) { // If Umbraco.Core.UseHttps is set, let base method handle redirect. Otherwise, we don't care. - if (Current.Configs.Global().UseHttps) + if (/*Current.Configs.Global().UseHttps*/ false) { base.HandleNonHttpsRequest(filterContext); } @@ -29,7 +29,7 @@ namespace Umbraco.Web.Mvc public override void OnAuthorization(AuthorizationContext filterContext) { // If umbracoSSL is set, let base method handle checking for HTTPS. Otherwise, we don't care. - if (Current.Configs.Global().UseHttps) + if (/*Current.Configs.Global().UseHttps*/ false) { base.OnAuthorization(filterContext); } diff --git a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs index a687e7c9cd..f461fb9a22 100644 --- a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs +++ b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs @@ -3,9 +3,11 @@ using System.Text; using System.Web; using System.Web.Mvc; using System.Web.WebPages; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -22,8 +24,8 @@ namespace Umbraco.Web.Mvc /// public abstract class UmbracoViewPage : WebViewPage { - private readonly IGlobalSettings _globalSettings; - private readonly IContentSettings _contentSettings; + private readonly GlobalSettings _globalSettings; + private readonly ContentSettings _contentSettings; private IUmbracoContext _umbracoContext; private UmbracoHelper _helper; @@ -105,18 +107,20 @@ namespace Umbraco.Web.Mvc : this( Current.Factory.GetInstance(), Current.Factory.GetInstance(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance() + Current.Factory.GetInstance>(), + Current.Factory.GetInstance>() ) { } - protected UmbracoViewPage(ServiceContext services, AppCaches appCaches, IGlobalSettings globalSettings, IContentSettings contentSettings) + protected UmbracoViewPage(ServiceContext services, AppCaches appCaches, IOptions globalSettings, IOptions contentSettings) { + if (globalSettings == null) throw new ArgumentNullException(nameof(globalSettings)); + if (contentSettings == null) throw new ArgumentNullException(nameof(contentSettings)); Services = services; AppCaches = appCaches; - _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _globalSettings = globalSettings.Value; + _contentSettings = contentSettings.Value; } // view logic below: diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 1dbe6ac556..487212840b 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -73,8 +73,10 @@ namespace Umbraco.Web { return content.IsAllowedTemplate( Current.Services.ContentTypeService, - Current.Configs.WebRouting().DisableAlternativeTemplates, + /*Current.Configs.WebRouting().DisableAlternativeTemplates, Current.Configs.WebRouting().ValidateAlternativeTemplates, + TODO get values from config*/ + false, false, templateId); } @@ -83,8 +85,10 @@ namespace Umbraco.Web return content.IsAllowedTemplate( Current.Services.FileService, Current.Services.ContentTypeService, - Current.Configs.WebRouting().DisableAlternativeTemplates, - Current.Configs.WebRouting().ValidateAlternativeTemplates, + /*Current.Configs.WebRouting().DisableAlternativeTemplates, + Current.Configs.WebRouting().ValidateAlternativeTemplates, + TODO get values from config*/ + false, false, templateAlias); } diff --git a/src/Umbraco.Web/RoutableDocumentFilter.cs b/src/Umbraco.Web/RoutableDocumentFilter.cs index 43e47a39b3..3580e25c78 100644 --- a/src/Umbraco.Web/RoutableDocumentFilter.cs +++ b/src/Umbraco.Web/RoutableDocumentFilter.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Collections.Concurrent; using Umbraco.Core.Collections; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Web.Composing; @@ -22,14 +23,14 @@ namespace Umbraco.Web /// public sealed class RoutableDocumentFilter { - public RoutableDocumentFilter(IGlobalSettings globalSettings, IIOHelper ioHelper) + public RoutableDocumentFilter(GlobalSettings globalSettings, IIOHelper ioHelper) { _globalSettings = globalSettings; _ioHelper = ioHelper; } private static readonly ConcurrentDictionary RouteChecks = new ConcurrentDictionary(); - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IIOHelper _ioHelper; private object _locker = new object(); private bool _isInit = false; diff --git a/src/Umbraco.Web/Runtime/WebInitialComponent.cs b/src/Umbraco.Web/Runtime/WebInitialComponent.cs index dbd0a1fb3a..9108dd820e 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComponent.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComponent.cs @@ -8,13 +8,11 @@ using System.Web.Routing; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Strings; -using Umbraco.Core.IO; -using Umbraco.Web.Install; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; - using Constants = Umbraco.Core.Constants; using Current = Umbraco.Web.Composing.Current; @@ -25,7 +23,7 @@ namespace Umbraco.Web.Runtime private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly SurfaceControllerTypeCollection _surfaceControllerTypes; private readonly UmbracoApiControllerTypeCollection _apiControllerTypes; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly IShortStringHelper _shortStringHelper; @@ -33,7 +31,7 @@ namespace Umbraco.Web.Runtime IUmbracoContextAccessor umbracoContextAccessor, SurfaceControllerTypeCollection surfaceControllerTypes, UmbracoApiControllerTypeCollection apiControllerTypes, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper) { @@ -111,7 +109,7 @@ namespace Umbraco.Web.Runtime // internal for tests internal static void CreateRoutes( IUmbracoContextAccessor umbracoContextAccessor, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IShortStringHelper shortStringHelper, SurfaceControllerTypeCollection surfaceControllerTypes, UmbracoApiControllerTypeCollection apiControllerTypes, @@ -149,7 +147,7 @@ namespace Umbraco.Web.Runtime } private static void RoutePluginControllers( - IGlobalSettings globalSettings, + GlobalSettings globalSettings, SurfaceControllerTypeCollection surfaceControllerTypes, UmbracoApiControllerTypeCollection apiControllerTypes, IHostingEnvironment hostingEnvironment) diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index ad6e1b830b..f6629ad5fd 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -1,5 +1,4 @@ -using System.Linq; -using System.Web.Security; +using System.Web.Security; using Microsoft.AspNet.SignalR; using Umbraco.Core; using Umbraco.Core.Composing; @@ -15,8 +14,7 @@ using Umbraco.Web.PublishedCache; using Umbraco.Web.Security; using Umbraco.Web.Security.Providers; using Umbraco.Web.SignalR; -using Umbraco.Web.Templates; -using Umbraco.Web.Trees; +using Umbraco.Web.Services; namespace Umbraco.Web.Runtime { diff --git a/src/Umbraco.Web/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs b/src/Umbraco.Web/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs index 930cabeee3..82c9cb8496 100644 --- a/src/Umbraco.Web/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs +++ b/src/Umbraco.Web/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs @@ -1,22 +1,24 @@ using System; using System.DirectoryServices.AccountManagement; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.Security { // TODO: This relies on an assembly that is not .NET Standard (at least not at the time of implementation) :( public class ActiveDirectoryBackOfficeUserPasswordChecker : IBackOfficeUserPasswordChecker { - private readonly IActiveDirectorySettings _settings; + private readonly IOptions _activeDirectorySettings; - public ActiveDirectoryBackOfficeUserPasswordChecker(IActiveDirectorySettings settings) + public ActiveDirectoryBackOfficeUserPasswordChecker(IOptions activeDirectorySettings) { - _settings = settings; + _activeDirectorySettings = activeDirectorySettings; } - public virtual string ActiveDirectoryDomain => _settings.ActiveDirectoryDomain; + public virtual string ActiveDirectoryDomain => _activeDirectorySettings.Value.Domain; public Task CheckPasswordAsync(BackOfficeIdentityUser user, string password) { diff --git a/src/Umbraco.Web/Security/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/AppBuilderExtensions.cs index ac5434aa4e..e51b68ef54 100644 --- a/src/Umbraco.Web/Security/AppBuilderExtensions.cs +++ b/src/Umbraco.Web/Security/AppBuilderExtensions.cs @@ -8,6 +8,7 @@ using Owin; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Web.Composing; using Constants = Umbraco.Core.Constants; @@ -34,7 +35,7 @@ namespace Umbraco.Web.Security /// /// By default this will be configured to execute on PipelineStage.Authenticate /// - public static IAppBuilder UseUmbracoBackOfficeExternalCookieAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState,IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IRequestCache requestCache) + public static IAppBuilder UseUmbracoBackOfficeExternalCookieAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState,GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IRequestCache requestCache) { return app.UseUmbracoBackOfficeExternalCookieAuthentication(umbracoContextAccessor, runtimeState, globalSettings, hostingEnvironment, requestCache, PipelineStage.Authenticate); } @@ -53,7 +54,7 @@ namespace Umbraco.Web.Security /// public static IAppBuilder UseUmbracoBackOfficeExternalCookieAuthentication(this IAppBuilder app, IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState, - IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IRequestCache requestCache, PipelineStage stage) + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IRequestCache requestCache, PipelineStage stage) { if (app == null) throw new ArgumentNullException(nameof(app)); if (runtimeState == null) throw new ArgumentNullException(nameof(runtimeState)); @@ -68,7 +69,7 @@ namespace Umbraco.Web.Security CookiePath = "/", CookieSecure = globalSettings.UseHttps ? CookieSecureOption.Always : CookieSecureOption.SameAsRequest, CookieHttpOnly = true, - CookieDomain = Current.Configs.Security().AuthCookieDomain + CookieDomain = new SecuritySettings().AuthCookieDomain // TODO inject settings }, stage); return app; diff --git a/src/Umbraco.Web/Security/AuthenticationExtensions.cs b/src/Umbraco.Web/Security/AuthenticationExtensions.cs index 2b8ba2ddfb..de5abf8a6b 100644 --- a/src/Umbraco.Web/Security/AuthenticationExtensions.cs +++ b/src/Umbraco.Web/Security/AuthenticationExtensions.cs @@ -13,6 +13,7 @@ using Microsoft.Owin.Security; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.BackOffice; +using Umbraco.Core.Configuration.Models; using Umbraco.Extensions; using Umbraco.Web.Composing; using Constants = Umbraco.Core.Constants; @@ -68,7 +69,7 @@ namespace Umbraco.Web.Security if (ex is FormatException || ex is JsonReaderException) { // this will occur if the cookie data is invalid - + } else { @@ -104,7 +105,7 @@ namespace Umbraco.Web.Security /// /// This will return the current back office identity. /// - /// + /// /// /// Returns the current back office identity if an admin is authenticated otherwise null /// @@ -151,7 +152,7 @@ namespace Umbraco.Web.Security public static AuthenticationTicket GetUmbracoAuthTicket(this HttpContextBase http) { if (http == null) throw new ArgumentNullException(nameof(http)); - return GetAuthTicket(http, Current.Configs.Security().AuthCookieName); + return GetAuthTicket(http, /*Current.Configs.Security() TODO*/new SecuritySettings().AuthCookieName); } internal static AuthenticationTicket GetUmbracoAuthTicket(this HttpContext http) @@ -163,7 +164,7 @@ namespace Umbraco.Web.Security public static AuthenticationTicket GetUmbracoAuthTicket(this IOwinContext ctx) { if (ctx == null) throw new ArgumentNullException(nameof(ctx)); - return GetAuthTicket(ctx, Current.Configs.Security().AuthCookieName); + return GetAuthTicket(ctx, /*Current.Configs.Security() TODO introduce injection instead of default value*/new SecuritySettings().AuthCookieName); } private static AuthenticationTicket GetAuthTicket(this IOwinContext owinCtx, string cookieName) @@ -215,7 +216,7 @@ namespace Umbraco.Web.Security catch (Exception) { // occurs when decryption fails - + return null; } } @@ -236,6 +237,6 @@ namespace Umbraco.Web.Security return secureDataFormat.Unprotect(formsCookie); } - + } } diff --git a/src/Umbraco.Web/Security/BackOfficeCookieAuthenticationProvider.cs b/src/Umbraco.Web/Security/BackOfficeCookieAuthenticationProvider.cs index 26b85d6c39..6ce61c90d6 100644 --- a/src/Umbraco.Web/Security/BackOfficeCookieAuthenticationProvider.cs +++ b/src/Umbraco.Web/Security/BackOfficeCookieAuthenticationProvider.cs @@ -1,11 +1,13 @@ using System; using System.Security.Claims; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Microsoft.Owin; using Microsoft.Owin.Security.Cookies; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Services; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Hosting; @@ -19,23 +21,23 @@ namespace Umbraco.Web.Security { private readonly IUserService _userService; private readonly IRuntimeState _runtimeState; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly ISecuritySettings _securitySettings; + private readonly SecuritySettings _securitySettings; - public BackOfficeCookieAuthenticationProvider(IUserService userService, IRuntimeState runtimeState, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, ISecuritySettings securitySettings) + public BackOfficeCookieAuthenticationProvider(IUserService userService, IRuntimeState runtimeState, GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IOptions securitySettings) { _userService = userService; _runtimeState = runtimeState; _globalSettings = globalSettings; _hostingEnvironment = hostingEnvironment; - _securitySettings = securitySettings; + _securitySettings = securitySettings.Value; } public override void ResponseSignOut(CookieResponseSignOutContext context) { - + } diff --git a/src/Umbraco.Web/Security/BackOfficeOwinUserManager.cs b/src/Umbraco.Web/Security/BackOfficeOwinUserManager.cs index 771c3239b6..65d7836d42 100644 --- a/src/Umbraco.Web/Security/BackOfficeOwinUserManager.cs +++ b/src/Umbraco.Web/Security/BackOfficeOwinUserManager.cs @@ -8,6 +8,7 @@ using Microsoft.Owin.Security.DataProtection; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Security; using Umbraco.Core.Services; @@ -20,7 +21,7 @@ namespace Umbraco.Web.Security public const string OwinMarkerKey = "Umbraco.Web.Security.Identity.BackOfficeUserManagerMarker"; public BackOfficeOwinUserManager( - IUserPasswordConfiguration passwordConfiguration, + IOptions passwordConfiguration, IIpResolver ipResolver, IUserStore store, IOptions optionsAccessor, @@ -32,7 +33,7 @@ namespace Umbraco.Web.Security ILogger> logger) : base(ipResolver, store, optionsAccessor, null, userValidators, passwordValidators, keyNormalizer, errors, null, logger, passwordConfiguration) { - PasswordConfiguration = passwordConfiguration; + PasswordConfiguration = passwordConfiguration.Value; InitUserManager(this, dataProtectionProvider); } @@ -45,9 +46,9 @@ namespace Umbraco.Web.Security IUserService userService, IEntityService entityService, IExternalLoginService externalLoginService, - IGlobalSettings globalSettings, + IOptions globalSettings, UmbracoMapper mapper, - IUserPasswordConfiguration passwordConfiguration, + IOptions passwordConfiguration, IIpResolver ipResolver, BackOfficeIdentityErrorDescriber errors, IDataProtectionProvider dataProtectionProvider, @@ -68,7 +69,7 @@ namespace Umbraco.Web.Security /// Creates a BackOfficeUserManager instance with all default options and a custom BackOfficeUserManager instance ///
public static BackOfficeOwinUserManager Create( - IUserPasswordConfiguration passwordConfiguration, + IOptions passwordConfiguration, IIpResolver ipResolver, IUserStore customUserStore, BackOfficeIdentityErrorDescriber errors, @@ -83,11 +84,11 @@ namespace Umbraco.Web.Security // Configure validation logic for passwords var passwordValidators = new List> { new PasswordValidator() }; - options.Password.RequiredLength = passwordConfiguration.RequiredLength; - options.Password.RequireNonAlphanumeric = passwordConfiguration.RequireNonLetterOrDigit; - options.Password.RequireDigit = passwordConfiguration.RequireDigit; - options.Password.RequireLowercase = passwordConfiguration.RequireLowercase; - options.Password.RequireUppercase = passwordConfiguration.RequireUppercase; + options.Password.RequiredLength = passwordConfiguration.Value.RequiredLength; + options.Password.RequireNonAlphanumeric = passwordConfiguration.Value.RequireNonLetterOrDigit; + options.Password.RequireDigit = passwordConfiguration.Value.RequireDigit; + options.Password.RequireLowercase = passwordConfiguration.Value.RequireLowercase; + options.Password.RequireUppercase = passwordConfiguration.Value.RequireUppercase; // Ensure Umbraco security stamp claim type is used options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier; @@ -96,7 +97,7 @@ namespace Umbraco.Web.Security options.ClaimsIdentity.SecurityStampClaimType = Constants.Security.SecurityStampClaimType; options.Lockout.AllowedForNewUsers = true; - options.Lockout.MaxFailedAccessAttempts = passwordConfiguration.MaxFailedAccessAttemptsBeforeLockout; + options.Lockout.MaxFailedAccessAttempts = passwordConfiguration.Value.MaxFailedAccessAttemptsBeforeLockout; //NOTE: This just needs to be in the future, we currently don't support a lockout timespan, it's either they are locked // or they are not locked, but this determines what is set on the account lockout date which corresponds to whether they are // locked out or not. diff --git a/src/Umbraco.Web/Security/BackOfficeSignInManager.cs b/src/Umbraco.Web/Security/BackOfficeSignInManager.cs index 021adaed97..8c14d2544f 100644 --- a/src/Umbraco.Web/Security/BackOfficeSignInManager.cs +++ b/src/Umbraco.Web/Security/BackOfficeSignInManager.cs @@ -9,8 +9,7 @@ using Microsoft.Owin.Logging; using Microsoft.Owin.Security; using Umbraco.Core; using Umbraco.Core.BackOffice; -using Umbraco.Core.Configuration; -using Umbraco.Core.BackOffice; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Web.Security { @@ -21,19 +20,19 @@ namespace Umbraco.Web.Security ///
public class BackOfficeSignInManager : IDisposable { - private readonly BackOfficeUserManager _userManager; + private readonly IBackOfficeUserManager _userManager; private readonly IUserClaimsPrincipalFactory _claimsPrincipalFactory; private readonly IAuthenticationManager _authenticationManager; private readonly ILogger _logger; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IOwinRequest _request; public BackOfficeSignInManager( - BackOfficeUserManager userManager, + IBackOfficeUserManager userManager, IUserClaimsPrincipalFactory claimsPrincipalFactory, IAuthenticationManager authenticationManager, ILogger logger, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IOwinRequest request) { _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); @@ -52,7 +51,7 @@ namespace Umbraco.Web.Security return claimsPrincipal.Identity as ClaimsIdentity; } - public static BackOfficeSignInManager Create(IOwinContext context, IGlobalSettings globalSettings, ILogger logger) + public static BackOfficeSignInManager Create(IOwinContext context, GlobalSettings globalSettings, ILogger logger) { var userManager = context.GetBackOfficeUserManager(); @@ -248,7 +247,7 @@ namespace Umbraco.Web.Security } return null; } - + /// /// Two factor verification step /// diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/BackofficeSecurity.cs similarity index 95% rename from src/Umbraco.Web/Security/WebSecurity.cs rename to src/Umbraco.Web/Security/BackofficeSecurity.cs index 5776ec876a..e5e46ea37f 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/BackofficeSecurity.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web.Security { // NOTE: Moved to netcore - public class WebSecurity : IWebSecurity + public class BackofficeSecurity : IBackofficeSecurity { public IUser CurrentUser => throw new NotImplementedException(); diff --git a/src/Umbraco.Web/Security/ExternalSignInAutoLinkOptions.cs b/src/Umbraco.Web/Security/ExternalSignInAutoLinkOptions.cs index fc84cd270d..52239f0fda 100644 --- a/src/Umbraco.Web/Security/ExternalSignInAutoLinkOptions.cs +++ b/src/Umbraco.Web/Security/ExternalSignInAutoLinkOptions.cs @@ -23,7 +23,7 @@ namespace Umbraco.Web.Security { _defaultUserGroups = defaultUserGroups ?? new[] { Constants.Security.EditorGroupAlias }; _autoLinkExternalAccount = autoLinkExternalAccount; - _defaultCulture = defaultCulture ?? Current.Configs.Global().DefaultUILanguage; + _defaultCulture = defaultCulture ?? /*Current.Configs.Global().DefaultUILanguage TODO reintroduce config value*/ "en-US"; } private readonly string[] _defaultUserGroups; diff --git a/src/Umbraco.Web/Security/GetUserSecondsMiddleWare.cs b/src/Umbraco.Web/Security/GetUserSecondsMiddleWare.cs index 3ab37f0f70..62724a4846 100644 --- a/src/Umbraco.Web/Security/GetUserSecondsMiddleWare.cs +++ b/src/Umbraco.Web/Security/GetUserSecondsMiddleWare.cs @@ -3,14 +3,13 @@ using System.Diagnostics; using System.Globalization; using System.Threading.Tasks; using System.Web; +using Microsoft.Extensions.Options; using Microsoft.Owin; using Microsoft.Owin.Logging; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using Umbraco.Core.Security; namespace Umbraco.Web.Security { @@ -25,23 +24,23 @@ namespace Umbraco.Web.Security internal class GetUserSecondsMiddleWare : OwinMiddleware { private readonly UmbracoBackOfficeCookieAuthOptions _authOptions; - private readonly IGlobalSettings _globalSettings; - private readonly ISecuritySettings _security; + private readonly GlobalSettings _globalSettings; + private readonly SecuritySettings _security; private readonly ILogger _logger; private readonly IHostingEnvironment _hostingEnvironment; public GetUserSecondsMiddleWare( OwinMiddleware next, UmbracoBackOfficeCookieAuthOptions authOptions, - IGlobalSettings globalSettings, - ISecuritySettings security, + GlobalSettings globalSettings, + IOptions security, ILogger logger, IHostingEnvironment hostingEnvironment) : base(next) { _authOptions = authOptions ?? throw new ArgumentNullException(nameof(authOptions)); _globalSettings = globalSettings; - _security = security; + _security = security.Value; _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _hostingEnvironment = hostingEnvironment; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 5d663b64c2..739bd2c95e 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -66,14 +66,14 @@ 2.0.0-alpha.20200128.15 - + - 4.0.217 + 5.0.343 2.7.0.100 - + @@ -83,11 +83,14 @@ - + - - + + + + + @@ -96,7 +99,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + @@ -104,16 +107,12 @@ runtime; build; native; contentfiles; analyzers all - + 1.0.5 - - {fbe7c065-dac0-4025-a78b-63b24d3ab00b} - Umbraco.Configuration - {29aa69d9-b597-4395-8d42-43b1263c240a} Umbraco.Core @@ -149,7 +148,6 @@ - @@ -159,7 +157,7 @@ - + @@ -176,7 +174,6 @@ - @@ -184,7 +181,6 @@ - @@ -244,7 +240,6 @@ - @@ -298,9 +293,7 @@ - - @@ -413,6 +406,8 @@ Mvc\web.config - + + + \ No newline at end of file diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index 6334f96d4b..989dcfaf83 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -1,19 +1,15 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading; +using System.Runtime.InteropServices; using System.Web; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Logging.Serilog; -using Umbraco.Core.Runtime; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Runtime; using Umbraco.Web.Runtime; +using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; namespace Umbraco.Web { @@ -22,15 +18,10 @@ namespace Umbraco.Web ///
public class UmbracoApplication : UmbracoApplicationBase { - protected override IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) + protected override IRuntime GetRuntime(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) { - - var connectionStringConfig = configs.ConnectionStrings()[Constants.System.UmbracoConnectionName]; - var dbProviderFactoryCreator = new UmbracoDbProviderFactoryCreator(); - var globalSettings = configs.Global(); - var connectionStrings = configs.ConnectionStrings(); // Determine if we should use the sql main dom or the default var appSettingMainDomLock = globalSettings.MainDomLock; @@ -43,9 +34,14 @@ namespace Umbraco.Web var mainDom = new MainDom(logger, mainDomLock); var requestCache = new HttpRequestAppCache(() => HttpContext.Current != null ? HttpContext.Current.Items : null); + var appCaches = new AppCaches( + new DeepCloneAppCache(new ObjectCacheAppCache()), + requestCache, + new IsolatedCaches(type => new DeepCloneAppCache(new ObjectCacheAppCache()))); + var umbracoBootPermissionChecker = new AspNetUmbracoBootPermissionChecker(); - return new CoreRuntime(configs, umbracoVersion, ioHelper, logger, profiler, umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, - GetTypeFinder(hostingEnvironment, logger, profiler), requestCache); + return new CoreRuntime(globalSettings, connectionStrings,umbracoVersion, ioHelper, logger, profiler, umbracoBootPermissionChecker, hostingEnvironment, backOfficeInfo, dbProviderFactoryCreator, mainDom, + GetTypeFinder(hostingEnvironment, logger, profiler), appCaches); } diff --git a/src/Umbraco.Web/UmbracoApplicationBase.cs b/src/Umbraco.Web/UmbracoApplicationBase.cs index 1c447b38aa..f144a52761 100644 --- a/src/Umbraco.Web/UmbracoApplicationBase.cs +++ b/src/Umbraco.Web/UmbracoApplicationBase.cs @@ -1,24 +1,27 @@ -using Serilog.Context; -using System; +using System; using System.IO; using System.Reflection; using System.Threading; using System.Web; using System.Web.Hosting; +using Microsoft.Extensions.Options; +using Serilog.Context; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Logging.Serilog.Enrichers; using Umbraco.Net; -using Umbraco.Web.AspNet; using Umbraco.Web.Hosting; using Umbraco.Web.Logging; +using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; using Current = Umbraco.Web.Composing.Current; +using GlobalSettings = Umbraco.Core.Configuration.Models.GlobalSettings; namespace Umbraco.Web { @@ -27,6 +30,9 @@ namespace Umbraco.Web /// public abstract class UmbracoApplicationBase : HttpApplication { + private readonly SecuritySettings _securitySettings; + private readonly GlobalSettings _globalSettings; + private readonly ConnectionStrings _connectionStrings; private IRuntime _runtime; private IFactory _factory; @@ -34,24 +40,25 @@ namespace Umbraco.Web { if (!Umbraco.Composing.Current.IsInitialized) { - var configFactory = new ConfigsFactory(); + HostingSettings hostingSettings = null; + GlobalSettings globalSettings = null; + SecuritySettings securitySettings = null; + WebRoutingSettings webRoutingSettings = null; - var hostingSettings = configFactory.HostingSettings; - var globalSettings = configFactory.GlobalSettings; - - var hostingEnvironment = new AspNetHostingEnvironment(hostingSettings); + var hostingEnvironment = new AspNetHostingEnvironment(Options.Create(hostingSettings)); var loggingConfiguration = new LoggingConfiguration( Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "App_Data\\Logs"), Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "config\\serilog.config"), Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "config\\serilog.user.config")); - var ioHelper = new IOHelper(hostingEnvironment, globalSettings); + var ioHelper = new IOHelper(hostingEnvironment); var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration); - var configs = configFactory.Create(); - - var backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, ioHelper, logger, configFactory.WebRoutingSettings); + var backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, ioHelper, logger, Options.Create(webRoutingSettings)); var profiler = GetWebProfiler(hostingEnvironment); - Umbraco.Composing.Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler); + Umbraco.Composing.Current.Initialize(logger, + securitySettings, + globalSettings, + ioHelper, hostingEnvironment, backOfficeInfo, profiler); Logger = logger; } } @@ -72,12 +79,16 @@ namespace Umbraco.Web return webProfiler; } - protected UmbracoApplicationBase(ILogger logger, Configs configs, IIOHelper ioHelper, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) + protected UmbracoApplicationBase(ILogger logger, SecuritySettings securitySettings, GlobalSettings globalSettings, ConnectionStrings connectionStrings, IIOHelper ioHelper, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) { + _securitySettings = securitySettings; + _globalSettings = globalSettings; + _connectionStrings = connectionStrings; + if (!Umbraco.Composing.Current.IsInitialized) { Logger = logger; - Umbraco.Composing.Current.Initialize(logger, configs, ioHelper, hostingEnvironment, backOfficeInfo, profiler); + Umbraco.Composing.Current.Initialize(logger, securitySettings, globalSettings, ioHelper, hostingEnvironment, backOfficeInfo, profiler); } } @@ -120,12 +131,12 @@ namespace Umbraco.Web /// /// Gets a runtime. /// - protected abstract IRuntime GetRuntime(Configs configs, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo); + protected abstract IRuntime GetRuntime(GlobalSettings globalSettings, ConnectionStrings connectionStrings, IUmbracoVersion umbracoVersion, IIOHelper ioHelper, ILogger logger, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo); /// /// Gets the application register. /// - protected virtual IRegister GetRegister(IGlobalSettings globalSettings) + protected virtual IRegister GetRegister(GlobalSettings globalSettings) { return RegisterFactory.Create(globalSettings); } @@ -159,14 +170,15 @@ namespace Umbraco.Web // ******** THIS IS WHERE EVERYTHING BEGINS ******** - var globalSettings = Umbraco.Composing.Current.Configs.Global(); - var umbracoVersion = new UmbracoVersion(globalSettings); + var globalSettings = _globalSettings; + var umbracoVersion = new UmbracoVersion(); // create the register for the application, and boot // the boot manager is responsible for registrations var register = GetRegister(globalSettings); _runtime = GetRuntime( - Umbraco.Composing.Current.Configs, + _globalSettings, + _connectionStrings, umbracoVersion, Umbraco.Composing.Current.IOHelper, Umbraco.Composing.Current.Logger, diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index ae1cf885b3..a4b6e1dd14 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -1,7 +1,7 @@ using System; using System.Web; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Composing; @@ -17,7 +17,7 @@ namespace Umbraco.Web public class UmbracoContext : DisposableObjectSlim, IDisposeOnRequestEnd, IUmbracoContext { private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly ICookieManager _cookieManager; private readonly Lazy _publishedSnapshot; @@ -30,8 +30,8 @@ namespace Umbraco.Web // warn: does *not* manage setting any IUmbracoContextAccessor internal UmbracoContext(IHttpContextAccessor httpContextAccessor, IPublishedSnapshotService publishedSnapshotService, - IWebSecurity webSecurity, - IGlobalSettings globalSettings, + IBackofficeSecurity backofficeSecurity, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IVariationContextAccessor variationContextAccessor, UriUtility uriUtility, @@ -39,7 +39,7 @@ namespace Umbraco.Web { if (httpContextAccessor == null) throw new ArgumentNullException(nameof(httpContextAccessor)); if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService)); - if (webSecurity == null) throw new ArgumentNullException(nameof(webSecurity)); + if (backofficeSecurity == null) throw new ArgumentNullException(nameof(backofficeSecurity)); VariationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); _httpContextAccessor = httpContextAccessor; _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); @@ -58,7 +58,7 @@ namespace Umbraco.Web ObjectCreated = DateTime.Now; UmbracoRequestId = Guid.NewGuid(); - Security = webSecurity; + Security = backofficeSecurity; // beware - we cannot expect a current user here, so detecting preview mode must be a lazy thing _publishedSnapshot = new Lazy(() => publishedSnapshotService.CreatePublishedSnapshot(PreviewToken)); @@ -87,9 +87,9 @@ namespace Umbraco.Web public Guid UmbracoRequestId { get; } /// - /// Gets the WebSecurity class + /// Gets the BackofficeSecurity class /// - public IWebSecurity Security { get; } + public IBackofficeSecurity Security { get; } /// /// Gets the uri that is handled by ASP.NET after server-side rewriting took place. diff --git a/src/Umbraco.Web/UmbracoContextFactory.cs b/src/Umbraco.Web/UmbracoContextFactory.cs index bfb4dd627d..cc0bd59fa1 100644 --- a/src/Umbraco.Web/UmbracoContextFactory.cs +++ b/src/Umbraco.Web/UmbracoContextFactory.cs @@ -2,6 +2,7 @@ using System.IO; using System.Text; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -20,7 +21,7 @@ namespace Umbraco.Web private readonly IVariationContextAccessor _variationContextAccessor; private readonly IDefaultCultureAccessor _defaultCultureAccessor; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IUserService _userService; private readonly IHostingEnvironment _hostingEnvironment; private readonly IHttpContextAccessor _httpContextAccessor; @@ -35,7 +36,7 @@ namespace Umbraco.Web IPublishedSnapshotService publishedSnapshotService, IVariationContextAccessor variationContextAccessor, IDefaultCultureAccessor defaultCultureAccessor, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IUserService userService, IHostingEnvironment hostingEnvironment, UriUtility uriUtility, @@ -67,7 +68,7 @@ namespace Umbraco.Web _variationContextAccessor.VariationContext = new VariationContext(_defaultCultureAccessor.DefaultCulture); } - return new UmbracoContext(_httpContextAccessor, _publishedSnapshotService, new WebSecurity(), _globalSettings, _hostingEnvironment, _variationContextAccessor, _uriUtility, _cookieManager); + return new UmbracoContext(_httpContextAccessor, _publishedSnapshotService, new BackofficeSecurity(), _globalSettings, _hostingEnvironment, _variationContextAccessor, _uriUtility, _cookieManager); } /// diff --git a/src/Umbraco.Web/UmbracoDefaultOwinStartup.cs b/src/Umbraco.Web/UmbracoDefaultOwinStartup.cs index 600b58cf06..edd429946f 100644 --- a/src/Umbraco.Web/UmbracoDefaultOwinStartup.cs +++ b/src/Umbraco.Web/UmbracoDefaultOwinStartup.cs @@ -1,9 +1,11 @@ using System; +using Microsoft.Extensions.Options; using Microsoft.Owin; using Owin; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Hosting; using Umbraco.Core.IO; @@ -28,9 +30,8 @@ namespace Umbraco.Web public class UmbracoDefaultOwinStartup { protected IUmbracoContextAccessor UmbracoContextAccessor => Current.UmbracoContextAccessor; - protected IGlobalSettings GlobalSettings => Current.Factory.GetInstance(); - protected IContentSettings ContentSettings => Current.Factory.GetInstance(); - protected ISecuritySettings SecuritySettings => Current.Factory.GetInstance(); + protected GlobalSettings GlobalSettings => Current.Factory.GetInstance(); + protected SecuritySettings SecuritySettings => Current.Factory.GetInstance>().Value; protected IUserPasswordConfiguration UserPasswordConfig => Current.Factory.GetInstance(); protected IRuntimeState RuntimeState => Current.RuntimeState; protected ServiceContext Services => Current.Services; diff --git a/src/Umbraco.Web/UmbracoHttpHandler.cs b/src/Umbraco.Web/UmbracoHttpHandler.cs index eb219f82d2..7db09b62ff 100644 --- a/src/Umbraco.Web/UmbracoHttpHandler.cs +++ b/src/Umbraco.Web/UmbracoHttpHandler.cs @@ -52,7 +52,7 @@ namespace Umbraco.Web /// /// Gets the web security helper. /// - public IWebSecurity Security => UmbracoContextAccessor.UmbracoContext.Security; + public IBackofficeSecurity Security => UmbracoContextAccessor.UmbracoContext.Security; /// /// Gets the Url helper. diff --git a/src/Umbraco.Web/UmbracoInjectedModule.cs b/src/Umbraco.Web/UmbracoInjectedModule.cs index ecb67c997d..06b8953338 100644 --- a/src/Umbraco.Web/UmbracoInjectedModule.cs +++ b/src/Umbraco.Web/UmbracoInjectedModule.cs @@ -1,18 +1,16 @@ using System; -using System.Collections.Generic; using System.Web; using System.Web.Routing; using Umbraco.Core; -using Umbraco.Core.Security; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Exceptions; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Security; using Umbraco.Web.Composing; using Umbraco.Web.Routing; -using Umbraco.Web.Security; namespace Umbraco.Web { @@ -39,7 +37,7 @@ namespace Umbraco.Web private readonly IUmbracoContextFactory _umbracoContextFactory; private readonly RoutableDocumentFilter _routableDocumentLookup; private readonly IRequestCache _requestCache; - private readonly IGlobalSettings _globalSettings; + private readonly GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private readonly UriUtility _uriUtility; @@ -51,7 +49,7 @@ namespace Umbraco.Web RoutableDocumentFilter routableDocumentLookup, UriUtility uriUtility, IRequestCache requestCache, - IGlobalSettings globalSettings, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) { _runtime = runtime; @@ -297,7 +295,7 @@ namespace Umbraco.Web } - + #endregion #region IHttpModule diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 2dffe13851..358d213bb8 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -75,7 +75,7 @@ namespace Umbraco.Web else if (pcr.Is404) { response.StatusCode = 404; - response.TrySkipIisCustomErrors = Current.Configs.WebRouting().TrySkipIisCustomErrors; + response.TrySkipIisCustomErrors = /*Current.Configs.WebRouting().TrySkipIisCustomErrors; TODO introduce from config*/ false; if (response.TrySkipIisCustomErrors == false) logger.Warn("Status code is 404 yet TrySkipIisCustomErrors is false - IIS will take over."); diff --git a/src/Umbraco.Web/UmbracoWebService.cs b/src/Umbraco.Web/UmbracoWebService.cs index 916ab5ad8e..9dca6f5d33 100644 --- a/src/Umbraco.Web/UmbracoWebService.cs +++ b/src/Umbraco.Web/UmbracoWebService.cs @@ -1,13 +1,7 @@ -using System; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; +using System.Web.Mvc; using System.Web.Services; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Security; @@ -21,7 +15,7 @@ namespace Umbraco.Web { private UrlHelper _url; - protected UmbracoWebService(IProfilingLogger profilingLogger, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, IGlobalSettings globalSettings) + protected UmbracoWebService(IProfilingLogger profilingLogger, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, GlobalSettings globalSettings) { Logger = profilingLogger; ProfilingLogger = profilingLogger; @@ -31,7 +25,7 @@ namespace Umbraco.Web } protected UmbracoWebService() - : this(Current.ProfilingLogger, Current.UmbracoContextAccessor, Current.Services, Current.Configs.Global()) + : this(Current.ProfilingLogger, Current.UmbracoContextAccessor, Current.Services, new GlobalSettings()) { } @@ -63,12 +57,12 @@ namespace Umbraco.Web /// /// Gets the global settings. /// - public IGlobalSettings GlobalSettings { get; } + public GlobalSettings GlobalSettings { get; } /// /// Gets the web security helper. /// - public IWebSecurity Security => UmbracoContext.Security; + public IBackofficeSecurity Security => UmbracoContext.Security; /// /// Gets the Url helper. diff --git a/src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs b/src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs deleted file mode 100644 index 09fd5e080c..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; -using Umbraco.Core; -using Umbraco.Web.Composing; -using Umbraco.Core.BackOffice; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Security; -using Umbraco.Web.Security; -using Umbraco.Core.Mapping; -using Umbraco.Core.Models; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// This filter will check if the current Principal/Identity assigned to the request has stale data in it compared - /// to what is persisted for the current user and will update the current auth ticket with the correct data if required and output - /// a custom response header for the UI to be notified of it. - /// - /// - /// This could/should be created as a filter on the BackOfficeCookieAuthenticationProvider just like the SecurityStampValidator does - /// - public sealed class CheckIfUserTicketDataIsStaleAttribute : ActionFilterAttribute - { - // this is an attribute - no choice - private UmbracoMapper Mapper => Current.Mapper; - - public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken) - { - await CheckStaleData(actionContext); - } - - public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken) - { - await CheckStaleData(actionExecutedContext.ActionContext); - - //we need new tokens and append the custom header if changes have been made - if (actionExecutedContext.ActionContext.Request.Properties.ContainsKey(typeof(CheckIfUserTicketDataIsStaleAttribute).Name)) - { - var tokenFilter = new SetAngularAntiForgeryTokensAttribute(); - tokenFilter.OnActionExecuted(actionExecutedContext); - - //add the header - AppendUserModifiedHeaderAttribute.AppendHeader(actionExecutedContext); - } - } - - private async Task CheckStaleData(HttpActionContext actionContext) - { - if (actionContext == null - || actionContext.Request == null - || actionContext.RequestContext == null - || actionContext.RequestContext.Principal == null - || actionContext.RequestContext.Principal.Identity == null) - { - return; - } - - //don't execute if it's already been done - if (actionContext.Request.Properties.ContainsKey(typeof(CheckIfUserTicketDataIsStaleAttribute).Name)) - return; - - var identity = actionContext.RequestContext.Principal.Identity as UmbracoBackOfficeIdentity; - if (identity == null) return; - - var userId = identity.Id.TryConvertTo(); - if (userId == false) return; - - var user = Current.Services.UserService.GetUserById(userId.Result); - if (user == null) return; - - //a list of checks to execute, if any of them pass then we resync - var checks = new Func[] - { - () => user.Username != identity.Username, - () => - { - var culture = user.GetUserCulture(Current.Services.TextService, Current.Configs.Global()); - return culture != null && culture.ToString() != identity.Culture; - }, - () => user.AllowedSections.UnsortedSequenceEqual(identity.AllowedApplications) == false, - () => user.Groups.Select(x => x.Alias).UnsortedSequenceEqual(identity.Roles) == false, - () => - { - var startContentIds = user.CalculateContentStartNodeIds(Current.Services.EntityService); - return startContentIds.UnsortedSequenceEqual(identity.StartContentNodes) == false; - }, - () => - { - var startMediaIds = user.CalculateMediaStartNodeIds(Current.Services.EntityService); - return startMediaIds.UnsortedSequenceEqual(identity.StartMediaNodes) == false; - } - }; - - if (checks.Any(check => check())) - { - await ReSync(user, actionContext); - } - } - - /// - /// This will update the current request IPrincipal to be correct and re-create the auth ticket - /// - /// - /// - /// - private async Task ReSync(IUser user, HttpActionContext actionContext) - { - var owinCtx = actionContext.Request.TryGetOwinContext(); - if (owinCtx) - { - var signInManager = owinCtx.Result.GetBackOfficeSignInManager(); - - var backOfficeIdentityUser = Mapper.Map(user); - await signInManager.SignInAsync(backOfficeIdentityUser, isPersistent: true, rememberBrowser: false); - - //ensure the remainder of the request has the correct principal set - actionContext.Request.SetPrincipalForRequest(owinCtx.Result.Request.User); - - //flag that we've made changes - actionContext.Request.Properties[typeof(CheckIfUserTicketDataIsStaleAttribute).Name] = true; - } - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/SetAngularAntiForgeryTokensAttribute.cs b/src/Umbraco.Web/WebApi/Filters/SetAngularAntiForgeryTokensAttribute.cs deleted file mode 100644 index dadf2367b6..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/SetAngularAntiForgeryTokensAttribute.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Web.Http.Filters; -using Umbraco.Core; -using Umbraco.Web.Composing; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// A filter to set the csrf cookie token based on angular conventions - /// - public sealed class SetAngularAntiForgeryTokensAttribute : ActionFilterAttribute - { - public override void OnActionExecuted(HttpActionExecutedContext context) - { - if (context.Response == null) return; - - //DO not set the token cookies if the request has failed!! - if (context.Response.StatusCode != HttpStatusCode.OK) return; - - //don't need to set the cookie if they already exist and they are valid - if (context.Request.Headers.GetCookies(Constants.Web.AngularCookieName).Any() - && context.Request.Headers.GetCookies(Constants.Web.CsrfValidationCookieName).Any()) - { - //if they are not valid for some strange reason - we need to continue setting valid ones - string failedReason; - if (AngularAntiForgeryHelper.ValidateHeaders(context.Request.Headers, out failedReason)) - { - return; - } - } - - string cookieToken, headerToken; - AngularAntiForgeryHelper.GetTokens(out cookieToken, out headerToken); - - //We need to set 2 cookies: one is the cookie value that angular will use to set a header value on each request, - // the 2nd is the validation value generated by the anti-forgery helper that we use to validate the header token against. - - var angularCookie = new CookieHeaderValue(Constants.Web.AngularCookieName, headerToken) - { - Path = "/", - //must be js readable - HttpOnly = false, - Secure = Current.Configs.Global().UseHttps - }; - - var validationCookie = new CookieHeaderValue(Constants.Web.CsrfValidationCookieName, cookieToken) - { - Path = "/", - HttpOnly = true, - Secure = Current.Configs.Global().UseHttps - }; - - context.Response.Headers.AddCookies(new[] { angularCookie, validationCookie }); - } - } -} diff --git a/src/Umbraco.Web/WebApi/HttpControllerContextExtensions.cs b/src/Umbraco.Web/WebApi/HttpControllerContextExtensions.cs deleted file mode 100644 index 323e52eb36..0000000000 --- a/src/Umbraco.Web/WebApi/HttpControllerContextExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using System.Web.Http; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; -using Umbraco.Web.WebApi.Filters; - -namespace Umbraco.Web.WebApi -{ - internal static class HttpControllerContextExtensions - { - /// - /// Invokes the authorization filters for the controller action. - /// - /// The response of the first filter returning a result, if any, otherwise null (authorized). - internal static async Task InvokeAuthorizationFiltersForRequest(this HttpControllerContext controllerContext) - { - var controllerDescriptor = controllerContext.ControllerDescriptor; - var controllerServices = controllerDescriptor.Configuration.Services; - var actionDescriptor = controllerServices.GetActionSelector().SelectAction(controllerContext); - - var filters = actionDescriptor.GetFilterPipeline(); - var filterGrouping = new FilterGrouping(filters); - - // because the continuation gets built from the inside out we need to reverse the filter list - // so that least specific filters (Global) get run first and the most specific filters (Action) get run last. - var authorizationFilters = filterGrouping.AuthorizationFilters.Reverse().ToList(); - - if (authorizationFilters.Count == 0) - return null; - - // if the authorization filter returns a result, it means it failed to authorize - var actionContext = new HttpActionContext(controllerContext, actionDescriptor); - return await ExecuteAuthorizationFiltersAsync(actionContext, CancellationToken.None, authorizationFilters); - } - - /// - /// Executes a chain of filters. - /// - /// - /// Recursively calls in to itself as its continuation for the next filter in the chain. - /// - private static async Task ExecuteAuthorizationFiltersAsync(HttpActionContext actionContext, CancellationToken token, IList filters, int index = 0) - { - return await filters[index].ExecuteAuthorizationFilterAsync(actionContext, token, - () => ++index == filters.Count - ? Task.FromResult(null) - : ExecuteAuthorizationFiltersAsync(actionContext, token, filters, index)); - } - } -} diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index a832b4e823..724ea810c9 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -3,6 +3,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Persistence; @@ -20,7 +21,7 @@ namespace Umbraco.Web.WebApi { } - protected UmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) + protected UmbracoApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { } diff --git a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs index d009528bc7..3434d825fe 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiControllerBase.cs @@ -6,6 +6,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Web.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Persistence; @@ -38,7 +39,7 @@ namespace Umbraco.Web.WebApi /// Dependencies are obtained from the service locator. protected UmbracoApiControllerBase() : this( - Current.Factory.GetInstance(), + Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), Current.Factory.GetInstance(), @@ -53,10 +54,9 @@ namespace Umbraco.Web.WebApi /// /// Initializes a new instance of the class with all its dependencies. /// - protected UmbracoApiControllerBase(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) + protected UmbracoApiControllerBase(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) { UmbracoContextAccessor = umbracoContextAccessor; - GlobalSettings = globalSettings; SqlContext = sqlContext; Services = services; AppCaches = appCaches; @@ -72,11 +72,6 @@ namespace Umbraco.Web.WebApi /// For debugging purposes. internal Guid InstanceId { get; } = Guid.NewGuid(); - /// - /// Gets the Umbraco context. - /// - public virtual IGlobalSettings GlobalSettings { get; } - /// /// Gets the Umbraco context. /// @@ -123,7 +118,7 @@ namespace Umbraco.Web.WebApi /// /// Gets the web security helper. /// - public IWebSecurity Security => UmbracoContext.Security; + public IBackofficeSecurity Security => UmbracoContext.Security; /// /// Tries to get the current HttpContext. diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs index 69c697d0fc..83f08660d9 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs @@ -1,6 +1,7 @@ using System; using System.Web.Http; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Web.Composing; using Umbraco.Web.Security; @@ -19,21 +20,21 @@ namespace Umbraco.Web.WebApi internal static bool Enable = true; // TODO: inject! - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly IRuntimeState _runtimeState; private IRuntimeState RuntimeState => _runtimeState ?? Current.RuntimeState; - private IWebSecurity WebSecurity => _webSecurity ?? Current.UmbracoContext.Security; + private IBackofficeSecurity BackofficeSecurity => _backofficeSecurityAccessor.BackofficeSecurity ?? Current.UmbracoContext.Security; /// /// THIS SHOULD BE ONLY USED FOR UNIT TESTS /// - /// + /// /// - public UmbracoAuthorizeAttribute(IWebSecurity webSecurity, IRuntimeState runtimeState) + public UmbracoAuthorizeAttribute(IBackofficeSecurityAccessor backofficeSecurityAccessor, IRuntimeState runtimeState) { - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor)); _runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState)); } @@ -58,7 +59,7 @@ namespace Umbraco.Web.WebApi // otherwise we need to ensure that a user is logged in return RuntimeState.Level == RuntimeLevel.Install || RuntimeState.Level == RuntimeLevel.Upgrade - || WebSecurity.ValidateCurrentUser(false, _requireApproval) == ValidateRequestAttempt.Success; + || BackofficeSecurity.ValidateCurrentUser(false, _requireApproval) == ValidateRequestAttempt.Success; } catch (Exception) { diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index 48b3de44fd..7858d6955a 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -1,6 +1,7 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Web.WebApi.Filters; using Umbraco.Core.Persistence; @@ -24,7 +25,7 @@ namespace Umbraco.Web.WebApi [UmbracoAuthorize] [DisableBrowserCache] // [UmbracoWebApiRequireHttps] - [CheckIfUserTicketDataIsStale] + // [CheckIfUserTicketDataIsStale] [UnhandedExceptionLoggerConfiguration] [EnableDetailedErrors] public abstract class UmbracoAuthorizedApiController : UmbracoApiController @@ -35,7 +36,7 @@ namespace Umbraco.Web.WebApi { } - protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) + protected UmbracoAuthorizedApiController(GlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoMapper umbracoMapper, IPublishedUrlProvider publishedUrlProvider) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) { } diff --git a/src/Umbraco.Web/WebAssets/CDF/ClientDependencyComponent.cs b/src/Umbraco.Web/WebAssets/CDF/ClientDependencyComponent.cs index 0d8d4b8bf2..47dd0908dd 100644 --- a/src/Umbraco.Web/WebAssets/CDF/ClientDependencyComponent.cs +++ b/src/Umbraco.Web/WebAssets/CDF/ClientDependencyComponent.cs @@ -3,9 +3,11 @@ using System.Collections.Specialized; using System.IO; using ClientDependency.Core.CompositeFiles.Providers; using ClientDependency.Core.Config; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Web.Runtime; @@ -14,18 +16,18 @@ namespace Umbraco.Web.WebAssets.CDF [ComposeAfter(typeof(WebInitialComponent))] public sealed class ClientDependencyComponent : IComponent { - private readonly IHostingSettings _hostingSettings; + private readonly HostingSettings _hostingSettings; private readonly IHostingEnvironment _hostingEnvironment; - private readonly IRuntimeSettings _settings; + private readonly RuntimeSettings _settings; public ClientDependencyComponent( - IHostingSettings hostingSettings, + IOptions hostingSettings, IHostingEnvironment hostingEnvironment, - IRuntimeSettings settings) + IOptions settings) { - _hostingSettings = hostingSettings; + _hostingSettings = hostingSettings.Value; _hostingEnvironment = hostingEnvironment; - _settings = settings; + _settings = settings.Value; } public void Initialize() diff --git a/src/Umbraco.Web/WebAssets/CDF/UmbracoClientDependencyLoader.cs b/src/Umbraco.Web/WebAssets/CDF/UmbracoClientDependencyLoader.cs index a89cf8f908..a0704140f1 100644 --- a/src/Umbraco.Web/WebAssets/CDF/UmbracoClientDependencyLoader.cs +++ b/src/Umbraco.Web/WebAssets/CDF/UmbracoClientDependencyLoader.cs @@ -2,6 +2,7 @@ using ClientDependency.Core.Controls; using ClientDependency.Core.FileRegistration.Providers; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; namespace Umbraco.Web.WebAssets.CDF @@ -15,7 +16,7 @@ namespace Umbraco.Web.WebAssets.CDF /// /// Set the defaults /// - public UmbracoClientDependencyLoader(IGlobalSettings globalSettings, IIOHelper ioHelper) + public UmbracoClientDependencyLoader(GlobalSettings globalSettings, IIOHelper ioHelper) : base() { this.AddPath("UmbracoRoot", ioHelper.ResolveUrl(globalSettings.UmbracoPath)); @@ -23,7 +24,7 @@ namespace Umbraco.Web.WebAssets.CDF } - public static ClientDependencyLoader TryCreate(Control parent, out bool isNew, IGlobalSettings globalSettings, IIOHelper ioHelper) + public static ClientDependencyLoader TryCreate(Control parent, out bool isNew, GlobalSettings globalSettings, IIOHelper ioHelper) { if (ClientDependencyLoader.Instance == null) { diff --git a/src/umbraco.sln b/src/umbraco.sln index b2922abf3e..6216b3128b 100644 --- a/src/umbraco.sln +++ b/src/umbraco.sln @@ -137,8 +137,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.ModelsBuilder.Embed EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Infrastructure", "Umbraco.Infrastructure\Umbraco.Infrastructure.csproj", "{3AE7BF57-966B-45A5-910A-954D7C554441}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Configuration", "Umbraco.Configuration\Umbraco.Configuration.csproj", "{FBE7C065-DAC0-4025-A78B-63B24D3AB00B}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Persistance.SqlCe", "Umbraco.Persistance.SqlCe\Umbraco.Persistance.SqlCe.csproj", "{33085570-9BF2-4065-A9B0-A29D920D13BA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.TestData", "Umbraco.TestData\Umbraco.TestData.csproj", "{FB5676ED-7A69-492C-B802-E7B24144C0FC}" @@ -199,10 +197,6 @@ Global {3AE7BF57-966B-45A5-910A-954D7C554441}.Debug|Any CPU.Build.0 = Debug|Any CPU {3AE7BF57-966B-45A5-910A-954D7C554441}.Release|Any CPU.ActiveCfg = Release|Any CPU {3AE7BF57-966B-45A5-910A-954D7C554441}.Release|Any CPU.Build.0 = Release|Any CPU - {FBE7C065-DAC0-4025-A78B-63B24D3AB00B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FBE7C065-DAC0-4025-A78B-63B24D3AB00B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FBE7C065-DAC0-4025-A78B-63B24D3AB00B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FBE7C065-DAC0-4025-A78B-63B24D3AB00B}.Release|Any CPU.Build.0 = Release|Any CPU {33085570-9BF2-4065-A9B0-A29D920D13BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {33085570-9BF2-4065-A9B0-A29D920D13BA}.Debug|Any CPU.Build.0 = Debug|Any CPU {33085570-9BF2-4065-A9B0-A29D920D13BA}.Release|Any CPU.ActiveCfg = Release|Any CPU