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..8fb2789eea 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/* @@ -187,3 +188,4 @@ cypress.env.json /src/Umbraco.Web.UI.NetCore/App_Data/TEMP/TypesCache/* /src/Umbraco.Web.UI.NetCore/App_Data/TEMP/* /src/Umbraco.Web.UI.NetCore/App_Data/Smidge/Cache/* +/src/Umbraco.Web.UI.NetCore/umbraco/logs diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index 477bb143f9..a88f260431 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -23,44 +23,45 @@ 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..2fea306ce0 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..04f77a556e 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-alpha003", "description": "The version of Umbraco to load using NuGet", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, diff --git a/build/templates/UmbracoSolution/Properties/launchSettings.json b/build/templates/UmbracoSolution/Properties/launchSettings.json new file mode 100644 index 0000000000..130f45dedf --- /dev/null +++ b/build/templates/UmbracoSolution/Properties/launchSettings.json @@ -0,0 +1,26 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:5000", + "sslPort": 5001 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Umbraco.Web.UI.NetCore": { + "commandName": "Project", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index 59c75192b9..0a2e2c5c54 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -19,4 +19,4 @@ using System.Resources; // these are FYI and changed automatically [assembly: AssemblyFileVersion("0.5.0")] -[assembly: AssemblyInformationalVersion("0.5.0-alpha001")] +[assembly: AssemblyInformationalVersion("0.5.0-alpha003")] 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/SmtpSettings.cs b/src/Umbraco.Configuration/Legacy/SmtpSettings.cs deleted file mode 100644 index dce3d85840..0000000000 --- a/src/Umbraco.Configuration/Legacy/SmtpSettings.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Net.Mail; -using Umbraco.Core.Configuration; - -namespace Umbraco.Configuration -{ - public class SmtpSettings : 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.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/Cache/MemberCacheRefresher.cs b/src/Umbraco.Core/Cache/MemberCacheRefresher.cs index 68c89c0bc7..a9a648acff 100644 --- a/src/Umbraco.Core/Cache/MemberCacheRefresher.cs +++ b/src/Umbraco.Core/Cache/MemberCacheRefresher.cs @@ -1,21 +1,37 @@ -using System; +//using Newtonsoft.Json; +using System; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; namespace Umbraco.Web.Cache { - public sealed class MemberCacheRefresher : TypedCacheRefresherBase + public sealed class MemberCacheRefresher : PayloadCacheRefresherBase { private readonly IIdKeyMap _idKeyMap; + private readonly LegacyMemberCacheRefresher _legacyMemberRefresher; - public MemberCacheRefresher(AppCaches appCaches, IIdKeyMap idKeyMap) - : base(appCaches) + public MemberCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IIdKeyMap idKeyMap) + : base(appCaches, serializer) { _idKeyMap = idKeyMap; + _legacyMemberRefresher = new LegacyMemberCacheRefresher(this, appCaches); + } + + public class JsonPayload + { + //[JsonConstructor] + public JsonPayload(int id, string username) + { + Id = id; + Username = username; + } + + public int Id { get; } + public string Username { get; } } #region Define @@ -32,38 +48,45 @@ namespace Umbraco.Web.Cache #region Refresher + public override void Refresh(JsonPayload[] payloads) + { + ClearCache(payloads); + base.Refresh(payloads); + } + public override void Refresh(int id) { - ClearCache(id); + ClearCache(new JsonPayload(id, null)); base.Refresh(id); } public override void Remove(int id) { - ClearCache(id); + ClearCache(new JsonPayload(id, null)); base.Remove(id); } - public override void Refresh(IMember instance) - { - ClearCache(instance.Id); - base.Refresh(instance); - } + [Obsolete("This is no longer used and will be removed from the codebase in the future")] + public void Refresh(IMember instance) => _legacyMemberRefresher.Refresh(instance); - public override void Remove(IMember instance) - { - ClearCache(instance.Id); - base.Remove(instance); - } + [Obsolete("This is no longer used and will be removed from the codebase in the future")] + public void Remove(IMember instance) => _legacyMemberRefresher.Remove(instance); - private void ClearCache(int id) + private void ClearCache(params JsonPayload[] payloads) { - _idKeyMap.ClearCache(id); AppCaches.ClearPartialViewCache(); - var memberCache = AppCaches.IsolatedCaches.Get(); - if (memberCache) - memberCache.Result.Clear(RepositoryCacheKeys.GetKey(id)); + + foreach (var p in payloads) + { + _idKeyMap.ClearCache(p.Id); + if (memberCache) + { + memberCache.Result.Clear(RepositoryCacheKeys.GetKey(p.Id)); + memberCache.Result.Clear(RepositoryCacheKeys.GetKey(p.Username)); + } + } + } #endregion @@ -76,5 +99,38 @@ namespace Umbraco.Web.Cache } #endregion + + #region Backwards Compat + + // TODO: this is here purely for backwards compat but should be removed in netcore + private class LegacyMemberCacheRefresher : TypedCacheRefresherBase + { + private readonly MemberCacheRefresher _parent; + + public LegacyMemberCacheRefresher(MemberCacheRefresher parent, AppCaches appCaches) : base(appCaches) + { + _parent = parent; + } + + public override Guid RefresherUniqueId => _parent.RefresherUniqueId; + + public override string Name => _parent.Name; + + protected override MemberCacheRefresher This => _parent; + + public override void Refresh(IMember instance) + { + _parent.ClearCache(new JsonPayload(instance.Id, instance.Username)); + base.Refresh(instance.Id); + } + + public override void Remove(IMember instance) + { + _parent.ClearCache(new JsonPayload(instance.Id, instance.Username)); + base.Remove(instance); + } + } + + #endregion } } diff --git a/src/Umbraco.Core/Composing/ComponentCollection.cs b/src/Umbraco.Core/Composing/ComponentCollection.cs index 62b240f10f..509962599c 100644 --- a/src/Umbraco.Core/Composing/ComponentCollection.cs +++ b/src/Umbraco.Core/Composing/ComponentCollection.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Logging; namespace Umbraco.Core.Composing @@ -12,22 +13,24 @@ namespace Umbraco.Core.Composing { private const int LogThresholdMilliseconds = 100; - private readonly IProfilingLogger _logger; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; - public ComponentCollection(IEnumerable items, IProfilingLogger logger) + public ComponentCollection(IEnumerable items, IProfilingLogger profilingLogger, ILogger logger) : base(items) { + _profilingLogger = profilingLogger; _logger = logger; } public void Initialize() { - using (_logger.DebugDuration($"Initializing. (log components when >{LogThresholdMilliseconds}ms)", "Initialized.")) + using (_profilingLogger.DebugDuration($"Initializing. (log components when >{LogThresholdMilliseconds}ms)", "Initialized.")) { foreach (var component in this) { var componentType = component.GetType(); - using (_logger.DebugDuration($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) + using (_profilingLogger.DebugDuration($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) { component.Initialize(); } @@ -37,12 +40,12 @@ namespace Umbraco.Core.Composing public void Terminate() { - using (_logger.DebugDuration($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated.")) + using (_profilingLogger.DebugDuration($"Terminating. (log components when >{LogThresholdMilliseconds}ms)", "Terminated.")) { foreach (var component in this.Reverse()) // terminate components in reverse order { var componentType = component.GetType(); - using (_logger.DebugDuration($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) + using (_profilingLogger.DebugDuration($"Terminating {componentType.FullName}.", $"Terminated {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) { try { @@ -51,7 +54,7 @@ namespace Umbraco.Core.Composing } catch (Exception ex) { - _logger.Error(ex, "Error while terminating component {ComponentType}.", componentType.FullName); + _logger.LogError(ex, "Error while terminating component {ComponentType}.", componentType.FullName); } } } diff --git a/src/Umbraco.Core/Composing/Composers.cs b/src/Umbraco.Core/Composing/Composers.cs index 004c2527e6..880b91c61b 100644 --- a/src/Umbraco.Core/Composing/Composers.cs +++ b/src/Umbraco.Core/Composing/Composers.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Text; using Umbraco.Core.Collections; using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Composing { @@ -16,7 +17,8 @@ namespace Umbraco.Core.Composing public class Composers { private readonly Composition _composition; - private readonly IProfilingLogger _logger; + private readonly ILogger _logger; + private readonly IProfilingLogger _profileLogger; private readonly IEnumerable _composerTypes; private readonly IEnumerable _enableDisableAttributes; @@ -28,7 +30,8 @@ namespace Umbraco.Core.Composing /// The composition. /// The types. /// The and/or attributes. - /// The profiling logger. + /// The logger. + /// The profiling logger. /// composition /// or /// composerTypes @@ -36,13 +39,13 @@ namespace Umbraco.Core.Composing /// enableDisableAttributes /// or /// logger - - public Composers(Composition composition, IEnumerable composerTypes, IEnumerable enableDisableAttributes, IProfilingLogger logger) + public Composers(Composition composition, IEnumerable composerTypes, IEnumerable enableDisableAttributes, ILogger logger, IProfilingLogger profileLogger) { _composition = composition ?? throw new ArgumentNullException(nameof(composition)); _composerTypes = composerTypes ?? throw new ArgumentNullException(nameof(composerTypes)); _enableDisableAttributes = enableDisableAttributes ?? throw new ArgumentNullException(nameof(enableDisableAttributes)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _profileLogger = profileLogger; } private class EnableInfo @@ -61,19 +64,19 @@ namespace Umbraco.Core.Composing IEnumerable orderedComposerTypes; - using (_logger.DebugDuration("Preparing composer types.", "Prepared composer types.")) + using (_profileLogger.DebugDuration("Preparing composer types.", "Prepared composer types.")) { orderedComposerTypes = PrepareComposerTypes(); } var composers = InstantiateComposers(orderedComposerTypes); - using (_logger.DebugDuration($"Composing composers. (log when >{LogThresholdMilliseconds}ms)", "Composed composers.")) + using (_profileLogger.DebugDuration($"Composing composers. (log when >{LogThresholdMilliseconds}ms)", "Composed composers.")) { foreach (var composer in composers) { var componentType = composer.GetType(); - using (_logger.DebugDuration($"Composing {componentType.FullName}.", $"Composed {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) + using (_profileLogger.DebugDuration($"Composing {componentType.FullName}.", $"Composed {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds)) { composer.Compose(_composition); } @@ -92,7 +95,7 @@ namespace Umbraco.Core.Composing // bit verbose but should help for troubleshooting //var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine; - _logger.Debug("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes); + _logger.LogDebug("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes); return sortedComposerTypes; } @@ -183,8 +186,8 @@ namespace Umbraco.Core.Composing catch (Exception e) { // in case of an error, force-dump everything to log - _logger.Info("Composer Report:\r\n{ComposerReport}", GetComposersReport(requirements)); - _logger.Error(e, "Failed to sort composers."); + _logger.LogInformation("Composer Report:\r\n{ComposerReport}", GetComposersReport(requirements)); + _logger.LogError(e, "Failed to sort composers."); throw; } @@ -370,7 +373,7 @@ namespace Umbraco.Core.Composing return (IComposer) ctor.Invoke(Array.Empty()); } - using (_logger.DebugDuration("Instantiating composers.", "Instantiated composers.")) + using (_profileLogger.DebugDuration("Instantiating composers.", "Instantiated composers.")) { return types.Select(InstantiateComposer).ToArray(); } 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..003f3ee6a2 100644 --- a/src/Umbraco.Core/Composing/Current.cs +++ b/src/Umbraco.Core/Composing/Current.cs @@ -1,28 +1,34 @@ using System; using System.Runtime.CompilerServices; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging.Abstractions; namespace Umbraco.Composing { public static class Current { - private static ILogger _logger = new NullLogger(); - private static Configs _configs; + private static ILogger _logger = new NullLogger(); 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 ILogger Logger => EnsureInitialized(_logger); 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; } @@ -36,8 +42,9 @@ namespace Umbraco.Composing } public static void Initialize( - ILogger logger, - Configs configs, + ILogger logger, + SecuritySettings securitySettings, + GlobalSettings globalSettings, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, @@ -49,13 +56,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..4cfcd9090c 100644 --- a/src/Umbraco.Core/Composing/TypeFinder.cs +++ b/src/Umbraco.Core/Composing/TypeFinder.cs @@ -6,7 +6,7 @@ using System.Reflection; using System.Security; using System.Text; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Composing { @@ -14,7 +14,7 @@ namespace Umbraco.Core.Composing /// public class TypeFinder : ITypeFinder { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IAssemblyProvider _assemblyProvider; private readonly IRuntimeHash _runtimeHash; private volatile HashSet _localFilteredAssemblyCache; @@ -26,7 +26,7 @@ namespace Umbraco.Core.Composing // used for benchmark tests internal bool QueryWithReferencingAssemblies = true; - public TypeFinder(ILogger logger, IAssemblyProvider assemblyProvider, IRuntimeHash runtimeHash, ITypeFinderConfig typeFinderConfig = null) + public TypeFinder(ILogger logger, IAssemblyProvider assemblyProvider, IRuntimeHash runtimeHash, ITypeFinderConfig typeFinderConfig = null) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _assemblyProvider = assemblyProvider; @@ -156,6 +156,7 @@ namespace Umbraco.Core.Composing "MiniProfiler.", "Owin,", "SQLite", + "ReSharperTestRunner32" // used by resharper testrunner }; /// @@ -296,7 +297,7 @@ namespace Umbraco.Core.Composing } catch (TypeLoadException ex) { - _logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly); + _logger.LogError(ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly); continue; } @@ -371,7 +372,7 @@ namespace Umbraco.Core.Composing } catch (TypeLoadException ex) { - _logger.Error(typeof(TypeFinder), ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly); + _logger.LogError(ex, "Could not query types on {Assembly} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly); continue; } @@ -441,7 +442,7 @@ namespace Umbraco.Core.Composing if (_notifiedLoadExceptionAssemblies.Contains(a.FullName) == false) { _notifiedLoadExceptionAssemblies.Add(a.FullName); - _logger.Warn(typeof (TypeFinder), ex, "Could not load all types from {TypeName}.", a.GetName().Name); + _logger.LogWarning(ex, "Could not load all types from {TypeName}.", a.GetName().Name); } } return rex.Types.WhereNotNull().ToArray(); 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/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index 1d40149936..c7bac236a6 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Collections; using Umbraco.Core.IO; using Umbraco.Core.Logging; using File = System.IO.File; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Composing { @@ -28,7 +29,8 @@ namespace Umbraco.Core.Composing private const string CacheKey = "umbraco-types.list"; private readonly IAppPolicyCache _runtimeCache; - private readonly IProfilingLogger _logger; + private readonly ILogger _logger; + private readonly IProfilingLogger _profilingLogger; private readonly Dictionary _types = new Dictionary(); private readonly object _locko = new object(); @@ -51,8 +53,8 @@ namespace Umbraco.Core.Composing /// Files storage location. /// A profiling logger. /// - public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, IEnumerable assembliesToScan = null) - : this(typeFinder, runtimeCache, localTempPath, logger, true, assembliesToScan) + public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, ILogger logger, IProfilingLogger profilingLogger, IEnumerable assembliesToScan = null) + : this(typeFinder, runtimeCache, localTempPath, logger, profilingLogger, true, assembliesToScan) { } /// @@ -64,12 +66,13 @@ namespace Umbraco.Core.Composing /// A profiling logger. /// Whether to detect changes using hashes. /// - public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, IProfilingLogger logger, bool detectChanges, IEnumerable assembliesToScan = null) + public TypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, DirectoryInfo localTempPath, ILogger logger, IProfilingLogger profilingLogger, bool detectChanges, IEnumerable assembliesToScan = null) { TypeFinder = typeFinder ?? throw new ArgumentNullException(nameof(typeFinder)); _runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache)); _localTempPath = localTempPath; _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger)); _assemblies = assembliesToScan; if (detectChanges) @@ -309,7 +312,7 @@ namespace Umbraco.Core.Composing // internal for tests public void WriteCache() { - _logger.Debug("Writing cache file."); + _logger.LogDebug("Writing cache file."); var typesListFilePath = GetTypesListFilePath(); using (var stream = GetFileStream(typesListFilePath, FileMode.Create, FileAccess.Write, FileShare.None, ListFileOpenWriteTimeout)) using (var writer = new StreamWriter(stream)) @@ -381,7 +384,7 @@ namespace Umbraco.Core.Composing if (--attempts == 0) throw; - _logger.Debug("Attempted to get filestream for file {Path} failed, {NumberOfAttempts} attempts left, pausing for {PauseMilliseconds} milliseconds", path, attempts, pauseMilliseconds); + _logger.LogDebug("Attempted to get filestream for file {Path} failed, {NumberOfAttempts} attempts left, pausing for {PauseMilliseconds} milliseconds", path, attempts, pauseMilliseconds); Thread.Sleep(pauseMilliseconds); } } @@ -402,7 +405,7 @@ namespace Umbraco.Core.Composing if (--attempts == 0) throw; - _logger.Debug("Attempted to delete file {Path} failed, {NumberOfAttempts} attempts left, pausing for {PauseMilliseconds} milliseconds", path, attempts, pauseMilliseconds); + _logger.LogDebug("Attempted to delete file {Path} failed, {NumberOfAttempts} attempts left, pausing for {PauseMilliseconds} milliseconds", path, attempts, pauseMilliseconds); Thread.Sleep(pauseMilliseconds); } } @@ -475,7 +478,7 @@ namespace Umbraco.Core.Composing if (!typeof(IDiscoverable).IsAssignableFrom(typeof(T))) { // warn - _logger.Debug("Running a full, " + (cache ? "" : "non-") + "cached, scan for non-discoverable type {TypeName} (slow).", typeof(T).FullName); + _logger.LogDebug("Running a full, " + (cache ? "" : "non-") + "cached, scan for non-discoverable type {TypeName} (slow).", typeof(T).FullName); return GetTypesInternal( typeof(T), null, @@ -493,7 +496,7 @@ namespace Umbraco.Core.Composing // warn if (!cache) - _logger.Debug("Running a non-cached, filter for discoverable type {TypeName} (slowish).", typeof(T).FullName); + _logger.LogDebug("Running a non-cached, filter for discoverable type {TypeName} (slowish).", typeof(T).FullName); // filter the cached discovered types (and maybe cache the result) return GetTypesInternal( @@ -525,7 +528,7 @@ namespace Umbraco.Core.Composing // if not IDiscoverable, directly get types if (!typeof(IDiscoverable).IsAssignableFrom(typeof(T))) { - _logger.Debug("Running a full, " + (cache ? "" : "non-") + "cached, scan for non-discoverable type {TypeName} / attribute {AttributeName} (slow).", typeof(T).FullName, typeof(TAttribute).FullName); + _logger.LogDebug("Running a full, " + (cache ? "" : "non-") + "cached, scan for non-discoverable type {TypeName} / attribute {AttributeName} (slow).", typeof(T).FullName, typeof(TAttribute).FullName); return GetTypesInternal( typeof(T), typeof(TAttribute), @@ -543,7 +546,7 @@ namespace Umbraco.Core.Composing // warn if (!cache) - _logger.Debug("Running a non-cached, filter for discoverable type {TypeName} / attribute {AttributeName} (slowish).", typeof(T).FullName, typeof(TAttribute).FullName); + _logger.LogDebug("Running a non-cached, filter for discoverable type {TypeName} / attribute {AttributeName} (slowish).", typeof(T).FullName, typeof(TAttribute).FullName); // filter the cached discovered types (and maybe cache the result) return GetTypesInternal( @@ -573,7 +576,7 @@ namespace Umbraco.Core.Composing cache &= specificAssemblies == null; if (!cache) - _logger.Debug("Running a full, non-cached, scan for types / attribute {AttributeName} (slow).", typeof(TAttribute).FullName); + _logger.LogDebug("Running a full, non-cached, scan for types / attribute {AttributeName} (slow).", typeof(TAttribute).FullName); return GetTypesInternal( typeof (object), typeof (TAttribute), @@ -596,7 +599,7 @@ namespace Umbraco.Core.Composing var name = GetName(baseType, attributeType); lock (_locko) - using (_logger.DebugDuration( + using (_profilingLogger.DebugDuration( "Getting " + name, "Got " + name)) // cannot contain typesFound.Count as it's evaluated before the find { @@ -629,7 +632,7 @@ namespace Umbraco.Core.Composing if (typeList != null) { // need to put some logging here to try to figure out why this is happening: http://issues.umbraco.org/issue/U4-3505 - _logger.Debug("Getting {TypeName}: found a cached type list.", GetName(baseType, attributeType)); + _logger.LogDebug("Getting {TypeName}: found a cached type list.", GetName(baseType, attributeType)); return typeList.Types; } @@ -645,7 +648,7 @@ namespace Umbraco.Core.Composing // report (only once) and scan and update the cache file if (_reportedChange == false) { - _logger.Debug("Assemblies changes detected, need to rescan everything."); + _logger.LogDebug("Assemblies changes detected, need to rescan everything."); _reportedChange = true; } } @@ -660,7 +663,7 @@ namespace Umbraco.Core.Composing // so in this instance there will never be a result. if (cacheResult.Exception is CachedTypeNotFoundInFileException || cacheResult.Success == false) { - _logger.Debug("Getting {TypeName}: failed to load from cache file, must scan assemblies.", GetName(baseType, attributeType)); + _logger.LogDebug("Getting {TypeName}: failed to load from cache file, must scan assemblies.", GetName(baseType, attributeType)); scan = true; } else @@ -674,7 +677,7 @@ namespace Umbraco.Core.Composing else { // in case of any exception, we have to exit, and revert to scanning - _logger.Warn("Getting {TypeName}: failed to load cache file type {CacheType}, reverting to scanning assemblies.", GetName(baseType, attributeType), type); + _logger.LogWarning("Getting {TypeName}: failed to load cache file type {CacheType}, reverting to scanning assemblies.", GetName(baseType, attributeType), type); scan = true; break; } @@ -682,7 +685,7 @@ namespace Umbraco.Core.Composing if (scan == false) { - _logger.Debug("Getting {TypeName}: loaded types from cache file.", GetName(baseType, attributeType)); + _logger.LogDebug("Getting {TypeName}: loaded types from cache file.", GetName(baseType, attributeType)); } } } @@ -690,7 +693,7 @@ namespace Umbraco.Core.Composing if (scan) { // either we had to scan, or we could not get the types from the cache file - scan now - _logger.Debug("Getting {TypeName}: " + action + ".", GetName(baseType, attributeType)); + _logger.LogDebug("Getting {TypeName}: " + action + ".", GetName(baseType, attributeType)); foreach (var t in finder()) typeList.Add(t); @@ -708,11 +711,11 @@ namespace Umbraco.Core.Composing UpdateCache(); } - _logger.Debug("Got {TypeName}, caching ({CacheType}).", GetName(baseType, attributeType), added.ToString().ToLowerInvariant()); + _logger.LogDebug("Got {TypeName}, caching ({CacheType}).", GetName(baseType, attributeType), added.ToString().ToLowerInvariant()); } else { - _logger.Debug("Got {TypeName}.", GetName(baseType, attributeType)); + _logger.LogDebug("Got {TypeName}.", GetName(baseType, attributeType)); } return typeList.Types; diff --git a/src/Umbraco.Core/CompositionExtensions.cs b/src/Umbraco.Core/CompositionExtensions.cs index bbea868f55..5b9abeeb45 100644 --- a/src/Umbraco.Core/CompositionExtensions.cs +++ b/src/Umbraco.Core/CompositionExtensions.cs @@ -1,4 +1,5 @@ using Umbraco.Core.Composing; +using Umbraco.Core.Manifest; using Umbraco.Core.PropertyEditors; using Umbraco.Web.Actions; using Umbraco.Web.ContentApps; @@ -94,7 +95,18 @@ namespace Umbraco.Core /// /// The composition. public static DashboardCollectionBuilder Dashboards(this Composition composition) - => composition.WithCollectionBuilder(); + => composition.WithCollectionBuilder() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add() + .Add(); /// 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..72408e212c 100644 --- a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs +++ b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs @@ -1,16 +1,64 @@ +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) + || builder.TryGetValue("DataSource", out 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/ContentSettingsExtensions.cs b/src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs new file mode 100644 index 0000000000..31f4373fd2 --- /dev/null +++ b/src/Umbraco.Core/Configuration/ContentSettingsExtensions.cs @@ -0,0 +1,33 @@ +using System.Linq; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Core.Configuration +{ + public static class ContentSettingsExtensions + { + /// + /// Determines if file extension is allowed for upload based on (optional) white list and black list + /// 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 ContentSettings contentSettings, string extension) + { + return contentSettings.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) || + (contentSettings.AllowedUploadFiles.Any() == false && + contentSettings.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false); + } + + /// + /// Gets the auto-fill configuration for a specified property alias. + /// + /// + /// The property type alias. + /// The auto-fill configuration for the specified property alias, or null. + public static ImagingAutoFillUploadField GetConfig(this ContentSettings contentSettings, string propertyTypeAlias) + { + 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/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs index 363dc7b048..d9816101fd 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs @@ -1,6 +1,6 @@ -using Umbraco.Core.Cache; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Cache; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.Serialization; @@ -8,9 +8,9 @@ namespace Umbraco.Core.Configuration.Grid { public class GridConfig : IGridConfig { - public GridConfig(AppCaches appCaches, IManifestParser manifestParser, IJsonSerializer jsonSerializer, IHostingEnvironment hostingEnvironment, ILogger logger) + public GridConfig(AppCaches appCaches, IManifestParser manifestParser, IJsonSerializer jsonSerializer, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) { - EditorsConfig = new GridEditorsConfig(appCaches, hostingEnvironment, manifestParser, jsonSerializer, logger); + EditorsConfig = new GridEditorsConfig(appCaches, hostingEnvironment, manifestParser, jsonSerializer, loggerFactory.CreateLogger()); } public IGridEditorsConfig EditorsConfig { get; } diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs index 6cf985fecb..6ee72f1d04 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.IO; +using Microsoft.Extensions.Logging; using Umbraco.Core.Cache; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; @@ -17,9 +17,9 @@ namespace Umbraco.Core.Configuration.Grid private readonly IManifestParser _manifestParser; private readonly IJsonSerializer _jsonSerializer; - private readonly ILogger _logger; + private readonly ILogger _logger; - public GridEditorsConfig(AppCaches appCaches, IHostingEnvironment hostingEnvironment, IManifestParser manifestParser,IJsonSerializer jsonSerializer, ILogger logger) + public GridEditorsConfig(AppCaches appCaches, IHostingEnvironment hostingEnvironment, IManifestParser manifestParser,IJsonSerializer jsonSerializer, ILogger logger) { _appCaches = appCaches; _hostingEnvironment = hostingEnvironment; @@ -47,7 +47,7 @@ namespace Umbraco.Core.Configuration.Grid } catch (Exception ex) { - _logger.Error(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString); + _logger.LogError(ex, "Could not parse the contents of grid.editors.config.js into a JSON array '{Json}", sourceString); } } diff --git a/src/Umbraco.Core/Configuration/HealthChecks/AbstractConfigCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/AbstractConfigCheck.cs index bebde2f99d..f3452131f0 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/AbstractConfigCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/AbstractConfigCheck.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -15,7 +16,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config private readonly ConfigurationService _configurationService; protected ILocalizedTextService TextService { get; } - protected ILogger Logger { get; } + protected ILoggerFactory LoggerFactory { get; } /// /// Gets the config file path. @@ -55,12 +56,12 @@ namespace Umbraco.Web.HealthCheck.Checks.Config get { return false; } } - protected AbstractConfigCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILogger logger) + protected AbstractConfigCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) { _hostingEnvironment = hostingEnvironment; TextService = textService; - Logger = logger; - _configurationService = new ConfigurationService(AbsoluteFilePath, XPath, textService, logger); + LoggerFactory = loggerFactory; + _configurationService = new ConfigurationService(AbsoluteFilePath, XPath, textService, loggerFactory.CreateLogger()); } /// diff --git a/src/Umbraco.Core/Configuration/HealthChecks/CompilationDebugCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/CompilationDebugCheck.cs index fe06ccc6f0..b400093a34 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/CompilationDebugCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/CompilationDebugCheck.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Config @@ -11,8 +11,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Config Group = "Live Environment")] public class CompilationDebugCheck : AbstractConfigCheck { - public CompilationDebugCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILogger logger) - : base(textService, hostingEnvironment, logger) + public CompilationDebugCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) + : base(textService, hostingEnvironment, loggerFactory) { } public override string FilePath => "~/Web.config"; diff --git a/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationService.cs b/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationService.cs index a4554a52fd..396d55b735 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationService.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationService.cs @@ -1,7 +1,7 @@ using System; using System.IO; using System.Xml; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Config @@ -13,14 +13,14 @@ namespace Umbraco.Web.HealthCheck.Checks.Config private readonly string _configFilePath; private readonly string _xPath; private readonly ILocalizedTextService _textService; - private readonly ILogger _logger; + private readonly ILogger _logger; /// The absolute file location of the configuration file /// The XPath to select the value /// /// /// - public ConfigurationService(string configFilePath, string xPath, ILocalizedTextService textService, ILogger logger) + public ConfigurationService(string configFilePath, string xPath, ILocalizedTextService textService, ILogger logger) { _configFilePath = configFilePath; _xPath = xPath; @@ -61,7 +61,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config } catch (Exception ex) { - _logger.Error(ex, "Error trying to get configuration value"); + _logger.LogError(ex, "Error trying to get configuration value"); return new ConfigurationServiceResult { Success = false, @@ -107,7 +107,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config } catch (Exception ex) { - _logger.Error(ex, "Error trying to update configuration"); + _logger.LogError(ex, "Error trying to update configuration"); return new ConfigurationServiceResult { Success = false, diff --git a/src/Umbraco.Core/Configuration/HealthChecks/CustomErrorsCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/CustomErrorsCheck.cs index 2338daf718..9b14847bdf 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/CustomErrorsCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/CustomErrorsCheck.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Config @@ -12,8 +12,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Config Group = "Live Environment")] public class CustomErrorsCheck : AbstractConfigCheck { - public CustomErrorsCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILogger logger) - : base(textService, hostingEnvironment, logger) + public CustomErrorsCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) + : base(textService, hostingEnvironment, loggerFactory) { } public override string FilePath => "~/Web.config"; 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/HealthChecks/MacroErrorsCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/MacroErrorsCheck.cs index 7e53b87b79..68e76dfc81 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/MacroErrorsCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/MacroErrorsCheck.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Config @@ -12,8 +12,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Config Group = "Configuration")] public class MacroErrorsCheck : AbstractConfigCheck { - public MacroErrorsCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILogger logger) - : base(textService, hostingEnvironment, logger) + public MacroErrorsCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) + : base(textService, hostingEnvironment, loggerFactory) { } public override string FilePath => "~/Config/umbracoSettings.config"; diff --git a/src/Umbraco.Core/Configuration/HealthChecks/NotificationEmailCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/NotificationEmailCheck.cs index 9ba88c4a13..bac2cf1c3c 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/NotificationEmailCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/NotificationEmailCheck.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Config @@ -13,8 +13,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Config { private const string DefaultFromEmail = "your@email.here"; - public NotificationEmailCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILogger logger) - : base(textService, hostingEnvironment, logger) + public NotificationEmailCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) + : base(textService, hostingEnvironment, loggerFactory) { } public override string FilePath => "~/Config/umbracoSettings.config"; diff --git a/src/Umbraco.Core/Configuration/HealthChecks/TraceCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/TraceCheck.cs index 16702e3a06..a2c5a84c55 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/TraceCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/TraceCheck.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Config @@ -12,8 +12,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Config public class TraceCheck : AbstractConfigCheck { - public TraceCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILogger logger) - : base(textService, hostingEnvironment, logger) + public TraceCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) + : base(textService, hostingEnvironment, loggerFactory) { } public override string FilePath => "~/Web.config"; diff --git a/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs index dc3abbc8a8..76269d961c 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.HealthCheck.Checks.Config @@ -15,9 +15,9 @@ namespace Umbraco.Web.HealthCheck.Checks.Config { private readonly Version _iisVersion; - public TrySkipIisCustomErrorsCheck(ILocalizedTextService textService, ILogger logger, + public TrySkipIisCustomErrorsCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment) - : base(textService, hostingEnvironment, logger) + : base(textService, hostingEnvironment, loggerFactory) { _iisVersion = hostingEnvironment.IISVersion; } 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..6a362c93a3 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Umbraco.Core.Configuration.Models.Validation; + +namespace Umbraco.Core.Configuration.Models +{ + public class ContentErrorPage : ValidatableEntryBase + { + public int ContentId { get; set; } + + public Guid ContentKey { get; set; } + + public string ContentXPath { get; set; } + + public bool HasContentId => ContentId != 0; + + public bool HasContentKey => ContentKey != Guid.Empty; + + public bool HasContentXPath => !string.IsNullOrEmpty(ContentXPath); + + [Required] + public string Culture { get; set; } + + internal override bool IsValid() + { + return base.IsValid() && + ((HasContentId ? 1 : 0) + (HasContentKey ? 1 : 0) + (HasContentXPath ? 1 : 0) == 1); + } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs b/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs new file mode 100644 index 0000000000..7c1e570426 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ContentImagingSettings.cs @@ -0,0 +1,21 @@ +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 string[] ImageFileTypes { get; set; } = new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" }; + + public ImagingAutoFillUploadField[] AutoFillImageProperties { get; set; } = DefaultImagingAutoFillUploadField; + } +} 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..65d7855dc7 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ContentSettings.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.Configuration.Models.Validation; +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 ContentErrorPage[] 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..b003315c56 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/HostingSettings.cs @@ -0,0 +1,20 @@ +using System; + +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/ImagingAutoFillUploadField.cs b/src/Umbraco.Core/Configuration/Models/ImagingAutoFillUploadField.cs new file mode 100644 index 0000000000..f58e2bb4f8 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ImagingAutoFillUploadField.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using Umbraco.Core.Configuration.Models.Validation; + +namespace Umbraco.Core.Configuration.Models +{ + public class ImagingAutoFillUploadField : ValidatableEntryBase + { + [Required] + public string Alias { get; set; } + + [Required] + public string WidthFieldAlias { get; set; } + + [Required] + public string HeightFieldAlias { get; set; } + + [Required] + public string LengthFieldAlias { get; set; } + + [Required] + public string ExtensionFieldAlias { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs b/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs new file mode 100644 index 0000000000..90249abc15 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs @@ -0,0 +1,17 @@ +using System; +using System.IO; +using System.Threading; + +namespace Umbraco.Core.Configuration.Models +{ + public class ImagingCacheSettings + { + public TimeSpan BrowserMaxAge { get; set; } = TimeSpan.FromDays(7); + + public TimeSpan CacheMaxAge { get; set; } = TimeSpan.FromDays(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/ModelsBuilderSettings.cs similarity index 59% rename from src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs rename to src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs index d111dbba70..414165d2e4 100644 --- a/src/Umbraco.Configuration/Models/ModelsBuilderConfig.cs +++ b/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.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 ModelsBuilderSettings { - 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..89a726f30a --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/NuCacheSettings.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Configuration.Models +{ + public class NuCacheSettings + { + public int? 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.Core/Configuration/Models/SmtpSettings.cs b/src/Umbraco.Core/Configuration/Models/SmtpSettings.cs new file mode 100644 index 0000000000..7c19f28d87 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/SmtpSettings.cs @@ -0,0 +1,26 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Net.Mail; +using Umbraco.Core.Configuration.Models.Validation; + +namespace Umbraco.Core.Configuration.Models +{ + public class SmtpSettings : ValidatableEntryBase + { + [Required] + [EmailAddress] + 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; } = SmtpDeliveryMethod.Network; + + public string Username { get; set; } + + public string Password { 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/Validation/ConfigurationValidatorBase.cs b/src/Umbraco.Core/Configuration/Models/Validation/ConfigurationValidatorBase.cs new file mode 100644 index 0000000000..fe8d077166 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/Validation/ConfigurationValidatorBase.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Umbraco.Core.Configuration.Models.Validation +{ + public abstract class ConfigurationValidatorBase + { + public bool ValidateStringIsOneOfValidValues(string configPath, string value, IEnumerable validValues, out string message) + { + if (!validValues.InvariantContains(value)) + { + message = $"Configuration entry {configPath} contains an invalid value '{value}', it should be one of the following: '{string.Join(", ", validValues)}'."; + return false; + } + + message = string.Empty; + return true; + } + + public bool ValidateCollection(string configPath, IEnumerable values, string validationDescription, out string message) + { + if (values.Any(x => !x.IsValid())) + { + message = $"Configuration entry {configPath} contains one or more invalid values. {validationDescription}."; + return false; + } + + message = string.Empty; + return true; + } + + public bool ValidateOptionalEntry(string configPath, ValidatableEntryBase value, string validationDescription, out string message) + { + if (value != null && !value.IsValid()) + { + message = $"Configuration entry {configPath} contains one or more invalid values. {validationDescription}."; + return false; + } + + message = string.Empty; + return true; + } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidator.cs b/src/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidator.cs new file mode 100644 index 0000000000..9ed22f922e --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidator.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Options; +using Umbraco.Core.Macros; + +namespace Umbraco.Core.Configuration.Models.Validation +{ + public class ContentSettingsValidator : ConfigurationValidatorBase, IValidateOptions + { + public ValidateOptionsResult Validate(string name, ContentSettings options) + { + string message; + if (!ValidateError404Collection(options.Error404Collection, out message)) + { + return ValidateOptionsResult.Fail(message); + } + + if (!ValidateAutoFillImageProperties(options.Imaging.AutoFillImageProperties, out message)) + { + return ValidateOptionsResult.Fail(message); + } + + return ValidateOptionsResult.Success; + } + + private bool ValidateError404Collection(IEnumerable values, out string message) + { + return ValidateCollection($"{Constants.Configuration.ConfigContent}:{nameof(ContentSettings.Error404Collection)}", values, "Culture and one and only one of ContentId, ContentKey and ContentXPath must be specified for each entry", out message); + } + + private bool ValidateAutoFillImageProperties(IEnumerable values, out string message) + { + return ValidateCollection($"{Constants.Configuration.ConfigContent}:{nameof(ContentSettings.Imaging)}:{nameof(ContentSettings.Imaging.AutoFillImageProperties)}", values, "Alias, WidthFieldAlias, HeightFieldAlias, LengthFieldAlias and ExtensionFieldAlias must be specified for each entry", out message); + } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidator.cs b/src/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidator.cs new file mode 100644 index 0000000000..ca3fee7999 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidator.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Options; + +namespace Umbraco.Core.Configuration.Models.Validation +{ + public class GlobalSettingsValidator + : ConfigurationValidatorBase, IValidateOptions + { + public ValidateOptionsResult Validate(string name, GlobalSettings options) + { + if (!ValidateSmtpSetting(options.Smtp, out var message)) + { + return ValidateOptionsResult.Fail(message); + } + + return ValidateOptionsResult.Success; + } + + private bool ValidateSmtpSetting(SmtpSettings value, out string message) + { + return ValidateOptionalEntry($"{Constants.Configuration.ConfigGlobal}:{nameof(GlobalSettings.Smtp)}", value, "A valid From email address is required", out message); + } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/Validation/RequestHandlerSettingsValidator.cs b/src/Umbraco.Core/Configuration/Models/Validation/RequestHandlerSettingsValidator.cs new file mode 100644 index 0000000000..305fe812f8 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/Validation/RequestHandlerSettingsValidator.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Options; + +namespace Umbraco.Core.Configuration.Models.Validation +{ + public class RequestHandlerSettingsValidator : ConfigurationValidatorBase, IValidateOptions + { + public ValidateOptionsResult Validate(string name, RequestHandlerSettings options) + { + if (!ValidateConvertUrlsToAscii(options.ConvertUrlsToAscii, out var message)) + { + return ValidateOptionsResult.Fail(message); + } + + return ValidateOptionsResult.Success; + } + + private bool ValidateConvertUrlsToAscii(string value, out string message) + { + var validValues = new[] { "try", "true", "false" }; + return ValidateStringIsOneOfValidValues($"{Constants.Configuration.ConfigRequestHandler}:{nameof(RequestHandlerSettings.ConvertUrlsToAscii)}", value, validValues, out message); + } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/Validation/ValidatableEntryBase.cs b/src/Umbraco.Core/Configuration/Models/Validation/ValidatableEntryBase.cs new file mode 100644 index 0000000000..32e3c3270b --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/Validation/ValidatableEntryBase.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Umbraco.Core.Configuration.Models.Validation +{ + public abstract class ValidatableEntryBase + { + internal virtual bool IsValid() + { + var ctx = new ValidationContext(this); + var results = new List(); + return Validator.TryValidateObject(this, ctx, results, true); + } + } +} diff --git a/src/Umbraco.Core/Configuration/Models/WebRoutingSettings.cs b/src/Umbraco.Core/Configuration/Models/WebRoutingSettings.cs new file mode 100644 index 0000000000..476d58c913 --- /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 UrlMode UrlProviderMode { get; set; } = UrlMode.Auto; + + public string UmbracoApplicationUrl { get; set; } + } +} diff --git a/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs b/src/Umbraco.Core/Configuration/ModelsBuilderConfigExtensions.cs index 3e3b116395..ef80796c8b 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 ModelsBuilderSettings 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/ContentSectionExtensions.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs deleted file mode 100644 index d100eb0a74..0000000000 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Linq; - -namespace Umbraco.Core.Configuration.UmbracoSettings -{ - public static class ContentSectionExtensions - { - /// - /// Gets a value indicating whether the file extension corresponds to an image. - /// - /// The file extension. - /// - /// A value indicating whether the file extension corresponds to an image. - public static bool IsImageFile(this IContentSettings contentConfig, string extension) - { - if (contentConfig == null) throw new ArgumentNullException(nameof(contentConfig)); - if (extension == null) return false; - extension = extension.TrimStart('.'); - return contentConfig.ImageFileTypes.InvariantContains(extension); - } - - /// - /// Determines if file extension is allowed for upload based on (optional) white list and black list - /// 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) - { - return contentSettings.AllowedUploadFiles.Any(x => x.InvariantEquals(extension)) || - (contentSettings.AllowedUploadFiles.Any() == false && - contentSettings.DisallowedUploadFiles.Any(x => x.InvariantEquals(extension)) == false); - } - - /// - /// Gets the auto-fill configuration for a specified property alias. - /// - /// - /// The property type alias. - /// The auto-fill configuration for the specified property alias, or null. - public static IImagingAutoFillUploadField GetConfig(this IContentSettings contentSettings, string propertyTypeAlias) - { - var autoFillConfigs = contentSettings.ImageAutoFillProperties; - return autoFillConfigs?.FirstOrDefault(x => x.Alias == propertyTypeAlias); - } - } -} diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs 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..b7c3d5d58b 100644 --- a/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs +++ b/src/Umbraco.Core/Configuration/XmlConfigManipulator.cs @@ -2,19 +2,19 @@ using System.Configuration; using System.IO; using System.Linq; +using System.Xml; using System.Xml.Linq; -using Umbraco.Composing; +using Microsoft.Extensions.Logging; using Umbraco.Core.IO; -using Umbraco.Core.Logging; namespace Umbraco.Core.Configuration { public class XmlConfigManipulator : IConfigManipulator { private readonly IIOHelper _ioHelper; - private readonly ILogger _logger; + private readonly ILogger _logger; - public XmlConfigManipulator(IIOHelper ioHelper, ILogger logger) + public XmlConfigManipulator(IIOHelper ioHelper, ILogger logger) { _ioHelper = ioHelper; _logger = logger; @@ -101,9 +101,9 @@ namespace Umbraco.Core.Configuration } // save - _logger.Info("Saving connection string to {ConfigFile}.", fileSource); + _logger.LogInformation("Saving connection string to {ConfigFile}.", fileSource); xml.Save(fileName, SaveOptions.DisableFormatting); - _logger.Info("Saved connection string to {ConfigFile}.", fileSource); + _logger.LogInformation("Saved connection string to {ConfigFile}.", fileSource); } public void SaveConfigValue(string itemPath, object value) @@ -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/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs index 86a02affb6..c06ec8f1ec 100644 --- a/src/Umbraco.Core/Constants-Configuration.cs +++ b/src/Umbraco.Core/Constants-Configuration.cs @@ -11,11 +11,30 @@ /// ":" is used as marker for nested objects in json. E.g. "Umbraco:CMS:" = {"Umbraco":{"CMS":{....}} /// public const string ConfigPrefix = "Umbraco:CMS:"; - public const string ConfigSecurityPrefix = ConfigPrefix+"Security:"; - public const string ConfigGlobalPrefix = ConfigPrefix + "Global:"; - public const string ConfigModelsBuilderPrefix = ConfigPrefix+"ModelsBuilder:"; - public const string ConfigRuntimeMinification = ConfigPrefix+"RuntimeMinification"; - public const string ConfigRuntimeMinificationVersion = ConfigRuntimeMinification+":Version"; + public const string ConfigActiveDirectory = ConfigPrefix + "ActiveDirectory"; + public const string ConfigContent = ConfigPrefix + "Content"; + public const string ConfigCoreDebug = ConfigPrefix + "Core:Debug"; + public const string ConfigExceptionFilter = ConfigPrefix + "ExceptionFilter"; + public const string ConfigGlobal = ConfigPrefix + "Global"; + public const string ConfigHealthChecks = ConfigPrefix + "HealthChecks"; + public const string ConfigHosting = ConfigPrefix + "Hosting"; + public const string ConfigImaging = ConfigPrefix + "Imaging"; + public const string ConfigExamine = ConfigPrefix + "Examine"; + public const string ConfigKeepAlive = ConfigPrefix + "KeepAlive"; + public const string ConfigLogging = ConfigPrefix + "Logging"; + public const string ConfigMemberPassword = ConfigPrefix + "Security:MemberPassword"; + public const string ConfigModelsBuilder = ConfigPrefix + "ModelsBuilder"; + public const string ConfigNuCache = ConfigPrefix + "NuCache"; + public const string ConfigRequestHandler = ConfigPrefix + "RequestHandler"; + public const string ConfigRuntime = ConfigPrefix + "Runtime"; + public const string ConfigSecurity = ConfigPrefix + "Security"; + public const string ConfigTours = ConfigPrefix + "Tours"; + public const string ConfigTypeFinder = ConfigPrefix + "TypeFinder"; + public const string ConfigWebRouting = ConfigPrefix + "WebRouting"; + public const string ConfigUserPassword = ConfigPrefix + "Security:UserPassword"; + + public const string ConfigRuntimeMinification = ConfigPrefix + "RuntimeMinification"; + public const string ConfigRuntimeMinificationVersion = ConfigRuntimeMinification + ":Version"; } } } diff --git a/src/Umbraco.Core/Constants-Security.cs b/src/Umbraco.Core/Constants-Security.cs index fda4c23dc0..9bcdedca70 100644 --- a/src/Umbraco.Core/Constants-Security.cs +++ b/src/Umbraco.Core/Constants-Security.cs @@ -62,6 +62,7 @@ public const string AspNetCoreV3PasswordHashAlgorithmName = "PBKDF2.ASPNETCORE.V3"; public const string AspNetCoreV2PasswordHashAlgorithmName = "PBKDF2.ASPNETCORE.V2"; public const string AspNetUmbraco8PasswordHashAlgorithmName = "HMACSHA256"; + public const string AspNetUmbraco4PasswordHashAlgorithmName = "HMACSHA1"; } } } diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs index d18e23a6c3..d0ae5550ca 100644 --- a/src/Umbraco.Core/Constants-Web.cs +++ b/src/Umbraco.Core/Constants-Web.cs @@ -51,6 +51,7 @@ public const string BackOfficePathSegment = "BackOffice"; // The path segment prefix for all back office controllers public const string BackOfficeArea = "UmbracoBackOffice"; // Used for area routes of non-api controllers public const string BackOfficeApiArea = "UmbracoApi"; // Same name as v8 so all routing remains the same + public const string BackOfficeTreeArea = "UmbracoTrees"; // Same name as v8 so all routing remains the same } } } diff --git a/src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs b/src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs index 4e85e51af3..7884126dc8 100644 --- a/src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs +++ b/src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs @@ -1,19 +1,19 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Models.ContentEditing; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Membership; namespace Umbraco.Web.ContentApps { public class ContentAppFactoryCollection : BuilderCollectionBase { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUmbracoContextAccessor _umbracoContextAccessor; - public ContentAppFactoryCollection(IEnumerable items, ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) + public ContentAppFactoryCollection(IEnumerable items, ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) : base(items) { _logger = logger; @@ -51,7 +51,7 @@ namespace Umbraco.Web.ContentApps // dying is not user-friendly, so let's write to log instead, and wish people read logs... //throw new InvalidOperationException($"Duplicate content app aliases found: {string.Join(",", dups)}"); - _logger.Warn("Duplicate content app aliases found: {DuplicateAliases}", string.Join(",", dups)); + _logger.LogWarning("Duplicate content app aliases found: {DuplicateAliases}", string.Join(",", dups)); } return apps; diff --git a/src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs b/src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs index f3d3a149d5..0e2c8e2f55 100644 --- a/src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs +++ b/src/Umbraco.Core/ContentApps/ContentAppFactoryCollectionBuilder.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.Models.ContentEditing; using Umbraco.Core.Models.Identity; @@ -17,10 +17,10 @@ namespace Umbraco.Web.ContentApps // need to inject dependencies in the collection, so override creation public override ContentAppFactoryCollection CreateCollection(IFactory factory) { - // get the logger just-in-time - see note below for manifest parser - var logger = factory.GetInstance(); + // get the logger factory just-in-time - see note below for manifest parser + var loggerFactory = factory.GetInstance(); var umbracoContextAccessor = factory.GetInstance(); - return new ContentAppFactoryCollection(CreateItems(factory), logger, umbracoContextAccessor); + return new ContentAppFactoryCollection(CreateItems(factory), loggerFactory.CreateLogger(), umbracoContextAccessor); } protected override IEnumerable CreateItems(IFactory factory) 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/Dashboards/IDashboard.cs b/src/Umbraco.Core/Dashboards/IDashboard.cs index c990e2ba61..6e429d9b40 100644 --- a/src/Umbraco.Core/Dashboards/IDashboard.cs +++ b/src/Umbraco.Core/Dashboards/IDashboard.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Dashboards /// /// Represents a dashboard. /// - public interface IDashboard : IDashboardSlim, IDiscoverable + public interface IDashboard : IDashboardSlim { /// /// Gets the aliases of sections/applications where this dashboard appears. diff --git a/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs b/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs index a4f51398e8..98cd7fcc92 100644 --- a/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs +++ b/src/Umbraco.Core/Dashboards/ProfilerDashboard.cs @@ -5,7 +5,7 @@ using Umbraco.Core.Dashboards; namespace Umbraco.Web.Dashboards { [Weight(60)] - public class ProfilerDashboardDashboard : IDashboard + public class ProfilerDashboard : IDashboard { public string Alias => "settingsProfiler"; 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..3f788f7460 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs @@ -2,12 +2,14 @@ using System.Collections.Generic; using System.Net; using System.Security.Cryptography.X509Certificates; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Configuration; 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,20 +21,24 @@ 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 readonly ILogger _logger; 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, + IRequestAccessor requestAccessor, + ILogger logger) { _textService = textService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _ioHelper = ioHelper; - _logger = logger; _requestAccessor = requestAccessor; + _logger = logger; } /// 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..e5c8caffe7 100644 --- a/src/Umbraco.Core/IO/FileSystems.cs +++ b/src/Umbraco.Core/IO/FileSystems.cs @@ -2,17 +2,20 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; -using Umbraco.Core.Logging; +using Microsoft.Extensions.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 { public class FileSystems : IFileSystems { private readonly IFactory _container; - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IIOHelper _ioHelper; private readonly ConcurrentDictionary> _filesystems = new ConcurrentDictionary>(); @@ -36,12 +39,13 @@ 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, ILoggerFactory loggerFactory, IIOHelper ioHelper, IOptions globalSettings, IHostingEnvironment hostingEnvironment) { _container = container; _logger = logger; + _loggerFactory = loggerFactory; _ioHelper = ioHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; } @@ -126,17 +130,18 @@ namespace Umbraco.Core.IO // but it does not really matter what we return - here, null private object CreateWellKnownFileSystems() { - var macroPartialFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, Constants.SystemDirectories.MacroPartials); - var partialViewsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, Constants.SystemDirectories.PartialViews); - var stylesheetsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, _globalSettings.UmbracoCssPath); - var scriptsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, _globalSettings.UmbracoScriptsPath); - var mvcViewsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, Constants.SystemDirectories.MvcViews); + var logger = _loggerFactory.CreateLogger(); + var macroPartialFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, Constants.SystemDirectories.MacroPartials); + var partialViewsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, Constants.SystemDirectories.PartialViews); + var stylesheetsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, _globalSettings.UmbracoCssPath); + var scriptsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, _globalSettings.UmbracoScriptsPath); + var mvcViewsFileSystem = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, logger, Constants.SystemDirectories.MvcViews); - _macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, _ioHelper, _hostingEnvironment, _logger,"macro-partials", IsScoped); - _partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, _ioHelper, _hostingEnvironment, _logger,"partials", IsScoped); - _stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, _ioHelper, _hostingEnvironment,_logger,"css", IsScoped); - _scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, _ioHelper, _hostingEnvironment,_logger,"scripts", IsScoped); - _mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, _ioHelper, _hostingEnvironment,_logger,"views", IsScoped); + _macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "macro-partials", IsScoped); + _partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "partials", IsScoped); + _stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "css", IsScoped); + _scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "scripts", IsScoped); + _mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, _ioHelper, _hostingEnvironment, _loggerFactory, "views", IsScoped); // TODO: do we need a lock here? _shadowWrappers.Add(_macroPartialFileSystem); @@ -156,7 +161,7 @@ namespace Umbraco.Core.IO // internal for tests internal IReadOnlyDictionary Paths => _paths; - private IGlobalSettings _globalSettings; + private GlobalSettings _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; /// @@ -233,7 +238,7 @@ namespace Umbraco.Core.IO _shadowCurrentId = id; - _logger.Debug("Shadow '{ShadowId}'", _shadowCurrentId); + _logger.LogDebug("Shadow '{ShadowId}'", _shadowCurrentId); foreach (var wrapper in _shadowWrappers) wrapper.Shadow(_shadowCurrentId); @@ -250,7 +255,7 @@ namespace Umbraco.Core.IO if (id != _shadowCurrentId) throw new InvalidOperationException("Not the current shadow."); - _logger.Debug("UnShadow '{ShadowId}' {Status}", id, completed ? "complete" : "abort"); + _logger.LogDebug("UnShadow '{ShadowId}' {Status}", id, completed ? "complete" : "abort"); var exceptions = new List(); foreach (var wrapper in _shadowWrappers) @@ -277,7 +282,7 @@ namespace Umbraco.Core.IO { lock (_shadowLocker) { - var wrapper = new ShadowWrapper(filesystem, _ioHelper, _hostingEnvironment, _logger, shadowPath, IsScoped); + var wrapper = new ShadowWrapper(filesystem, _ioHelper, _hostingEnvironment, _loggerFactory, shadowPath, IsScoped); if (_shadowCurrentId != null) wrapper.Shadow(_shadowCurrentId); _shadowWrappers.Add(wrapper); 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/MediaFileSystem.cs b/src/Umbraco.Core/IO/MediaFileSystem.cs index 1df4e4a0fb..5e5a3f3e97 100644 --- a/src/Umbraco.Core/IO/MediaFileSystem.cs +++ b/src/Umbraco.Core/IO/MediaFileSystem.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Strings; @@ -15,13 +15,13 @@ namespace Umbraco.Core.IO public class MediaFileSystem : FileSystemWrapper, IMediaFileSystem { private readonly IMediaPathScheme _mediaPathScheme; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IShortStringHelper _shortStringHelper; /// /// Initializes a new instance of the class. /// - public MediaFileSystem(IFileSystem innerFileSystem, IMediaPathScheme mediaPathScheme, ILogger logger, IShortStringHelper shortStringHelper) + public MediaFileSystem(IFileSystem innerFileSystem, IMediaPathScheme mediaPathScheme, ILogger logger, IShortStringHelper shortStringHelper) : base(innerFileSystem) { _mediaPathScheme = mediaPathScheme; @@ -51,7 +51,7 @@ namespace Umbraco.Core.IO } catch (Exception e) { - _logger.Error(e, "Failed to delete media file '{File}'.", file); + _logger.LogError(e, "Failed to delete media file '{File}'.", file); } }); } diff --git a/src/Umbraco.Core/IO/PhysicalFileSystem.cs b/src/Umbraco.Core/IO/PhysicalFileSystem.cs index aa9d6174dd..04e3df6ab3 100644 --- a/src/Umbraco.Core/IO/PhysicalFileSystem.cs +++ b/src/Umbraco.Core/IO/PhysicalFileSystem.cs @@ -2,18 +2,18 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Exceptions; using Umbraco.Core.Composing; using System.Threading; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; namespace Umbraco.Core.IO { public class PhysicalFileSystem : IFileSystem { private readonly IIOHelper _ioHelper; - private readonly ILogger _logger; + private readonly ILogger _logger; // the rooted, filesystem path, using directory separator chars, NOT ending with a separator // eg "c:" or "c:\path\to\site" or "\\server\path" @@ -30,7 +30,7 @@ namespace Umbraco.Core.IO // virtualRoot should be "~/path/to/root" eg "~/Views" // the "~/" is mandatory. - public PhysicalFileSystem(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILogger logger, string virtualRoot) + public PhysicalFileSystem(IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILogger logger, string virtualRoot) { _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); if (hostingEnvironment == null) throw new ArgumentNullException(nameof(hostingEnvironment)); @@ -45,7 +45,7 @@ namespace Umbraco.Core.IO _rootUrl = EnsureUrlSeparatorChar(hostingEnvironment.ToAbsolute(virtualRoot)).TrimEnd('/'); } - public PhysicalFileSystem(IIOHelper ioHelper,IHostingEnvironment hostingEnvironment, ILogger logger, string rootPath, string rootUrl) + public PhysicalFileSystem(IIOHelper ioHelper,IHostingEnvironment hostingEnvironment, ILogger logger, string rootPath, string rootUrl) { _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -87,11 +87,11 @@ namespace Umbraco.Core.IO } catch (UnauthorizedAccessException ex) { - _logger.Error(ex, "Not authorized to get directories for '{Path}'", fullPath); + _logger.LogError(ex, "Not authorized to get directories for '{Path}'", fullPath); } catch (DirectoryNotFoundException ex) { - _logger.Error(ex, "Directory not found for '{Path}'", fullPath); + _logger.LogError(ex, "Directory not found for '{Path}'", fullPath); } return Enumerable.Empty(); @@ -123,7 +123,7 @@ namespace Umbraco.Core.IO } catch (DirectoryNotFoundException ex) { - _logger.Error(ex, "Directory not found for '{Path}'", fullPath); + _logger.LogError(ex, "Directory not found for '{Path}'", fullPath); } } @@ -203,11 +203,11 @@ namespace Umbraco.Core.IO } catch (UnauthorizedAccessException ex) { - _logger.Error(ex, "Not authorized to get directories for '{Path}'", fullPath); + _logger.LogError(ex, "Not authorized to get directories for '{Path}'", fullPath); } catch (DirectoryNotFoundException ex) { - _logger.Error(ex, "Directory not found for '{FullPath}'", fullPath); + _logger.LogError(ex, "Directory not found for '{FullPath}'", fullPath); } return Enumerable.Empty(); @@ -240,7 +240,7 @@ namespace Umbraco.Core.IO } catch (FileNotFoundException ex) { - _logger.Error(ex.InnerException, "DeleteFile failed with FileNotFoundException for '{Path}'", fullPath); + _logger.LogError(ex.InnerException, "DeleteFile failed with FileNotFoundException for '{Path}'", fullPath); } } diff --git a/src/Umbraco.Core/IO/ShadowWrapper.cs b/src/Umbraco.Core/IO/ShadowWrapper.cs index 7ddd6a48b7..83fe5aafe7 100644 --- a/src/Umbraco.Core/IO/ShadowWrapper.cs +++ b/src/Umbraco.Core/IO/ShadowWrapper.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; namespace Umbraco.Core.IO { @@ -19,14 +19,14 @@ namespace Umbraco.Core.IO private string _shadowDir; private readonly IIOHelper _ioHelper; private readonly IHostingEnvironment _hostingEnvironment; - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; - public ShadowWrapper(IFileSystem innerFileSystem, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILogger logger, string shadowPath, Func isScoped = null) + public ShadowWrapper(IFileSystem innerFileSystem, IIOHelper ioHelper, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory, string shadowPath, Func isScoped = null) { _innerFileSystem = innerFileSystem; _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _loggerFactory = loggerFactory; _shadowPath = shadowPath; _isScoped = isScoped; } @@ -66,7 +66,7 @@ namespace Umbraco.Core.IO var virt = ShadowFsPath + "/" + id + "/" + _shadowPath; _shadowDir = _ioHelper.MapPath(virt); Directory.CreateDirectory(_shadowDir); - var tempfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, virt); + var tempfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _loggerFactory.CreateLogger(), virt); _shadowFileSystem = new ShadowFileSystem(_innerFileSystem, tempfs); } 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/Logging/ConsoleLogger.cs b/src/Umbraco.Core/Logging/ConsoleLogger.cs deleted file mode 100644 index 275b8d988b..0000000000 --- a/src/Umbraco.Core/Logging/ConsoleLogger.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; - -namespace Umbraco.Core.Logging -{ - public class ConsoleLogger : ILogger - { - private readonly IMessageTemplates _messageTemplates; - - public ConsoleLogger(IMessageTemplates messageTemplates) - { - _messageTemplates = messageTemplates; - } - - public bool IsEnabled(Type reporting, LogLevel level) - => true; - - public void Fatal(Type reporting, Exception exception, string message) - { - Console.WriteLine("FATAL {0} - {1}", reporting.Name, message); - Console.WriteLine(exception); - } - - public void Fatal(Type reporting, Exception exception) - { - Console.WriteLine("FATAL {0}", reporting.Name); - Console.WriteLine(exception); - } - - public void Fatal(Type reporting, string message) - { - Console.WriteLine("FATAL {0} - {1}", reporting.Name, message); - } - - public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - { - Console.WriteLine("FATAL {0} - {1}", reporting.Name, _messageTemplates.Render(messageTemplate, propertyValues)); - Console.WriteLine(exception); - } - - public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues) - { - Console.WriteLine("FATAL {0} - {1}", reporting.Name, _messageTemplates.Render(messageTemplate, propertyValues)); - } - - public void Error(Type reporting, Exception exception, string message) - { - Console.WriteLine("ERROR {0} - {1}", reporting.Name, message); - Console.WriteLine(exception); - } - - public void Error(Type reporting, Exception exception) - { - Console.WriteLine("ERROR {0}", reporting.Name); - Console.WriteLine(exception); - } - - public void Error(Type reporting, string message) - { - Console.WriteLine("ERROR {0} - {1}", reporting.Name, message); - } - - public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - { - Console.WriteLine("ERROR {0} - {1}", reporting.Name, _messageTemplates.Render(messageTemplate, propertyValues)); - Console.WriteLine(exception); - } - - public void Error(Type reporting, string messageTemplate, params object[] propertyValues) - { - Console.WriteLine("ERROR {0} - {1}", reporting.Name, _messageTemplates.Render(messageTemplate, propertyValues)); - } - - public void Warn(Type reporting, string message) - { - Console.WriteLine("WARN {0} - {1}", reporting.Name, message); - } - - public void Warn(Type reporting, string message, params object[] propertyValues) - { - Console.WriteLine("WARN {0} - {1}", reporting.Name, _messageTemplates.Render(message, propertyValues)); - } - - public void Warn(Type reporting, Exception exception, string message) - { - Console.WriteLine("WARN {0} - {1}", reporting.Name, message); - Console.WriteLine(exception); - } - - public void Warn(Type reporting, Exception exception, string message, params object[] propertyValues) - { - Console.WriteLine("WARN {0} - {1}", reporting.Name, _messageTemplates.Render(message, propertyValues)); - Console.WriteLine(exception); - } - - public void Info(Type reporting, string messageTemplate, params object[] propertyValues) - { - Console.WriteLine("INFO {0} - {1}", reporting.Name, _messageTemplates.Render(messageTemplate, propertyValues)); - } - - public void Info(Type reporting, string message) - { - Console.WriteLine("INFO {0} - {1}", reporting.Name, message); - } - - public void Debug(Type reporting, string message) - { - Console.WriteLine("DEBUG {0} - {1}", reporting.Name, message); - } - - public void Debug(Type reporting, string messageTemplate, params object[] propertyValues) - { - Console.WriteLine("DEBUG {0} - {1}", reporting.Name, _messageTemplates.Render(messageTemplate, propertyValues)); - } - - public void Verbose(Type reporting, string message) - { - Console.WriteLine("VERBOSE {0} - {1}", reporting.Name, message); - } - - public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues) - { - Console.WriteLine("VERBOSE {0} - {1}", reporting.Name, _messageTemplates.Render(messageTemplate, propertyValues)); - } - } -} diff --git a/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs b/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs deleted file mode 100644 index 552daba713..0000000000 --- a/src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; - -namespace Umbraco.Core.Logging -{ - /// - /// Implements on top of . - /// - public class DebugDiagnosticsLogger : ILogger - { - private readonly IMessageTemplates _messageTemplates; - - public DebugDiagnosticsLogger(IMessageTemplates messageTemplates) - { - _messageTemplates = messageTemplates; - } - - public bool IsEnabled(Type reporting, LogLevel level) - => true; - - /// - public void Fatal(Type reporting, Exception exception, string message) - { - System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, reporting.FullName); - } - - /// - public void Fatal(Type reporting, Exception exception) - { - System.Diagnostics.Debug.WriteLine(Environment.NewLine + exception, reporting.FullName); - } - - /// - public void Fatal(Type reporting, string message) - { - System.Diagnostics.Debug.WriteLine(message); - } - - /// - public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName); - } - - /// - public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(messageTemplate, propertyValues); - } - - /// - public void Error(Type reporting, Exception exception, string message) - { - System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, reporting.FullName); - } - - /// - public void Error(Type reporting, Exception exception) - { - System.Diagnostics.Debug.WriteLine(Environment.NewLine + exception, reporting.FullName); - } - - /// - public void Error(Type reporting, string message) - { - System.Diagnostics.Debug.WriteLine(message); - } - - /// - public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues) + Environment.NewLine + exception, reporting.FullName); - } - - /// - public void Error(Type reporting, string messageTemplate, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(messageTemplate, propertyValues); - } - - /// - public void Warn(Type reporting, string message) - { - System.Diagnostics.Debug.WriteLine(message, reporting.FullName); - } - - /// - public void Warn(Type reporting, string message, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(message, propertyValues), reporting.FullName); - } - - /// - public void Warn(Type reporting, Exception exception, string message) - { - System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, reporting.FullName); - } - - /// - public void Warn(Type reporting, Exception exception, string message, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(message + Environment.NewLine + exception, propertyValues), reporting.FullName); - } - - /// - public void Info(Type reporting, string message) - { - System.Diagnostics.Debug.WriteLine(message, reporting.FullName); - } - - /// - public void Info(Type reporting, string messageTemplate, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues), reporting.FullName); - } - - /// - public void Debug(Type reporting, string message) - { - System.Diagnostics.Debug.WriteLine(message, reporting.FullName); - } - - /// - public void Debug(Type reporting, string messageTemplate, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues), reporting.FullName); - } - - /// - public void Verbose(Type reporting, string message) - { - System.Diagnostics.Debug.WriteLine(message, reporting.FullName); - } - - /// - public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues) - { - System.Diagnostics.Debug.WriteLine(_messageTemplates.Render(messageTemplate, propertyValues), reporting.FullName); - } - } -} diff --git a/src/Umbraco.Core/Logging/DisposableTimer.cs b/src/Umbraco.Core/Logging/DisposableTimer.cs index d854813b7d..9fdb93c057 100644 --- a/src/Umbraco.Core/Logging/DisposableTimer.cs +++ b/src/Umbraco.Core/Logging/DisposableTimer.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Logging { @@ -37,10 +38,10 @@ namespace Umbraco.Core.Logging switch (_level) { case LogLevel.Debug: - logger.Debug(loggerType, "{StartMessage} [Timing {TimingId}]", startMessage, _timingId); + logger.LogDebug("{StartMessage} [Timing {TimingId}]", startMessage, _timingId); break; case LogLevel.Information: - logger.Info(loggerType, "{StartMessage} [Timing {TimingId}]", startMessage, _timingId); + logger.LogInformation("{StartMessage} [Timing {TimingId}]", startMessage, _timingId); break; default: throw new ArgumentOutOfRangeException(nameof(level)); @@ -84,15 +85,15 @@ namespace Umbraco.Core.Logging { if (_failed) { - _logger.Error(_loggerType, _failException, "{FailMessage} ({Duration}ms) [Timing {TimingId}]", _failMessage, Stopwatch.ElapsedMilliseconds, _timingId); + _logger.LogError(_failException, "{FailMessage} ({Duration}ms) [Timing {TimingId}]", _failMessage, Stopwatch.ElapsedMilliseconds, _timingId); } else switch (_level) { case LogLevel.Debug: - _logger.Debug(_loggerType, "{EndMessage} ({Duration}ms) [Timing {TimingId}]", _endMessage, Stopwatch.ElapsedMilliseconds, _timingId); + _logger.LogDebug("{EndMessage} ({Duration}ms) [Timing {TimingId}]", _endMessage, Stopwatch.ElapsedMilliseconds, _timingId); break; case LogLevel.Information: - _logger.Info(_loggerType, "{EndMessage} ({Duration}ms) [Timing {TimingId}]", _endMessage, Stopwatch.ElapsedMilliseconds, _timingId); + _logger.LogInformation("{EndMessage} ({Duration}ms) [Timing {TimingId}]", _endMessage, Stopwatch.ElapsedMilliseconds, _timingId); break; // filtered in the ctor //default: diff --git a/src/Umbraco.Core/Logging/ILogger.cs b/src/Umbraco.Core/Logging/ILogger.cs deleted file mode 100644 index fe7d798ebf..0000000000 --- a/src/Umbraco.Core/Logging/ILogger.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System; - -namespace Umbraco.Core.Logging -{ - - /// - /// Defines the logging service. - /// - /// - /// Message templates in logging methods follow the Message Templates specification - /// available at https://messagetemplates.org/ in order to support structured logging. - /// Implementations must ensure that they support these templates. Note that the - /// specification includes support for traditional C# numeric placeholders. - /// For instance, "Processed {Input} in {Time}ms." - /// - public interface ILogger - { - /// - /// Determines if logging is enabled at a specified level, for a reporting type. - /// - /// The reporting type. - /// The level. - bool IsEnabled(Type reporting, LogLevel level); - - /// - /// Logs a fatal message with an exception. - /// - /// The reporting type. - /// An exception. - /// A message. - void Fatal(Type reporting, Exception exception, string message); - - /// - /// Logs a fatal exception. - /// - /// The reporting type. - /// An exception. - /// The message string is unspecified and is implementation-specific. - void Fatal(Type reporting, Exception exception); - - /// - /// Logs a fatal message. - /// - /// The reporting type. - /// A message. - void Fatal(Type reporting, string message); - - /// - /// Logs a fatal message with an exception. - /// - /// The reporting type. - /// An exception. - /// A message template. - /// Property values. - void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues); - - /// - /// Logs a fatal message. - /// - /// The reporting type. - /// A message template. - /// Property values. - void Fatal(Type reporting, string messageTemplate, params object[] propertyValues); - - /// - /// Logs an error message with an exception. - /// - /// The reporting type. - /// An exception. - /// A message. - void Error(Type reporting, Exception exception, string message); - - /// - /// Logs an error exception. - /// - /// The reporting type. - /// An exception. - /// The message string is unspecified and is implementation-specific. - void Error(Type reporting, Exception exception); - - /// - /// Logs an error message. - /// - /// The reporting type. - /// A message. - void Error(Type reporting, string message); - - /// - /// Logs an error message with an exception. - /// - /// The reporting type. - /// An exception. - /// A message template. - /// Property values. - void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues); - - /// - /// Logs an error message. - /// - /// The reporting type. - /// A message template. - /// Property values. - void Error(Type reporting, string messageTemplate, params object[] propertyValues); - - /// - /// Logs a warning message. - /// - /// The reporting type. - /// A message. - void Warn(Type reporting, string message); - - /// - /// Logs a warning message. - /// - /// The reporting type. - /// A message template. - /// Property values. - void Warn(Type reporting, string messageTemplate, params object[] propertyValues); - - /// - /// Logs a warning message with an exception. - /// - /// The reporting type. - /// An exception. - /// A message. - void Warn(Type reporting, Exception exception, string message); - - /// - /// Logs a warning message with an exception. - /// - /// The reporting type. - /// An exception. - /// A message template. - /// Property values. - void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues); - - /// - /// Logs an information message. - /// - /// The reporting type. - /// A message. - void Info(Type reporting, string message); - - /// - /// Logs a info message. - /// - /// The reporting type. - /// A message template. - /// Property values. - void Info(Type reporting, string messageTemplate, params object[] propertyValues); - - /// - /// Logs a debugging message. - /// - /// The reporting type. - /// A message. - void Debug(Type reporting, string message); - - /// - /// Logs a debug message. - /// - /// The reporting type. - /// A message template. - /// Property values. - void Debug(Type reporting, string messageTemplate, params object[] propertyValues); - - /// - /// Logs a verbose message. - /// - /// The reporting type. - /// A message. - void Verbose(Type reporting, string message); - - /// - /// Logs a verbose message. - /// - /// The reporting type. - /// A message template. - /// Property values. - void Verbose(Type reporting, string messageTemplate, params object[] propertyValues); - } -} diff --git a/src/Umbraco.Core/Logging/ILoggingConfiguration.cs b/src/Umbraco.Core/Logging/ILoggingConfiguration.cs index 47e2d8fa7c..d21a08e688 100644 --- a/src/Umbraco.Core/Logging/ILoggingConfiguration.cs +++ b/src/Umbraco.Core/Logging/ILoggingConfiguration.cs @@ -7,7 +7,5 @@ /// The physical path where logs are stored /// string LogDirectory { get; } - string LogConfigurationFile { get; } - string UserLogConfigurationFile { get; } } } diff --git a/src/Umbraco.Core/Logging/IProfilingLogger.cs b/src/Umbraco.Core/Logging/IProfilingLogger.cs index 1d7c231e95..019b43d61e 100644 --- a/src/Umbraco.Core/Logging/IProfilingLogger.cs +++ b/src/Umbraco.Core/Logging/IProfilingLogger.cs @@ -5,7 +5,7 @@ namespace Umbraco.Core.Logging /// /// Defines the profiling logging service. /// - public interface IProfilingLogger : ILogger + public interface IProfilingLogger { /// /// Profiles an action and log as information messages. diff --git a/src/Umbraco.Core/Logging/LogProfiler.cs b/src/Umbraco.Core/Logging/LogProfiler.cs index a1d2a2e61f..047331fd3a 100644 --- a/src/Umbraco.Core/Logging/LogProfiler.cs +++ b/src/Umbraco.Core/Logging/LogProfiler.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Logging { @@ -8,9 +9,9 @@ namespace Umbraco.Core.Logging /// public class LogProfiler : IProfiler { - private readonly ILogger _logger; + private readonly ILogger _logger; - public LogProfiler(ILogger logger) + public LogProfiler(ILogger logger) { _logger = logger; } @@ -18,8 +19,8 @@ namespace Umbraco.Core.Logging /// public IDisposable Step(string name) { - _logger.Debug("Begin: {ProfileName}", name); - return new LightDisposableTimer(duration => _logger.Info("End {ProfileName} ({ProfileDuration}ms)", name, duration)); + _logger.LogDebug("Begin: {ProfileName}", name); + return new LightDisposableTimer(duration => _logger.LogInformation("End {ProfileName} ({ProfileDuration}ms)", name, duration)); } /// diff --git a/src/Umbraco.Core/Logging/LoggerExtensions.cs b/src/Umbraco.Core/Logging/LoggerExtensions.cs deleted file mode 100644 index 3b105ed888..0000000000 --- a/src/Umbraco.Core/Logging/LoggerExtensions.cs +++ /dev/null @@ -1,186 +0,0 @@ -using System; - -namespace Umbraco.Core.Logging -{ - /// - /// Provides extension methods for the interface. - /// - public static class LoggerExtensions - { - /// - /// Determines if logging is enabled at a specified level, for a reporting type. - /// - /// The reporting type. - /// The logger. - /// The level. - public static bool IsEnabled(this ILogger logger, LogLevel level) - => logger.IsEnabled(typeof(T), level); - - /// - /// Logs an error message with an exception. - /// - /// The reporting type. - /// The logger. - /// A message. - /// An exception. - public static void Error(this ILogger logger, Exception exception, string message) - => logger.Error(typeof(T), exception, message); - - /// - /// Logs an error message with an exception. - /// - /// The reporting type. - /// The logger. - /// An exception. - /// A message template. - /// Property values. - public static void Error(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues) - => logger.Error(typeof(T), exception, messageTemplate, propertyValues); - - /// - /// Logs an error exception. - /// - /// The reporting type. - /// The logger. - /// An exception. - public static void Error(this ILogger logger, Exception exception) - => logger.Error(typeof(T), exception); - - /// - /// Logs an error message. - /// - /// The reporting type. - /// The logger. - /// A message. - public static void Error(this ILogger logger, string message) - => logger.Error(typeof(T), message); - - /// - /// Logs an error message. - /// - /// The reporting type. - /// The logger. - /// A message template. - /// Property values. - public static void Error(this ILogger logger, string messageTemplate, params object[] propertyValues) - => logger.Error(typeof(T), messageTemplate, propertyValues); - - /// - /// Logs a warning message. - /// - /// The reporting type. - /// The logger. - /// A message. - public static void Warn(this ILogger logger, string message) - => logger.Warn(typeof(T), message); - - /// - /// Logs a warning message. - /// - /// The reporting type. - /// The logger. - /// A message template. - /// Property values. - public static void Warn(this ILogger logger, string messageTemplate, params object[] propertyValues) - => logger.Warn(typeof(T), messageTemplate, propertyValues); - - /// - /// Logs a warning message with an exception. - /// - /// The reporting type. - /// The logger. - /// An exception. - /// A message. - public static void Warn(this ILogger logger, Exception exception, string message) - => logger.Warn(typeof(T), exception, message); - - /// - /// Logs a warning message with an exception. - /// - /// The reporting type. - /// The logger. - /// An exception. - /// A message template. - /// Property values. - public static void Warn(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues) - => logger.Warn(typeof(T), exception, messageTemplate, propertyValues); - - /// - /// Logs an information message. - /// - /// The reporting type. - /// The logger. - /// A message. - public static void Info(this ILogger logger, string message) - => logger.Info(typeof(T), message); - - /// - /// Logs a information message. - /// - /// The reporting type - /// The logger. - /// A message template. - /// Property values. - public static void Info(this ILogger logger, string messageTemplate, params object[] propertyValues) - => logger.Info(typeof(T), messageTemplate, propertyValues); - - /// - /// Logs a debugging message. - /// - /// The reporting type. - /// The logger. - /// A message. - public static void Debug(this ILogger logger, string message) - => logger.Debug(typeof(T), message); - - /// - /// Logs a debugging message. - /// - /// The reporting type - /// The logger. - /// A message template. - /// Property values. - public static void Debug(this ILogger logger, string messageTemplate, params object[] propertyValues) - => logger.Debug(typeof(T), messageTemplate, propertyValues); - - /// - /// Logs a verbose message. - /// - /// The reporting type. - /// The logger. - /// A message. - public static void Verbose(this ILogger logger, string message) - => logger.Verbose(typeof(T), message); - - /// - /// Logs a verbose message. - /// - /// The reporting type. - /// The logger. - /// A message template. - /// Property values. - public static void Verbose(this ILogger logger, string messageTemplate, params object[] propertyValues) - => logger.Verbose(typeof(T), messageTemplate, propertyValues); - - /// - /// Logs a fatal message. - /// - /// The reporting type. - /// The logger. - /// An exception. - /// A message. - public static void Fatal(this ILogger logger, Exception exception, string message) - => logger.Fatal(typeof(T), exception, message); - - /// - /// Logs a fatal message. - /// - /// The reporting type. - /// The logger. - /// An exception. - /// A message template. - /// Property values. - public static void Fatal(this ILogger logger, Exception exception, string messageTemplate, params object[] propertyValues) - => logger.Fatal(typeof(T), exception, messageTemplate, propertyValues); - } -} diff --git a/src/Umbraco.Core/Logging/LoggingConfiguration.cs b/src/Umbraco.Core/Logging/LoggingConfiguration.cs index c657c9d430..ecd806211c 100644 --- a/src/Umbraco.Core/Logging/LoggingConfiguration.cs +++ b/src/Umbraco.Core/Logging/LoggingConfiguration.cs @@ -4,17 +4,11 @@ namespace Umbraco.Core.Logging { public class LoggingConfiguration : ILoggingConfiguration { - public LoggingConfiguration(string logDirectory, string logConfigurationFile, string userLogConfigurationFile) + public LoggingConfiguration(string logDirectory) { LogDirectory = logDirectory ?? throw new ArgumentNullException(nameof(logDirectory)); - LogConfigurationFile = logConfigurationFile ?? throw new ArgumentNullException(nameof(logConfigurationFile)); - UserLogConfigurationFile = userLogConfigurationFile ?? throw new ArgumentNullException(nameof(userLogConfigurationFile)); } public string LogDirectory { get; } - - public string LogConfigurationFile { get; } - - public string UserLogConfigurationFile { get; } } } diff --git a/src/Umbraco.Core/Logging/NullLogger.cs b/src/Umbraco.Core/Logging/NullLogger.cs deleted file mode 100644 index 7945e0b965..0000000000 --- a/src/Umbraco.Core/Logging/NullLogger.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; - -namespace Umbraco.Core.Logging -{ - public class NullLogger : ILogger - { - public bool IsEnabled(Type reporting, LogLevel level) => false; - - public void Fatal(Type reporting, Exception exception, string message) - { - - } - - public void Fatal(Type reporting, Exception exception) - { - - } - - public void Fatal(Type reporting, string message) - { - - } - - public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - { - - } - - public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues) - { - - } - - public void Error(Type reporting, Exception exception, string message) - { - - } - - public void Error(Type reporting, Exception exception) - { - - } - - public void Error(Type reporting, string message) - { - - } - - public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - { - - } - - public void Error(Type reporting, string messageTemplate, params object[] propertyValues) - { - - } - - public void Warn(Type reporting, string message) - { - - } - - public void Warn(Type reporting, string messageTemplate, params object[] propertyValues) - { - - } - - public void Warn(Type reporting, Exception exception, string message) - { - - } - - public void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - { - - } - - public void Info(Type reporting, string message) - { - - } - - public void Info(Type reporting, string messageTemplate, params object[] propertyValues) - { - - } - - public void Debug(Type reporting, string message) - { - - } - - public void Debug(Type reporting, string messageTemplate, params object[] propertyValues) - { - - } - - public void Verbose(Type reporting, string message) - { - - } - - public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues) - { - - } - } -} diff --git a/src/Umbraco.Core/Logging/ProfilingLogger.cs b/src/Umbraco.Core/Logging/ProfilingLogger.cs index d642926147..7bf04e3d77 100644 --- a/src/Umbraco.Core/Logging/ProfilingLogger.cs +++ b/src/Umbraco.Core/Logging/ProfilingLogger.cs @@ -1,4 +1,7 @@ using System; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Models; + namespace Umbraco.Core.Logging { @@ -43,89 +46,56 @@ namespace Umbraco.Core.Logging public DisposableTimer DebugDuration(string startMessage) { - return Logger.IsEnabled(LogLevel.Debug) + return Logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug) ? DebugDuration(startMessage, "Completed.") : null; } public DisposableTimer DebugDuration(string startMessage, string completeMessage, string failMessage = null, int thresholdMilliseconds = 0) { - return Logger.IsEnabled(LogLevel.Debug) + return Logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug) ? new DisposableTimer(Logger, LogLevel.Debug, Profiler, typeof(T), startMessage, completeMessage, failMessage, thresholdMilliseconds) : null; } public DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage, string failMessage = null, int thresholdMilliseconds = 0) { - return Logger.IsEnabled(loggerType, LogLevel.Debug) + return Logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug) ? new DisposableTimer(Logger, LogLevel.Debug, Profiler, loggerType, startMessage, completeMessage, failMessage, thresholdMilliseconds) : null; } #region ILogger - public bool IsEnabled(Type reporting, LogLevel level) - => Logger.IsEnabled(reporting, level); + public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel level) + => Logger.IsEnabled(level); - public void Fatal(Type reporting, Exception exception, string message) - => Logger.Fatal(reporting, exception, message); + public void LogCritical(Exception exception, string messageTemplate, params object[] propertyValues) + => Logger.LogCritical(exception, messageTemplate, propertyValues); - public void Fatal(Type reporting, Exception exception) - => Logger.Fatal(reporting, exception); + public void LogCritical(string messageTemplate, params object[] propertyValues) + => Logger.LogCritical(messageTemplate, propertyValues); - public void Fatal(Type reporting, string message) - => Logger.Fatal(reporting, message); + public void LogError(Exception exception, string messageTemplate, params object[] propertyValues) + => Logger.LogError(exception, messageTemplate, propertyValues); - public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - => Logger.Fatal(reporting, exception, messageTemplate, propertyValues); + public void LogError(string messageTemplate, params object[] propertyValues) + => Logger.LogError(messageTemplate, propertyValues); - public void Fatal(Type reporting, string messageTemplate, params object[] propertyValues) - => Logger.Fatal(reporting, messageTemplate, propertyValues); + public void LogWarning(string messageTemplate, params object[] propertyValues) + => Logger.LogWarning(messageTemplate, propertyValues); - public void Error(Type reporting, Exception exception, string message) - => Logger.Error(reporting, exception, message); + public void LogWarning(Exception exception, string messageTemplate, params object[] propertyValues) + => Logger.LogWarning(exception, messageTemplate, propertyValues); - public void Error(Type reporting, Exception exception) - => Logger.Error(reporting, exception); + public void LogInformation(string messageTemplate, params object[] propertyValues) + => Logger.LogInformation(messageTemplate, propertyValues); - public void Error(Type reporting, string message) - => Logger.Error(reporting, message); + public void LogDebug(string messageTemplate, params object[] propertyValues) + => Logger.LogDebug(messageTemplate, propertyValues); - public void Error(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - => Logger.Error(reporting, exception, messageTemplate, propertyValues); - - public void Error(Type reporting, string messageTemplate, params object[] propertyValues) - => Logger.Error(reporting, messageTemplate, propertyValues); - - public void Warn(Type reporting, string message) - => Logger.Warn(reporting, message); - - public void Warn(Type reporting, string messageTemplate, params object[] propertyValues) - => Logger.Warn(reporting, messageTemplate, propertyValues); - - public void Warn(Type reporting, Exception exception, string message) - => Logger.Warn(reporting, exception, message); - - public void Warn(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) - => Logger.Warn(reporting, exception, messageTemplate, propertyValues); - - public void Info(Type reporting, string message) - => Logger.Info(reporting, message); - - public void Info(Type reporting, string messageTemplate, params object[] propertyValues) - => Logger.Info(reporting, messageTemplate, propertyValues); - - public void Debug(Type reporting, string message) - => Logger.Debug(reporting, message); - - public void Debug(Type reporting, string messageTemplate, params object[] propertyValues) - => Logger.Debug(reporting, messageTemplate, propertyValues); - - public void Verbose(Type reporting, string message) - => Logger.Verbose(reporting, message); - - public void Verbose(Type reporting, string messageTemplate, params object[] propertyValues) - => Logger.Verbose(reporting, messageTemplate, propertyValues); + public void LogTrace(string messageTemplate, params object[] propertyValues) + => Logger.LogTrace(messageTemplate, propertyValues); #endregion } diff --git a/src/Umbraco.Core/Manifest/ManifestWatcher.cs b/src/Umbraco.Core/Manifest/ManifestWatcher.cs index 23caac3a1b..6bd893d298 100644 --- a/src/Umbraco.Core/Manifest/ManifestWatcher.cs +++ b/src/Umbraco.Core/Manifest/ManifestWatcher.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Net; namespace Umbraco.Core.Manifest @@ -13,11 +13,11 @@ namespace Umbraco.Core.Manifest private static readonly object Locker = new object(); private static volatile bool _isRestarting; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; private readonly List _fws = new List(); - public ManifestWatcher(ILogger logger, IUmbracoApplicationLifetime umbracoApplicationLifetime) + public ManifestWatcher(ILogger logger, IUmbracoApplicationLifetime umbracoApplicationLifetime) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _umbracoApplicationLifetime = umbracoApplicationLifetime; @@ -57,7 +57,7 @@ namespace Umbraco.Core.Manifest if (_isRestarting) return; _isRestarting = true; - _logger.Info("Manifest has changed, app pool is restarting ({Path})", e.FullPath); + _logger.LogInformation("Manifest has changed, app pool is restarting ({Path})", e.FullPath); _umbracoApplicationLifetime.Restart(); Dispose(); // uh? if the app restarts then this should be disposed anyways? } diff --git a/src/Umbraco.Core/Media/IImageUrlGenerator.cs b/src/Umbraco.Core/Media/IImageUrlGenerator.cs index f9e67cdd2b..7c77a34388 100644 --- a/src/Umbraco.Core/Media/IImageUrlGenerator.cs +++ b/src/Umbraco.Core/Media/IImageUrlGenerator.cs @@ -1,9 +1,12 @@ -using Umbraco.Core.Models; +using System.Collections.Generic; +using Umbraco.Core.Models; namespace Umbraco.Core.Media { public interface IImageUrlGenerator { + IEnumerable SupportedImageFileTypes { get; } + string GetImageUrl(ImageUrlGenerationOptions options); } } diff --git a/src/Umbraco.Core/Media/ImageUrlGeneratorExtensions.cs b/src/Umbraco.Core/Media/ImageUrlGeneratorExtensions.cs new file mode 100644 index 0000000000..902f84331b --- /dev/null +++ b/src/Umbraco.Core/Media/ImageUrlGeneratorExtensions.cs @@ -0,0 +1,21 @@ +using System; + +namespace Umbraco.Core.Media +{ + public static class ImageUrlGeneratorExtensions + { + /// + /// Gets a value indicating whether the file extension corresponds to a supported image. + /// + /// The image URL generator implementation that provides detail on which image extension sare supported. + /// The file extension. + /// A value indicating whether the file extension corresponds to an image. + public static bool IsSupportedImageFormat(this IImageUrlGenerator imageUrlGenerator, string extension) + { + if (imageUrlGenerator == null) throw new ArgumentNullException(nameof(imageUrlGenerator)); + if (extension == null) return false; + extension = extension.TrimStart('.'); + return imageUrlGenerator.SupportedImageFileTypes.InvariantContains(extension); + } + } +} 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/Mapping/ContentPropertyBasicMapper.cs b/src/Umbraco.Core/Models/Mapping/ContentPropertyBasicMapper.cs index a46a0b0d86..9742753b47 100644 --- a/src/Umbraco.Core/Models/Mapping/ContentPropertyBasicMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentPropertyBasicMapper.cs @@ -1,7 +1,7 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -17,11 +17,11 @@ namespace Umbraco.Web.Models.Mapping where TDestination : ContentPropertyBasic, new() { private readonly IEntityService _entityService; - private readonly ILogger _logger; + private readonly ILogger> _logger; private readonly PropertyEditorCollection _propertyEditors; protected IDataTypeService DataTypeService { get; } - public ContentPropertyBasicMapper(IDataTypeService dataTypeService, IEntityService entityService, ILogger logger, PropertyEditorCollection propertyEditors) + public ContentPropertyBasicMapper(IDataTypeService dataTypeService, IEntityService entityService, ILogger> logger, PropertyEditorCollection propertyEditors) { _logger = logger; _propertyEditors = propertyEditors; @@ -38,7 +38,7 @@ namespace Umbraco.Web.Models.Mapping var editor = _propertyEditors[property.PropertyType.PropertyEditorAlias]; if (editor == null) { - _logger.Error>( + _logger.LogError( new NullReferenceException("The property editor with alias " + property.PropertyType.PropertyEditorAlias + " does not exist"), "No property editor '{PropertyEditorAlias}' found, converting to a Label", property.PropertyType.PropertyEditorAlias); diff --git a/src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs b/src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs index 2bde6d72b1..a7771015a0 100644 --- a/src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs @@ -1,5 +1,5 @@ -using Umbraco.Core.Dictionary; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Dictionary; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -16,7 +16,7 @@ namespace Umbraco.Web.Models.Mapping private readonly ICultureDictionary _cultureDictionary; private readonly ILocalizedTextService _textService; - public ContentPropertyDisplayMapper(ICultureDictionary cultureDictionary, IDataTypeService dataTypeService, IEntityService entityService, ILocalizedTextService textService, ILogger logger, PropertyEditorCollection propertyEditors) + public ContentPropertyDisplayMapper(ICultureDictionary cultureDictionary, IDataTypeService dataTypeService, IEntityService entityService, ILocalizedTextService textService, ILogger logger, PropertyEditorCollection propertyEditors) : base(dataTypeService, entityService, logger, propertyEditors) { _cultureDictionary = cultureDictionary; diff --git a/src/Umbraco.Core/Models/Mapping/ContentPropertyDtoMapper.cs b/src/Umbraco.Core/Models/Mapping/ContentPropertyDtoMapper.cs index bc37bf6e2b..e431614afc 100644 --- a/src/Umbraco.Core/Models/Mapping/ContentPropertyDtoMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentPropertyDtoMapper.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -12,7 +12,7 @@ namespace Umbraco.Web.Models.Mapping /// internal class ContentPropertyDtoMapper : ContentPropertyBasicMapper { - public ContentPropertyDtoMapper(IDataTypeService dataTypeService, IEntityService entityService, ILogger logger, PropertyEditorCollection propertyEditors) + public ContentPropertyDtoMapper(IDataTypeService dataTypeService, IEntityService entityService, ILogger logger, PropertyEditorCollection propertyEditors) : base(dataTypeService, entityService, logger, propertyEditors) { } diff --git a/src/Umbraco.Core/Models/Mapping/ContentPropertyMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/ContentPropertyMapDefinition.cs index c5b989e39c..a74b0467e2 100644 --- a/src/Umbraco.Core/Models/Mapping/ContentPropertyMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentPropertyMapDefinition.cs @@ -1,5 +1,5 @@ -using Umbraco.Core.Dictionary; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Dictionary; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -18,11 +18,11 @@ namespace Umbraco.Web.Models.Mapping private readonly ContentPropertyDtoMapper _contentPropertyDtoConverter; private readonly ContentPropertyDisplayMapper _contentPropertyDisplayMapper; - public ContentPropertyMapDefinition(ICultureDictionary cultureDictionary, IDataTypeService dataTypeService, IEntityService entityService, ILocalizedTextService textService, ILogger logger, PropertyEditorCollection propertyEditors) + public ContentPropertyMapDefinition(ICultureDictionary cultureDictionary, IDataTypeService dataTypeService, IEntityService entityService, ILocalizedTextService textService, ILoggerFactory loggerFactory, PropertyEditorCollection propertyEditors) { - _contentPropertyBasicConverter = new ContentPropertyBasicMapper(dataTypeService, entityService, logger, propertyEditors); - _contentPropertyDtoConverter = new ContentPropertyDtoMapper(dataTypeService, entityService, logger, propertyEditors); - _contentPropertyDisplayMapper = new ContentPropertyDisplayMapper(cultureDictionary, dataTypeService, entityService, textService, logger, propertyEditors); + _contentPropertyBasicConverter = new ContentPropertyBasicMapper(dataTypeService, entityService, loggerFactory.CreateLogger>(), propertyEditors); + _contentPropertyDtoConverter = new ContentPropertyDtoMapper(dataTypeService, entityService, loggerFactory.CreateLogger(), propertyEditors); + _contentPropertyDisplayMapper = new ContentPropertyDisplayMapper(cultureDictionary, dataTypeService, entityService, textService, loggerFactory.CreateLogger(), propertyEditors); } public void DefineMaps(UmbracoMapper mapper) 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/Member.cs b/src/Umbraco.Core/Models/Member.cs index 706729b71a..d155db8b7c 100644 --- a/src/Umbraco.Core/Models/Member.cs +++ b/src/Umbraco.Core/Models/Member.cs @@ -2,8 +2,9 @@ using System.Collections.Generic; using System.ComponentModel; using System.Runtime.Serialization; +using Microsoft.Extensions.Logging; using Umbraco.Composing; -using Umbraco.Core.Logging; + namespace Umbraco.Core.Models { @@ -414,7 +415,7 @@ namespace Umbraco.Core.Models public virtual string ContentTypeAlias => ContentType.Alias; /// - /// Internal/Experimental - only used for mapping queries. + /// Internal/Experimental - only used for mapping queries. /// /// /// Adding these to have first level properties instead of the Properties collection. @@ -423,7 +424,7 @@ namespace Umbraco.Core.Models [EditorBrowsable(EditorBrowsableState.Never)] public string LongStringPropertyValue { get; set; } /// - /// Internal/Experimental - only used for mapping queries. + /// Internal/Experimental - only used for mapping queries. /// /// /// Adding these to have first level properties instead of the Properties collection. @@ -432,7 +433,7 @@ namespace Umbraco.Core.Models [EditorBrowsable(EditorBrowsableState.Never)] public string ShortStringPropertyValue { get; set; } /// - /// Internal/Experimental - only used for mapping queries. + /// Internal/Experimental - only used for mapping queries. /// /// /// Adding these to have first level properties instead of the Properties collection. @@ -441,7 +442,7 @@ namespace Umbraco.Core.Models [EditorBrowsable(EditorBrowsableState.Never)] public int IntegerPropertyValue { get; set; } /// - /// Internal/Experimental - only used for mapping queries. + /// Internal/Experimental - only used for mapping queries. /// /// /// Adding these to have first level properties instead of the Properties collection. @@ -450,7 +451,7 @@ namespace Umbraco.Core.Models [EditorBrowsable(EditorBrowsableState.Never)] public bool BoolPropertyValue { get; set; } /// - /// Internal/Experimental - only used for mapping queries. + /// Internal/Experimental - only used for mapping queries. /// /// /// Adding these to have first level properties instead of the Properties collection. @@ -459,7 +460,7 @@ namespace Umbraco.Core.Models [EditorBrowsable(EditorBrowsableState.Never)] public DateTime DateTimePropertyValue { get; set; } /// - /// Internal/Experimental - only used for mapping queries. + /// Internal/Experimental - only used for mapping queries. /// /// /// Adding these to have first level properties instead of the Properties collection. @@ -472,7 +473,7 @@ namespace Umbraco.Core.Models { void DoLog(string logPropertyAlias, string logPropertyName) { - Current.Logger.Warn("Trying to access the '{PropertyName}' property on '{MemberType}' " + + Current.Logger.LogWarning("Trying to access the '{PropertyName}' property on '{MemberType}' " + "but the {PropertyAlias} property does not exist on the member type so a default value is returned. " + "Ensure that you have a property type with alias: {PropertyAlias} configured on your member type in order to use the '{PropertyName}' property on the model correctly.", logPropertyName, @@ -497,7 +498,7 @@ namespace Umbraco.Core.Models { void DoLog(string logPropertyAlias, string logPropertyName) { - Current.Logger.Warn("An attempt was made to set a value on the property '{PropertyName}' on type '{MemberType}' but the " + + Current.Logger.LogWarning("An attempt was made to set a value on the property '{PropertyName}' on type '{MemberType}' but the " + "property type {PropertyAlias} does not exist on the member type, ensure that this property type exists so that setting this property works correctly.", logPropertyName, typeof(Member), @@ -524,6 +525,6 @@ namespace Umbraco.Core.Models /// [IgnoreDataMember] - public bool HasAdditionalData => _additionalData != null; + public bool HasAdditionalData => _additionalData != null; } } 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/ReadOnlyRelation.cs b/src/Umbraco.Core/Models/ReadOnlyRelation.cs new file mode 100644 index 0000000000..f2801a93ec --- /dev/null +++ b/src/Umbraco.Core/Models/ReadOnlyRelation.cs @@ -0,0 +1,35 @@ +using System; + +namespace Umbraco.Core.Models +{ + /// + /// A read only relation. Can be used to bulk save witch performs better than the normal save operation, + /// but do not populate Ids back to the model + /// + public class ReadOnlyRelation + { + public ReadOnlyRelation(int id, int parentId, int childId, int relationTypeId, DateTime createDate, string comment) + { + Id = id; + ParentId = parentId; + ChildId = childId; + RelationTypeId = relationTypeId; + CreateDate = createDate; + Comment = comment; + } + + public ReadOnlyRelation(int parentId, int childId, int relationTypeId): this(0, parentId, childId, relationTypeId, DateTime.Now, string.Empty) + { + + } + + public int Id { get; } + public int ParentId { get; } + public int ChildId { get; } + public int RelationTypeId { get; } + public DateTime CreateDate { get; } + public string Comment { get; } + + public bool HasIdentity => Id != 0; + } +} 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/PackageActionRunner.cs b/src/Umbraco.Core/Packaging/PackageActionRunner.cs index 42a1a7042d..138feadf29 100644 --- a/src/Umbraco.Core/Packaging/PackageActionRunner.cs +++ b/src/Umbraco.Core/Packaging/PackageActionRunner.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Xml.Linq; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.PackageActions; namespace Umbraco.Core.Packaging @@ -11,10 +11,10 @@ namespace Umbraco.Core.Packaging /// public class PackageActionRunner : IPackageActionRunner { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly PackageActionCollection _packageActions; - public PackageActionRunner(ILogger logger, PackageActionCollection packageActions) + public PackageActionRunner(ILogger logger, PackageActionCollection packageActions) { _logger = logger; _packageActions = packageActions; @@ -34,7 +34,7 @@ namespace Umbraco.Core.Packaging catch (Exception ex) { e.Add($"{ipa.Alias()} - {ex.Message}"); - _logger.Error(ex, "Error loading package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); + _logger.LogError(ex, "Error loading package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); } } @@ -56,7 +56,7 @@ namespace Umbraco.Core.Packaging catch (Exception ex) { e.Add($"{ipa.Alias()} - {ex.Message}"); - _logger.Error(ex, "Error undoing package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); + _logger.LogError(ex, "Error undoing package action '{PackageActionAlias}' for package {PackageName}", ipa.Alias(), packageName); } } errors = e; diff --git a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs index d28ee828c5..a9516d7e25 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Packaging; namespace Umbraco.Core.Packaging @@ -13,10 +13,10 @@ namespace Umbraco.Core.Packaging /// public class PackageDefinitionXmlParser { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUmbracoVersion _umbracoVersion; - public PackageDefinitionXmlParser(ILogger logger, IUmbracoVersion umbracoVersion) + public PackageDefinitionXmlParser(ILogger logger, IUmbracoVersion umbracoVersion) { _logger = logger; _umbracoVersion = umbracoVersion; @@ -68,7 +68,7 @@ namespace Umbraco.Core.Packaging } catch (Exception e) { - _logger.Warn(e, "Could not add package actions to the package xml definition, the xml did not parse"); + _logger.LogWarning(e, "Could not add package actions to the package xml definition, the xml did not parse"); } var packageXml = new XElement("package", 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..59741ab1ce 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -5,10 +5,11 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; 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; using Umbraco.Core.Services; @@ -28,7 +29,8 @@ namespace Umbraco.Core.Packaging private readonly IMacroService _macroService; private readonly ILocalizationService _languageService; private readonly IEntityXmlSerializer _serializer; - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; + private readonly ILogger _logger; private readonly IHostingEnvironment _hostingEnvironment; private readonly string _packageRepositoryFileName; private readonly string _mediaFolderPath; @@ -59,9 +61,10 @@ namespace Umbraco.Core.Packaging IDataTypeService dataTypeService, IFileService fileService, IMacroService macroService, ILocalizationService languageService, IHostingEnvironment hostingEnvironment, - IEntityXmlSerializer serializer, ILogger logger, + IEntityXmlSerializer serializer, + ILoggerFactory loggerFactory, IUmbracoVersion umbracoVersion, - IGlobalSettings globalSettings, + IOptions globalSettings, string packageRepositoryFileName, string tempFolderPath = null, string packagesFolderPath = null, string mediaFolderPath = null) { @@ -73,15 +76,16 @@ namespace Umbraco.Core.Packaging _macroService = macroService; _languageService = languageService; _serializer = serializer; - _logger = logger; + _loggerFactory = loggerFactory; + _logger = _loggerFactory.CreateLogger(); _hostingEnvironment = hostingEnvironment; _packageRepositoryFileName = packageRepositoryFileName; _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); + _parser = new PackageDefinitionXmlParser(_loggerFactory.CreateLogger(), umbracoVersion); _umbracoVersion = umbracoVersion; } @@ -213,7 +217,7 @@ namespace Umbraco.Core.Packaging } catch (Exception e) { - _logger.Warn(e, "Could not add package actions to the package, the xml did not parse"); + _logger.LogWarning(e, "Could not add package actions to the package, the xml did not parse"); } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IRelationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IRelationRepository.cs index fc1be20e6f..ca40848138 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IRelationRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IRelationRepository.cs @@ -17,6 +17,12 @@ namespace Umbraco.Core.Persistence.Repositories /// void Save(IEnumerable relations); + /// + /// Persist multiple at once but Ids are not returned on created relations + /// + /// + void SaveBulk(IEnumerable relations); + /// /// Deletes all relations for a parent for any specified relation type alias /// 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..856b91e36f 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs @@ -1,9 +1,11 @@ -using Umbraco.Core.Logging; using Umbraco.Core; 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; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.Routing { @@ -15,13 +17,13 @@ namespace Umbraco.Web.Routing /// public class ContentFinderByIdPath : IContentFinder { - private readonly ILogger _logger; + 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; } @@ -51,7 +53,7 @@ namespace Umbraco.Web.Routing if (nodeId > 0) { - _logger.Debug("Id={NodeId}", nodeId); + _logger.LogDebug("Id={NodeId}", nodeId); node = frequest.UmbracoContext.Content.GetById(nodeId); if (node != null) @@ -67,7 +69,7 @@ namespace Umbraco.Web.Routing } frequest.PublishedContent = node; - _logger.Debug("Found node with id={PublishedContentId}", frequest.PublishedContent.Id); + _logger.LogDebug("Found node with id={PublishedContentId}", frequest.PublishedContent.Id); } else { @@ -77,7 +79,7 @@ namespace Umbraco.Web.Routing } if (nodeId == -1) - _logger.Debug("Not a node id"); + _logger.LogDebug("Not a node id"); return node != null; } diff --git a/src/Umbraco.Core/Routing/ContentFinderByRedirectUrl.cs b/src/Umbraco.Core/Routing/ContentFinderByRedirectUrl.cs index 4e67779c1c..7a58b1c995 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByRedirectUrl.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByRedirectUrl.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Services; namespace Umbraco.Web.Routing @@ -15,10 +15,10 @@ namespace Umbraco.Web.Routing public class ContentFinderByRedirectUrl : IContentFinder { private readonly IRedirectUrlService _redirectUrlService; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IPublishedUrlProvider _publishedUrlProvider; - public ContentFinderByRedirectUrl(IRedirectUrlService redirectUrlService, ILogger logger, IPublishedUrlProvider publishedUrlProvider) + public ContentFinderByRedirectUrl(IRedirectUrlService redirectUrlService, ILogger logger, IPublishedUrlProvider publishedUrlProvider) { _redirectUrlService = redirectUrlService; _logger = logger; @@ -41,7 +41,7 @@ namespace Umbraco.Web.Routing if (redirectUrl == null) { - _logger.Debug("No match for route: {Route}", route); + _logger.LogDebug("No match for route: {Route}", route); return false; } @@ -49,14 +49,14 @@ namespace Umbraco.Web.Routing var url = content == null ? "#" : content.Url(_publishedUrlProvider, redirectUrl.Culture); if (url.StartsWith("#")) { - _logger.Debug("Route {Route} matches content {ContentId} which has no url.", route, redirectUrl.ContentId); + _logger.LogDebug("Route {Route} matches content {ContentId} which has no url.", route, redirectUrl.ContentId); return false; } // Appending any querystring from the incoming request to the redirect url. url = string.IsNullOrEmpty(frequest.Uri.Query) ? url : url + frequest.Uri.Query; - _logger.Debug("Route {Route} matches content {ContentId} with url '{Url}', redirecting.", route, content.Id, url); + _logger.LogDebug("Route {Route} matches content {ContentId} with url '{Url}', redirecting.", route, content.Id, url); frequest.SetRedirectPermanent(url); diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrl.cs b/src/Umbraco.Core/Routing/ContentFinderByUrl.cs index 3fcffff842..85e8195c75 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByUrl.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByUrl.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; @@ -12,11 +12,11 @@ namespace Umbraco.Web.Routing /// public class ContentFinderByUrl : IContentFinder { - protected ILogger Logger { get; } + private readonly ILogger _logger; - public ContentFinderByUrl(ILogger logger) + public ContentFinderByUrl(ILogger logger) { - Logger = logger; + _logger = logger; } /// @@ -46,17 +46,17 @@ namespace Umbraco.Web.Routing { if (docreq == null) throw new System.ArgumentNullException(nameof(docreq)); - Logger.Debug("Test route {Route}", route); + _logger.LogDebug("Test route {Route}", route); var node = docreq.UmbracoContext.Content.GetByRoute(docreq.UmbracoContext.InPreviewMode, route, culture: docreq.Culture?.Name); if (node != null) { docreq.PublishedContent = node; - Logger.Debug("Got content, id={NodeId}", node.Id); + _logger.LogDebug("Got content, id={NodeId}", node.Id); } else { - Logger.Debug("No match."); + _logger.LogDebug("No match."); } return node; diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs index 6bc1b329ed..cbb93aedb9 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs @@ -1,7 +1,7 @@ using System; using System.Text; using System.Linq; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Xml; @@ -20,13 +20,13 @@ namespace Umbraco.Web.Routing { private readonly IPublishedValueFallback _publishedValueFallback; private readonly IVariationContextAccessor _variationContextAccessor; - protected ILogger Logger { get; } + private readonly ILogger _logger; - public ContentFinderByUrlAlias(ILogger logger, IPublishedValueFallback publishedValueFallback, IVariationContextAccessor variationContextAccessor) + public ContentFinderByUrlAlias(ILogger logger, IPublishedValueFallback publishedValueFallback, IVariationContextAccessor variationContextAccessor) { _publishedValueFallback = publishedValueFallback; _variationContextAccessor = variationContextAccessor; - Logger = logger; + _logger = logger; } /// @@ -48,7 +48,7 @@ namespace Umbraco.Web.Routing if (node != null) { frequest.PublishedContent = node; - Logger.Debug("Path '{UriAbsolutePath}' is an alias for id={PublishedContentId}", frequest.Uri.AbsolutePath, frequest.PublishedContent.Id); + _logger.LogDebug("Path '{UriAbsolutePath}' is an alias for id={PublishedContentId}", frequest.Uri.AbsolutePath, frequest.PublishedContent.Id); } } diff --git a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs index 7bcea4681e..dc2f46b7cf 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByUrlAndTemplate.cs @@ -1,8 +1,10 @@ -using Umbraco.Core.Logging; 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; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.Routing { @@ -16,17 +18,19 @@ namespace Umbraco.Web.Routing /// public class ContentFinderByUrlAndTemplate : ContentFinderByUrl { + private readonly ILogger _logger; 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) { + _logger = logger; _fileService = fileService; _contentTypeService = contentTypeService; - _webRoutingSettings = webRoutingSettings; + _webRoutingSettings = webRoutingSettings.Value; } /// @@ -46,7 +50,7 @@ namespace Umbraco.Web.Routing // no template if "/" if (path == "/") { - Logger.Debug("No template in path '/'"); + _logger.LogDebug("No template in path '/'"); return false; } @@ -59,11 +63,11 @@ namespace Umbraco.Web.Routing if (template == null) { - Logger.Debug("Not a valid template: '{TemplateAlias}'", templateAlias); + _logger.LogDebug("Not a valid template: '{TemplateAlias}'", templateAlias); return false; } - Logger.Debug("Valid template: '{TemplateAlias}'", templateAlias); + _logger.LogDebug("Valid template: '{TemplateAlias}'", templateAlias); // look for node corresponding to the rest of the route var route = frequest.HasDomain ? (frequest.Domain.ContentId + path) : path; @@ -71,14 +75,14 @@ namespace Umbraco.Web.Routing if (node == null) { - Logger.Debug("Not a valid route to node: '{Route}'", route); + _logger.LogDebug("Not a valid route to node: '{Route}'", route); return false; } // IsAllowedTemplate deals both with DisableAlternativeTemplates and ValidateAlternativeTemplates settings if (!node.IsAllowedTemplate(_contentTypeService, _webRoutingSettings, template.Id)) { - Logger.Warn("Alternative template '{TemplateAlias}' is not allowed on node {NodeId}.", template.Alias, node.Id); + _logger.LogWarning("Alternative template '{TemplateAlias}' is not allowed on node {NodeId}.", template.Alias, node.Id); frequest.PublishedContent = null; // clear return false; } diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs index f56d96b6b3..5c85bfe68d 100644 --- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Routing @@ -12,18 +14,18 @@ namespace Umbraco.Web.Routing /// public class DefaultUrlProvider : IUrlProvider { - private readonly IRequestHandlerSettings _requestSettings; - private readonly ILogger _logger; - private readonly IGlobalSettings _globalSettings; + private readonly RequestHandlerSettings _requestSettings; + private readonly ILogger _logger; + 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; @@ -47,7 +49,7 @@ namespace Umbraco.Web.Routing { if (string.IsNullOrWhiteSpace(route)) { - _logger.Debug("Couldn't find any page with nodeId={NodeId}. This is most likely caused by the page not being published.", id); + _logger.LogDebug("Couldn't find any page with nodeId={NodeId}. This is most likely caused by the page not being published.", id); return null; } @@ -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..21f760f5a0 100644 --- a/src/Umbraco.Core/Routing/PublishedRouter.cs +++ b/src/Umbraco.Core/Routing/PublishedRouter.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; using System.Globalization; using System.IO; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; @@ -10,6 +11,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,12 +21,12 @@ 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; private readonly IVariationContextAccessor _variationContextAccessor; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IRequestAccessor _requestAccessor; private readonly IPublishedValueFallback _publishedValueFallback; @@ -36,11 +39,12 @@ namespace Umbraco.Web.Routing /// Initializes a new instance of the class. /// public PublishedRouter( - IWebRoutingSettings webRoutingSettings, + IOptions webRoutingSettings, ContentFinderCollection contentFinders, IContentLastChanceFinder contentLastChanceFinder, IVariationContextAccessor variationContextAccessor, IProfilingLogger proflog, + ILogger logger, IPublishedUrlProvider publishedUrlProvider, IRequestAccessor requestAccessor, IPublishedValueFallback publishedValueFallback, @@ -49,12 +53,12 @@ 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)); _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); - _logger = proflog; + _logger = logger; _publishedUrlProvider = publishedUrlProvider; _requestAccessor = requestAccessor; _publishedValueFallback = publishedValueFallback; @@ -67,7 +71,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 @@ -247,7 +251,7 @@ namespace Umbraco.Web.Routing // note - we are not handling schemes nor ports here. - _logger.Debug("{TracePrefix}Uri={RequestUri}", tracePrefix, request.Uri); + _logger.LogDebug("{TracePrefix}Uri={RequestUri}", tracePrefix, request.Uri); var domainsCache = request.UmbracoContext.PublishedSnapshot.Domains; var domains = domainsCache.GetAll(includeWildcards: false).ToList(); @@ -284,7 +288,7 @@ namespace Umbraco.Web.Routing if (domainAndUri != null) { // matching an existing domain - _logger.Debug("{TracePrefix}Matches domain={Domain}, rootId={RootContentId}, culture={Culture}", tracePrefix, domainAndUri.Name, domainAndUri.ContentId, domainAndUri.Culture); + _logger.LogDebug("{TracePrefix}Matches domain={Domain}, rootId={RootContentId}, culture={Culture}", tracePrefix, domainAndUri.Name, domainAndUri.ContentId, domainAndUri.Culture); request.Domain = domainAndUri; request.Culture = domainAndUri.Culture; @@ -299,12 +303,12 @@ namespace Umbraco.Web.Routing else { // not matching any existing domain - _logger.Debug("{TracePrefix}Matches no domain", tracePrefix); + _logger.LogDebug("{TracePrefix}Matches no domain", tracePrefix); request.Culture = defaultCulture == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultCulture); } - _logger.Debug("{TracePrefix}Culture={CultureName}", tracePrefix, request.Culture.Name); + _logger.LogDebug("{TracePrefix}Culture={CultureName}", tracePrefix, request.Culture.Name); return request.Domain != null; } @@ -320,7 +324,7 @@ namespace Umbraco.Web.Routing return; var nodePath = request.PublishedContent.Path; - _logger.Debug("{TracePrefix}Path={NodePath}", tracePrefix, nodePath); + _logger.LogDebug("{TracePrefix}Path={NodePath}", tracePrefix, nodePath); var rootNodeId = request.HasDomain ? request.Domain.ContentId : (int?)null; var domain = DomainUtilities.FindWildcardDomainInPath(request.UmbracoContext.PublishedSnapshot.Domains.GetAll(true), nodePath, rootNodeId); @@ -328,11 +332,11 @@ namespace Umbraco.Web.Routing if (domain != null) { request.Culture = domain.Culture; - _logger.Debug("{TracePrefix}Got domain on node {DomainContentId}, set culture to {CultureName}", tracePrefix, domain.ContentId, request.Culture.Name); + _logger.LogDebug("{TracePrefix}Got domain on node {DomainContentId}, set culture to {CultureName}", tracePrefix, domain.ContentId, request.Culture.Name); } else { - _logger.Debug("{TracePrefix}No match.", tracePrefix); + _logger.LogDebug("{TracePrefix}No match.", tracePrefix); } } @@ -374,7 +378,7 @@ namespace Umbraco.Web.Routing /// A value indicating whether a document and template were found. private void FindPublishedContentAndTemplate(IPublishedRequest request) { - _logger.Debug("FindPublishedContentAndTemplate: Path={UriAbsolutePath}", request.Uri.AbsolutePath); + _logger.LogDebug("FindPublishedContentAndTemplate: Path={UriAbsolutePath}", request.Uri.AbsolutePath); // run the document finders FindPublishedContent(request); @@ -417,7 +421,7 @@ namespace Umbraco.Web.Routing //iterate but return on first one that finds it var found = _contentFinders.Any(finder => { - _logger.Debug("Finder {ContentFinderType}", finder.GetType().FullName); + _logger.LogDebug("Finder {ContentFinderType}", finder.GetType().FullName); return finder.TryFindContent(request); }); } @@ -441,22 +445,22 @@ namespace Umbraco.Web.Routing const int maxLoop = 8; do { - _logger.Debug("HandlePublishedContent: Loop {LoopCounter}", i); + _logger.LogDebug("HandlePublishedContent: Loop {LoopCounter}", i); // handle not found if (request.HasPublishedContent == false) { request.Is404 = true; - _logger.Debug("HandlePublishedContent: No document, try last chance lookup"); + _logger.LogDebug("HandlePublishedContent: No document, try last chance lookup"); // if it fails then give up, there isn't much more that we can do if (_contentLastChanceFinder.TryFindContent(request) == false) { - _logger.Debug("HandlePublishedContent: Failed to find a document, give up"); + _logger.LogDebug("HandlePublishedContent: Failed to find a document, give up"); break; } - _logger.Debug("HandlePublishedContent: Found a document"); + _logger.LogDebug("HandlePublishedContent: Found a document"); } // follow internal redirects as long as it's not running out of control ie infinite loop of some sort @@ -478,11 +482,11 @@ namespace Umbraco.Web.Routing if (i == maxLoop || j == maxLoop) { - _logger.Debug("HandlePublishedContent: Looks like we are running into an infinite loop, abort"); + _logger.LogDebug("HandlePublishedContent: Looks like we are running into an infinite loop, abort"); request.PublishedContent = null; } - _logger.Debug("HandlePublishedContent: End"); + _logger.LogDebug("HandlePublishedContent: End"); } /// @@ -527,25 +531,25 @@ namespace Umbraco.Web.Routing if (valid == false) { // bad redirect - log and display the current page (legacy behavior) - _logger.Debug("FollowInternalRedirects: Failed to redirect to id={InternalRedirectId}: value is not an int nor a GuidUdi.", + _logger.LogDebug("FollowInternalRedirects: Failed to redirect to id={InternalRedirectId}: value is not an int nor a GuidUdi.", request.PublishedContent.GetProperty(Constants.Conventions.Content.InternalRedirectId).GetSourceValue()); } if (internalRedirectNode == null) { - _logger.Debug("FollowInternalRedirects: Failed to redirect to id={InternalRedirectId}: no such published document.", + _logger.LogDebug("FollowInternalRedirects: Failed to redirect to id={InternalRedirectId}: no such published document.", request.PublishedContent.GetProperty(Constants.Conventions.Content.InternalRedirectId).GetSourceValue()); } else if (internalRedirectId == request.PublishedContent.Id) { // redirect to self - _logger.Debug("FollowInternalRedirects: Redirecting to self, ignore"); + _logger.LogDebug("FollowInternalRedirects: Redirecting to self, ignore"); } else { request.SetInternalRedirectPublishedContent(internalRedirectNode); // don't use .PublishedContent here redirect = true; - _logger.Debug("FollowInternalRedirects: Redirecting to id={InternalRedirectId}", internalRedirectId); + _logger.LogDebug("FollowInternalRedirects: Redirecting to id={InternalRedirectId}", internalRedirectId); } return redirect; @@ -566,35 +570,35 @@ namespace Umbraco.Web.Routing if (publicAccessAttempt) { - _logger.Debug("EnsurePublishedContentAccess: Page is protected, check for access"); + _logger.LogDebug("EnsurePublishedContentAccess: Page is protected, check for access"); var status = _publicAccessChecker.HasMemberAccessToContent(request.PublishedContent.Id); switch (status) { case PublicAccessStatus.NotLoggedIn: - _logger.Debug("EnsurePublishedContentAccess: Not logged in, redirect to login page"); + _logger.LogDebug("EnsurePublishedContentAccess: Not logged in, redirect to login page"); SetPublishedContentAsOtherPage(request, publicAccessAttempt.Result.LoginNodeId); break; case PublicAccessStatus.AccessDenied: - _logger.Debug("EnsurePublishedContentAccess: Current member has not access, redirect to error page"); + _logger.LogDebug("EnsurePublishedContentAccess: Current member has not access, redirect to error page"); SetPublishedContentAsOtherPage(request, publicAccessAttempt.Result.NoAccessNodeId); break; case PublicAccessStatus.LockedOut: - _logger.Debug("Current member is locked out, redirect to error page"); + _logger.LogDebug("Current member is locked out, redirect to error page"); SetPublishedContentAsOtherPage(request, publicAccessAttempt.Result.NoAccessNodeId); break; case PublicAccessStatus.NotApproved: - _logger.Debug("Current member is unapproved, redirect to error page"); + _logger.LogDebug("Current member is unapproved, redirect to error page"); SetPublishedContentAsOtherPage(request, publicAccessAttempt.Result.NoAccessNodeId); break; case PublicAccessStatus.AccessAccepted: - _logger.Debug("Current member has access"); + _logger.LogDebug("Current member has access"); break; } } else { - _logger.Debug("EnsurePublishedContentAccess: Page is not protected"); + _logger.LogDebug("EnsurePublishedContentAccess: Page is not protected"); } } @@ -637,7 +641,7 @@ namespace Umbraco.Web.Routing if (request.HasTemplate) { - _logger.Debug("FindTemplate: Has a template already, and no alternate template."); + _logger.LogDebug("FindTemplate: Has a template already, and no alternate template."); return; } @@ -659,8 +663,8 @@ namespace Umbraco.Web.Routing // ignore if the alias does not match - just trace if (request.HasTemplate) - _logger.Debug("FindTemplate: Has a template already, but also an alternative template."); - _logger.Debug("FindTemplate: Look for alternative template alias={AltTemplate}", altTemplate); + _logger.LogDebug("FindTemplate: Has a template already, but also an alternative template."); + _logger.LogDebug("FindTemplate: Look for alternative template alias={AltTemplate}", altTemplate); // IsAllowedTemplate deals both with DisableAlternativeTemplates and ValidateAlternativeTemplates settings if (request.PublishedContent.IsAllowedTemplate( @@ -676,16 +680,16 @@ namespace Umbraco.Web.Routing if (template != null) { request.TemplateModel = template; - _logger.Debug("FindTemplate: Got alternative template id={TemplateId} alias={TemplateAlias}", template.Id, template.Alias); + _logger.LogDebug("FindTemplate: Got alternative template id={TemplateId} alias={TemplateAlias}", template.Id, template.Alias); } else { - _logger.Debug("FindTemplate: The alternative template with alias={AltTemplate} does not exist, ignoring.", altTemplate); + _logger.LogDebug("FindTemplate: The alternative template with alias={AltTemplate} does not exist, ignoring.", altTemplate); } } else { - _logger.Warn("FindTemplate: Alternative template {TemplateAlias} is not allowed on node {NodeId}, ignoring.", altTemplate, request.PublishedContent.Id); + _logger.LogWarning("FindTemplate: Alternative template {TemplateAlias} is not allowed on node {NodeId}, ignoring.", altTemplate, request.PublishedContent.Id); // no allowed, back to default var templateId = request.PublishedContent.TemplateId; @@ -695,7 +699,7 @@ namespace Umbraco.Web.Routing if (request.HasTemplate == false) { - _logger.Debug("FindTemplate: No template was found."); + _logger.LogDebug("FindTemplate: No template was found."); // initial idea was: if we're not already 404 and UmbracoSettings.HandleMissingTemplateAs404 is true // then reset _pcr.Document to null to force a 404. @@ -708,7 +712,7 @@ namespace Umbraco.Web.Routing } else { - _logger.Debug("FindTemplate: Running with template id={TemplateId} alias={TemplateAlias}", request.TemplateModel.Id, request.TemplateModel.Alias); + _logger.LogDebug("FindTemplate: Running with template id={TemplateId} alias={TemplateAlias}", request.TemplateModel.Id, request.TemplateModel.Alias); } } @@ -716,11 +720,11 @@ namespace Umbraco.Web.Routing { if (templateId.HasValue == false || templateId.Value == default) { - _logger.Debug("GetTemplateModel: No template."); + _logger.LogDebug("GetTemplateModel: No template."); return null; } - _logger.Debug("GetTemplateModel: Get template id={TemplateId}", templateId); + _logger.LogDebug("GetTemplateModel: Get template id={TemplateId}", templateId); if (templateId == null) throw new InvalidOperationException("The template is not set, the page cannot render."); @@ -728,7 +732,7 @@ namespace Umbraco.Web.Routing var template = _fileService.GetTemplate(templateId.Value); if (template == null) throw new InvalidOperationException("The template with Id " + templateId + " does not exist, the page cannot render."); - _logger.Debug("GetTemplateModel: Got template id={TemplateId} alias={TemplateAlias}", template.Id, template.Alias); + _logger.LogDebug("GetTemplateModel: Got template id={TemplateId} alias={TemplateAlias}", template.Id, template.Alias); return template; } 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..9dd4a413a2 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,24 +25,15 @@ 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; _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); - var provider = UrlMode.Auto; - Mode = provider; - - if (Enum.TryParse(routingSettings.UrlProviderMode, out provider)) - { - Mode = provider; - } + Mode = routingSettings.Value.UrlProviderMode; } - private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IEnumerable _urlProviders; private readonly IEnumerable _mediaUrlProviders; diff --git a/src/Umbraco.Core/Routing/UrlProviderExtensions.cs b/src/Umbraco.Core/Routing/UrlProviderExtensions.cs index 352209b987..1dc48be96e 100644 --- a/src/Umbraco.Core/Routing/UrlProviderExtensions.cs +++ b/src/Umbraco.Core/Routing/UrlProviderExtensions.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Web.Routing @@ -25,7 +25,7 @@ namespace Umbraco.Web.Routing ILocalizedTextService textService, IContentService contentService, IVariationContextAccessor variationContextAccessor, - ILogger logger, + ILogger logger, UriUtility uriUtility, IPublishedUrlProvider publishedUrlProvider) { @@ -123,7 +123,7 @@ namespace Umbraco.Web.Routing } catch (Exception ex) { - logger.Error(ex, "GetUrl exception."); + logger.LogError(ex, "GetUrl exception."); url = "#ex"; } diff --git a/src/Umbraco.Core/Runtime/MainDom.cs b/src/Umbraco.Core/Runtime/MainDom.cs index 81db1b700d..797dfa36e1 100644 --- a/src/Umbraco.Core/Runtime/MainDom.cs +++ b/src/Umbraco.Core/Runtime/MainDom.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Threading; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; namespace Umbraco.Core.Runtime { @@ -20,7 +20,7 @@ namespace Umbraco.Core.Runtime { #region Vars - private readonly ILogger _logger; + private readonly ILogger _logger; private IApplicationShutdownRegistry _hostingEnvironment; private readonly IMainDomLock _mainDomLock; @@ -42,7 +42,7 @@ namespace Umbraco.Core.Runtime #region Ctor // initializes a new instance of MainDom - public MainDom(ILogger logger, IMainDomLock systemLock) + public MainDom(ILogger logger, IMainDomLock systemLock) { _logger = logger; _mainDomLock = systemLock; @@ -86,7 +86,7 @@ namespace Umbraco.Core.Runtime if (_signaled) return false; if (_isMainDom == false) { - _logger.Warn("Register called when MainDom has not been acquired"); + _logger.LogWarning("Register called when MainDom has not been acquired"); return false; } @@ -105,14 +105,14 @@ namespace Umbraco.Core.Runtime lock (_locko) { - _logger.Debug("Signaled ({Signaled}) ({SignalSource})", _signaled ? "again" : "first", source); + _logger.LogDebug("Signaled ({Signaled}) ({SignalSource})", _signaled ? "again" : "first", source); if (_signaled) return; if (_isMainDom == false) return; // probably not needed _signaled = true; try { - _logger.Info("Stopping ({SignalSource})", source); + _logger.LogInformation("Stopping ({SignalSource})", source); foreach (var callback in _callbacks.OrderBy(x => x.Key).Select(x => x.Value)) { try @@ -121,19 +121,19 @@ namespace Umbraco.Core.Runtime } catch (Exception e) { - _logger.Error(e, "Error while running callback"); + _logger.LogError(e, "Error while running callback"); continue; } } - _logger.Debug("Stopped ({SignalSource})", source); + _logger.LogDebug("Stopped ({SignalSource})", source); } finally { // in any case... _isMainDom = false; _mainDomLock.Dispose(); - _logger.Info("Released ({SignalSource})", source); + _logger.LogInformation("Released ({SignalSource})", source); } } @@ -146,18 +146,18 @@ namespace Umbraco.Core.Runtime // the handler is not installed so that would be the hosting environment if (_signaled) { - _logger.Info("Cannot acquire (signaled)."); + _logger.LogInformation("Cannot acquire (signaled)."); return false; } - _logger.Info("Acquiring."); + _logger.LogInformation("Acquiring."); // Get the lock var acquired = _mainDomLock.AcquireLockAsync(LockTimeoutMilliseconds).GetAwaiter().GetResult(); if (!acquired) { - _logger.Info("Cannot acquire (timeout)."); + _logger.LogInformation("Cannot acquire (timeout)."); // In previous versions we'd let a TimeoutException be thrown // and the appdomain would not start. We have the opportunity to allow it to @@ -177,10 +177,10 @@ namespace Umbraco.Core.Runtime catch (OperationCanceledException ex) { // the waiting task could be canceled if this appdomain is naturally shutting down, we'll just swallow this exception - _logger.Warn(ex, ex.Message); + _logger.LogWarning(ex, ex.Message); } - _logger.Info("Acquired."); + _logger.LogInformation("Acquired."); return true; } diff --git a/src/Umbraco.Core/Scheduling/KeepAlive.cs b/src/Umbraco.Core/Scheduling/KeepAlive.cs index a47080912c..9b09a81cc3 100644 --- a/src/Umbraco.Core/Scheduling/KeepAlive.cs +++ b/src/Umbraco.Core/Scheduling/KeepAlive.cs @@ -2,10 +2,12 @@ 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; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.Scheduling { @@ -13,22 +15,26 @@ namespace Umbraco.Web.Scheduling { private readonly IRequestAccessor _requestAccessor; private readonly IMainDom _mainDom; - private readonly IKeepAliveSettings _keepAliveSettings; - private readonly IProfilingLogger _logger; + private readonly KeepAliveSettings _keepAliveSettings; + private readonly ILogger _logger; + private readonly IProfilingLogger _profilingLogger; 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, ILogger logger, IProfilingLogger profilingLogger, IServerRegistrar serverRegistrar) : base(runner, delayMilliseconds, periodMilliseconds) { _requestAccessor = requestAccessor; _mainDom = mainDom; - _keepAliveSettings = keepAliveSettings; + _keepAliveSettings = keepAliveSettings.Value; _logger = logger; + _profilingLogger = profilingLogger; _serverRegistrar = serverRegistrar; if (_httpClient == null) + { _httpClient = new HttpClient(); + } } public override async Task PerformRunAsync(CancellationToken token) @@ -37,21 +43,21 @@ namespace Umbraco.Web.Scheduling switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Replica: - _logger.Debug("Does not run on replica servers."); + _logger.LogDebug("Does not run on replica servers."); return true; // role may change! case ServerRole.Unknown: - _logger.Debug("Does not run on servers with unknown role."); + _logger.LogDebug("Does not run on servers with unknown role."); return true; // role may change! } // ensure we do not run if not main domain, but do NOT lock it if (_mainDom.IsMainDom == false) { - _logger.Debug("Does not run if not MainDom."); + _logger.LogDebug("Does not run if not MainDom."); return false; // do NOT repeat, going down } - using (_logger.DebugDuration("Keep alive executing", "Keep alive complete")) + using (_profilingLogger.DebugDuration("Keep alive executing", "Keep alive complete")) { var keepAlivePingUrl = _keepAliveSettings.KeepAlivePingUrl; try @@ -61,7 +67,7 @@ namespace Umbraco.Web.Scheduling var umbracoAppUrl = _requestAccessor.GetApplicationUrl().ToString(); if (umbracoAppUrl.IsNullOrWhiteSpace()) { - _logger.Warn("No umbracoApplicationUrl for service (yet), skip."); + _logger.LogWarning("No umbracoApplicationUrl for service (yet), skip."); return true; // repeat } @@ -73,7 +79,7 @@ namespace Umbraco.Web.Scheduling } catch (Exception ex) { - _logger.Error(ex, "Keep alive failed (at '{keepAlivePingUrl}').", keepAlivePingUrl); + _logger.LogError(ex, "Keep alive failed (at '{keepAlivePingUrl}').", keepAlivePingUrl); } } diff --git a/src/Umbraco.Core/Scheduling/TempFileCleanup.cs b/src/Umbraco.Core/Scheduling/TempFileCleanup.cs index 6ac1ff61fe..1a8ece78d1 100644 --- a/src/Umbraco.Core/Scheduling/TempFileCleanup.cs +++ b/src/Umbraco.Core/Scheduling/TempFileCleanup.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using Umbraco.Core; using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.Scheduling { @@ -15,11 +16,12 @@ namespace Umbraco.Web.Scheduling private readonly DirectoryInfo[] _tempFolders; private readonly TimeSpan _age; private readonly IMainDom _mainDom; - private readonly IProfilingLogger _logger; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; public TempFileCleanup(IBackgroundTaskRunner runner, int delayMilliseconds, int periodMilliseconds, IEnumerable tempFolders, TimeSpan age, - IMainDom mainDom, IProfilingLogger logger) + IMainDom mainDom, IProfilingLogger profilingLogger, ILogger logger) : base(runner, delayMilliseconds, periodMilliseconds) { //SystemDirectories.TempFileUploads @@ -27,6 +29,7 @@ namespace Umbraco.Web.Scheduling _tempFolders = tempFolders.ToArray(); _age = age; _mainDom = mainDom; + _profilingLogger = profilingLogger; _logger = logger; } @@ -35,7 +38,7 @@ namespace Umbraco.Web.Scheduling // ensure we do not run if not main domain if (_mainDom.IsMainDom == false) { - _logger.Debug("Does not run if not MainDom."); + _logger.LogDebug("Does not run if not MainDom."); return false; // do NOT repeat, going down } @@ -50,7 +53,7 @@ namespace Umbraco.Web.Scheduling dir.Refresh(); //in case it's changed during runtime if (!dir.Exists) { - _logger.Debug("The cleanup folder doesn't exist {Folder}", dir.FullName); + _logger.LogDebug("The cleanup folder doesn't exist {Folder}", dir.FullName); return; } @@ -66,7 +69,7 @@ namespace Umbraco.Web.Scheduling } catch (Exception ex) { - _logger.Error(ex, "Could not delete temp file {FileName}", file.FullName); + _logger.LogError(ex, "Could not delete temp file {FileName}", file.FullName); } } } diff --git a/src/Umbraco.Core/Scoping/CallContext.cs b/src/Umbraco.Core/Scoping/CallContext.cs index 2937990eab..cc8bf7cc7e 100644 --- a/src/Umbraco.Core/Scoping/CallContext.cs +++ b/src/Umbraco.Core/Scoping/CallContext.cs @@ -20,7 +20,15 @@ namespace Umbraco.Core.Scoping /// The name with which to associate the new item in the call context. /// The object to store in the call context. public static void SetData(string name, T data) => _state.GetOrAdd(name, _ => new AsyncLocal()).Value = data; - + + //Replace the SetData with the following when you need to debug AsyncLocal. The args.ThreadContextChanged can be usefull + //public static void SetData(string name, T data) => _state.GetOrAdd(name, _ => new AsyncLocal(OnValueChanged)).Value = data; + // public static void OnValueChanged(AsyncLocalValueChangedArgs args) + // { + // var typeName = typeof(T).ToString(); + // Console.WriteLine($"OnValueChanged!, Type: {typeName} Prev: #{args.PreviousValue} Current: #{args.CurrentValue}"); + // } + /// /// Retrieves an object with the specified name from the . /// 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/Security/LegacyPasswordSecurity.cs b/src/Umbraco.Core/Security/LegacyPasswordSecurity.cs index 9b14c3ccba..d72ecda56c 100644 --- a/src/Umbraco.Core/Security/LegacyPasswordSecurity.cs +++ b/src/Umbraco.Core/Security/LegacyPasswordSecurity.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Security.Cryptography; using System.Text; using Umbraco.Core.Configuration; @@ -11,66 +12,115 @@ namespace Umbraco.Core.Security /// public class LegacyPasswordSecurity { - // TODO: This class no longer has the logic available to verify the old old old password format, we should - // include this ability so that upgrades for very old versions/data can work and then auto-migrate to the new password format. - - private readonly IPasswordConfiguration _passwordConfiguration; - private readonly PasswordGenerator _generator; - - /// - /// Constructor - /// - /// - public LegacyPasswordSecurity(IPasswordConfiguration passwordConfiguration) - { - _passwordConfiguration = passwordConfiguration; - _generator = new PasswordGenerator(passwordConfiguration); - } - - public string GeneratePassword() => _generator.GeneratePassword(); - - /// - /// Returns a hashed password value used to store in a data store - /// - /// - /// - public string HashPasswordForStorage(string password) + // Used for tests + [EditorBrowsable(EditorBrowsableState.Never)] + public string HashPasswordForStorage(string algorithmType, string password) { if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("password cannot be empty", nameof(password)); string salt; - var hashed = HashNewPassword(password, out salt); - return FormatPasswordForStorage(hashed, salt); + var hashed = HashNewPassword(algorithmType, password, out salt); + return FormatPasswordForStorage(algorithmType, hashed, salt); + } + + // Used for tests + [EditorBrowsable(EditorBrowsableState.Never)] + public string FormatPasswordForStorage(string algorithmType, string hashedPassword, string salt) + { + if (IsLegacySHA1Algorithm(algorithmType)) + { + return hashedPassword; + } + + return salt + hashedPassword; } /// - /// If the password format is a hashed keyed algorithm then we will pre-pend the salt used to hash the password - /// to the hashed password itself. + /// Verifies if the password matches the expected hash+salt of the stored password string /// - /// + /// The hashing algorithm for the stored password. + /// The password. + /// The value of the password stored in a data store. + /// + public bool VerifyPassword(string algorithm, string password, string dbPassword) + { + if (string.IsNullOrWhiteSpace(dbPassword)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(dbPassword)); + + if (dbPassword.StartsWith(Constants.Security.EmptyPasswordPrefix)) + return false; + + var storedHashedPass = ParseStoredHashPassword(algorithm, dbPassword, out var salt); + var hashed = HashPassword(algorithm, password, salt); + return storedHashedPass == hashed; + } + + /// + /// Create a new password hash and a new salt + /// + /// The hashing algorithm for the password. + /// /// /// - public string FormatPasswordForStorage(string hashedPassword, string salt) + // TODO: Do we need this method? We shouldn't be using this class to create new password hashes for storage + public string HashNewPassword(string algorithm, string newPassword, out string salt) { - return salt + hashedPassword; + salt = GenerateSalt(); + return HashPassword(algorithm, newPassword, salt); + } + + /// + /// Parses out the hashed password and the salt from the stored password string value + /// + /// The hashing algorithm for the stored password. + /// + /// returns the salt + /// + public string ParseStoredHashPassword(string algorithm, string storedString, out string salt) + { + if (string.IsNullOrWhiteSpace(storedString)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(storedString)); + + // This is for the <= v4 hashing algorithm for which there was no salt + if (IsLegacySHA1Algorithm(algorithm)) + { + salt = string.Empty; + return storedString; + } + + + var saltLen = GenerateSalt(); + salt = storedString.Substring(0, saltLen.Length); + return storedString.Substring(saltLen.Length); + } + + public static string GenerateSalt() + { + var numArray = new byte[16]; + new RNGCryptoServiceProvider().GetBytes(numArray); + return Convert.ToBase64String(numArray); } /// /// Hashes a password with a given salt /// + /// The hashing algorithm for the password. /// /// /// - public string HashPassword(string pass, string salt) + private string HashPassword(string algorithmType, string pass, string salt) { + if (IsLegacySHA1Algorithm(algorithmType)) + { + return HashLegacySHA1Password(pass); + } + //This is the correct way to implement this (as per the sql membership provider) var bytes = Encoding.Unicode.GetBytes(pass); var saltBytes = Convert.FromBase64String(salt); byte[] inArray; - var hashAlgorithm = GetCurrentHashAlgorithm(); + var hashAlgorithm = GetHashAlgorithm(algorithmType); var algorithm = hashAlgorithm as KeyedHashAlgorithm; if (algorithm != null) { @@ -113,83 +163,64 @@ namespace Umbraco.Core.Security return Convert.ToBase64String(inArray); } - /// - /// Verifies if the password matches the expected hash+salt of the stored password string - /// - /// The password. - /// The value of the password stored in a data store. - /// - public bool VerifyPassword(string password, string dbPassword) - { - if (string.IsNullOrWhiteSpace(dbPassword)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(dbPassword)); - - if (dbPassword.StartsWith(Constants.Security.EmptyPasswordPrefix)) - return false; - - var storedHashedPass = ParseStoredHashPassword(dbPassword, out var salt); - var hashed = HashPassword(password, salt); - return storedHashedPass == hashed; - } - - /// - /// Create a new password hash and a new salt - /// - /// - /// - /// - public string HashNewPassword(string newPassword, out string salt) - { - salt = GenerateSalt(); - return HashPassword(newPassword, salt); - } - - /// - /// Parses out the hashed password and the salt from the stored password string value - /// - /// - /// returns the salt - /// - public string ParseStoredHashPassword(string storedString, out string salt) - { - if (string.IsNullOrWhiteSpace(storedString)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(storedString)); - - var saltLen = GenerateSalt(); - salt = storedString.Substring(0, saltLen.Length); - return storedString.Substring(saltLen.Length); - } - - public static string GenerateSalt() - { - var numArray = new byte[16]; - new RNGCryptoServiceProvider().GetBytes(numArray); - return Convert.ToBase64String(numArray); - } - /// /// Return the hash algorithm to use based on the /// + /// The hashing algorithm name. /// /// - private HashAlgorithm GetCurrentHashAlgorithm() + private HashAlgorithm GetHashAlgorithm(string algorithm) { - if (_passwordConfiguration.HashAlgorithmType.IsNullOrWhiteSpace()) + if (algorithm.IsNullOrWhiteSpace()) throw new InvalidOperationException("No hash algorithm type specified"); - var alg = HashAlgorithm.Create(_passwordConfiguration.HashAlgorithmType); + var alg = HashAlgorithm.Create(algorithm); if (alg == null) - throw new InvalidOperationException($"The hash algorithm specified {_passwordConfiguration.HashAlgorithmType} cannot be resolved"); + throw new InvalidOperationException($"The hash algorithm specified {algorithm} cannot be resolved"); return alg; } public bool SupportHashAlgorithm(string algorithm) { - if (algorithm.InvariantEquals(typeof(HMACSHA256).Name)) + // This is for the v6-v8 hashing algorithm + if (algorithm.InvariantEquals(Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName)) + return true; + + // This is for the <= v4 hashing algorithm + if (IsLegacySHA1Algorithm(algorithm)) return true; - // TODO: Need to add the old old old format in here too which was just HMACSHA1 IIRC but had a custom key implementation as the password itself return false; } + private bool IsLegacySHA1Algorithm(string algorithm) => algorithm.InvariantEquals(Constants.Security.AspNetUmbraco4PasswordHashAlgorithmName); + + /// + /// Hashes the password with the old v4 algorithm + /// + /// The password. + /// The encoded password. + private string HashLegacySHA1Password(string password) + { + var hashAlgorithm = GetLegacySHA1Algorithm(password); + var hash = Convert.ToBase64String(hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(password))); + return hash; + } + + /// + /// Returns the old v4 algorithm and settings + /// + /// + /// + private HashAlgorithm GetLegacySHA1Algorithm(string password) + { + return new HMACSHA1 + { + //the legacy salt was actually the password :( + Key = Encoding.Unicode.GetBytes(password) + }; + } + } } diff --git a/src/Umbraco.Core/Services/IIconService.cs b/src/Umbraco.Core/Services/IIconService.cs new file mode 100644 index 0000000000..963edb22a5 --- /dev/null +++ b/src/Umbraco.Core/Services/IIconService.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Umbraco.Core.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/IMembershipMemberService.cs b/src/Umbraco.Core/Services/IMembershipMemberService.cs index d3ca954de8..839d8e3af3 100644 --- a/src/Umbraco.Core/Services/IMembershipMemberService.cs +++ b/src/Umbraco.Core/Services/IMembershipMemberService.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Querying; @@ -107,6 +108,18 @@ namespace Umbraco.Core.Services /// or to Delete void Delete(T membershipUser); + /// + /// Sets the last login date for the member if they are found by username + /// + /// + /// + /// + /// This is a specialized method because whenever a member logs in, the membership provider requires us to set the 'online' which requires + /// updating their login date. This operation must be fast and cannot use database locks which is fine if we are only executing a single query + /// for this data since there won't be any other data contention issues. + /// + void SetLastLogin(string username, DateTime date); + /// /// Saves an /// diff --git a/src/Umbraco.Core/Services/IRelationService.cs b/src/Umbraco.Core/Services/IRelationService.cs index bf8bcd5b2a..a3c0317685 100644 --- a/src/Umbraco.Core/Services/IRelationService.cs +++ b/src/Umbraco.Core/Services/IRelationService.cs @@ -133,6 +133,15 @@ namespace Umbraco.Core.Services IEnumerable GetByParentOrChildId(int id, string relationTypeAlias); + /// + /// Gets a relation by the unique combination of parentId, childId and relationType. + /// + /// The id of the parent item. + /// The id of the child item. + /// The RelationType. + /// The relation or null + IRelation GetByParentAndChildId(int parentId, int childId, IRelationType relationType); + /// /// Gets a list of objects by the Name of the /// @@ -341,5 +350,8 @@ namespace Umbraco.Core.Services /// /// to Delete Relations for void DeleteRelationsOfType(IRelationType relationType); + + + } } 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..7f7db6130c 100644 --- a/src/Umbraco.Core/Templates/HtmlUrlParser.cs +++ b/src/Umbraco.Core/Templates/HtmlUrlParser.cs @@ -1,5 +1,7 @@ using System.Text.RegularExpressions; -using Umbraco.Core.Configuration.UmbracoSettings; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -7,18 +9,20 @@ namespace Umbraco.Web.Templates { public sealed class HtmlUrlParser { - private readonly IContentSettings _contentSettings; + private readonly ContentSettings _contentSettings; + private readonly ILogger _logger; private readonly IIOHelper _ioHelper; - private readonly IProfilingLogger _logger; + private readonly IProfilingLogger _profilingLogger; 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, ILogger logger ,IProfilingLogger profilingLogger, IIOHelper ioHelper) { - _contentSettings = contentSettings; - _ioHelper = ioHelper; + _contentSettings = contentSettings.Value; _logger = logger; + _ioHelper = ioHelper; + _profilingLogger = profilingLogger; } /// @@ -34,11 +38,11 @@ namespace Umbraco.Web.Templates { if (_contentSettings.ResolveUrlsFromTextString == false) return text; - using (var timer = _logger.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete")) + using (var timer = _profilingLogger.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete")) { // find all relative urls (ie. urls that contain ~) var tags = ResolveUrlPattern.Matches(text); - _logger.Debug(typeof(IOHelper), "After regex: {Duration} matched: {TagsCount}", timer.Stopwatch.ElapsedMilliseconds, tags.Count); + _logger.LogDebug("After regex: {Duration} matched: {TagsCount}", timer.Stopwatch.ElapsedMilliseconds, tags.Count); foreach (Match tag in tags) { var url = ""; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index b5e553a78e..07dea8d299 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -4,9 +4,9 @@ netstandard2.0 8 Umbraco.Core - 9.0.0 - 9.0.0 - 9.0.0 + 0.5.0 + 0.5.0 + 0.5.0 Umbraco CMS @@ -15,16 +15,21 @@ + + - - + + <_Parameter1>Umbraco.Tests + + <_Parameter1>Umbraco.Tests.Common + <_Parameter1>Umbraco.Tests.UnitTests @@ -34,5 +39,8 @@ <_Parameter1>Umbraco.Tests.Integration + + <_Parameter1>DynamicProxyGenAssembly2 + diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 13aa6bde46..446e60e18f 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -1,10 +1,11 @@ using System; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; 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 +39,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 +129,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("/")) @@ -159,7 +160,7 @@ namespace Umbraco.Core } catch (ArgumentException) { - Current.Logger.Debug(typeof(UriExtensions), "Failed to determine if request was client side (invalid chars in path \"{Path}\"?)", url.LocalPath); + Current.Logger.LogDebug("Failed to determine if request was client side (invalid chars in path \"{Path}\"?)", url.LocalPath); return false; } } diff --git a/src/Umbraco.Examine.Lucene/ExamineExtensions.cs b/src/Umbraco.Examine.Lucene/ExamineExtensions.cs index d697bf6f0d..6f476ec79d 100644 --- a/src/Umbraco.Examine.Lucene/ExamineExtensions.cs +++ b/src/Umbraco.Examine.Lucene/ExamineExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; using Examine; using Examine.LuceneEngine.Providers; using Lucene.Net.Analysis; @@ -8,7 +9,6 @@ using Lucene.Net.QueryParsers; using Lucene.Net.Search; using Umbraco.Core; using Version = Lucene.Net.Util.Version; -using Umbraco.Core.Logging; using System.Threading; namespace Umbraco.Examine @@ -29,7 +29,7 @@ namespace Umbraco.Examine /// /// Configures and unlocks all Lucene based indexes registered with the . /// - internal static void ConfigureIndexes(this IExamineManager examineManager, IMainDom mainDom, ILogger logger) + internal static void ConfigureIndexes(this IExamineManager examineManager, IMainDom mainDom, ILogger logger) { LazyInitializer.EnsureInitialized( ref _configuredInit, @@ -71,7 +71,7 @@ namespace Umbraco.Examine /// /// This is not thread safe, use with care /// - private static void ConfigureLuceneIndexes(this IExamineManager examineManager, ILogger logger, bool disableExamineIndexing) + private static void ConfigureLuceneIndexes(this IExamineManager examineManager, ILogger logger, bool disableExamineIndexing) { foreach (var luceneIndexer in examineManager.Indexes.OfType()) { @@ -87,7 +87,7 @@ namespace Umbraco.Examine var dir = luceneIndexer.GetLuceneDirectory(); if (IndexWriter.IsLocked(dir)) { - logger.Info(typeof(ExamineExtensions), "Forcing index {IndexerName} to be unlocked since it was left in a locked state", luceneIndexer.Name); + logger.LogDebug("Forcing index {IndexerName} to be unlocked since it was left in a locked state", luceneIndexer.Name); IndexWriter.Unlock(dir); } } diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs index 0d701d388d..1bdb579e62 100644 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs @@ -1,8 +1,8 @@ -using Examine; +using Microsoft.Extensions.Logging; +using Examine; using Examine.LuceneEngine.Directories; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; namespace Umbraco.Examine { @@ -12,14 +12,14 @@ namespace Umbraco.Examine private readonly IndexRebuilder _indexRebuilder; private readonly IExamineManager _examineManager; private readonly IMainDom _mainDom; - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; - public ExamineLuceneComponent(IndexRebuilder indexRebuilder, IExamineManager examineManager, IMainDom mainDom, ILogger logger) + public ExamineLuceneComponent(IndexRebuilder indexRebuilder, IExamineManager examineManager, IMainDom mainDom, ILoggerFactory loggerFactory) { _indexRebuilder = indexRebuilder; _examineManager = examineManager; _mainDom = mainDom; - _logger = logger; + _loggerFactory = loggerFactory; } public void Initialize() @@ -41,7 +41,7 @@ namespace Umbraco.Examine /// /// /// - private void IndexRebuilder_RebuildingIndexes(object sender, IndexRebuildingEventArgs e) => _examineManager.ConfigureIndexes(_mainDom, _logger); + private void IndexRebuilder_RebuildingIndexes(object sender, IndexRebuildingEventArgs e) => _examineManager.ConfigureIndexes(_mainDom, _loggerFactory.CreateLogger()); public void Terminate() { 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/ExamineLuceneFinalComponent.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs index e1e80ead2f..745a5fb583 100644 --- a/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs +++ b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs @@ -1,19 +1,19 @@ -using Examine; +using Microsoft.Extensions.Logging; +using Examine; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; namespace Umbraco.Examine { public class ExamineLuceneFinalComponent : IComponent { - private readonly IProfilingLogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IExamineManager _examineManager; private readonly IMainDom _mainDom; - public ExamineLuceneFinalComponent(IProfilingLogger logger, IExamineManager examineManager, IMainDom mainDom) + public ExamineLuceneFinalComponent(ILoggerFactory loggerFactory, IExamineManager examineManager, IMainDom mainDom) { - _logger = logger; + _loggerFactory = loggerFactory; _examineManager = examineManager; _mainDom = mainDom; } @@ -23,7 +23,7 @@ namespace Umbraco.Examine if (!_mainDom.IsMainDom) return; // Ensures all lucene based indexes are unlocked and ready to go - _examineManager.ConfigureIndexes(_mainDom, _logger); + _examineManager.ConfigureIndexes(_mainDom, _loggerFactory.CreateLogger()); } public void Terminate() 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/LuceneIndexDiagnostics.cs b/src/Umbraco.Examine.Lucene/LuceneIndexDiagnostics.cs index 836d5f6e66..525f7372bf 100644 --- a/src/Umbraco.Examine.Lucene/LuceneIndexDiagnostics.cs +++ b/src/Umbraco.Examine.Lucene/LuceneIndexDiagnostics.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Examine.LuceneEngine.Providers; using Umbraco.Core; -using Umbraco.Core.Logging; using Lucene.Net.Store; using Umbraco.Core.IO; using System.Linq; @@ -14,7 +14,7 @@ namespace Umbraco.Examine { private readonly IHostingEnvironment _hostingEnvironment; - public LuceneIndexDiagnostics(LuceneIndex index, ILogger logger, IHostingEnvironment hostingEnvironment) + public LuceneIndexDiagnostics(LuceneIndex index, ILogger logger, IHostingEnvironment hostingEnvironment) { _hostingEnvironment = hostingEnvironment; Index = index; @@ -22,7 +22,7 @@ namespace Umbraco.Examine } public LuceneIndex Index { get; } - public ILogger Logger { get; } + public ILogger Logger { get; } public int DocumentCount { @@ -34,7 +34,7 @@ namespace Umbraco.Examine } catch (AlreadyClosedException) { - Logger.Warn(typeof(UmbracoContentIndex), "Cannot get GetIndexDocumentCount, the writer is already closed"); + Logger.LogWarning("Cannot get GetIndexDocumentCount, the writer is already closed"); return 0; } } @@ -50,7 +50,7 @@ namespace Umbraco.Examine } catch (AlreadyClosedException) { - Logger.Warn(typeof(UmbracoContentIndex), "Cannot get GetIndexFieldCount, the writer is already closed"); + Logger.LogWarning("Cannot get GetIndexFieldCount, the writer is already closed"); return 0; } } diff --git a/src/Umbraco.Examine.Lucene/LuceneIndexDiagnosticsFactory.cs b/src/Umbraco.Examine.Lucene/LuceneIndexDiagnosticsFactory.cs index 9141f7f6dd..feeac4bf77 100644 --- a/src/Umbraco.Examine.Lucene/LuceneIndexDiagnosticsFactory.cs +++ b/src/Umbraco.Examine.Lucene/LuceneIndexDiagnosticsFactory.cs @@ -1,7 +1,7 @@ using Examine; using Examine.LuceneEngine.Providers; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Core.IO; namespace Umbraco.Examine @@ -12,12 +12,12 @@ namespace Umbraco.Examine ///
public class LuceneIndexDiagnosticsFactory : IndexDiagnosticsFactory { - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IHostingEnvironment _hostingEnvironment; - public LuceneIndexDiagnosticsFactory(ILogger logger, IHostingEnvironment hostingEnvironment) + public LuceneIndexDiagnosticsFactory(ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment) { - _logger = logger; + _loggerFactory = loggerFactory; _hostingEnvironment = hostingEnvironment; } @@ -26,7 +26,7 @@ namespace Umbraco.Examine if (!(index is IIndexDiagnostics indexDiag)) { if (index is LuceneIndex luceneIndex) - indexDiag = new LuceneIndexDiagnostics(luceneIndex, _logger, _hostingEnvironment); + indexDiag = new LuceneIndexDiagnostics(luceneIndex, _loggerFactory.CreateLogger(), _hostingEnvironment); else indexDiag = base.Create(index); } 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/Umbraco.Examine.Lucene.csproj b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj index 932d6d318b..137d4d425c 100644 --- a/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj +++ b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj @@ -40,7 +40,7 @@ - 3.4.0 + 3.5.3 runtime; build; native; contentfiles; analyzers all diff --git a/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs b/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs index dc2a5570a6..0dcf269902 100644 --- a/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs +++ b/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; +using Microsoft.Extensions.Logging; using Examine; using Umbraco.Core; using Umbraco.Core.Services; @@ -19,9 +20,9 @@ namespace Umbraco.Examine /// /// An indexer for Umbraco content and media /// - public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex + public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex, IDisposable { - + private readonly ILogger _logger; protected ILocalizationService LanguageService { get; } #region Constructors @@ -34,6 +35,8 @@ namespace Umbraco.Examine /// /// /// + /// + /// /// /// /// @@ -45,14 +48,17 @@ namespace Umbraco.Examine FieldDefinitionCollection fieldDefinitions, Analyzer defaultAnalyzer, IProfilingLogger profilingLogger, + ILogger logger, + ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment, IRuntimeState runtimeState, ILocalizationService languageService, IContentValueSetValidator validator, IReadOnlyDictionary indexValueTypes = null) - : base(name, luceneDirectory, fieldDefinitions, defaultAnalyzer, profilingLogger, hostingEnvironment, runtimeState, validator, indexValueTypes) + : base(name, luceneDirectory, fieldDefinitions, defaultAnalyzer, profilingLogger, logger, loggerFactory ,hostingEnvironment, runtimeState, validator, indexValueTypes) { if (validator == null) throw new ArgumentNullException(nameof(validator)); + _logger = logger; LanguageService = languageService ?? throw new ArgumentNullException(nameof(languageService)); if (validator is IContentValueSetValidator contentValueSetValidator) @@ -68,7 +74,7 @@ namespace Umbraco.Examine /// protected override void PerformIndexItems(IEnumerable values, Action onComplete) { - //We don't want to re-enumerate this list, but we need to split it into 2x enumerables: invalid and valid items. + // We don't want to re-enumerate this list, but we need to split it into 2x enumerables: invalid and valid items. // The Invalid items will be deleted, these are items that have invalid paths (i.e. moved to the recycle bin, etc...) // Then we'll index the Value group all together. // We return 0 or 1 here so we can order the results and do the invalid first and then the valid. @@ -139,7 +145,8 @@ namespace Umbraco.Examine var filtered = c.NativeQuery(rawQuery); var results = filtered.Execute(); - ProfilingLogger.Debug(GetType(), "DeleteFromIndex with query: {Query} (found {TotalItems} results)", rawQuery, results.TotalItemCount); + _logger. + LogDebug("DeleteFromIndex with query: {Query} (found {TotalItems} results)", rawQuery, results.TotalItemCount); //need to queue a delete item for each one found QueueIndexOperation(results.Select(r => new IndexOperation(new ValueSet(r.Id), IndexOperationType.Delete))); diff --git a/src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs b/src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs index 696c6a58a5..ceec013eaa 100644 --- a/src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs +++ b/src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Directory = Lucene.Net.Store.Directory; +using Microsoft.Extensions.Logging; namespace Umbraco.Examine { @@ -22,6 +23,9 @@ namespace Umbraco.Examine ///
public abstract class UmbracoExamineIndex : LuceneIndex, IUmbracoIndex, IIndexDiagnostics { + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; + private readonly IRuntimeState _runtimeState; // note // wrapping all operations that end up calling base.SafelyProcessQueueItems in a safe call @@ -29,7 +33,6 @@ namespace Umbraco.Examine // call context (and the database it can contain)! ideally we should be able to override // SafelyProcessQueueItems but that's not possible in the current version of Examine. - /// /// Create a new @@ -39,6 +42,8 @@ namespace Umbraco.Examine /// /// /// + /// + /// /// /// /// @@ -49,12 +54,16 @@ namespace Umbraco.Examine FieldDefinitionCollection fieldDefinitions, Analyzer defaultAnalyzer, IProfilingLogger profilingLogger, + ILogger logger, + ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment, IRuntimeState runtimeState, IValueSetValidator validator = null, IReadOnlyDictionary indexValueTypes = null) : base(name, luceneDirectory, fieldDefinitions, defaultAnalyzer, validator, indexValueTypes) { + _logger = logger; + _loggerFactory = loggerFactory; _runtimeState = runtimeState; ProfilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger)); @@ -62,7 +71,7 @@ namespace Umbraco.Examine if (luceneDirectory is FSDirectory fsDir) LuceneIndexFolder = fsDir.Directory; - _diagnostics = new UmbracoExamineIndexDiagnostics(this, ProfilingLogger, hostingEnvironment); + _diagnostics = new UmbracoExamineIndexDiagnostics(this, _loggerFactory.CreateLogger(), hostingEnvironment); } private readonly bool _configBased = false; @@ -118,7 +127,7 @@ namespace Umbraco.Examine /// protected override void OnIndexingError(IndexingErrorEventArgs ex) { - ProfilingLogger.Error(GetType(), ex.InnerException, ex.Message); + _logger.LogError(ex.InnerException, ex.Message); base.OnIndexingError(ex); } @@ -154,8 +163,7 @@ namespace Umbraco.Examine /// protected override void AddDocument(Document doc, ValueSet valueSet, IndexWriter writer) { - ProfilingLogger.Debug(GetType(), - "Write lucene doc id:{DocumentId}, category:{DocumentCategory}, type:{DocumentItemType}", + _logger.LogDebug("Write lucene doc id:{DocumentId}, category:{DocumentCategory}, type:{DocumentItemType}", valueSet.Id, valueSet.Category, valueSet.ItemType); diff --git a/src/Umbraco.Examine.Lucene/UmbracoExamineIndexDiagnostics.cs b/src/Umbraco.Examine.Lucene/UmbracoExamineIndexDiagnostics.cs index 777b198232..5952f410fc 100644 --- a/src/Umbraco.Examine.Lucene/UmbracoExamineIndexDiagnostics.cs +++ b/src/Umbraco.Examine.Lucene/UmbracoExamineIndexDiagnostics.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Lucene.Net.Store; using Umbraco.Core; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; namespace Umbraco.Examine { @@ -12,7 +12,7 @@ namespace Umbraco.Examine { private readonly UmbracoExamineIndex _index; - public UmbracoExamineIndexDiagnostics(UmbracoExamineIndex index, ILogger logger, IHostingEnvironment hostingEnvironment) + public UmbracoExamineIndexDiagnostics(UmbracoExamineIndex index, ILogger logger, IHostingEnvironment hostingEnvironment) : base(index, logger, hostingEnvironment) { _index = index; diff --git a/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs b/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs index 3cf7d6d386..2184108b4a 100644 --- a/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs +++ b/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs @@ -9,9 +9,13 @@ using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Hosting; using Umbraco.Core.IO; +using Umbraco.Core.Configuration.Models; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; namespace Umbraco.Examine { + /// /// Creates the indexes used by Umbraco /// @@ -22,26 +26,32 @@ namespace Umbraco.Examine public UmbracoIndexesCreator( ITypeFinder typeFinder, IProfilingLogger profilingLogger, + ILoggerFactory loggerFactory, ILocalizationService languageService, IPublicAccessService publicAccessService, IMemberService memberService, 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)); + LoggerFactory = loggerFactory; LanguageService = languageService ?? throw new System.ArgumentNullException(nameof(languageService)); PublicAccessService = publicAccessService ?? throw new System.ArgumentNullException(nameof(publicAccessService)); MemberService = memberService ?? throw new System.ArgumentNullException(nameof(memberService)); 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 ILoggerFactory LoggerFactory { 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,10 +75,12 @@ namespace Umbraco.Examine { var index = new UmbracoContentIndex( Constants.UmbracoIndexes.InternalIndexName, - CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.InternalIndexPath), + DirectoryFactory.CreateDirectory(Constants.UmbracoIndexes.InternalIndexPath), new UmbracoFieldDefinitionCollection(), new CultureInvariantWhitespaceAnalyzer(), ProfilingLogger, + LoggerFactory.CreateLogger(), + LoggerFactory, HostingEnvironment, RuntimeState, LanguageService, @@ -81,10 +93,12 @@ 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, + LoggerFactory.CreateLogger(), + LoggerFactory, HostingEnvironment, RuntimeState, LanguageService, @@ -97,9 +111,11 @@ namespace Umbraco.Examine var index = new UmbracoMemberIndex( Constants.UmbracoIndexes.MembersIndexName, new UmbracoFieldDefinitionCollection(), - CreateFileSystemLuceneDirectory(Constants.UmbracoIndexes.MembersIndexPath), + DirectoryFactory.CreateDirectory(Constants.UmbracoIndexes.MembersIndexPath), new CultureInvariantWhitespaceAnalyzer(), ProfilingLogger, + LoggerFactory.CreateLogger(), + LoggerFactory, HostingEnvironment, RuntimeState, UmbracoIndexConfig.GetMemberValueSetValidator() diff --git a/src/Umbraco.Examine.Lucene/UmbracoMemberIndex.cs b/src/Umbraco.Examine.Lucene/UmbracoMemberIndex.cs index 12678fa00a..a753df15ee 100644 --- a/src/Umbraco.Examine.Lucene/UmbracoMemberIndex.cs +++ b/src/Umbraco.Examine.Lucene/UmbracoMemberIndex.cs @@ -1,5 +1,6 @@ using Examine; using Lucene.Net.Analysis; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Hosting; using Umbraco.Core.IO; @@ -31,10 +32,12 @@ namespace Umbraco.Examine Directory luceneDirectory, Analyzer analyzer, IProfilingLogger profilingLogger, + ILogger logger, + ILoggerFactory loggerFactory, IHostingEnvironment hostingEnvironment, IRuntimeState runtimeState, IValueSetValidator validator = null) : - base(name, luceneDirectory, fieldDefinitions, analyzer, profilingLogger, hostingEnvironment, runtimeState, validator) + base(name, luceneDirectory, fieldDefinitions, analyzer, profilingLogger, logger, loggerFactory, hostingEnvironment, runtimeState, validator) { } 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..84fc0e599c 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; @@ -244,6 +246,7 @@ namespace Umbraco.Core.BackOffice if (string.IsNullOrEmpty(passwordHash)) throw new ArgumentException("Value can't be empty.", nameof(passwordHash)); user.PasswordHash = passwordHash; + user.PasswordConfig = null; // Clear this so that it's reset at the repository level return Task.CompletedTask; } 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/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs index fa76fb6f11..693246257a 100644 --- a/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/BatchedDatabaseServerMessenger.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Sync; @@ -32,13 +33,14 @@ namespace Umbraco.Web IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, + ILogger logger, IServerRegistrar serverRegistrar, DatabaseServerMessengerOptions options, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers, IRequestCache requestCache, IRequestAccessor requestAccessor) - : base(mainDom, scopeProvider, sqlContext, proflog, serverRegistrar, true, options, hostingEnvironment, cacheRefreshers) + : base(mainDom, scopeProvider, sqlContext, proflog, logger, serverRegistrar, true, options, hostingEnvironment, cacheRefreshers) { _databaseFactory = databaseFactory; _requestCache = requestCache; @@ -52,7 +54,7 @@ namespace Umbraco.Web if (_databaseFactory.CanConnect == false) { - Logger.Warn("Cannot connect to the database, distributed calls will not be enabled for this server."); + Logger.LogWarning("Cannot connect to the database, distributed calls will not be enabled for this server."); } else { diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder.cs index 92ed7de881..f345f40bd7 100644 --- a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder.cs +++ b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder.cs @@ -3,9 +3,9 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Events; -using Umbraco.Core.Logging; namespace Umbraco.Web.Cache { @@ -17,12 +17,12 @@ namespace Umbraco.Web.Cache private static readonly ConcurrentDictionary FoundHandlers = new ConcurrentDictionary(); private readonly DistributedCache _distributedCache; private readonly IUmbracoContextFactory _umbracoContextFactory; - private readonly ILogger _logger; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// - public DistributedCacheBinder(DistributedCache distributedCache, IUmbracoContextFactory umbracoContextFactory, ILogger logger) + public DistributedCacheBinder(DistributedCache distributedCache, IUmbracoContextFactory umbracoContextFactory, ILogger logger) { _distributedCache = distributedCache; _logger = logger; @@ -73,7 +73,7 @@ namespace Umbraco.Web.Cache { // TODO: should this be fatal (ie, an exception)? var name = e.Sender.GetType().Name + "_" + e.EventName; - _logger.Warn("Dropping event {EventName} because no corresponding handler was found.", name); + _logger.LogWarning("Dropping event {EventName} because no corresponding handler was found.", name); continue; } diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs index c0200933ab..46968e81dc 100644 --- a/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs +++ b/src/Umbraco.Infrastructure/Cache/DistributedCacheBinder_Handlers.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; @@ -43,7 +43,7 @@ namespace Umbraco.Web.Cache if (supportUnbinding) _unbinders = new List(); - _logger.Info("Initializing Umbraco internal event handlers for cache refreshing."); + _logger.LogInformation("Initializing Umbraco internal event handlers for cache refreshing."); // bind to user and user group events Bind(() => UserService.SavedUserGroup += UserService_SavedUserGroup, diff --git a/src/Umbraco.Infrastructure/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Infrastructure/Cache/DistributedCacheExtensions.cs index 7cfac1b9a0..ef968e8fa6 100644 --- a/src/Umbraco.Infrastructure/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Infrastructure/Cache/DistributedCacheExtensions.cs @@ -128,15 +128,16 @@ namespace Umbraco.Web.Cache public static void RefreshMemberCache(this DistributedCache dc, params IMember[] members) { - dc.Refresh(MemberCacheRefresher.UniqueId, x => x.Id, members); + if (members.Length == 0) return; + dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username))); } public static void RemoveMemberCache(this DistributedCache dc, params IMember[] members) { - dc.Remove(MemberCacheRefresher.UniqueId, x => x.Id, members); + if (members.Length == 0) return; + dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username))); } - #endregion #region MemberGroupCache 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.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs index c8bc02f604..096c5d5686 100644 --- a/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/DatabaseServerRegistrarAndMessengerComponent.cs @@ -1,9 +1,9 @@ using System; using System.Threading; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Sync; @@ -83,7 +83,8 @@ namespace Umbraco.Web.Compose private object _locker = new object(); private readonly DatabaseServerRegistrar _registrar; private readonly IBatchedDatabaseServerMessenger _messenger; - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IServerRegistrationService _registrationService; private readonly BackgroundTaskRunner _touchTaskRunner; private readonly BackgroundTaskRunner _processTaskRunner; @@ -95,11 +96,13 @@ namespace Umbraco.Web.Compose IServerRegistrar serverRegistrar, IServerMessenger serverMessenger, IServerRegistrationService registrationService, - ILogger logger, + ILogger logger, + ILoggerFactory loggerFactory, IApplicationShutdownRegistry hostingEnvironment, IRequestAccessor requestAccessor) { _logger = logger; + _loggerFactory = loggerFactory; _registrationService = registrationService; _requestAccessor = requestAccessor; @@ -108,7 +111,7 @@ namespace Umbraco.Web.Compose if (_registrar != null) { _touchTaskRunner = new BackgroundTaskRunner("ServerRegistration", - new BackgroundTaskRunnerOptions { AutoStart = true }, logger, hostingEnvironment); + new BackgroundTaskRunnerOptions { AutoStart = true }, _loggerFactory.CreateLogger>(), hostingEnvironment); } // create task runner for BatchedDatabaseServerMessenger @@ -116,7 +119,7 @@ namespace Umbraco.Web.Compose if (_messenger != null) { _processTaskRunner = new BackgroundTaskRunner("ServerInstProcess", - new BackgroundTaskRunnerOptions { AutoStart = true }, logger, hostingEnvironment); + new BackgroundTaskRunnerOptions { AutoStart = true }, _loggerFactory.CreateLogger>(), hostingEnvironment); } } @@ -225,7 +228,7 @@ namespace Umbraco.Web.Compose } catch (Exception e) { - _logger.Error(e, "Failed (will repeat)."); + _logger.LogError(e, "Failed (will repeat)."); } return true; // repeat } @@ -268,7 +271,7 @@ namespace Umbraco.Web.Compose } catch (Exception ex) { - _logger.Error(ex, "Failed to update server record in database."); + _logger.LogError(ex, "Failed to update server record in database."); return false; // probably stop if we have an error } } diff --git a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs b/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs index a2ee650595..c99d7c992e 100644 --- a/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/ManifestWatcherComponent.cs @@ -1,8 +1,8 @@ using System.IO; +using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Net; @@ -11,7 +11,7 @@ namespace Umbraco.Core.Compose public sealed class ManifestWatcherComponent : IComponent { private readonly IHostingEnvironment _hosting; - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IIOHelper _ioHelper; private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; @@ -19,10 +19,10 @@ namespace Umbraco.Core.Compose // package.manifest chances and restarts the application on any change private ManifestWatcher _mw; - public ManifestWatcherComponent(IHostingEnvironment hosting, ILogger logger, IIOHelper ioHelper, IUmbracoApplicationLifetime umbracoApplicationLifetime) + public ManifestWatcherComponent(IHostingEnvironment hosting, ILoggerFactory loggerFactory, IIOHelper ioHelper, IUmbracoApplicationLifetime umbracoApplicationLifetime) { _hosting = hosting; - _logger = logger; + _loggerFactory = loggerFactory; _ioHelper = ioHelper; _umbracoApplicationLifetime = umbracoApplicationLifetime; } @@ -37,7 +37,7 @@ namespace Umbraco.Core.Compose var appPlugins = _ioHelper.MapPath("~/App_Plugins/"); if (Directory.Exists(appPlugins) == false) return; - _mw = new ManifestWatcher(_logger, _umbracoApplicationLifetime); + _mw = new ManifestWatcher(_loggerFactory.CreateLogger(), _umbracoApplicationLifetime); _mw.Start(Directory.GetDirectories(appPlugins)); } 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..81a41cf575 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 Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; 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) + 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()); @@ -127,20 +162,20 @@ namespace Umbraco.Web.Compose .Where(m => m.OriginalPath.Contains(Constants.System.RecycleBinContentString)) .Select(m => m.Entity) .ToArray(); - if(restoredEntities.Any()) + if (restoredEntities.Any()) { _notifier.Notify(_actions.GetAction(), restoredEntities); } } - 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) + if (entities.Any() == false) { return; } - notifier.Notify(actions.GetAction(), entities); + _notifier.Notify(_actions.GetAction(), entities); } /// @@ -153,8 +188,8 @@ namespace Umbraco.Web.Compose private readonly INotificationService _notificationService; private readonly IUserService _userService; private readonly ILocalizedTextService _textService; - private readonly IGlobalSettings _globalSettings; - private readonly ILogger _logger; + private readonly GlobalSettings _globalSettings; + private readonly ILogger _logger; /// /// Constructor @@ -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; } @@ -184,11 +226,11 @@ namespace Umbraco.Web.Compose //if there is no current user, then use the admin if (user == null) { - _logger.Debug(typeof(Notifier), "There is no current Umbraco user logged in, the notifications will be sent from the administrator"); + _logger.LogDebug("There is no current Umbraco user logged in, the notifications will be sent from the administrator"); user = _userService.GetUserById(Constants.Security.SuperUserId); if (user == null) { - _logger.Warn(typeof(Notifier), "Notifications can not be sent, no admin user with id {SuperUserId} could be resolved", Constants.Security.SuperUserId); + _logger.LogWarning("Notifications can not be sent, no admin user with id {SuperUserId} could be resolved", Constants.Security.SuperUserId); return; } } @@ -201,7 +243,7 @@ namespace Umbraco.Web.Compose if (sender == null) throw new ArgumentNullException(nameof(sender)); if (siteUri == null) { - _logger.Warn(typeof(Notifier), "Notifications can not be sent, no site url is set (might be during boot process?)"); + _logger.LogWarning("Notifications can not be sent, no site url is set (might be during boot process?)"); return; } 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..bac5b27ae7 100644 --- a/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs @@ -2,6 +2,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.Events; using Umbraco.Core.Models; +using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; @@ -13,129 +14,160 @@ namespace Umbraco.Core.Compose private readonly IEntityService _entityService; private readonly ILocalizedTextService _textService; private readonly IAuditService _auditService; + private readonly IScopeProvider _scopeProvider; - public RelateOnTrashComponent(IRelationService relationService, IEntityService entityService, ILocalizedTextService textService, IAuditService auditService) + public RelateOnTrashComponent( + IRelationService relationService, + IEntityService entityService, + ILocalizedTextService textService, + IAuditService auditService, + IScopeProvider scopeProvider) { _relationService = relationService; _entityService = entityService; _textService = textService; _auditService = auditService; + _scopeProvider = scopeProvider; } 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); - - // check that the relation-type exists, if not, then recreate it - if (relationType == null) + using (var scope = _scopeProvider.CreateScope()) { - var documentObjectType = Constants.ObjectTypes.Document; - const string relationTypeName = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteName; + const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias; + var relationType = _relationService.GetRelationTypeByAlias(relationTypeAlias); - relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, documentObjectType); - relationService.Save(relationType); - } - - foreach (var item in e.MoveInfoCollection) - { - var originalPath = item.OriginalPath.ToDelimitedList(); - var originalParentId = originalPath.Count > 2 - ? int.Parse(originalPath[originalPath.Count - 2]) - : 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)) + // check that the relation-type exists, if not, then recreate it + if (relationType == null) { - // 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); + var documentObjectType = Constants.ObjectTypes.Document; + const string relationTypeName = + Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteName; - auditService.Add(AuditType.Delete, - item.Entity.WriterId, - item.Entity.Id, - ObjectTypes.GetName(UmbracoObjectTypes.Document), - string.Format(textService.Localize( - "recycleBin/contentTrashed"), - item.Entity.Id, originalParentId)); + relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, + documentObjectType); + _relationService.Save(relationType); } + + foreach (var item in e.MoveInfoCollection) + { + var originalPath = item.OriginalPath.ToDelimitedList(); + var originalParentId = originalPath.Count > 2 + ? int.Parse(originalPath[originalPath.Count - 2]) + : 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)) + { + // 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 = _relationService.GetByParentAndChildId(originalParentId, item.Entity.Id, relationType) ?? + new Relation(originalParentId, item.Entity.Id, relationType); + _relationService.Save(relation); + + _auditService.Add(AuditType.Delete, + item.Entity.WriterId, + item.Entity.Id, + ObjectTypes.GetName(UmbracoObjectTypes.Document), + string.Format(_textService.Localize( + "recycleBin/contentTrashed"), + item.Entity.Id, originalParentId)); + } + } + + scope.Complete(); } } - private static void MediaService_Trashed(IMediaService sender, MoveEventArgs e, IRelationService relationService, IEntityService entityService, ILocalizedTextService textService, IAuditService auditService) + public void MediaService_Trashed(IMediaService sender, MoveEventArgs e) { - const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias; - var relationType = relationService.GetRelationTypeByAlias(relationTypeAlias); - // check that the relation-type exists, if not, then recreate it - if (relationType == null) + using (var scope = _scopeProvider.CreateScope()) { - var documentObjectType = Constants.ObjectTypes.Document; - const string relationTypeName = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName; - relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, documentObjectType); - relationService.Save(relationType); - } - foreach (var item in e.MoveInfoCollection) - { - var originalPath = item.OriginalPath.ToDelimitedList(); - var originalParentId = originalPath.Count > 2 - ? int.Parse(originalPath[originalPath.Count - 2]) - : 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)) + const string relationTypeAlias = + Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias; + var relationType = _relationService.GetRelationTypeByAlias(relationTypeAlias); + // check that the relation-type exists, if not, then recreate it + if (relationType == null) { - // 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, - item.Entity.CreatorId, - item.Entity.Id, - ObjectTypes.GetName(UmbracoObjectTypes.Media), - string.Format(textService.Localize( - "recycleBin/mediaTrashed"), - item.Entity.Id, originalParentId)); + var documentObjectType = Constants.ObjectTypes.Document; + const string relationTypeName = + Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName; + relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, + documentObjectType); + _relationService.Save(relationType); } + + foreach (var item in e.MoveInfoCollection) + { + var originalPath = item.OriginalPath.ToDelimitedList(); + var originalParentId = originalPath.Count > 2 + ? int.Parse(originalPath[originalPath.Count - 2]) + : 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)) + { + // 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 = + _relationService.GetByParentAndChildId(originalParentId, item.Entity.Id, relationType) ?? + new Relation(originalParentId, item.Entity.Id, relationType); + _relationService.Save(relation); + _auditService.Add(AuditType.Delete, + item.Entity.CreatorId, + item.Entity.Id, + ObjectTypes.GetName(UmbracoObjectTypes.Media), + string.Format(_textService.Localize( + "recycleBin/mediaTrashed"), + item.Entity.Id, originalParentId)); + } + } + + scope.Complete(); } } } diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs index 9dc130fcba..d6b8288b88 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/FileSystems.cs @@ -1,8 +1,10 @@ -using Umbraco.Core.Configuration; +using Microsoft.Extensions.Logging; +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; -using Umbraco.Core.Logging; namespace Umbraco.Core.Composing.CompositionExtensions { @@ -96,8 +98,8 @@ namespace Umbraco.Core.Composing.CompositionExtensions { var ioHelper = factory.GetInstance(); var hostingEnvironment = factory.GetInstance(); - var logger = factory.GetInstance(); - var globalSettings = factory.GetInstance(); + var logger = 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..a4744d3d2d 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Services.cs @@ -1,12 +1,14 @@ using System; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; 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; -using Umbraco.Core.Logging; using Umbraco.Core.Packaging; using Umbraco.Core.Routing; using Umbraco.Core.Services; @@ -59,7 +61,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions composition.Register(SourcesFactory); composition.RegisterUnique(factory => new LocalizedTextService( factory.GetInstance>(), - factory.GetInstance())); + factory.GetInstance>())); composition.RegisterUnique(); @@ -92,15 +94,15 @@ namespace Umbraco.Core.Composing.CompositionExtensions factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), - 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"))); @@ -120,7 +122,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions .Select(x => new LocalizedTextServiceSupplementaryFileSource(x, true)); return new LocalizedTextServiceFileSources( - container.GetInstance(), + container.GetInstance>(), container.GetInstance(), mainLangFolder, pluginLangFolders.Concat(userLangFolders)); diff --git a/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs b/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs index f6d980f62a..ad7c75b94f 100644 --- a/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs +++ b/src/Umbraco.Infrastructure/Composing/HostBuilderExtensions.cs @@ -26,7 +26,6 @@ namespace Umbraco.Core.Composing /// /// public static IHostBuilder UseUmbraco(this IHostBuilder builder, UmbracoServiceProviderFactory umbracoServiceProviderFactory) - => builder.UseServiceProviderFactory(umbracoServiceProviderFactory) - .UseSerilog(); + => builder.UseServiceProviderFactory(umbracoServiceProviderFactory); } } diff --git a/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs b/src/Umbraco.Infrastructure/Composing/RegisterFactory.cs index 835bd0b9a8..e065852538 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 { @@ -20,7 +21,7 @@ namespace Umbraco.Core.Composing // cannot use typeof().AssemblyQualifiedName on the web container - we don't reference it // a normal Umbraco site should run on the web container, but an app may run on the core one private const string CoreLightInjectContainerTypeName = "Umbraco.Core.Composing.LightInject.LightInjectContainer,Umbraco.Core"; - private const string WebLightInjectContainerTypeName = "Umbraco.Web.Composing.LightInject.LightInjectContainer,Umbraco.Web"; + private const string WebLightInjectContainerTypeName = "Umbraco.Core.Composing.LightInject.LightInjectContainer,Umbraco.Infrastructure"; /// /// Creates a new instance of the configured container. @@ -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..70737ab569 100644 --- a/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs +++ b/src/Umbraco.Infrastructure/Composing/UmbracoServiceProviderFactory.cs @@ -2,9 +2,12 @@ using LightInject.Microsoft.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using System; +using Microsoft.Extensions.Logging; +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 @@ -85,8 +88,9 @@ namespace Umbraco.Core.Composing { // after cross wiring, configure "Current" Current.Initialize( - _container.GetInstance(), - _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..a7e7981daf 100644 --- a/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs +++ b/src/Umbraco.Infrastructure/CompositionExtensions_Essentials.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Cache; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; @@ -24,7 +25,7 @@ namespace Umbraco.Core // then we pre-resolve them which means that the instance re-resolved later is different... BUT if we register that // pre-resolved instance here again, then it will be the same instance re-resolved later, just like we are doing with // IDbProviderFactoryCreator. - ILogger logger, IProfiler profiler, IProfilingLogger profilingLogger, + ILogger logger, ILoggerFactory loggerFactory, IProfiler profiler, IProfilingLogger profilingLogger, IMainDom mainDom, AppCaches appCaches, IUmbracoDatabaseFactory databaseFactory, @@ -36,8 +37,9 @@ namespace Umbraco.Core IDbProviderFactoryCreator dbProviderFactoryCreator, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) - { + { composition.RegisterUnique(logger); + composition.RegisterUnique(loggerFactory); composition.RegisterUnique(profiler); composition.RegisterUnique(profilingLogger); composition.RegisterUnique(mainDom); 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/Examine/ContentValueSetBuilder.cs b/src/Umbraco.Infrastructure/Examine/ContentValueSetBuilder.cs index 01e6d993b4..f03fcca181 100644 --- a/src/Umbraco.Infrastructure/Examine/ContentValueSetBuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/ContentValueSetBuilder.cs @@ -53,6 +53,11 @@ namespace Umbraco.Examine scope.Complete(); } + return GetValueSetsEnumerable(content, creatorIds, writerIds); + } + + private IEnumerable GetValueSetsEnumerable(IContent[] content, Dictionary creatorIds, Dictionary writerIds) + { // TODO: There is a lot of boxing going on here and ultimately all values will be boxed by Lucene anyways // but I wonder if there's a way to reduce the boxing that we have to do or if it will matter in the end since // Lucene will do it no matter what? One idea was to create a `FieldValue` struct which would contain `object`, `object[]`, `ValueType` and `ValueType[]` diff --git a/src/Umbraco.Infrastructure/Examine/IndexRebuilder.cs b/src/Umbraco.Infrastructure/Examine/IndexRebuilder.cs index d9bef752a9..bafdfc72f4 100644 --- a/src/Umbraco.Infrastructure/Examine/IndexRebuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/IndexRebuilder.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using System.Threading.Tasks; using Examine; using Umbraco.Core.Composing; @@ -14,12 +15,14 @@ namespace Umbraco.Examine /// public class IndexRebuilder { - private readonly IProfilingLogger _logger; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; private readonly IEnumerable _populators; public IExamineManager ExamineManager { get; } - public IndexRebuilder(IProfilingLogger logger, IExamineManager examineManager, IEnumerable populators) + public IndexRebuilder(IProfilingLogger profilingLogger , ILogger logger, IExamineManager examineManager, IEnumerable populators) { + _profilingLogger = profilingLogger ; _populators = populators; _logger = logger; ExamineManager = examineManager; @@ -65,7 +68,7 @@ namespace Umbraco.Examine } catch (Exception e) { - _logger.Error(e, "Index populating failed for populator {Populator}", populator.GetType()); + _logger.LogError(e, "Index populating failed for populator {Populator}", populator.GetType()); } } } diff --git a/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs b/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs index e9aa87a25c..73ad31e115 100644 --- a/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs @@ -2,8 +2,8 @@ using Examine; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -17,13 +17,13 @@ namespace Umbraco.Examine { private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly IUserService _userService; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IShortStringHelper _shortStringHelper; private readonly IJsonSerializer _serializer; public MediaValueSetBuilder(PropertyEditorCollection propertyEditors, UrlSegmentProviderCollection urlSegmentProviders, - IUserService userService, ILogger logger, IShortStringHelper shortStringHelper, IJsonSerializer serializer) + IUserService userService, ILogger logger, IShortStringHelper shortStringHelper, IJsonSerializer serializer) : base(propertyEditors, false) { _urlSegmentProviders = urlSegmentProviders; @@ -55,7 +55,7 @@ namespace Umbraco.Examine } catch (Exception ex) { - _logger.Error(ex, $"Could not Deserialize ImageCropperValue for item with key {m.Key} "); + _logger.LogError(ex, $"Could not Deserialize ImageCropperValue for item with key {m.Key} "); } if (cropper != null) diff --git a/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs b/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs index 8f3c05f5bd..7eebf61b22 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs @@ -5,7 +5,7 @@ using System.Text; using HeyRed.MarkdownSharp; using Umbraco.Composing; using Umbraco.Core.Configuration.HealthChecks; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.HealthCheck { @@ -27,7 +27,7 @@ namespace Umbraco.Web.HealthCheck } catch (Exception ex) { - Logger.Error(ex, "Error running scheduled health check: {HealthCheckName}", t.Name); + Logger.LogError(ex, "Error running scheduled health check: {HealthCheckName}", t.Name); var message = $"Health check failed with exception: {ex.Message}. See logs for details."; return new List { @@ -54,7 +54,7 @@ namespace Umbraco.Web.HealthCheck public void LogResults() { - Logger.Info("Scheduled health check results:"); + Logger.LogInformation("Scheduled health check results:"); foreach (var result in _results) { var checkName = result.Key; @@ -62,16 +62,16 @@ namespace Umbraco.Web.HealthCheck var checkIsSuccess = result.Value.All(x => x.ResultType == StatusResultType.Success); if (checkIsSuccess) { - Logger.Info("Checks for '{HealthCheckName}' all completed successfully.", checkName); + Logger.LogInformation("Checks for '{HealthCheckName}' all completed successfully.", checkName); } else { - Logger.Warn("Checks for '{HealthCheckName}' completed with errors.", checkName); + Logger.LogWarning("Checks for '{HealthCheckName}' completed with errors.", checkName); } foreach (var checkResult in checkResults) { - Logger.Info("Result for {HealthCheckName}: {HealthCheckResult}, Message: '{HealthCheckMessage}'", checkName, checkResult.ResultType, checkResult.Message); + Logger.LogInformation("Result for {HealthCheckName}: {HealthCheckResult}, Message: '{HealthCheckMessage}'", checkName, checkResult.ResultType, checkResult.Message); } } } 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..1538187528 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Models; using Umbraco.Net; @@ -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 { @@ -20,9 +22,9 @@ namespace Umbraco.Web.Install { private static HttpClient _httpClient; private readonly DatabaseBuilder _databaseBuilder; - private readonly ILogger _logger; + 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; @@ -31,9 +33,9 @@ namespace Umbraco.Web.Install private InstallationType? _installationType; public InstallHelper(DatabaseBuilder databaseBuilder, - ILogger logger, + 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; @@ -103,7 +105,7 @@ namespace Umbraco.Web.Install } catch (Exception ex) { - _logger.Error(ex, "An error occurred in InstallStatus trying to check upgrades"); + _logger.LogError(ex, "An error occurred in InstallStatus trying to check upgrades"); } } @@ -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 @@ -154,7 +156,7 @@ namespace Umbraco.Web.Install } catch (AggregateException ex) { - _logger.Error(ex, "Could not download list of available starter kits"); + _logger.LogError(ex, "Could not download list of available starter kits"); } return packages; diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs index 0c88c7a096..7727b6b760 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; 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 { @@ -15,13 +16,14 @@ namespace Umbraco.Web.Install.InstallSteps public class DatabaseConfigureStep : InstallSetupStep { private readonly DatabaseBuilder _databaseBuilder; - private readonly ILogger _logger; - private readonly IConnectionStrings _connectionStrings; + private readonly ILogger _logger; + private readonly ConnectionStrings _connectionStrings; - public DatabaseConfigureStep(DatabaseBuilder databaseBuilder, IConnectionStrings connectionStrings) + public DatabaseConfigureStep(DatabaseBuilder databaseBuilder, IOptions connectionStrings, ILogger logger) { _databaseBuilder = databaseBuilder; - _connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings)); + _connectionStrings = connectionStrings.Value ?? throw new ArgumentNullException(nameof(connectionStrings)); + _logger = logger; } public override Task ExecuteAsync(DatabaseModel database) @@ -107,7 +109,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()) { @@ -119,7 +121,7 @@ namespace Umbraco.Web.Install.InstallSteps } catch (Exception ex) { - _logger.Error(ex, "An error occurred, reconfiguring..."); + _logger.LogError(ex, "An error occurred, reconfiguring..."); //something went wrong, could not connect so probably need to reconfigure return true; } 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..7258628b7d 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -1,10 +1,12 @@ using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; 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; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Web.Install.Models; @@ -18,31 +20,22 @@ namespace Umbraco.Web.Install.InstallSteps { private readonly DatabaseBuilder _databaseBuilder; private readonly IRuntimeState _runtime; - private readonly ILogger _logger; + 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, + 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) @@ -53,9 +46,9 @@ namespace Umbraco.Web.Install.InstallSteps if (upgrade) { - _logger.Info("Running 'Upgrade' service"); + _logger.LogInformation("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/Logging/Serilog/LoggerConfigExtensions.cs b/src/Umbraco.Infrastructure/Logging/Serilog/LoggerConfigExtensions.cs index f2e028e6de..84270b95bf 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/LoggerConfigExtensions.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/LoggerConfigExtensions.cs @@ -7,7 +7,6 @@ using Serilog.Core; using Serilog.Events; using Serilog.Formatting; using Serilog.Formatting.Compact; -using Umbraco.Core.IO; using Umbraco.Core.Hosting; using Umbraco.Core.Logging.Serilog.Enrichers; @@ -48,6 +47,11 @@ namespace Umbraco.Core.Logging.Serilog .Enrich.With() .Enrich.FromLogContext(); // allows us to dynamically enrich + + logConfig.WriteTo.UmbracoFile( + Path.Combine(loggingConfiguration.LogDirectory, $"UmbracoTraceLog.{Environment.MachineName}..json") + ); + return logConfig; } @@ -61,7 +65,7 @@ namespace Umbraco.Core.Logging.Serilog public static LoggerConfiguration OutputDefaultTextFile( this LoggerConfiguration logConfig, IHostingEnvironment hostingEnvironment, - ILoggingConfiguration loggingConfiguration, LogEventLevel minimumLevel = LogEventLevel.Verbose, int? retainedFileCount = null) + LogEventLevel minimumLevel = LogEventLevel.Verbose) { //Main .txt logfile - in similar format to older Log4Net output //Ends with ..txt as Date is inserted before file extension substring @@ -79,18 +83,25 @@ namespace Umbraco.Core.Logging.Serilog /// /// Used in config - If renamed or moved to other assembly the config file also has be updated. /// - public static LoggerConfiguration File(this LoggerSinkConfiguration configuration, ITextFormatter formatter, + public static LoggerConfiguration UmbracoFile(this LoggerSinkConfiguration configuration, string path, + ITextFormatter formatter = null, LogEventLevel restrictedToMinimumLevel = LogEventLevel.Verbose, LoggingLevelSwitch levelSwitch = null, long? fileSizeLimitBytes = 1073741824, TimeSpan? flushToDiskInterval = null, - RollingInterval rollingInterval = RollingInterval.Infinite, + RollingInterval rollingInterval = RollingInterval.Day, bool rollOnFileSizeLimit = false, int? retainedFileCountLimit = 31, Encoding encoding = null ) { + + if (formatter is null) + { + formatter = new CompactJsonFormatter(); + } + return configuration.Async( asyncConfiguration => asyncConfiguration.Map(AppDomainId, (_,mapConfiguration) => mapConfiguration.File( @@ -136,34 +147,5 @@ namespace Umbraco.Core.Logging.Serilog return logConfig; } - /// - /// Reads settings from /config/serilog.config - /// That allows the main logging pipeline to be configured - /// - /// A Serilog LoggerConfiguration - /// - public static LoggerConfiguration ReadFromConfigFile(this LoggerConfiguration logConfig, ILoggingConfiguration loggingConfiguration) - { - //Read from main serilog.config file - logConfig.ReadFrom.AppSettings(filePath: loggingConfiguration.LogConfigurationFile); - - return logConfig; - } - - /// - /// Reads settings from /config/serilog.user.config - /// That allows a separate logging pipeline to be configured that will not affect the main Umbraco log - /// - /// A Serilog LoggerConfiguration - /// - public static LoggerConfiguration ReadFromUserConfigFile(this LoggerConfiguration logConfig, ILoggingConfiguration loggingConfiguration) - { - //A nested logger - where any user configured sinks via config can not effect the main 'umbraco' logger above - logConfig.WriteTo.Logger(cfg => - cfg.ReadFrom.AppSettings(filePath: loggingConfiguration.UserLogConfigurationFile)); - - return logConfig; - } - } } diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs index 38af9554ab..9e14a6407a 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/SerilogLogger.cs @@ -1,7 +1,10 @@ using System; using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; using Serilog; using Serilog.Events; +using Serilog.Extensions.Logging; using Umbraco.Core.Hosting; namespace Umbraco.Core.Logging.Serilog @@ -10,7 +13,7 @@ namespace Umbraco.Core.Logging.Serilog /// /// Implements on top of Serilog. /// - public class SerilogLogger : ILogger, IDisposable + public class SerilogLogger : IDisposable { public global::Serilog.ILogger SerilogLog { get; } @@ -35,13 +38,14 @@ namespace Umbraco.Core.Logging.Serilog /// Creates a logger with some pre-defined configuration and remainder from config file /// /// Used by UmbracoApplicationBase to get its logger. - public static SerilogLogger CreateWithDefaultConfiguration(IHostingEnvironment hostingEnvironment, ILoggingConfiguration loggingConfiguration) + public static SerilogLogger CreateWithDefaultConfiguration( + IHostingEnvironment hostingEnvironment, + ILoggingConfiguration loggingConfiguration, + IConfiguration configuration) { - var loggerConfig = new LoggerConfiguration(); - loggerConfig + var loggerConfig = new LoggerConfiguration() .MinimalConfiguration(hostingEnvironment, loggingConfiguration) - .ReadFromConfigFile(loggingConfiguration) - .ReadFromUserConfigFile(loggingConfiguration); + .ReadFrom.Configuration(configuration); return new SerilogLogger(loggerConfig); } @@ -83,7 +87,7 @@ namespace Umbraco.Core.Logging.Serilog /// public void Fatal(Type reporting, Exception exception, string message) { - var logger = LoggerFor(reporting); + var logger = LoggerFor(reporting); logger.Fatal(exception, message); } @@ -91,7 +95,7 @@ namespace Umbraco.Core.Logging.Serilog public void Fatal(Type reporting, Exception exception) { var logger = LoggerFor(reporting); - var message = "Exception."; + var message = "Exception."; logger.Fatal(exception, message); } @@ -110,14 +114,14 @@ namespace Umbraco.Core.Logging.Serilog /// public void Fatal(Type reporting, Exception exception, string messageTemplate, params object[] propertyValues) { - var logger = LoggerFor(reporting); + var logger = LoggerFor(reporting); logger.Fatal(exception, messageTemplate, propertyValues); } /// public void Error(Type reporting, Exception exception, string message) { - var logger = LoggerFor(reporting); + var logger = LoggerFor(reporting); logger.Error(exception, message); } @@ -212,5 +216,6 @@ namespace Umbraco.Core.Logging.Serilog { SerilogLog.DisposeIfDisposable(); } + } } diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs b/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs index 0909ec67ad..797e353fcf 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/LogViewerComposer.cs @@ -1,4 +1,5 @@ using System.IO; +using Microsoft.Extensions.Logging; using Serilog; using Umbraco.Core.Composing; using Umbraco.Core.Hosting; @@ -11,22 +12,12 @@ namespace Umbraco.Core.Logging.Viewer { public void Compose(Composition composition) { - - - composition.RegisterUnique(factory => - { - var hostingEnvironment = factory.GetInstance(); - return new LoggingConfiguration( - Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "App_Data", "Logs"), - Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "config", "serilog.config"), - Path.Combine(hostingEnvironment.ApplicationPhysicalPath, "config", "serilog.user.config")); - }); composition.RegisterUnique(); composition.SetLogViewer(); composition.RegisterUnique(factory => { - return new SerilogJsonLogViewer(factory.GetInstance(), + return new SerilogJsonLogViewer(factory.GetInstance>(), factory.GetInstance(), factory.GetInstance(), Log.Logger); diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/SerilogJsonLogViewer.cs b/src/Umbraco.Infrastructure/Logging/Viewer/SerilogJsonLogViewer.cs index 5bf079c1b4..8e74dbe194 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/SerilogJsonLogViewer.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/SerilogJsonLogViewer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Serilog.Events; using Serilog.Formatting.Compact.Reader; @@ -11,10 +12,10 @@ namespace Umbraco.Core.Logging.Viewer internal class SerilogJsonLogViewer : SerilogLogViewerSourceBase { private readonly string _logsPath; - private readonly ILogger _logger; + private readonly ILogger _logger; public SerilogJsonLogViewer( - ILogger logger, + ILogger logger, ILogViewerConfig logViewerConfig, ILoggingConfiguration loggingConfiguration, global::Serilog.ILogger serilogLog) @@ -128,7 +129,7 @@ namespace Umbraco.Core.Logging.Viewer { // As we are reading/streaming one line at a time in the JSON file // Thus we can not report the line number, as it will always be 1 - _logger.Error(ex, "Unable to parse a line in the JSON log file"); + _logger.LogError(ex, "Unable to parse a line in the JSON log file"); evt = null; return true; diff --git a/src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs b/src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs index 9a6b37a9bb..94b868f145 100644 --- a/src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs +++ b/src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs @@ -1,9 +1,9 @@ using System; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core.Composing; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; using Umbraco.Core.Services; @@ -16,7 +16,7 @@ namespace Umbraco.Core.Manifest /// internal class DataEditorConverter : JsonReadConverter { - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IIOHelper _ioHelper; private readonly IDataTypeService _dataTypeService; private readonly ILocalizationService _localizationService; @@ -26,9 +26,9 @@ namespace Umbraco.Core.Manifest /// /// Initializes a new instance of the class. /// - public DataEditorConverter(ILogger logger, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService textService, IShortStringHelper shortStringHelper) + public DataEditorConverter(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService textService, IShortStringHelper shortStringHelper) { - _logger = logger; + _loggerFactory = loggerFactory; _ioHelper = ioHelper; _dataTypeService = dataTypeService; _localizationService = localizationService; @@ -61,7 +61,7 @@ namespace Umbraco.Core.Manifest type = EditorType.MacroParameter; } - return new DataEditor(_logger, _dataTypeService, _localizationService, _textService, _shortStringHelper, type); + return new DataEditor(_loggerFactory, _dataTypeService, _localizationService, _textService, _shortStringHelper, type); } /// diff --git a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs index c6ffb9b6ef..7392506d2b 100644 --- a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs +++ b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Umbraco.Core.Cache; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; using Umbraco.Core.Services; @@ -19,13 +19,14 @@ namespace Umbraco.Core.Manifest /// public class ManifestParser : IManifestParser { + private readonly ILoggerFactory _loggerFactory; private readonly IJsonSerializer _jsonSerializer; private readonly ILocalizedTextService _localizedTextService; private readonly IShortStringHelper _shortStringHelper; private static readonly string Utf8Preamble = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()); private readonly IAppPolicyCache _cache; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IIOHelper _ioHelper; private readonly IDataTypeService _dataTypeService; private readonly ILocalizationService _localizationService; @@ -41,15 +42,17 @@ namespace Umbraco.Core.Manifest AppCaches appCaches, ManifestValueValidatorCollection validators, ManifestFilterCollection filters, - ILogger logger, + ILogger logger, + ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, IJsonSerializer jsonSerializer, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : this(appCaches, validators, filters, "~/App_Plugins", logger, ioHelper, dataTypeService, localizationService) + : this(appCaches, validators, filters, "~/App_Plugins", logger, loggerFactory, ioHelper, dataTypeService, localizationService) { + _loggerFactory = loggerFactory; _jsonSerializer = jsonSerializer; _localizedTextService = localizedTextService; _shortStringHelper = shortStringHelper; @@ -58,7 +61,7 @@ namespace Umbraco.Core.Manifest /// /// Initializes a new instance of the class. /// - private ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, ManifestFilterCollection filters, string path, ILogger logger, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService) + private ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, ManifestFilterCollection filters, string path, ILogger logger, ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService) { if (appCaches == null) throw new ArgumentNullException(nameof(appCaches)); _cache = appCaches.RuntimeCache; @@ -70,6 +73,7 @@ namespace Umbraco.Core.Manifest if (path == null) throw new ArgumentNullException(nameof(path)); if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(path)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); _ioHelper = ioHelper; Path = path; @@ -115,7 +119,7 @@ namespace Umbraco.Core.Manifest } catch (Exception e) { - _logger.Error(e, "Failed to parse manifest at '{Path}', ignoring.", path); + _logger.LogError(e, "Failed to parse manifest at '{Path}', ignoring.", path); } } @@ -189,7 +193,7 @@ namespace Umbraco.Core.Manifest if (string.IsNullOrWhiteSpace(text)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(text)); var manifest = JsonConvert.DeserializeObject(text, - new DataEditorConverter(_logger, _ioHelper, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper), + new DataEditorConverter(_loggerFactory, _ioHelper, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper), new ValueValidatorConverter(_validators), new DashboardAccessRuleConverter()); diff --git a/src/Umbraco.Infrastructure/Media/ImageSharpImageUrlGenerator.cs b/src/Umbraco.Infrastructure/Media/ImageSharpImageUrlGenerator.cs index 48ff16f85b..cfe542badc 100644 --- a/src/Umbraco.Infrastructure/Media/ImageSharpImageUrlGenerator.cs +++ b/src/Umbraco.Infrastructure/Media/ImageSharpImageUrlGenerator.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System.Collections.Generic; +using System.Globalization; using System.Text; using Umbraco.Core; using Umbraco.Core.Media; @@ -9,6 +10,8 @@ namespace Umbraco.Infrastructure.Media { public class ImageSharpImageUrlGenerator : IImageUrlGenerator { + public IEnumerable SupportedImageFileTypes => new[] { "jpeg", "jpg", "gif", "bmp", "png" }; + public string GetImageUrl(ImageUrlGenerationOptions options) { if (options == null) return null; diff --git a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs b/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs index 05d4744526..deeed7a07c 100644 --- a/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs +++ b/src/Umbraco.Infrastructure/Media/UploadAutoFillProperties.cs @@ -1,11 +1,11 @@ using System; using System.Drawing; using System.IO; -using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; -using Umbraco.Core.Logging; +using Umbraco.Core.Media; using Umbraco.Core.Models; namespace Umbraco.Web.Media @@ -16,14 +16,17 @@ namespace Umbraco.Web.Media public class UploadAutoFillProperties { private readonly IMediaFileSystem _mediaFileSystem; - private readonly ILogger _logger; - private readonly IContentSettings _contentSettings; + private readonly ILogger _logger; + private readonly IImageUrlGenerator _imageUrlGenerator; - public UploadAutoFillProperties(IMediaFileSystem mediaFileSystem, ILogger logger, IContentSettings contentSettings) + public UploadAutoFillProperties( + IMediaFileSystem mediaFileSystem, + ILogger logger, + IImageUrlGenerator imageUrlGenerator) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); + _imageUrlGenerator = imageUrlGenerator ?? throw new ArgumentNullException(nameof(imageUrlGenerator)); } /// @@ -33,7 +36,7 @@ namespace Umbraco.Web.Media /// The auto-fill configuration. /// Variation language. /// Variation segment. - public void Reset(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string culture, string segment) + public void Reset(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -50,7 +53,7 @@ namespace Umbraco.Web.Media /// The parameter is the path relative to the filesystem. /// Variation language. /// Variation segment. - public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, string culture, string segment) + public void Populate(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -68,13 +71,13 @@ namespace Umbraco.Web.Media using (var filestream = _mediaFileSystem.OpenFile(filepath)) { var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.'); - var size = _contentSettings.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; + var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment); } } catch (Exception ex) { - _logger.Error(typeof(UploadAutoFillProperties), ex, "Could not populate upload auto-fill properties for file '{File}'.", filepath); + _logger.LogError(ex, "Could not populate upload auto-fill properties for file '{File}'.", filepath); ResetProperties(content, autoFillConfig, culture, segment); } } @@ -89,7 +92,7 @@ namespace Umbraco.Web.Media /// The stream containing the file data. /// Variation language. /// Variation segment. - public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream, string culture, string segment) + public void Populate(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -102,12 +105,12 @@ namespace Umbraco.Web.Media else { var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.'); - var size = _contentSettings.IsImageFile(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; + var size = _imageUrlGenerator.IsSupportedImageFormat(extension) ? (Size?)ImageHelper.GetDimensions(filestream) : null; SetProperties(content, autoFillConfig, size, filestream.Length, extension, culture, segment); } } - private static void SetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension, string culture, string segment) + private static void SetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, Size? size, long length, string extension, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); @@ -125,7 +128,7 @@ namespace Umbraco.Web.Media content.Properties[autoFillConfig.ExtensionFieldAlias].SetValue(extension, culture, segment); } - private static void ResetProperties(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string culture, string segment) + private static void ResetProperties(IContentBase content, ImagingAutoFillUploadField autoFillConfig, string culture, string segment) { if (content == null) throw new ArgumentNullException(nameof(content)); if (autoFillConfig == null) throw new ArgumentNullException(nameof(autoFillConfig)); diff --git a/src/Umbraco.Infrastructure/Migrations/IMigrationContext.cs b/src/Umbraco.Infrastructure/Migrations/IMigrationContext.cs index c76de8dfb3..b276d5b171 100644 --- a/src/Umbraco.Infrastructure/Migrations/IMigrationContext.cs +++ b/src/Umbraco.Infrastructure/Migrations/IMigrationContext.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations @@ -13,7 +13,7 @@ namespace Umbraco.Core.Migrations /// /// Gets the logger. /// - ILogger Logger { get; } + ILogger Logger { get; } /// /// Gets the database instance. diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index 98d50d61b1..b27bc48c8e 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -2,10 +2,12 @@ using System.IO; using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Logging; +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.Migrations.Upgrade; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; @@ -21,12 +23,12 @@ 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; private readonly IHostingEnvironment _hostingEnvironment; - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IUmbracoVersion _umbracoVersion; private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; private readonly IConfigManipulator _configManipulator; @@ -38,10 +40,10 @@ namespace Umbraco.Core.Migrations.Install /// public DatabaseBuilder( IScopeProvider scopeProvider, - IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, - ILogger logger, + ILogger logger, + ILoggerFactory loggerFactory, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, IHostingEnvironment hostingEnvironment, @@ -50,10 +52,10 @@ namespace Umbraco.Core.Migrations.Install IConfigManipulator configManipulator) { _scopeProvider = scopeProvider; - _globalSettings = globalSettings; _databaseFactory = databaseFactory; _runtime = runtime; _logger = logger; + _loggerFactory = loggerFactory; _migrationBuilder = migrationBuilder; _keyValueService = keyValueService; _hostingEnvironment = hostingEnvironment; @@ -319,7 +321,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, _loggerFactory.CreateLogger(), _loggerFactory, _umbracoVersion); _databaseSchemaValidationResult = dbSchema.ValidateSchema(); return _databaseSchemaValidationResult; } @@ -351,7 +353,7 @@ namespace Umbraco.Core.Migrations.Install return readyForInstall.Result; } - _logger.Info("Database configuration status: Started"); + _logger.LogInformation("Database configuration status: Started"); var database = scope.Database; @@ -367,18 +369,18 @@ 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, _loggerFactory.CreateLogger(), _loggerFactory, _umbracoVersion); creator.InitializeDatabaseSchema(); message = message + "

Installation completed!

"; //now that everything is done, we need to determine the version of SQL server that is executing - _logger.Info("Database configuration status: {DbConfigStatus}", message); + _logger.LogInformation("Database configuration status: {DbConfigStatus}", message); return new Result { Message = message, Success = true, Percentage = "100" }; } //we need to do an upgrade so return a new status message and it will need to be done during the next step - _logger.Info("Database requires upgrade"); + _logger.LogInformation("Database requires upgrade"); message = "

Upgrading database, this may take some time...

"; return new Result { @@ -412,17 +414,17 @@ namespace Umbraco.Core.Migrations.Install return readyForInstall.Result; } - _logger.Info("Database upgrade started"); + _logger.LogInformation("Database upgrade started"); // upgrade var upgrader = new Upgrader(plan); - upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger); + upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _loggerFactory.CreateLogger(), _loggerFactory); var message = "

Upgrade completed!

"; //now that everything is done, we need to determine the version of SQL server that is executing - _logger.Info("Database configuration status: {DbConfigStatus}", message); + _logger.LogInformation("Database configuration status: {DbConfigStatus}", message); return new Result { Message = message, Success = true, Percentage = "100" }; } @@ -449,11 +451,11 @@ namespace Umbraco.Core.Migrations.Install private Result HandleInstallException(Exception ex) { - _logger.Error(ex, "Database configuration failed"); + _logger.LogError(ex, "Database configuration failed"); if (_databaseSchemaValidationResult != null) { - _logger.Info("The database schema validation produced the following summary: {DbSchemaSummary}", _databaseSchemaValidationResult.GetSummary()); + _logger.LogInformation("The database schema validation produced the following summary: {DbSchemaSummary}", _databaseSchemaValidationResult.GetSummary()); } return new Result diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index 36f1a30b20..1ade2f5153 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -1,7 +1,8 @@ using System; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; @@ -14,16 +15,14 @@ namespace Umbraco.Core.Migrations.Install internal class DatabaseDataCreator { private readonly IDatabase _database; - private readonly ILogger _logger; + 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; } /// @@ -33,7 +32,7 @@ namespace Umbraco.Core.Migrations.Install /// Name of the table to create base data for public void InitializeBaseData(string tableName) { - _logger.Info("Creating data in {TableName}", tableName); + _logger.LogInformation("Creating data in {TableName}", tableName); if (tableName.Equals(Constants.DatabaseSchema.Tables.Node)) CreateNodeData(); @@ -77,7 +76,7 @@ namespace Umbraco.Core.Migrations.Install if (tableName.Equals(Constants.DatabaseSchema.Tables.KeyValue)) CreateKeyValueData(); - _logger.Info("Done creating table {TableName} data.", tableName); + _logger.LogInformation("Done creating table {TableName} data.", tableName); } private void CreateNodeData() @@ -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..5bca64e1e1 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Dtos; @@ -18,16 +19,16 @@ namespace Umbraco.Core.Migrations.Install public class DatabaseSchemaCreator { private readonly IUmbracoDatabase _database; - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IUmbracoVersion _umbracoVersion; - private readonly IGlobalSettings _globalSettings; - public DatabaseSchemaCreator(IUmbracoDatabase database, ILogger logger, IUmbracoVersion umbracoVersion, IGlobalSettings globalSettings) + public DatabaseSchemaCreator(IUmbracoDatabase database, ILogger logger, ILoggerFactory loggerFactory, IUmbracoVersion umbracoVersion) { _database = database; _logger = logger; + _loggerFactory = loggerFactory; _umbracoVersion = umbracoVersion; - _globalSettings = globalSettings; } private ISqlSyntaxProvider SqlSyntax => _database.SqlContext.SqlSyntax; @@ -93,14 +94,14 @@ namespace Umbraco.Core.Migrations.Install /// internal void UninstallDatabaseSchema() { - _logger.Info("Start UninstallDatabaseSchema"); + _logger.LogInformation("Start UninstallDatabaseSchema"); foreach (var table in OrderedTables.AsEnumerable().Reverse()) { var tableNameAttribute = table.FirstAttribute(); var tableName = tableNameAttribute == null ? table.Name : tableNameAttribute.Value; - _logger.Info("Uninstall {TableName}", tableName); + _logger.LogInformation("Uninstall {TableName}", tableName); try { @@ -111,7 +112,7 @@ namespace Umbraco.Core.Migrations.Install { //swallow this for now, not sure how best to handle this with diff databases... though this is internal // and only used for unit tests. If this fails its because the table doesn't exist... generally! - _logger.Error(ex, "Could not drop table {TableName}", tableName); + _logger.LogError(ex, "Could not drop table {TableName}", tableName); } } } @@ -130,7 +131,7 @@ namespace Umbraco.Core.Migrations.Install if (e.Cancel == false) { - var dataCreation = new DatabaseDataCreator(_database, _logger, _umbracoVersion, _globalSettings); + var dataCreation = new DatabaseDataCreator(_database, _loggerFactory.CreateLogger(), _umbracoVersion); foreach (var table in OrderedTables) CreateTable(false, table, dataCreation); } @@ -400,7 +401,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, _loggerFactory.CreateLogger(), _umbracoVersion)); } /// @@ -436,7 +437,7 @@ namespace Umbraco.Core.Migrations.Install var tableExist = TableExists(tableName); if (overwrite && tableExist) { - _logger.Info("Table {TableName} already exists, but will be recreated", tableName); + _logger.LogInformation("Table {TableName} already exists, but will be recreated", tableName); DropTable(tableName); tableExist = false; @@ -445,19 +446,19 @@ namespace Umbraco.Core.Migrations.Install if (tableExist) { // The table exists and was not recreated/overwritten. - _logger.Info("Table {TableName} already exists - no changes were made", tableName); + _logger.LogInformation("Table {TableName} already exists - no changes were made", tableName); return; } //Execute the Create Table sql var created = _database.Execute(new Sql(createSql)); - _logger.Info("Create Table {TableName} ({Created}): \n {Sql}", tableName, created, createSql); + _logger.LogInformation("Create Table {TableName} ({Created}): \n {Sql}", tableName, created, createSql); //If any statements exists for the primary key execute them here if (string.IsNullOrEmpty(createPrimaryKeySql) == false) { var createdPk = _database.Execute(new Sql(createPrimaryKeySql)); - _logger.Info("Create Primary Key ({CreatedPk}):\n {Sql}", createdPk, createPrimaryKeySql); + _logger.LogInformation("Create Primary Key ({CreatedPk}):\n {Sql}", createdPk, createPrimaryKeySql); } if (SqlSyntax.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity)) @@ -475,23 +476,23 @@ namespace Umbraco.Core.Migrations.Install foreach (var sql in indexSql) { var createdIndex = _database.Execute(new Sql(sql)); - _logger.Info("Create Index ({CreatedIndex}):\n {Sql}", createdIndex, sql); + _logger.LogInformation("Create Index ({CreatedIndex}):\n {Sql}", createdIndex, sql); } //Loop through foreignkey statements and execute sql foreach (var sql in foreignSql) { var createdFk = _database.Execute(new Sql(sql)); - _logger.Info("Create Foreign Key ({CreatedFk}):\n {Sql}", createdFk, sql); + _logger.LogInformation("Create Foreign Key ({CreatedFk}):\n {Sql}", createdFk, sql); } if (overwrite) { - _logger.Info("Table {TableName} was recreated", tableName); + _logger.LogInformation("Table {TableName} was recreated", tableName); } else { - _logger.Info("New table {TableName} was created", tableName); + _logger.LogInformation("New table {TableName} was created", tableName); } } diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationBase.cs b/src/Umbraco.Infrastructure/Migrations/MigrationBase.cs index 58edcae80a..b24313bebb 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationBase.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationBase.cs @@ -1,6 +1,6 @@ using System; using NPoco; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Migrations.Expressions.Alter; using Umbraco.Core.Migrations.Expressions.Create; using Umbraco.Core.Migrations.Expressions.Delete; diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs b/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs index 0bb2bc11ae..5c53c3cc46 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations @@ -13,14 +13,14 @@ namespace Umbraco.Core.Migrations /// /// Initializes a new instance of the class. /// - public MigrationContext(IUmbracoDatabase database, ILogger logger) + public MigrationContext(IUmbracoDatabase database, ILogger logger) { Database = database ?? throw new ArgumentNullException(nameof(database)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); } /// - public ILogger Logger { get; } + public ILogger Logger { get; } /// public IUmbracoDatabase Database { get; } diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs b/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs index be06a32ec7..56ba221205 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationExpressionBase.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Text; +using Microsoft.Extensions.Logging; using NPoco; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; @@ -55,7 +55,7 @@ namespace Umbraco.Core.Migrations if (string.IsNullOrWhiteSpace(sql)) { - Logger.Info(GetType(), "SQL [{ContextIndex}]: ", Context.Index); + Logger.LogInformation("SQL [{ContextIndex}]: ", Context.Index); } else { @@ -96,11 +96,11 @@ namespace Umbraco.Core.Migrations if (sql == null) { - Logger.Info(GetType(), $"SQL [{Context.Index}]: "); + Logger.LogInformation($"SQL [{Context.Index}]: "); } else { - Logger.Info(GetType(), $"SQL [{Context.Index}]: {sql.ToText()}"); + Logger.LogInformation($"SQL [{Context.Index}]: {sql.ToText()}"); Database.Execute(sql); } @@ -116,7 +116,7 @@ namespace Umbraco.Core.Migrations private void ExecuteStatement(StringBuilder stmtBuilder) { var stmt = stmtBuilder.ToString(); - Logger.Info(GetType(), "SQL [{ContextIndex}]: {Sql}", Context.Index, stmt); + Logger.LogInformation("SQL [{ContextIndex}]: {Sql}", Context.Index, stmt); Database.Execute(stmt); stmtBuilder.Clear(); } diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs b/src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs index 89c3c809e8..67e5d0b41a 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Scoping; using Type = System.Type; @@ -285,30 +285,31 @@ namespace Umbraco.Core.Migrations /// The state to start execution at. /// A migration builder. /// A logger. + /// /// The final state. /// The plan executes within the scope, which must then be completed. - public string Execute(IScope scope, string fromState, IMigrationBuilder migrationBuilder, ILogger logger) + public string Execute(IScope scope, string fromState, IMigrationBuilder migrationBuilder, ILogger logger, ILoggerFactory loggerFactory) { Validate(); if (migrationBuilder == null) throw new ArgumentNullException(nameof(migrationBuilder)); if (logger == null) throw new ArgumentNullException(nameof(logger)); - logger.Info("Starting '{MigrationName}'...", Name); + logger.LogInformation("Starting '{MigrationName}'...", Name); var origState = fromState ?? string.Empty; - logger.Info("At {OrigState}", string.IsNullOrWhiteSpace(origState) ? "origin": origState); + logger.LogInformation("At {OrigState}", string.IsNullOrWhiteSpace(origState) ? "origin": origState); if (!_transitions.TryGetValue(origState, out var transition)) ThrowOnUnknownInitialState(origState); - var context = new MigrationContext(scope.Database, logger); + var context = new MigrationContext(scope.Database, loggerFactory.CreateLogger()); context.PostMigrations.AddRange(_postMigrationTypes); while (transition != null) { - logger.Info("Execute {MigrationType}", transition.MigrationType.Name); + logger.LogInformation("Execute {MigrationType}", transition.MigrationType.Name); var migration = migrationBuilder.Build(transition.MigrationType, context); migration.Migrate(); @@ -316,7 +317,7 @@ namespace Umbraco.Core.Migrations var nextState = transition.TargetState; origState = nextState; - logger.Info("At {OrigState}", origState); + logger.LogInformation("At {OrigState}", origState); // throw a raw exception here: this should never happen as the plan has // been validated - this is just a paranoid safety test @@ -333,12 +334,12 @@ namespace Umbraco.Core.Migrations // run post-migrations foreach (var postMigrationType in postMigrationTypes) { - logger.Info($"PostMigration: {postMigrationType.FullName}."); + logger.LogInformation($"PostMigration: {postMigrationType.FullName}."); var postMigration = migrationBuilder.Build(postMigrationType, context); postMigration.Migrate(); } - logger.Info("Done (pending scope completion)."); + logger.LogInformation("Done (pending scope completion)."); // safety check - again, this should never happen as the plan has been validated, // and this is just a paranoid safety test 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/Migrations/Upgrade/Upgrader.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/Upgrader.cs index f6df52bc1e..9096a14146 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/Upgrader.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/Upgrader.cs @@ -1,5 +1,5 @@ using System; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Scoping; using Umbraco.Core.Services; @@ -40,7 +40,8 @@ namespace Umbraco.Core.Migrations.Upgrade /// A migration builder. /// A key-value service. /// A logger. - public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger) + /// A logger factory + public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, ILoggerFactory loggerFactory) { if (scopeProvider == null) throw new ArgumentNullException(nameof(scopeProvider)); if (migrationBuilder == null) throw new ArgumentNullException(nameof(migrationBuilder)); @@ -64,7 +65,7 @@ namespace Umbraco.Core.Migrations.Upgrade } // execute plan - var state = plan.Execute(scope, currentState, migrationBuilder, logger); + var state = plan.Execute(scope, currentState, migrationBuilder, loggerFactory.CreateLogger(), loggerFactory); if (string.IsNullOrWhiteSpace(state)) throw new Exception("Plan execution returned an invalid null or empty state."); @@ -83,13 +84,13 @@ namespace Umbraco.Core.Migrations.Upgrade /// /// Executes as part of the upgrade scope and before all migrations have executed. /// - public virtual void BeforeMigrations(IScope scope, ILogger logger) + public virtual void BeforeMigrations(IScope scope, ILogger logger) { } /// /// Executes as part of the upgrade scope and after all migrations have executed. /// - public virtual void AfterMigrations(IScope scope, ILogger logger) + public virtual void AfterMigrations(IScope scope, ILogger logger) { } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs index 95b272dcb4..fcd3a98218 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; +using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; @@ -17,7 +17,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { private readonly PreValueMigratorCollection _preValueMigrators; private readonly PropertyEditorCollection _propertyEditors; - private readonly ILogger _logger; + private readonly ILogger _logger; private static readonly ISet LegacyAliases = new HashSet() { @@ -31,7 +31,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 Constants.PropertyEditors.Legacy.Aliases.MultiNodeTreePicker2, }; - public DataTypeMigration(IMigrationContext context, PreValueMigratorCollection preValueMigrators, PropertyEditorCollection propertyEditors, ILogger logger) + public DataTypeMigration(IMigrationContext context, PreValueMigratorCollection preValueMigrators, PropertyEditorCollection propertyEditors, ILogger logger) : base(context) { _preValueMigrators = preValueMigrators; @@ -94,7 +94,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { if (!LegacyAliases.Contains(dataType.EditorAlias)) { - _logger.Warn( + _logger.LogWarning( "Skipping validation of configuration for data type {NodeId} : {EditorAlias}." + " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.", dataType.NodeId, dataType.EditorAlias); @@ -104,7 +104,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { if (!LegacyAliases.Contains(newAlias)) { - _logger.Warn("Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})" + _logger.LogWarning("Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})" + " because no property editor with that alias was found." + " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.", dataType.NodeId, newAlias, dataType.EditorAlias); @@ -119,7 +119,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 } catch (Exception e) { - _logger.Warn(e, "Failed to validate configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})." + _logger.LogWarning(e, "Failed to validate configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})." + " Please fix the configuration and ensure it is valid. The site may fail to start and / or load data types and run.", dataType.NodeId, newAlias, dataType.EditorAlias); } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs index 06f5d45deb..fbe8e38688 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs @@ -1,25 +1,25 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes { public class PreValueMigratorCollection : BuilderCollectionBase { - private readonly ILogger _logger; + private readonly ILogger _logger; - public PreValueMigratorCollection(IEnumerable items, ILogger logger) + public PreValueMigratorCollection(IEnumerable items, ILogger logger) : base(items) { _logger = logger; - _logger.Debug(GetType(), "Migrators: " + string.Join(", ", items.Select(x => x.GetType().Name))); + _logger.LogDebug("Migrators: " + string.Join(", ", items.Select(x => x.GetType().Name))); } public IPreValueMigrator GetMigrator(string editorAlias) { var migrator = this.FirstOrDefault(x => x.CanMigrate(editorAlias)); - _logger.Debug(GetType(), "Getting migrator for \"{EditorAlias}\" = {MigratorType}", editorAlias, migrator == null ? "" : migrator.GetType().Name); + _logger.LogDebug("Getting migrator for \"{EditorAlias}\" = {MigratorType}", editorAlias, migrator == null ? "" : migrator.GetType().Name); return migrator; } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs index 243446c5df..6b1d734bc8 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.IO; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models; @@ -51,7 +51,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 } catch (Exception ex) { - Logger.Error( + Logger.LogError( ex, "Invalid configuration: \"{Configuration}\", cannot convert editor.", dataType.Configuration); diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs index 4ab5d386b0..00092f3feb 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; @@ -40,7 +40,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 } catch (Exception ex) { - Logger.Error( + Logger.LogError( ex, "Invalid property editor configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared", dataType.Configuration); diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs index 5ac92b7966..79bbcece0d 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; @@ -78,7 +78,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 continue; } - Logger.Warn(GetType(), "Could not find PropertyData {PropertyDataId} value '{PropertyValue}' in the datatype configuration: {Values}.", + Logger.LogWarning("Could not find PropertyData {PropertyDataId} value '{PropertyValue}' in the datatype configuration: {Values}.", propData.Id, id, string.Join(", ", config.Items.Select(x => x.Id + ":" + x.Value))); canConvert = false; } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs index cdd330f190..20218dc2c6 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models; using Umbraco.Core.Persistence; @@ -55,7 +55,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 } catch (Exception ex) { - Logger.Error( + Logger.LogError( ex, "Invalid configuration: \"{Configuration}\", cannot convert editor.", dataType.Configuration); 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..efe24a6efd 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -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 { @@ -28,15 +30,15 @@ namespace Umbraco.Web.Models.Mapping private readonly IContentTypeService _contentTypeService; private readonly IMediaTypeService _mediaTypeService; private readonly IMemberTypeService _memberTypeService; - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; + 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) + ILoggerFactory loggerFactory, IShortStringHelper shortStringHelper, IOptions globalSettings, IHostingEnvironment hostingEnvironment) { _commonMapper = commonMapper; _propertyEditors = propertyEditors; @@ -45,9 +47,10 @@ namespace Umbraco.Web.Models.Mapping _contentTypeService = contentTypeService; _mediaTypeService = mediaTypeService; _memberTypeService = memberTypeService; - _logger = logger; + _loggerFactory = loggerFactory; + _logger = _loggerFactory.CreateLogger(); _shortStringHelper = shortStringHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _hostingEnvironment = hostingEnvironment; } @@ -533,7 +536,7 @@ namespace Umbraco.Web.Models.Mapping { MapTypeToDisplayBase(source, target); - var groupsMapper = new PropertyTypeGroupMapper(_propertyEditors, _dataTypeService, _shortStringHelper, _logger); + var groupsMapper = new PropertyTypeGroupMapper(_propertyEditors, _dataTypeService, _shortStringHelper, _loggerFactory.CreateLogger>()); target.Groups = groupsMapper.Map(source); } diff --git a/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs index 0bd6d54c08..0e403cd88b 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -14,14 +15,14 @@ namespace Umbraco.Web.Models.Mapping public class DataTypeMapDefinition : IMapDefinition { private readonly PropertyEditorCollection _propertyEditors; - private readonly ILogger _logger; - private readonly IContentSettings _contentSettings; + private readonly ILogger _logger; + 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 = @@ -174,7 +175,7 @@ namespace Umbraco.Web.Models.Mapping else { // weird - just leave the field without a value - but warn - _logger.Warn("Could not find a value for configuration field '{ConfigField}'", field.Key); + _logger.LogWarning("Could not find a value for configuration field '{ConfigField}'", field.Key); } } } diff --git a/src/Umbraco.Infrastructure/Models/Mapping/MacroMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/MacroMapDefinition.cs index d980958a91..9aef0e598c 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/MacroMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/MacroMapDefinition.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; @@ -13,9 +13,9 @@ namespace Umbraco.Web.Models.Mapping public class MacroMapDefinition : IMapDefinition { private readonly ParameterEditorCollection _parameterEditors; - private readonly ILogger _logger; + private readonly ILogger _logger; - public MacroMapDefinition(ParameterEditorCollection parameterEditors, ILogger logger) + public MacroMapDefinition(ParameterEditorCollection parameterEditors, ILogger logger) { _parameterEditors = parameterEditors; _logger = logger; @@ -73,7 +73,7 @@ namespace Umbraco.Web.Models.Mapping { //we'll just map this to a text box paramEditor = _parameterEditors[Constants.PropertyEditors.Aliases.TextBox]; - _logger.Warn("Could not resolve a parameter editor with alias {PropertyEditorAlias}, a textbox will be rendered in it's place", source.EditorAlias); + _logger.LogWarning("Could not resolve a parameter editor with alias {PropertyEditorAlias}, a textbox will be rendered in it's place", source.EditorAlias); } target.View = paramEditor.GetValueEditor().View; 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/PropertyTypeGroupMapper.cs b/src/Umbraco.Infrastructure/Models/Mapping/PropertyTypeGroupMapper.cs index 32ea6fce3f..1bdac7618c 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/PropertyTypeGroupMapper.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/PropertyTypeGroupMapper.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -17,9 +17,9 @@ namespace Umbraco.Web.Models.Mapping private readonly PropertyEditorCollection _propertyEditors; private readonly IDataTypeService _dataTypeService; private readonly IShortStringHelper _shortStringHelper; - private readonly ILogger _logger; + private readonly ILogger> _logger; - public PropertyTypeGroupMapper(PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IShortStringHelper shortStringHelper, ILogger logger) + public PropertyTypeGroupMapper(PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IShortStringHelper shortStringHelper, ILogger> logger) { _propertyEditors = propertyEditors; _dataTypeService = dataTypeService; @@ -210,8 +210,7 @@ namespace Umbraco.Web.Models.Mapping //fixme: Don't explode if we can't find this, log an error and change this to a label if (propertyEditor == null) { - _logger.Error(GetType(), - "No property editor could be resolved with the alias: {PropertyEditorAlias}, defaulting to label", p.PropertyEditorAlias); + _logger.LogError("No property editor could be resolved with the alias: {PropertyEditorAlias}, defaulting to label", p.PropertyEditorAlias); propertyEditorAlias = Constants.PropertyEditors.Aliases.Label; propertyEditor = _propertyEditors[propertyEditorAlias]; } 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/PathValidationExtensions.cs b/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs index 2db954b316..f6ed96fb99 100644 --- a/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs +++ b/src/Umbraco.Infrastructure/Models/PathValidationExtensions.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -78,7 +78,7 @@ namespace Umbraco.Core.Models /// A callback specified to retrieve the parent entity of the entity /// A callback specified to update a fixed entity public static void EnsureValidPath(this T entity, - ILogger logger, + ILogger logger, Func getParent, Action update) where T: IUmbracoEntity @@ -88,7 +88,7 @@ namespace Umbraco.Core.Models if (entity.ValidatePath() == false) { - logger.Warn(typeof(PathValidationExtensions), "The content item {EntityId} has an invalid path: {EntityPath} with parentID: {EntityParentId}", entity.Id, entity.Path, entity.ParentId); + logger.LogWarning("The content item {EntityId} has an invalid path: {EntityPath} with parentID: {EntityParentId}", entity.Id, entity.Path, entity.ParentId); if (entity.ParentId == -1) { entity.Path = string.Concat("-1,", entity.Id); diff --git a/src/Umbraco.Infrastructure/Models/PropertyTagsExtensions.cs b/src/Umbraco.Infrastructure/Models/PropertyTagsExtensions.cs index b9e471d961..bea07879fb 100644 --- a/src/Umbraco.Infrastructure/Models/PropertyTagsExtensions.cs +++ b/src/Umbraco.Infrastructure/Models/PropertyTagsExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Composing; @@ -218,7 +219,7 @@ namespace Umbraco.Core.Models } catch (Exception ex) { - Current.Logger.Warn(typeof(PropertyTagsExtensions), ex, "Could not automatically convert stored json value to an enumerable string '{Json}'", value.ToString()); + Current.Logger.LogWarning(ex, "Could not automatically convert stored json value to an enumerable string '{Json}'", value.ToString()); } break; 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..16f4a8bc25 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -5,9 +5,11 @@ using System.Linq; using System.Net; using System.Xml.Linq; using System.Xml.XPath; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Core.Collections; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Packaging; @@ -21,7 +23,8 @@ namespace Umbraco.Core.Packaging { public class PackageDataInstallation { - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IFileService _fileService; private readonly IMacroService _macroService; private readonly ILocalizationService _localizationService; @@ -29,18 +32,19 @@ 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; private readonly IContentService _contentService; - public PackageDataInstallation(ILogger logger, IFileService fileService, IMacroService macroService, ILocalizationService localizationService, + public PackageDataInstallation(ILogger logger, ILoggerFactory loggerFactory, 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; + _loggerFactory = loggerFactory; _fileService = fileService; _macroService = macroService; _localizationService = localizationService; @@ -48,7 +52,7 @@ namespace Umbraco.Core.Packaging _propertyEditors = propertyEditors; _scopeProvider = scopeProvider; _shortStringHelper = shortStringHelper; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _localizedTextService = localizedTextService; _entityService = entityService; _contentTypeService = contentTypeService; @@ -539,7 +543,7 @@ namespace Umbraco.Core.Packaging var tryCreateFolder = _contentTypeService.CreateContainer(-1, rootFolder); if (tryCreateFolder == false) { - _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder); + _logger.LogError(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder); throw tryCreateFolder.Exception; } var rootFolderId = tryCreateFolder.Result.Entity.Id; @@ -573,7 +577,7 @@ namespace Umbraco.Core.Packaging var tryCreateFolder = _contentTypeService.CreateContainer(current.Id, folderName); if (tryCreateFolder == false) { - _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName); + _logger.LogError(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName); throw tryCreateFolder.Exception; } return _contentTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); @@ -686,7 +690,7 @@ namespace Umbraco.Core.Packaging } else { - _logger.Warn("Packager: Error handling allowed templates. Template with alias '{TemplateAlias}' could not be found.", alias); + _logger.LogWarning("Packager: Error handling allowed templates. Template with alias '{TemplateAlias}' could not be found.", alias); } } @@ -702,7 +706,7 @@ namespace Umbraco.Core.Packaging } else { - _logger.Warn("Packager: Error handling default template. Default template with alias '{DefaultTemplateAlias}' could not be found.", defaultTemplateElement.Value); + _logger.LogWarning("Packager: Error handling default template. Default template with alias '{DefaultTemplateAlias}' could not be found.", defaultTemplateElement.Value); } } } @@ -774,7 +778,7 @@ namespace Umbraco.Core.Packaging if (dataTypeDefinition == null) { // TODO: We should expose this to the UI during install! - _logger.Warn("Packager: Error handling creation of PropertyType '{PropertyType}'. Could not find DataTypeDefintion with unique id '{DataTypeDefinitionId}' nor one referencing the DataType with a property editor alias (or legacy control id) '{PropertyEditorAlias}'. Did the package creator forget to package up custom datatypes? This property will be converted to a label/readonly editor if one exists.", + _logger.LogWarning("Packager: Error handling creation of PropertyType '{PropertyType}'. Could not find DataTypeDefintion with unique id '{DataTypeDefinitionId}' nor one referencing the DataType with a property editor alias (or legacy control id) '{PropertyEditorAlias}'. Did the package creator forget to package up custom datatypes? This property will be converted to a label/readonly editor if one exists.", property.Element("Name").Value, dataTypeDefinitionId, property.Element("Type").Value.Trim()); //convert to a label! @@ -831,7 +835,7 @@ namespace Umbraco.Core.Packaging var allowedChild = importedContentTypes.ContainsKey(alias) ? importedContentTypes[alias] : _contentTypeService.Get(alias); if (allowedChild == null) { - _logger.Warn( + _logger.LogWarning( "Packager: Error handling DocumentType structure. DocumentType with alias '{DoctypeAlias}' could not be found and was not added to the structure for '{DoctypeStructureAlias}'.", alias, contentType.Alias); continue; @@ -902,7 +906,7 @@ namespace Umbraco.Core.Packaging var editorAlias = dataTypeElement.Attribute("Id")?.Value?.Trim(); if (!_propertyEditors.TryGet(editorAlias, out var editor)) - editor = new VoidEditor(_logger, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper) { Alias = editorAlias }; + editor = new VoidEditor(_loggerFactory, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper) { Alias = editorAlias }; var dataType = new DataType(editor) { @@ -952,7 +956,7 @@ namespace Umbraco.Core.Packaging var tryCreateFolder = _dataTypeService.CreateContainer(-1, rootFolder); if (tryCreateFolder == false) { - _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder); + _logger.LogError(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder); throw tryCreateFolder.Exception; } current = _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); @@ -985,7 +989,7 @@ namespace Umbraco.Core.Packaging var tryCreateFolder = _dataTypeService.CreateContainer(current.Id, folderName); if (tryCreateFolder == false) { - _logger.Error(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName); + _logger.LogError(tryCreateFolder.Exception, "Could not create folder: {FolderName}", folderName); throw tryCreateFolder.Exception; } return _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id); @@ -1289,7 +1293,7 @@ namespace Umbraco.Core.Packaging else if (string.IsNullOrEmpty((string)elementCopy.Element("Master")) == false && templateElements.Any(x => (string)x.Element("Alias") == (string)elementCopy.Element("Master")) == false) { - _logger.Info( + _logger.LogInformation( "Template '{TemplateAlias}' has an invalid Master '{TemplateMaster}', so the reference has been ignored.", (string)elementCopy.Element("Alias"), (string)elementCopy.Element("Master")); 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/DbConnectionExtensions.cs b/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs index b79b1160b1..e00288d94c 100644 --- a/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs @@ -3,9 +3,9 @@ using System.Data; using System.Data.Common; using System.Data.SqlClient; using System.Linq; +using Microsoft.Extensions.Logging; using StackExchange.Profiling.Data; using Umbraco.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence.FaultHandling; namespace Umbraco.Core.Persistence @@ -53,7 +53,7 @@ namespace Umbraco.Core.Persistence catch (DbException e) { // Don't swallow this error, the exception is super handy for knowing "why" its not available - Current.Logger.Warn(e, "Configured database is reporting as not being available."); + Current.Logger.LogWarning(e, "Configured database is reporting as not being available."); return false; } diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs index fa991d6679..77d8199775 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs @@ -1,5 +1,5 @@ using System; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; @@ -8,13 +8,13 @@ namespace Umbraco.Core.Persistence.Factories { internal static class DataTypeFactory { - public static IDataType BuildEntity(DataTypeDto dto, PropertyEditorCollection editors, ILogger logger) + public static IDataType BuildEntity(DataTypeDto dto, PropertyEditorCollection editors, ILogger logger) { // Check we have an editor for the data type. if (!editors.TryGet(dto.EditorAlias, out var editor)) { - logger.Warn(typeof(DataType), "Could not find an editor with alias {EditorAlias}, treating as Label. " + - "The site may fail to boot and/or load data types and run.", dto.EditorAlias); + logger.LogWarning("Could not find an editor with alias {EditorAlias}, treating as Label. " + + "The site may fail to boot and/or load data types and run.", dto.EditorAlias); // Create as special type, which downstream can be handled by converting to a LabelPropertyEditor to make clear // the situation to the user. 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/RelationFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs index d8f100cdbe..f4117cc358 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/RelationFactory.cs @@ -45,5 +45,22 @@ namespace Umbraco.Core.Persistence.Factories return dto; } + public static RelationDto BuildDto(ReadOnlyRelation entity) + { + var dto = new RelationDto + { + ChildId = entity.ChildId, + Comment = string.IsNullOrEmpty(entity.Comment) ? string.Empty : entity.Comment, + Datetime = entity.CreateDate, + ParentId = entity.ParentId, + RelationType = entity.RelationTypeId + }; + + if (entity.HasIdentity) + dto.Id = entity.Id; + + return dto; + } + } } 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/IMemberRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/IMemberRepository.cs index 245c024356..c737c2bf66 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/IMemberRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/IMemberRepository.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Querying; @@ -6,6 +7,8 @@ namespace Umbraco.Core.Persistence.Repositories { public interface IMemberRepository : IContentRepository { + IMember GetByUsername(string username); + /// /// Finds members in a given role /// @@ -35,5 +38,17 @@ namespace Umbraco.Core.Persistence.Repositories /// /// int GetCountByQuery(IQuery query); + + /// + /// Sets a members last login date based on their username + /// + /// + /// + /// + /// This is a specialized method because whenever a member logs in, the membership provider requires us to set the 'online' which requires + /// updating their login date. This operation must be fast and cannot use database locks which is fine if we are only executing a single query + /// for this data since there won't be any other data contention issues. + /// + void SetLastLogin(string username, DateTime date); } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs index c3d34cc3e9..4031047970 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -21,7 +21,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Initializes a new instance of the class. /// - public AuditEntryRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public AuditEntryRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs index 4cb533e86f..a42019e59f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; using NPoco; +using Microsoft.Extensions.Logging; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Dtos; @@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class AuditRepository : NPocoRepositoryBase, IAuditRepository { - public AuditRepository(IScopeAccessor scopeAccessor, ILogger logger) + public AuditRepository(IScopeAccessor scopeAccessor, ILogger logger) : base(scopeAccessor, AppCaches.NoCache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs index 57d5dfa864..47ebddf698 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Querying; @@ -20,7 +20,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Initializes a new instance of the class. /// - public ConsentRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public ConsentRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs index 6c216e938f..a0a26ea428 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.Models.Entities; @@ -49,8 +49,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// protected ContentRepositoryBase( IScopeAccessor scopeAccessor, - AppCaches cache - , ILogger logger, + AppCaches cache, + ILogger> logger, ILanguageRepository languageRepository, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository, @@ -709,7 +709,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { if (ContentRepositoryBase.ThrowOnWarning) throw new InvalidOperationException($"The query returned multiple property sets for content {temp.Id}, {temp.ContentType.Name}"); - Logger.Warn>("The query returned multiple property sets for content {ContentId}, {ContentTypeName}", temp.Id, temp.ContentType.Name); + Logger.LogWarning("The query returned multiple property sets for content {ContentId}, {ContentTypeName}", temp.Id, temp.ContentType.Name); } result[temp.VersionId] = new PropertyCollection(properties); @@ -980,11 +980,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (!keyToIds.TryGetValue(guid, out var id)) return null; // This shouldn't happen! - return new Relation(entity.Id, id, relationType); + return new ReadOnlyRelation(entity.Id, id, relationType.Id); }).WhereNotNull(); // Save bulk relations - RelationRepository.Save(toSave); + RelationRepository.SaveBulk(toSave); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs index 61aabdc1b5..d5243f5019 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -20,7 +20,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class ContentTypeRepository : ContentTypeRepositoryBase, IContentTypeRepository { - public ContentTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) + public ContentTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper) { } @@ -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); @@ -229,7 +226,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (string.IsNullOrWhiteSpace(entity.Alias)) { var ex = new Exception($"ContentType '{entity.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias."); - Logger.Error("ContentType '{EntityName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", entity.Name); + Logger.LogError("ContentType '{EntityName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", entity.Name); throw ex; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index b2a83e83fd..26596410bf 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -3,12 +3,12 @@ using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; +using Microsoft.Extensions.Logging; using System.Threading.Tasks; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Factories; @@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly IShortStringHelper _shortStringHelper; - protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) + protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger> logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) : base(scopeAccessor, cache, logger) { _shortStringHelper = shortStringHelper; @@ -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", @@ -1198,7 +1216,7 @@ AND umbracoNode.id <> @id", { var ex = new InvalidOperationException($"Property Type '{pt.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias."); - Logger.Error>("Property Type '{PropertyTypeName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", + Logger.LogError("Property Type '{PropertyTypeName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", pt.Name); throw ex; @@ -1211,7 +1229,7 @@ AND umbracoNode.id <> @id", { var ex = new InvalidOperationException($"{typeof(TEntity).Name} '{entity.Name}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias."); - Logger.Error>("{EntityTypeName} '{EntityName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", + Logger.LogError("{EntityTypeName} '{EntityName}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.", typeof(TEntity).Name, entity.Name); @@ -1243,7 +1261,7 @@ AND umbracoNode.id <> @id", } else { - Logger.Warn>("Could not assign a data type for the property type {PropertyTypeAlias} since no data type was found with a property editor {PropertyEditorAlias}", propertyType.Alias, propertyType.PropertyEditorAlias); + Logger.LogWarning("Could not assign a data type for the property type {PropertyTypeAlias} since no data type was found with a property editor {PropertyEditorAlias}", propertyType.Alias, propertyType.PropertyEditorAlias); } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeContainerRepository.cs index f36b60484a..7ac72b0cb3 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeContainerRepository.cs @@ -1,12 +1,12 @@ -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Cache; using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { internal class DataTypeContainerRepository : EntityContainerRepository, IDataTypeContainerRepository { - public DataTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public DataTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger, Constants.ObjectTypes.DataTypeContainer) { } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs index 42a89384d7..853e0da181 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -26,11 +26,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class DataTypeRepository : NPocoRepositoryBase, IDataTypeRepository { private readonly Lazy _editors; + private readonly ILogger _dataTypeLogger; - public DataTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, Lazy editors, ILogger logger) + public DataTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, Lazy editors, ILogger logger, ILoggerFactory loggerFactory) : base(scopeAccessor, cache, logger) { _editors = editors; + _dataTypeLogger = loggerFactory.CreateLogger(); } #region Overrides of RepositoryBase @@ -54,7 +56,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } var dtos = Database.Fetch(dataTypeSql); - return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, Logger)).ToArray(); + return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, _dataTypeLogger)).ToArray(); } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -65,7 +67,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var dtos = Database.Fetch(sql); - return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, Logger)).ToArray(); + return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, _dataTypeLogger)).ToArray(); } #endregion diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs index 0b58663952..0c58d26a2a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -18,9 +18,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement ///
internal class DictionaryRepository : NPocoRepositoryBase, IDictionaryRepository { - public DictionaryRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + private readonly ILoggerFactory _loggerFactory; + + public DictionaryRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, ILoggerFactory loggerFactory) : base(scopeAccessor, cache, logger) - { } + { + _loggerFactory = loggerFactory; + } protected override IRepositoryCachePolicy CreateCachePolicy() { @@ -130,7 +134,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement foreach (var translation in dictionaryItem.Translations) translation.Value = translation.Value.ToValidXmlString(); - + var dto = DictionaryItemFactory.BuildDto(dictionaryItem); var id = Convert.ToInt32(Database.Insert(dto)); @@ -152,7 +156,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement foreach (var translation in entity.Translations) translation.Value = translation.Value.ToValidXmlString(); - + var dto = DictionaryItemFactory.BuildDto(entity); Database.Update(dto); @@ -224,13 +228,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public IDictionaryItem Get(Guid uniqueId) { - var uniqueIdRepo = new DictionaryByUniqueIdRepository(this, ScopeAccessor, AppCaches, Logger); + var uniqueIdRepo = new DictionaryByUniqueIdRepository(this, ScopeAccessor, AppCaches, _loggerFactory.CreateLogger()); return uniqueIdRepo.Get(uniqueId); } public IDictionaryItem Get(string key) { - var keyRepo = new DictionaryByKeyRepository(this, ScopeAccessor, AppCaches, Logger); + var keyRepo = new DictionaryByKeyRepository(this, ScopeAccessor, AppCaches, _loggerFactory.CreateLogger()); return keyRepo.Get(key); } @@ -290,7 +294,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly DictionaryRepository _dictionaryRepository; - public DictionaryByUniqueIdRepository(DictionaryRepository dictionaryRepository, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public DictionaryByUniqueIdRepository(DictionaryRepository dictionaryRepository, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _dictionaryRepository = dictionaryRepository; @@ -343,7 +347,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly DictionaryRepository _dictionaryRepository; - public DictionaryByKeyRepository(DictionaryRepository dictionaryRepository, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public DictionaryByKeyRepository(DictionaryRepository dictionaryRepository, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _dictionaryRepository = dictionaryRepository; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs index 7e3592ac09..32553a8fd4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs @@ -1,7 +1,7 @@ using System; +using Microsoft.Extensions.Logging; using Umbraco.Core.Cache; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Services; @@ -22,7 +22,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public DocumentBlueprintRepository( IScopeAccessor scopeAccessor, AppCaches appCaches, - ILogger logger, + ILogger logger, + ILoggerFactory loggerFactory, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, @@ -32,7 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Lazy propertyEditorCollection, IDataTypeService dataTypeService, DataValueReferenceFactoryCollection dataValueReferenceFactories) - : base(scopeAccessor, appCaches, logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, dataValueReferenceFactories, dataTypeService) + : base(scopeAccessor, appCaches, logger, loggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, dataValueReferenceFactories, dataTypeService) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs index 97d3dbcd50..7e19c1aef4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -26,6 +26,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly ITemplateRepository _templateRepository; private readonly ITagRepository _tagRepository; private readonly AppCaches _appCaches; + private readonly ILoggerFactory _loggerFactory; private PermissionRepository _permissionRepository; private readonly ContentByGuidReadRepository _contentByGuidReadRepository; private readonly IScopeAccessor _scopeAccessor; @@ -36,6 +37,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// /// + /// /// /// /// @@ -46,7 +48,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public DocumentRepository( IScopeAccessor scopeAccessor, AppCaches appCaches, - ILogger logger, + ILogger logger, + ILoggerFactory loggerFactory, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, @@ -62,8 +65,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement _templateRepository = templateRepository ?? throw new ArgumentNullException(nameof(templateRepository)); _tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository)); _appCaches = appCaches; + _loggerFactory = loggerFactory; _scopeAccessor = scopeAccessor; - _contentByGuidReadRepository = new ContentByGuidReadRepository(this, scopeAccessor, appCaches, logger); + _contentByGuidReadRepository = new ContentByGuidReadRepository(this, scopeAccessor, appCaches, loggerFactory.CreateLogger()); } protected override DocumentRepository This => this; @@ -75,7 +79,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // note: is ok to 'new' the repo here as it's a sub-repo really private PermissionRepository PermissionRepository => _permissionRepository - ?? (_permissionRepository = new PermissionRepository(_scopeAccessor, _appCaches, Logger)); + ?? (_permissionRepository = new PermissionRepository(_scopeAccessor, _appCaches, _loggerFactory.CreateLogger>())); #region Repository Base @@ -460,6 +464,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement //insert the schedule PersistContentSchedule(entity, false); + // persist the variations if (entity.ContentType.VariesByCulture()) { @@ -645,7 +650,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // names also impact 'edited' // ReSharper disable once UseDeconstruction - foreach (var cultureInfo in entity.CultureInfos) + foreach (var cultureInfo in entity.CultureInfos) if (cultureInfo.Name != entity.GetPublishName(cultureInfo.Culture)) { edited = true; @@ -953,7 +958,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly DocumentRepository _outerRepo; - public ContentByGuidReadRepository(DocumentRepository outerRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public ContentByGuidReadRepository(DocumentRepository outerRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _outerRepo = outerRepo; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentTypeContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentTypeContainerRepository.cs index 4b5fe8817b..a79247d17d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentTypeContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentTypeContainerRepository.cs @@ -1,12 +1,12 @@ -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Cache; using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { internal class DocumentTypeContainerRepository : EntityContainerRepository, IDocumentTypeContainerRepository { - public DocumentTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public DocumentTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger, Constants.ObjectTypes.DocumentTypeContainer) { } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs index 9aa28fb18a..f0315f747c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class DomainRepository : NPocoRepositoryBase, IDomainRepository { - public DomainRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public DomainRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs index 505cbfc816..36213b089f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityContainerRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; @@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly Guid _containerObjectType; - public EntityContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, Guid containerObjectType) + public EntityContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, Guid containerObjectType) : base(scopeAccessor, cache, logger) { var allowedContainers = new[] { Constants.ObjectTypes.DocumentTypeContainer, Constants.ObjectTypes.MediaTypeContainer, Constants.ObjectTypes.DataTypeContainer }; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs index 6d6a654d4e..b984085bdb 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Identity; using Umbraco.Core.Persistence.Dtos; @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class ExternalLoginRepository : NPocoRepositoryBase, IExternalLoginRepository { - public ExternalLoginRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public ExternalLoginRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs index 3c2da4d5b7..eb55b476c7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; @@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class KeyValueRepository : NPocoRepositoryBase, IKeyValueRepository { - public KeyValueRepository(IScopeAccessor scopeAccessor, ILogger logger) + public KeyValueRepository(IScopeAccessor scopeAccessor, ILogger logger) : base(scopeAccessor, AppCaches.NoCache, logger) { } @@ -111,8 +111,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Value = dto.Value, UpdateDate = dto.UpdateDate, }; - } + } - #endregion + #endregion } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs index 245ff10f7f..fd791fe01f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -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) @@ -317,7 +319,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (language != null) return language; // this is an anomaly, the service/repo should ensure it cannot happen - Logger.Warn("There is no default language. Fix this anomaly by editing the language table in database and setting one language as the default language."); + Logger.LogWarning("There is no default language. Fix this anomaly by editing the language table in database and setting one language as the default language."); // still, don't kill the site, and return "something" diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs index ef5a41b21d..61dad47378 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MacroRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly IShortStringHelper _shortStringHelper; - public MacroRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IShortStringHelper shortStringHelper) + public MacroRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IShortStringHelper shortStringHelper) : base(scopeAccessor, cache, logger) { _shortStringHelper = shortStringHelper; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs index 83088de9bd..9f47fd2f6b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -31,7 +31,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public MediaRepository( IScopeAccessor scopeAccessor, AppCaches cache, - ILogger logger, + ILogger logger, + ILoggerFactory loggerFactory, IMediaTypeRepository mediaTypeRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, @@ -46,7 +47,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement _mediaTypeRepository = mediaTypeRepository ?? throw new ArgumentNullException(nameof(mediaTypeRepository)); _tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository)); _mediaUrlGenerators = mediaUrlGenerators; - _mediaByGuidReadRepository = new MediaByGuidReadRepository(this, scopeAccessor, cache, logger); + _mediaByGuidReadRepository = new MediaByGuidReadRepository(this, scopeAccessor, cache, loggerFactory.CreateLogger()); } protected override MediaRepository This => this; @@ -417,7 +418,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly MediaRepository _outerRepo; - public MediaByGuidReadRepository(MediaRepository outerRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public MediaByGuidReadRepository(MediaRepository outerRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _outerRepo = outerRepo; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs index 68b33e989d..d660ebb0b0 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs @@ -1,12 +1,12 @@ -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Cache; using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { class MediaTypeContainerRepository : EntityContainerRepository, IMediaTypeContainerRepository { - public MediaTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public MediaTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger, Constants.ObjectTypes.MediaTypeContainer) { } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs index c6caa40750..fdb4817aeb 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class MediaTypeRepository : ContentTypeRepositoryBase, IMediaTypeRepository { - public MediaTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) + public MediaTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper) { } @@ -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/MemberGroupRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs index edd6dc0ebb..482a0e627f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class MemberGroupRepository : NPocoRepositoryBase, IMemberGroupRepository { - public MemberGroupRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public MemberGroupRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs index 64266f9df8..5b1aba12ca 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -26,8 +26,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly ITagRepository _tagRepository; private readonly IPasswordHasher _passwordHasher; private readonly IMemberGroupRepository _memberGroupRepository; + private readonly IRepositoryCachePolicy _memberByUsernameCachePolicy; - public MemberRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, + public MemberRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, ITagRepository tagRepository, ILanguageRepository languageRepository, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository, IPasswordHasher passwordHasher, Lazy propertyEditors, @@ -39,6 +40,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement _tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository)); _passwordHasher = passwordHasher; _memberGroupRepository = memberGroupRepository; + + _memberByUsernameCachePolicy = new DefaultRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, DefaultOptions); } protected override MemberRepository This => this; @@ -383,12 +386,27 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (changedCols.Count > 0) Database.Update(dto, changedCols); - // replace the property data - var deletePropertyDataSql = SqlContext.Sql().Delete().Where(x => x.VersionId == member.VersionId); - Database.Execute(deletePropertyDataSql); + // Replace the property data + // Lookup the data to update with a UPDLOCK (using ForUpdate()) this is because we have another method that doesn't take an explicit WriteLock + // in SetLastLogin which is called very often and we want to avoid the lock timeout for the explicit lock table but we still need to ensure atomic + // operations between that method and this one. + + var propDataSql = SqlContext.Sql().Select("*").From().Where(x => x.VersionId == member.VersionId).ForUpdate(); + var existingPropData = Database.Fetch(propDataSql).ToDictionary(x => x.PropertyTypeId); var propertyDataDtos = PropertyFactory.BuildDtos(member.ContentType.Variations, member.VersionId, 0, entity.Properties, LanguageRepository, out _, out _); foreach (var propertyDataDto in propertyDataDtos) - Database.Insert(propertyDataDto); + { + // Check if this already exists and update, else insert a new one + if (existingPropData.TryGetValue(propertyDataDto.PropertyTypeId, out var propData)) + { + propertyDataDto.Id = propData.Id; + Database.Update(propertyDataDto); + } + else + { + Database.Insert(propertyDataDto); + } + } SetEntityTags(entity, _tagRepository); @@ -506,6 +524,56 @@ namespace Umbraco.Core.Persistence.Repositories.Implement return Database.ExecuteScalar(fullSql); } + /// + public void SetLastLogin(string username, DateTime date) + { + // Important - these queries are designed to execute without an exclusive WriteLock taken in our distributed lock + // table. However due to the data that we are updating which relies on version data we cannot update this data + // without taking some locks, otherwise we'll end up with strange situations because when a member is updated, that operation + // deletes and re-inserts all property data. So if there are concurrent transactions, one deleting and re-inserting and another trying + // to update there can be problems. This is only an issue for cmsPropertyData, not umbracoContentVersion because that table just + // maintains a single row and it isn't deleted/re-inserted. + // So the important part here is the ForUpdate() call on the select to fetch the property data to update. + + // Update the cms property value for the member + + var sqlSelectTemplateProperty = SqlContext.Templates.Get("Umbraco.Core.MemberRepository.SetLastLogin1", s => s + .Select(x => x.Id) + .From() + .InnerJoin().On((l, r) => l.Id == r.PropertyTypeId) + .InnerJoin().On((l, r) => l.Id == r.VersionId) + .InnerJoin().On((l, r) => l.NodeId == r.NodeId) + .InnerJoin().On((l, r) => l.NodeId == r.NodeId) + .Where(x => x.NodeObjectType == SqlTemplate.Arg("nodeObjectType")) + .Where(x => x.Alias == SqlTemplate.Arg("propertyTypeAlias")) + .Where(x => x.LoginName == SqlTemplate.Arg("username")) + .ForUpdate()); + var sqlSelectProperty = sqlSelectTemplateProperty.Sql(Constants.ObjectTypes.Member, Constants.Conventions.Member.LastLoginDate, username); + + var update = Sql() + .Update(u => u + .Set(x => x.DateValue, date)) + .WhereIn(x => x.Id, sqlSelectProperty); + + Database.Execute(update); + + // Update the umbracoContentVersion value for the member + + var sqlSelectTemplateVersion = SqlContext.Templates.Get("Umbraco.Core.MemberRepository.SetLastLogin2", s => s + .Select(x => x.Id) + .From() + .InnerJoin().On((l, r) => l.NodeId == r.NodeId) + .InnerJoin().On((l, r) => l.NodeId == r.NodeId) + .Where(x => x.NodeObjectType == SqlTemplate.Arg("nodeObjectType")) + .Where(x => x.LoginName == SqlTemplate.Arg("username"))); + var sqlSelectVersion = sqlSelectTemplateVersion.Sql(Constants.ObjectTypes.Member, username); + + Database.Execute(Sql() + .Update(u => u + .Set(x => x.VersionDate, date)) + .WhereIn(x => x.Id, sqlSelectVersion)); + } + /// /// Gets paged member results. /// @@ -529,20 +597,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement ordering); } - private string _pagedResultsByQueryWhere; - - private string GetPagedResultsByQueryWhere() - { - if (_pagedResultsByQueryWhere == null) - _pagedResultsByQueryWhere = " AND (" - + $"({SqlSyntax.GetQuotedTableName("umbracoNode")}.{SqlSyntax.GetQuotedColumnName("text")} LIKE @0)" - + " OR " - + $"({SqlSyntax.GetQuotedTableName("cmsMember")}.{SqlSyntax.GetQuotedColumnName("LoginName")} LIKE @0)" - + ")"; - - return _pagedResultsByQueryWhere; - } - protected override string ApplySystemOrdering(ref Sql sql, Ordering ordering) { if (ordering.OrderBy.InvariantEquals("email")) @@ -632,5 +686,22 @@ namespace Umbraco.Core.Persistence.Repositories.Implement member.ResetDirtyProperties(false); return member; } + + public IMember GetByUsername(string username) + { + return _memberByUsernameCachePolicy.Get(username, PerformGetByUsername, PerformGetAllByUsername); + } + + private IMember PerformGetByUsername(string username) + { + var query = Query().Where(x => x.Username.Equals(username)); + return PerformGetByQuery(query).FirstOrDefault(); + } + + private IEnumerable PerformGetAllByUsername(params string[] usernames) + { + var query = Query().WhereIn(x => x.Username, usernames); + return PerformGetByQuery(query); + } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs index b9c40eebc9..28b364129d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly IShortStringHelper _shortStringHelper; - public MemberTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) + public MemberTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper) { _shortStringHelper = shortStringHelper; @@ -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/NPocoRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NPocoRepositoryBase.cs index d72eb9de9b..392e7bdf1f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NPocoRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/NPocoRepositoryBase.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using NPoco; +using Microsoft.Extensions.Logging; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.SqlSyntax; @@ -21,7 +21,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Initializes a new instance of the class. /// - protected NPocoRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + protected NPocoRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, ILogger> logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs index 259f0b89c0..279a7075ea 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs @@ -5,12 +5,12 @@ using System.Linq; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Scoping; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Persistence.Repositories.Implement { @@ -25,7 +25,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class PermissionRepository : NPocoRepositoryBase where TEntity : class, IEntity { - public PermissionRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public PermissionRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger> logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs index 1dc7aa478d..6d2f95bb4d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class PublicAccessRepository : NPocoRepositoryBase, IPublicAccessRepository { - public PublicAccessRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public PublicAccessRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } @@ -40,7 +40,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } sql.OrderBy(x => x.NodeId); - + var dtos = Database.FetchOneToMany(x => x.Rules, sql); return dtos.Select(PublicAccessEntryFactory.BuildEntity); } @@ -50,7 +50,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var sqlClause = GetBaseQuery(false); var translator = new SqlTranslator(sqlClause, query); var sql = translator.Translate(); - + var dtos = Database.FetchOneToMany(x => x.Rules, sql); return dtos.Select(PublicAccessEntryFactory.BuildEntity); } @@ -86,7 +86,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.AddingEntity(); foreach (var rule in entity.Rules) rule.AddingEntity(); - + var dto = PublicAccessEntryFactory.BuildDto(entity); Database.Insert(dto); @@ -116,7 +116,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement else rule.AddingEntity(); } - + var dto = PublicAccessEntryFactory.BuildDto(entity); Database.Update(dto); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs index acf6bb7df2..5df508e5ef 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; @@ -14,7 +14,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class RedirectUrlRepository : NPocoRepositoryBase, IRedirectUrlRepository { - public RedirectUrlRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public RedirectUrlRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs index 667e997953..21b4ce5911 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly IRelationTypeRepository _relationTypeRepository; private readonly IEntityRepository _entityRepository; - public RelationRepository(IScopeAccessor scopeAccessor, ILogger logger, IRelationTypeRepository relationTypeRepository, IEntityRepository entityRepository) + public RelationRepository(IScopeAccessor scopeAccessor, ILogger logger, IRelationTypeRepository relationTypeRepository, IEntityRepository entityRepository) : base(scopeAccessor, AppCaches.NoCache, logger) { _relationTypeRepository = relationTypeRepository; @@ -235,9 +235,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement }, RelationFactory.BuildDto); // value = DTO - // Use NPoco's own InsertBulk command which will automatically re-populate the new Ids on the entities, our own - // BulkInsertRecords does not cater for this. - Database.InsertBulk(entitiesAndDtos.Values); + + foreach (var dto in entitiesAndDtos.Values) + { + Database.Insert(dto); + } // All dtos now have IDs assigned foreach (var de in entitiesAndDtos) @@ -251,6 +253,33 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } } + public void SaveBulk(IEnumerable relations) + { + foreach (var hasIdentityGroup in relations.GroupBy(r => r.HasIdentity)) + { + if (hasIdentityGroup.Key) + { + // Do updates, we can't really do a bulk update so this is still a 1 by 1 operation + // however we can bulk populate the object types. It might be possible to bulk update + // with SQL but would be pretty ugly and we're not really too worried about that for perf, + // it's the bulk inserts we care about. + foreach (var relation in hasIdentityGroup) + { + var dto = RelationFactory.BuildDto(relation); + Database.Update(dto); + } + } + else + { + // Do bulk inserts + var dtos = hasIdentityGroup.Select(RelationFactory.BuildDto); + + Database.InsertBulk(dtos); + + } + } + } + public IEnumerable GetPagedRelationsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, Ordering ordering) { var sql = GetBaseQuery(false); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs index 623b55b6f8..398dd225ba 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationTypeRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// internal class RelationTypeRepository : NPocoRepositoryBase, IRelationTypeRepository { - public RelationTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public RelationTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } @@ -50,12 +50,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { var sql = GetBaseQuery(false); - // should not happen due to the cache policy - if (ids.Any()) - throw new NotImplementedException(); - var dtos = Database.Fetch(sql); - + return dtos.Select(x => DtoToEntity(x)); } @@ -75,7 +71,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var sql = translator.Translate(); var dtos = Database.Fetch(sql); - + return dtos.Select(x => DtoToEntity(x)); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index 6985bf78da..a9e8f4bb16 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Scoping; @@ -19,14 +19,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private IRepositoryCachePolicy _cachePolicy; - protected RepositoryBase(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger) + protected RepositoryBase(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger> logger) { ScopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor)); Logger = logger ?? throw new ArgumentNullException(nameof(logger)); AppCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches)); } - protected ILogger Logger { get; } + protected ILogger> Logger { get; } protected AppCaches AppCaches { get; } 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/ServerRegistrationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs index 1497c2857c..f215a8997b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class ServerRegistrationRepository : NPocoRepositoryBase, IServerRegistrationRepository { - public ServerRegistrationRepository(IScopeAccessor scopeAccessor, ILogger logger) + public ServerRegistrationRepository(IScopeAccessor scopeAccessor, ILogger logger) : base(scopeAccessor, AppCaches.NoCache, logger) { } @@ -110,7 +110,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override void PersistUpdatedItem(IServerRegistration entity) { entity.UpdatingEntity(); - + var dto = ServerRegistrationFactory.BuildDto(entity); Database.Update(dto); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs index f7e59820c3..bbe751d2c6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimpleGetRepository.cs @@ -1,16 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Scoping; namespace Umbraco.Core.Persistence.Repositories.Implement { + // TODO: Obsolete this, change all implementations of this like in Dictionary to just use custom Cache policies like in the member repository. + /// /// Simple abstract ReadOnly repository used to simply have PerformGet and PeformGetAll with an underlying cache /// @@ -18,7 +20,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement where TEntity : class, IEntity where TDto: class { - protected SimpleGetRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + protected SimpleGetRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger> logger) : base(scopeAccessor, cache, logger) { } 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/TagRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs index 87564b9ac9..dcd9464ae0 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { internal class TagRepository : NPocoRepositoryBase, ITagRepository { - public TagRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public TagRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs index c02329aac4..b36474d688 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; @@ -27,7 +27,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly IFileSystem _viewsFileSystem; private readonly ViewHelper _viewHelper; - public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IFileSystems fileSystems, IIOHelper ioHelper, IShortStringHelper shortStringHelper) + public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger, IFileSystems fileSystems, IIOHelper ioHelper, IShortStringHelper shortStringHelper) : base(scopeAccessor, cache, logger) { _ioHelper = ioHelper; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs index 863f3dc455..30b9b29416 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -24,12 +24,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly UserGroupWithUsersRepository _userGroupWithUsersRepository; private readonly PermissionRepository _permissionRepository; - public UserGroupRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, IShortStringHelper shortStringHelper) + public UserGroupRepository(IScopeAccessor scopeAccessor, AppCaches appCaches, ILogger logger, ILoggerFactory loggerFactory, IShortStringHelper shortStringHelper) : base(scopeAccessor, appCaches, logger) { _shortStringHelper = shortStringHelper; - _userGroupWithUsersRepository = new UserGroupWithUsersRepository(this, scopeAccessor, appCaches, logger); - _permissionRepository = new PermissionRepository(scopeAccessor, appCaches, logger); + _userGroupWithUsersRepository = new UserGroupWithUsersRepository(this, scopeAccessor, appCaches, loggerFactory.CreateLogger()); + _permissionRepository = new PermissionRepository(scopeAccessor, appCaches, loggerFactory.CreateLogger>()); } @@ -362,7 +362,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly UserGroupRepository _userGroupRepo; - public UserGroupWithUsersRepository(UserGroupRepository userGroupRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) + public UserGroupWithUsersRepository(UserGroupRepository userGroupRepo, IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) { _userGroupRepo = userGroupRepo; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs index 5ba32a4d2f..51000dbe70 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs @@ -3,10 +3,12 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Dtos; @@ -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; } @@ -159,10 +168,7 @@ ORDER BY colName"; } public Guid CreateLoginSession(int userId, string requestingIpAddress, bool cleanStaleSessions = true) - { - // TODO: I know this doesn't follow the normal repository conventions which would require us to create a UserSessionRepository - //and also business logic models for these objects but that's just so overkill for what we are doing - //and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore + { var now = DateTime.UtcNow; var dto = new UserLoginDto { @@ -192,13 +198,14 @@ ORDER BY colName"; // that query is going to run a *lot*, make it a template var t = SqlContext.Templates.Get("Umbraco.Core.UserRepository.ValidateLoginSession", s => s .Select() + .SelectTop(1) .From() .Where(x => x.SessionId == SqlTemplate.Arg("sessionId")) .ForUpdate()); var sql = t.Sql(sessionId); - var found = Database.Query(sql).FirstOrDefault(); + var found = Database.FirstOrDefault(sql); if (found == null || found.UserId != userId || found.LoggedOutUtc.HasValue) return false; diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs index ec4cfca498..c24aaf3f7a 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs @@ -4,6 +4,7 @@ using System.Data; using System.Data.Common; using System.Data.SqlClient; using System.Linq; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core.Logging; using Umbraco.Core.Persistence.DatabaseModelDefinitions; @@ -161,7 +162,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax } catch (Exception e) { - logger.Error(e, "Failed to detected SqlServer version."); + logger.LogError(e, "Failed to detected SqlServer version."); version = new ServerVersionInfo(); // all unknown } } 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/UmbracoDatabase.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs index a4b4afbe25..37c47da50d 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs @@ -5,9 +5,9 @@ using System.Data.Common; using System.Data.SqlClient; using System.Linq; using System.Text; +using Microsoft.Extensions.Logging; using NPoco; using StackExchange.Profiling; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence.FaultHandling; using Umbraco.Core.Persistence.SqlSyntax; @@ -23,7 +23,7 @@ namespace Umbraco.Core.Persistence /// public class UmbracoDatabase : Database, IUmbracoDatabase { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IBulkSqlInsertProvider _bulkSqlInsertProvider; private readonly RetryPolicy _connectionRetryPolicy; private readonly RetryPolicy _commandRetryPolicy; @@ -39,7 +39,7 @@ namespace Umbraco.Core.Persistence /// Used by UmbracoDatabaseFactory to create databases. /// Also used by DatabaseBuilder for creating databases and installing/upgrading. /// - public UmbracoDatabase(string connectionString, ISqlContext sqlContext, DbProviderFactory provider, ILogger logger, IBulkSqlInsertProvider bulkSqlInsertProvider, RetryPolicy connectionRetryPolicy = null, RetryPolicy commandRetryPolicy = null) + public UmbracoDatabase(string connectionString, ISqlContext sqlContext, DbProviderFactory provider, ILogger logger, IBulkSqlInsertProvider bulkSqlInsertProvider, RetryPolicy connectionRetryPolicy = null, RetryPolicy commandRetryPolicy = null) : base(connectionString, sqlContext.DatabaseType, provider, sqlContext.SqlSyntax.DefaultIsolationLevel) { SqlContext = sqlContext; @@ -58,7 +58,7 @@ namespace Umbraco.Core.Persistence /// Initializes a new instance of the class. /// /// Internal for unit tests only. - internal UmbracoDatabase(DbConnection connection, ISqlContext sqlContext, ILogger logger, IBulkSqlInsertProvider bulkSqlInsertProvider) + internal UmbracoDatabase(DbConnection connection, ISqlContext sqlContext, ILogger logger, IBulkSqlInsertProvider bulkSqlInsertProvider) : base(connection, sqlContext.DatabaseType, sqlContext.SqlSyntax.DefaultIsolationLevel) { SqlContext = sqlContext; @@ -226,10 +226,10 @@ namespace Umbraco.Core.Persistence protected override void OnException(Exception ex) { - _logger.Error(ex, "Exception ({InstanceId}).", InstanceId); - _logger.Debug("At:\r\n{StackTrace}", Environment.StackTrace); + _logger.LogError(ex, "Exception ({InstanceId}).", InstanceId); + _logger.LogDebug("At:\r\n{StackTrace}", Environment.StackTrace); if (EnableSqlTrace == false) - _logger.Debug("Sql:\r\n{Sql}", CommandToString(LastSQL, LastArgs)); + _logger.LogDebug("Sql:\r\n{Sql}", CommandToString(LastSQL, LastArgs)); base.OnException(ex); } @@ -242,13 +242,13 @@ namespace Umbraco.Core.Persistence cmd.CommandTimeout = cmd.Connection.ConnectionTimeout; if (EnableSqlTrace) - _logger.Debug("SQL Trace:\r\n{Sql}", CommandToString(cmd).Replace("{", "{{").Replace("}", "}}")); // TODO: these escapes should be builtin + _logger.LogDebug("SQL Trace:\r\n{Sql}", CommandToString(cmd).Replace("{", "{{").Replace("}", "}}")); // TODO: these escapes should be builtin #if DEBUG_DATABASES // detects whether the command is already in use (eg still has an open reader...) DatabaseDebugHelper.SetCommand(cmd, InstanceId + " [T" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]"); var refsobj = DatabaseDebugHelper.GetReferencedObjects(cmd.Connection); - if (refsobj != null) _logger.Debug("Oops!" + Environment.NewLine + refsobj); + if (refsobj != null) _logger.LogDebug("Oops!" + Environment.NewLine + refsobj); #endif _cmd = cmd; diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index e243ea45ef..65933399a3 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -1,12 +1,11 @@ using System; using System.Data.Common; -using System.Data.SqlClient; using System.Threading; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using NPoco; using NPoco.FluentMappings; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Persistence.FaultHandling; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; @@ -28,9 +27,10 @@ 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; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private object _lock = new object(); @@ -70,8 +70,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, ILoggerFactory loggerFactory, IOptions globalSettings, IOptions connectionStrings, Lazy mappers,IDbProviderFactoryCreator dbProviderFactoryCreator) + : this(logger, loggerFactory, globalSettings.Value, connectionStrings.Value, mappers, dbProviderFactoryCreator) { } @@ -80,21 +80,20 @@ 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, ILoggerFactory loggerFactory, 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)); + _loggerFactory = loggerFactory; - var settings = connectionStrings[connectionStringName]; + var settings = connectionStrings.UmbracoConnectionString; if (settings == null) { - logger.Debug("Missing connection string, defer configuration."); + logger.LogDebug("Missing connection string, defer configuration."); return; // not configured } @@ -104,7 +103,7 @@ namespace Umbraco.Core.Persistence var providerName = settings.ProviderName; if (string.IsNullOrWhiteSpace(connectionString) || string.IsNullOrWhiteSpace(providerName)) { - logger.Debug("Empty connection string or provider name, defer configuration."); + logger.LogDebug("Empty connection string or provider name, defer configuration."); return; // not configured } @@ -115,15 +114,16 @@ namespace Umbraco.Core.Persistence /// Initializes a new instance of the . /// /// Used in tests. - public UmbracoDatabaseFactory(ILogger logger, string connectionString, string providerName, Lazy mappers, IDbProviderFactoryCreator dbProviderFactoryCreator) + public UmbracoDatabaseFactory(ILogger logger, ILoggerFactory loggerFactory, string connectionString, string providerName, Lazy mappers, IDbProviderFactoryCreator dbProviderFactoryCreator) { _mappers = mappers ?? throw new ArgumentNullException(nameof(mappers)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _loggerFactory = loggerFactory; _dbProviderFactoryCreator = dbProviderFactoryCreator ?? throw new ArgumentNullException(nameof(dbProviderFactoryCreator)); if (string.IsNullOrWhiteSpace(connectionString) || string.IsNullOrWhiteSpace(providerName)) { - logger.Debug("Missing connection string or provider name, defer configuration."); + logger.LogDebug("Missing connection string or provider name, defer configuration."); return; // not configured } @@ -188,7 +188,7 @@ namespace Umbraco.Core.Persistence // else leave unchanged } - _logger.Debug("SqlServer {SqlServerVersion}, DatabaseType is {DatabaseType} ({Source}).", + _logger.LogDebug("SqlServer {SqlServerVersion}, DatabaseType is {DatabaseType} ({Source}).", versionName, _databaseType, fromSettings ? "settings" : "detected"); } @@ -245,7 +245,7 @@ namespace Umbraco.Core.Persistence private SqlContext Initialize() { - _logger.Debug("Initializing."); + _logger.LogDebug("Initializing."); if (ConnectionString.IsNullOrWhiteSpace()) throw new InvalidOperationException("The factory has not been configured with a proper connection string."); if (_providerName.IsNullOrWhiteSpace()) throw new InvalidOperationException("The factory has not been configured with a proper provider name."); @@ -290,7 +290,7 @@ namespace Umbraco.Core.Persistence if (_npocoDatabaseFactory == null) throw new NullReferenceException("The call to UmbracoDatabaseFactory.Config yielded a null UmbracoDatabaseFactory instance."); - _logger.Debug("Initialized."); + _logger.LogDebug("Initialized."); return new SqlContext(_sqlSyntax, _databaseType, _pocoDataFactory, _mappers); } @@ -312,7 +312,7 @@ namespace Umbraco.Core.Persistence // method used by NPoco's UmbracoDatabaseFactory to actually create the database instance private UmbracoDatabase CreateDatabaseInstance() { - return new UmbracoDatabase(ConnectionString, SqlContext, DbProviderFactory, _logger, _bulkSqlInsertProvider, _connectionRetryPolicy, _commandRetryPolicy); + return new UmbracoDatabase(ConnectionString, SqlContext, DbProviderFactory, _loggerFactory.CreateLogger(), _bulkSqlInsertProvider, _connectionRetryPolicy, _commandRetryPolicy); } protected override void DisposeResources() diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs index b78cae7ac4..b1e5fb0199 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Blocks; using Umbraco.Core.Models.Editors; @@ -29,14 +29,14 @@ namespace Umbraco.Web.PropertyEditors private readonly IContentTypeService _contentTypeService; public BlockEditorPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, Lazy propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService,localizationService,localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService,localizationService,localizedTextService, shortStringHelper) { _localizedTextService = localizedTextService; _propertyEditors = propertyEditors; @@ -49,16 +49,16 @@ namespace Umbraco.Web.PropertyEditors #region Value Editor - protected override IDataValueEditor CreateValueEditor() => new BlockEditorPropertyValueEditor(Attribute, PropertyEditors, _dataTypeService, _contentTypeService, _localizedTextService, Logger, LocalizationService,ShortStringHelper); + protected override IDataValueEditor CreateValueEditor() => new BlockEditorPropertyValueEditor(Attribute, PropertyEditors, _dataTypeService, _contentTypeService, _localizedTextService, LoggerFactory.CreateLogger(), LocalizationService,ShortStringHelper); internal class BlockEditorPropertyValueEditor : DataValueEditor, IDataValueReference { private readonly PropertyEditorCollection _propertyEditors; private readonly IDataTypeService _dataTypeService; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly BlockEditorValues _blockEditorValues; - public BlockEditorPropertyValueEditor(DataEditorAttribute attribute, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, ILocalizedTextService textService, ILogger logger, ILocalizationService localizationService, IShortStringHelper shortStringHelper) + public BlockEditorPropertyValueEditor(DataEditorAttribute attribute, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, ILocalizedTextService textService, ILogger logger, ILocalizationService localizationService, IShortStringHelper shortStringHelper) : base(dataTypeService, localizationService, textService, shortStringHelper, attribute) { _propertyEditors = propertyEditors; @@ -156,7 +156,7 @@ namespace Umbraco.Web.PropertyEditors { // deal with weird situations by ignoring them (no comment) row.PropertyValues.Remove(prop.Key); - _logger.Warn( + _logger.LogWarning( "ToEditor removed property value {PropertyKey} in row {RowId} for property type {PropertyTypeAlias}", prop.Key, row.Key, property.PropertyType.Alias); continue; @@ -405,7 +405,7 @@ namespace Umbraco.Web.PropertyEditors if (!propertyTypes.TryGetValue(prop.Key, out var propType)) { block.RawPropertyValues.Remove(prop.Key); - _logger.Warn("The property {PropertyKey} for block {BlockKey} was removed because the property type {PropertyTypeAlias} was not found on {ContentTypeAlias}", + _logger.LogWarning("The property {PropertyKey} for block {BlockKey} was removed because the property type {PropertyTypeAlias} was not found on {ContentTypeAlias}", prop.Key, block.Key, prop.Key, contentType.Alias); } else 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/BlockListPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs index 8426385813..6a23d0da00 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditor.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Blocks; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -27,7 +27,7 @@ namespace Umbraco.Web.PropertyEditors private readonly IIOHelper _ioHelper; public BlockListPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, Lazy propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, @@ -35,7 +35,7 @@ namespace Umbraco.Web.PropertyEditors IIOHelper ioHelper, ILocalizationService localizationService, IShortStringHelper shortStringHelper) - : base(logger, propertyEditors, dataTypeService, contentTypeService, localizedTextService, localizationService, shortStringHelper) + : base(loggerFactory, propertyEditors, dataTypeService, contentTypeService, localizedTextService, localizationService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs index 67f3dd61cd..09600d86ae 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/CheckBoxListPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -28,8 +28,8 @@ namespace Umbraco.Web.PropertyEditors /// /// The constructor will setup the property editor based on the attribute if one is found /// - public CheckBoxListPropertyEditor(ILogger logger, ILocalizedTextService textService, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IIOHelper ioHelper, ILocalizedTextService localizedTextService) - : base(logger, dataTypeService, localizationService,localizedTextService, shortStringHelper) + public CheckBoxListPropertyEditor(ILoggerFactory loggerFactory, ILocalizedTextService textService, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IIOHelper ioHelper, ILocalizedTextService localizedTextService) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) { _textService = textService; _dataTypeService = dataTypeService; @@ -43,6 +43,6 @@ namespace Umbraco.Web.PropertyEditors protected override IConfigurationEditor CreateConfigurationEditor() => new ValueListConfigurationEditor(_textService, _ioHelper); /// - protected override IDataValueEditor CreateValueEditor() => new MultipleValueEditor(Logger, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new MultipleValueEditor(LoggerFactory.CreateLogger(), _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper, Attribute); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs index 0f6996ddd4..575609a934 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -17,8 +17,8 @@ namespace Umbraco.Web.PropertyEditors { private readonly IIOHelper _ioHelper; - public ColorPickerPropertyEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public ColorPickerPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = 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/ContentPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ContentPickerPropertyEditor.cs index 4c996fd4fc..4c172ccb2e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ContentPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ContentPickerPropertyEditor.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -30,10 +30,10 @@ namespace Umbraco.Web.PropertyEditors IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, - ILogger logger, + ILoggerFactory loggerFactory, IIOHelper ioHelper, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService,localizationService,localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService,localizationService,localizedTextService, shortStringHelper) { _dataTypeService = dataTypeService; _localizationService = localizationService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs index 1c52a007dd..ebac6a763d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DataEditor.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.Serialization; +using Microsoft.Extensions.Logging; using Umbraco.Composing; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -27,9 +27,9 @@ namespace Umbraco.Core.PropertyEditors /// /// Initializes a new instance of the class. /// - public DataEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, EditorType type = EditorType.PropertyValue) + public DataEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, EditorType type = EditorType.PropertyValue) { - Logger = logger ?? throw new ArgumentNullException(nameof(logger)); + LoggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); DataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService)); LocalizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService)); LocalizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); @@ -61,13 +61,9 @@ namespace Umbraco.Core.PropertyEditors protected IShortStringHelper ShortStringHelper { get; } protected ILocalizedTextService LocalizedTextService { get; } protected ILocalizationService LocalizationService { get; } + protected ILoggerFactory LoggerFactory { get; } protected IDataTypeService DataTypeService { get; } - /// - /// Gets a logger. - /// - protected ILogger Logger { get; } - /// [DataMember(Name = "alias", IsRequired = true)] public string Alias { get; internal set; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DataValueEditor.cs index 9765038adf..df9a06515c 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DataValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DataValueEditor.cs @@ -4,11 +4,11 @@ using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Composing; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors.Validators; @@ -217,7 +217,7 @@ namespace Umbraco.Core.PropertyEditors var result = TryConvertValueToCrlType(editorValue.Value); if (result.Success == false) { - Current.Logger.Warn("The value {EditorValue} cannot be converted to the type {StorageTypeValue}", editorValue.Value, ValueTypes.ToStorageType(ValueType)); + Current.Logger.LogWarning("The value {EditorValue} cannot be converted to the type {StorageTypeValue}", editorValue.Value, ValueTypes.ToStorageType(ValueType)); return null; } return result.Result; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs index d2a08c3a2b..db4c6734a8 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DateTimePropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -23,9 +23,9 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - /// - public DateTimePropertyEditor(ILogger logger, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService,localizedTextService, shortStringHelper) + /// + public DateTimePropertyEditor(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DecimalPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DecimalPropertyEditor.cs index e5ca56878f..8d2280b23b 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DecimalPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DecimalPropertyEditor.cs @@ -1,5 +1,5 @@ -using Umbraco.Core; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.Services; @@ -21,12 +21,13 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public DecimalPropertyEditor(ILogger logger, + public DecimalPropertyEditor( + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs index 73ce726257..66f605bc36 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexiblePropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -21,8 +21,8 @@ namespace Umbraco.Web.PropertyEditors private readonly IShortStringHelper _shortStringHelper; private readonly IIOHelper _ioHelper; - public DropDownFlexiblePropertyEditor(ILocalizedTextService textService, ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IIOHelper ioHelper) - : base(logger, dataTypeService, localizationService, textService, shortStringHelper) + public DropDownFlexiblePropertyEditor(ILocalizedTextService textService, ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, IIOHelper ioHelper) + : base(loggerFactory, dataTypeService, localizationService, textService, shortStringHelper) { _textService = textService; _dataTypeService = dataTypeService; @@ -33,7 +33,7 @@ namespace Umbraco.Web.PropertyEditors protected override IDataValueEditor CreateValueEditor() { - return new MultipleValueEditor(Logger, _dataTypeService, _localizationService, _textService, _shortStringHelper, Attribute); + return new MultipleValueEditor(LoggerFactory.CreateLogger(), _dataTypeService, _localizationService, _textService, _shortStringHelper, Attribute); } protected override IConfigurationEditor CreateConfigurationEditor() => new DropDownFlexibleConfigurationEditor(_textService, _ioHelper); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/EmailAddressPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/EmailAddressPropertyEditor.cs index c5bcaf0f86..2cdfd4f7eb 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/EmailAddressPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/EmailAddressPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.Services; @@ -22,13 +22,13 @@ namespace Umbraco.Web.PropertyEditors /// The constructor will setup the property editor based on the attribute if one is found /// public EmailAddressPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs index 698fcb10b3..448e2043c0 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyEditor.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; +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.Media; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -22,21 +25,29 @@ 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) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public FileUploadPropertyEditor( + ILoggerFactory loggerFactory, + IMediaFileSystem mediaFileSystem, + IOptions contentSettings, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + UploadAutoFillProperties uploadAutoFillProperties) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _dataTypeService = dataTypeService; _localizationService = localizationService; _localizedTextService = localizedTextService; - _uploadAutoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, contentSettings); + _uploadAutoFillProperties = uploadAutoFillProperties; } /// @@ -45,8 +56,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/GridPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs index e061766ebc..c34ce59fe6 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyEditor.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; @@ -36,7 +36,7 @@ namespace Umbraco.Web.PropertyEditors private readonly IImageUrlGenerator _imageUrlGenerator; public GridPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IUmbracoContextAccessor umbracoContextAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, @@ -47,7 +47,7 @@ namespace Umbraco.Web.PropertyEditors IIOHelper ioHelper, IShortStringHelper shortStringHelper, IImageUrlGenerator imageUrlGenerator) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _umbracoContextAccessor = umbracoContextAccessor; _ioHelper = ioHelper; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index 586a120609..3434ee5bcb 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; 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.Media; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -29,26 +32,33 @@ 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; private readonly UploadAutoFillProperties _autoFillProperties; + private readonly ILogger _logger; /// /// 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( + ILoggerFactory loggerFactory, + IMediaFileSystem mediaFileSystem, + IOptions contentSettings, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + IIOHelper ioHelper, + IShortStringHelper shortStringHelper, + ILocalizedTextService localizedTextService, + UploadAutoFillProperties uploadAutoFillProperties) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _mediaFileSystem = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem)); - _contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings)); - _dataTypeService = dataTypeService; - _localizationService = localizationService; - _ioHelper = ioHelper; - - // TODO: inject? - _autoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, _contentSettings); + _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); + _dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService)); + _ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper)); + _autoFillProperties = uploadAutoFillProperties ?? throw new ArgumentNullException(nameof(uploadAutoFillProperties)); + _logger = loggerFactory.CreateLogger(); } public bool TryGetMediaPath(string alias, object value, out string mediaPath) @@ -66,7 +76,7 @@ namespace Umbraco.Web.PropertyEditors /// Creates the corresponding property value editor. /// /// The corresponding property value editor. - protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, Logger, _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _contentSettings); + protected override IDataValueEditor CreateValueEditor() => new ImageCropperPropertyValueEditor(Attribute, LoggerFactory.CreateLogger(), _mediaFileSystem, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, _contentSettings); /// /// Creates the corresponding preValue editor. @@ -103,7 +113,7 @@ namespace Umbraco.Web.PropertyEditors catch (Exception ex) { if (writeLog) - Logger.Error(ex, "Could not parse image cropper value '{Json}'", value); + _logger.LogError(ex, "Could not parse image cropper value '{Json}'", value); return null; } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index 1c7c8b922a..6a1f3072d4 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -1,10 +1,10 @@ using System; +using Microsoft.Extensions.Logging; 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; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; @@ -20,11 +20,19 @@ namespace Umbraco.Web.PropertyEditors /// internal class ImageCropperPropertyValueEditor : DataValueEditor // TODO: core vs web? { - private readonly ILogger _logger; + 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)); @@ -82,7 +90,7 @@ namespace Umbraco.Web.PropertyEditors catch (Exception ex) { // for some reason the value is invalid so continue as if there was no value there - _logger.Warn(ex, "Could not parse current db value to a JObject."); + _logger.LogWarning(ex, "Could not parse current db value to a JObject."); } if (string.IsNullOrWhiteSpace(currentPath) == false) currentPath = _mediaFileSystem.GetRelativePath(currentPath); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IntegerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/IntegerPropertyEditor.cs index 49e49e005a..417ec112d7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IntegerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/IntegerPropertyEditor.cs @@ -1,5 +1,5 @@ -using Umbraco.Core; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.Services; @@ -18,8 +18,8 @@ namespace Umbraco.Web.PropertyEditors ValueType = ValueTypes.Integer)] public class IntegerPropertyEditor : DataEditor { - public IntegerPropertyEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(logger, dataTypeService, localizationService,localizedTextService, shortStringHelper) + public IntegerPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) { } /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/LabelPropertyEditor.cs index f91c8efdd1..639a9c928d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/LabelPropertyEditor.cs @@ -1,7 +1,5 @@ -using Umbraco.Composing; -using Umbraco.Core.Composing; +using Microsoft.Extensions.Logging; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -23,8 +21,8 @@ namespace Umbraco.Core.PropertyEditors /// /// Initializes a new instance of the class. /// - public LabelPropertyEditor(ILogger logger, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public LabelPropertyEditor(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs index f46743f0cc..e01258eb80 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ListViewPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -24,15 +24,15 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - /// + /// public ListViewPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IIOHelper iioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _iioHelper = iioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MarkdownPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MarkdownPropertyEditor.cs index 167b05df53..ab4e6f3d97 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MarkdownPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MarkdownPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -25,13 +25,13 @@ namespace Umbraco.Web.PropertyEditors /// Initializes a new instance of the class. /// public MarkdownPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs index f0c5110e1e..476674b1ff 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPickerPropertyEditor.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -28,13 +28,13 @@ namespace Umbraco.Web.PropertyEditors /// Initializes a new instance of the class. /// public MediaPickerPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MemberGroupPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MemberGroupPickerPropertyEditor.cs index fd1bd0d102..eb50d02284 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MemberGroupPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MemberGroupPickerPropertyEditor.cs @@ -1,5 +1,5 @@ -using Umbraco.Core; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -16,12 +16,12 @@ namespace Umbraco.Web.PropertyEditors public class MemberGroupPickerPropertyEditor : DataEditor { public MemberGroupPickerPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerPropertyEditor.cs index 092e790e51..3676340aee 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerPropertyEditor.cs @@ -1,5 +1,5 @@ -using Umbraco.Core; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -16,12 +16,12 @@ namespace Umbraco.Web.PropertyEditors public class MemberPickerPropertyEditor : DataEditor { public MemberPickerPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { } protected override IConfigurationEditor CreateConfigurationEditor() => new MemberPickerConfiguration(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs index f1ed4e6c44..fc80aabdd9 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -20,8 +20,8 @@ namespace Umbraco.Web.PropertyEditors { private readonly IIOHelper _ioHelper; - public MultiNodeTreePickerPropertyEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IIOHelper ioHelper, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public MultiNodeTreePickerPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IIOHelper ioHelper, IShortStringHelper shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs index 1be4067763..e88849002b 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerPropertyEditor.cs @@ -1,8 +1,8 @@ using System; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.PublishedCache; @@ -26,8 +26,8 @@ namespace Umbraco.Web.PropertyEditors private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IPublishedUrlProvider _publishedUrlProvider; - public MultiUrlPickerPropertyEditor(ILogger logger, Lazy entityService, IPublishedSnapshotAccessor publishedSnapshotAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, IUmbracoContextAccessor umbracoContextAccessor, IPublishedUrlProvider publishedUrlProvider) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper, EditorType.PropertyValue) + public MultiUrlPickerPropertyEditor(ILoggerFactory loggerFactory, Lazy entityService, IPublishedSnapshotAccessor publishedSnapshotAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, IUmbracoContextAccessor umbracoContextAccessor, IPublishedUrlProvider publishedUrlProvider) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper, EditorType.PropertyValue) { _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _publishedSnapshotAccessor = publishedSnapshotAccessor ?? throw new ArgumentNullException(nameof(publishedSnapshotAccessor)); @@ -38,6 +38,6 @@ namespace Umbraco.Web.PropertyEditors protected override IConfigurationEditor CreateConfigurationEditor() => new MultiUrlPickerConfigurationEditor(_ioHelper); - protected override IDataValueEditor CreateValueEditor() => new MultiUrlPickerValueEditor(_entityService.Value, _publishedSnapshotAccessor, Logger, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute, _umbracoContextAccessor, _publishedUrlProvider); + protected override IDataValueEditor CreateValueEditor() => new MultiUrlPickerValueEditor(_entityService.Value, _publishedSnapshotAccessor, LoggerFactory.CreateLogger(), DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute, _umbracoContextAccessor, _publishedUrlProvider); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs index 63814c05c7..b6afa0a1b5 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.Models.Entities; @@ -20,12 +20,12 @@ namespace Umbraco.Web.PropertyEditors public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference { private readonly IEntityService _entityService; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - public MultiUrlPickerValueEditor(IEntityService entityService, IPublishedSnapshotAccessor publishedSnapshotAccessor, ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute, IUmbracoContextAccessor umbracoContextAccessor, IPublishedUrlProvider publishedUrlProvider) + public MultiUrlPickerValueEditor(IEntityService entityService, IPublishedSnapshotAccessor publishedSnapshotAccessor, ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute, IUmbracoContextAccessor umbracoContextAccessor, IPublishedUrlProvider publishedUrlProvider) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) { _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); @@ -122,7 +122,7 @@ namespace Umbraco.Web.PropertyEditors } catch (Exception ex) { - _logger.Error("Error getting links", ex); + _logger.LogError("Error getting links", ex); } return base.ToEditor(property, culture, segment); @@ -157,7 +157,7 @@ namespace Umbraco.Web.PropertyEditors } catch (Exception ex) { - _logger.Error("Error saving links", ex); + _logger.LogError("Error saving links", ex); } return base.FromEditor(editorValue, currentValue); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs index 8aba505aed..b4e1287315 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; @@ -36,8 +36,8 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public MultipleTextStringPropertyEditor(ILogger logger, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public MultipleTextStringPropertyEditor(ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = ioHelper; _dataTypeService = dataTypeService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs index 40525bff79..a960ac51ad 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleValueEditor.cs @@ -1,8 +1,8 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -18,9 +18,9 @@ namespace Umbraco.Web.PropertyEditors /// public class MultipleValueEditor : DataValueEditor { - private readonly ILogger _logger; + private readonly ILogger _logger; - public MultipleValueEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) + public MultipleValueEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, DataEditorAttribute attribute) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) { _logger = logger; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs index 6ad465ecd5..b257f69e98 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; @@ -35,7 +35,7 @@ namespace Umbraco.Web.PropertyEditors public const string ContentTypeAliasPropertyKey = "ncContentTypeAlias"; public NestedContentPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, Lazy propertyEditors, IDataTypeService dataTypeService, ILocalizationService localizationService, @@ -43,7 +43,7 @@ namespace Umbraco.Web.PropertyEditors IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base (logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base (loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _propertyEditors = propertyEditors; _contentTypeService = contentTypeService; @@ -62,14 +62,14 @@ namespace Umbraco.Web.PropertyEditors #region Value Editor - protected override IDataValueEditor CreateValueEditor() => new NestedContentPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, _contentTypeService, ShortStringHelper, Attribute, PropertyEditors, Logger); + protected override IDataValueEditor CreateValueEditor() => new NestedContentPropertyValueEditor(DataTypeService, LocalizationService, LocalizedTextService, _contentTypeService, ShortStringHelper, Attribute, PropertyEditors, LoggerFactory.CreateLogger()); internal class NestedContentPropertyValueEditor : DataValueEditor, IDataValueReference { private readonly PropertyEditorCollection _propertyEditors; private readonly IContentTypeService _contentTypeService; private readonly IDataTypeService _dataTypeService; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly NestedContentValues _nestedContentValues; private readonly Lazy> _contentTypes; @@ -82,7 +82,7 @@ namespace Umbraco.Web.PropertyEditors IShortStringHelper shortStringHelper, DataEditorAttribute attribute, PropertyEditorCollection propertyEditors, - ILogger logger) + ILogger logger) : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) { _propertyEditors = propertyEditors; @@ -95,7 +95,6 @@ namespace Umbraco.Web.PropertyEditors _contentTypes = new Lazy>(() => _contentTypeService.GetAll().ToDictionary(c => c.Alias) ); - } /// @@ -144,7 +143,7 @@ namespace Umbraco.Web.PropertyEditors { // deal with weird situations by ignoring them (no comment) row.RawPropertyValues.Remove(prop.Key); - _logger.Warn( + _logger.LogWarning( ex, "ConvertDbToString removed property value {PropertyKey} in row {RowId} for property type {PropertyTypeAlias}", prop.Key, row.Id, propertyType.Alias); @@ -213,7 +212,7 @@ namespace Umbraco.Web.PropertyEditors { // deal with weird situations by ignoring them (no comment) row.RawPropertyValues.Remove(prop.Key); - _logger.Warn( + _logger.LogWarning( ex, "ToEditor removed property value {PropertyKey} in row {RowId} for property type {PropertyTypeAlias}", prop.Key, row.Id, property.PropertyType.Alias); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs index 726963b9c5..2da9e184c3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/ContentTypeParameterEditor.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -19,12 +19,12 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors /// Initializes a new instance of the class. /// public ContentTypeParameterEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { // configure DefaultConfiguration.Add("multiple", false); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs index a514a47a01..d416cf111a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentPickerParameterEditor.cs @@ -1,5 +1,5 @@ -using Umbraco.Core; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -20,12 +20,12 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors /// Initializes a new instance of the class. /// public MultipleContentPickerParameterEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { // configure DefaultConfiguration.Add("multiPicker", "1"); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs index 7097f951c6..613d6a6a5e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleContentTypeParameterEditor.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -13,12 +13,12 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors public class MultipleContentTypeParameterEditor : DataEditor { public MultipleContentTypeParameterEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { // configure DefaultConfiguration.Add("multiple", true); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs index 7b6a965706..73a3b42610 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultipleMediaPickerParameterEditor.cs @@ -1,5 +1,5 @@ using Umbraco.Core; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -20,12 +20,13 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors /// /// Initializes a new instance of the class. /// - public MultipleMediaPickerParameterEditor(ILogger logger, + public MultipleMediaPickerParameterEditor( + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { DefaultConfiguration.Add("multiPicker", "1"); } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs index da98492442..16cd596fc8 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyGroupParameterEditor.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -13,12 +13,12 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors public class MultiplePropertyGroupParameterEditor : DataEditor { public MultiplePropertyGroupParameterEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { // configure DefaultConfiguration.Add("multiple", true); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs index 46a5652455..e9576fab02 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/MultiplePropertyTypeParameterEditor.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -12,12 +12,13 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors "entitypicker")] public class MultiplePropertyTypeParameterEditor : DataEditor { - public MultiplePropertyTypeParameterEditor(ILogger logger, + public MultiplePropertyTypeParameterEditor( + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { // configure DefaultConfiguration.Add("multiple", "1"); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs index d331fee6ee..345afa3b46 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyGroupParameterEditor.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -13,12 +13,12 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors public class PropertyGroupParameterEditor : DataEditor { public PropertyGroupParameterEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { // configure DefaultConfiguration.Add("multiple", "0"); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs index affcd4738d..be682a35d3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ParameterEditors/PropertyTypeParameterEditor.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -13,12 +13,12 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors public class PropertyTypeParameterEditor : DataEditor { public PropertyTypeParameterEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { // configure DefaultConfiguration.Add("multiple", "0"); 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/RadioButtonsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs index f6b24e5859..6a863b1dd1 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -25,13 +25,13 @@ namespace Umbraco.Web.PropertyEditors /// The constructor will setup the property editor based on the attribute if one is found /// public RadioButtonsPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService,localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs index 58a280e5db..cd8b228a6f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; using System.IO; +using Microsoft.Extensions.Logging; using HtmlAgilityPack; using Umbraco.Core; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Services; @@ -19,7 +19,7 @@ namespace Umbraco.Web.PropertyEditors public sealed class RichTextEditorPastedImages { private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IIOHelper _ioHelper; private readonly IMediaService _mediaService; private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; @@ -29,7 +29,7 @@ namespace Umbraco.Web.PropertyEditors const string TemporaryImageDataAttribute = "data-tmpimg"; - public RichTextEditorPastedImages(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IIOHelper ioHelper, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IPublishedUrlProvider publishedUrlProvider) + public RichTextEditorPastedImages(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IIOHelper ioHelper, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IPublishedUrlProvider publishedUrlProvider) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -144,7 +144,7 @@ namespace Umbraco.Web.PropertyEditors } catch (Exception ex) { - _logger.Error(typeof(HtmlImageSourceParser), ex, "Could not delete temp file or folder {FileName}", absoluteTempImagePath); + _logger.LogError(ex, "Could not delete temp file or folder {FileName}", absoluteTempImagePath); } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs index 2f283b2709..bf867ce648 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; @@ -39,7 +39,7 @@ namespace Umbraco.Web.PropertyEditors /// The constructor will setup the property editor based on the attribute if one is found /// public RichTextPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IUmbracoContextAccessor umbracoContextAccessor, IDataTypeService dataTypeService, ILocalizationService localizationService, @@ -50,7 +50,7 @@ namespace Umbraco.Web.PropertyEditors IIOHelper ioHelper, ILocalizedTextService localizedTextService, IImageUrlGenerator imageUrlGenerator) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _umbracoContextAccessor = umbracoContextAccessor; _imageSourceParser = imageSourceParser; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs index 88bfc3f4e3..bb62c3461d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -23,13 +23,13 @@ namespace Umbraco.Web.PropertyEditors /// Initializes a new instance of the class. /// public SliderPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs index 7fccd3a15f..708f4d8c9f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -29,13 +29,13 @@ namespace Umbraco.Web.PropertyEditors public TagsPropertyEditor( ManifestValueValidatorCollection validators, - ILogger logger, + ILoggerFactory loggerFactory, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _validators = validators; _ioHelper = ioHelper; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs index dd3c1fd350..8d173e58bc 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TextAreaPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -28,8 +28,8 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public TextAreaPropertyEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService,shortStringHelper) + public TextAreaPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService,shortStringHelper) { _dataTypeService = dataTypeService; _localizationService = localizationService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TextOnlyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TextOnlyValueEditor.cs index e53c673986..ec48cf8b57 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TextOnlyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TextOnlyValueEditor.cs @@ -20,7 +20,6 @@ namespace Umbraco.Web.PropertyEditors /// A method used to format the database value to a value that can be used by the editor /// /// - /// /// /// /// diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs index b89f5e228a..1ec87abe9b 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TextboxPropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -27,8 +27,8 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public TextboxPropertyEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(logger, dataTypeService, localizationService,localizedTextService, shortStringHelper) + public TextboxPropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) + : base(loggerFactory, dataTypeService, localizationService,localizedTextService, shortStringHelper) { _dataTypeService = dataTypeService; _localizationService = localizationService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs index 0bfa5899c9..db72887fff 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs @@ -1,6 +1,6 @@ -using Umbraco.Core; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -25,8 +25,8 @@ namespace Umbraco.Web.PropertyEditors /// /// Initializes a new instance of the class. /// - public TrueFalsePropertyEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public TrueFalsePropertyEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, IIOHelper ioHelper, IShortStringHelper shortStringHelper, ILocalizedTextService localizedTextService) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { _ioHelper = ioHelper; } 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/UserPickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/UserPickerPropertyEditor.cs index 194924adf1..891fb54ee3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/UserPickerPropertyEditor.cs @@ -1,5 +1,5 @@ -using Umbraco.Core; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -16,12 +16,12 @@ namespace Umbraco.Web.PropertyEditors public class UserPickerPropertyEditor : DataEditor { public UserPickerPropertyEditor( - ILogger logger, + ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { } protected override IConfigurationEditor CreateConfigurationEditor() => new UserPickerConfiguration(); 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/PropertyEditors/ValueConverters/GridValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/GridValueConverter.cs index 3a35bdfc9a..83866d958f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/GridValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/GridValueConverter.cs @@ -1,10 +1,10 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.Grid; -using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Composing; @@ -18,8 +18,8 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters { private readonly IGridConfig _config; - public GridValueConverter(PropertyEditorCollection propertyEditors, IGridConfig config) - : base(propertyEditors) + public GridValueConverter(PropertyEditorCollection propertyEditors, IGridConfig config, ILogger logger) + : base(propertyEditors, logger) { _config = config; } @@ -92,7 +92,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters } catch (Exception ex) { - Current.Logger.Error(ex, "Could not parse the string '{JsonString}' to a json object", sourceString); + Current.Logger.LogError(ex, "Could not parse the string '{JsonString}' to a json object", sourceString); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs index 0043eeed72..b27955210f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs @@ -1,10 +1,8 @@ using System; using System.Globalization; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Composing; namespace Umbraco.Core.PropertyEditors.ValueConverters { @@ -14,6 +12,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters [DefaultPropertyValueConverter(typeof(JsonValueConverter))] public class ImageCropperValueConverter : PropertyValueConverterBase { + private readonly ILogger _logger; + + public ImageCropperValueConverter(ILogger logger) + { + _logger = logger; + } + /// public override bool IsConverter(IPublishedPropertyType propertyType) => propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.ImageCropper); @@ -44,7 +49,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters catch (Exception ex) { // cannot deserialize, assume it may be a raw image url - Current.Logger.Error(ex, "Could not deserialize string '{JsonString}' into an image cropper value.", sourceString); + _logger.LogError(ex, "Could not deserialize string '{JsonString}' into an image cropper value.", sourceString); value = new ImageCropperValue { Src = sourceString }; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs index 3e6abdac64..f5228bd47e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs @@ -1,10 +1,8 @@ using System; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Composing; namespace Umbraco.Core.PropertyEditors.ValueConverters { @@ -18,13 +16,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class JsonValueConverter : PropertyValueConverterBase { private readonly PropertyEditorCollection _propertyEditors; + private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// - public JsonValueConverter(PropertyEditorCollection propertyEditors) + public JsonValueConverter(PropertyEditorCollection propertyEditors, ILogger logger) { _propertyEditors = propertyEditors; + _logger = logger; } /// @@ -58,7 +58,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters } catch (Exception ex) { - Current.Logger.Error(ex, "Could not parse the string '{JsonString}' to a json object", sourceString); + _logger.LogError(ex, "Could not parse the string '{JsonString}' to a json object", sourceString); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/VoidEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/VoidEditor.cs index f9a90a1323..e26cd4129a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/VoidEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/VoidEditor.cs @@ -1,5 +1,5 @@ -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Composing; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -18,11 +18,11 @@ namespace Umbraco.Core.PropertyEditors /// Initializes a new instance of the class. /// /// An optional alias suffix. - /// A logger. + /// A logger factory. /// The default alias of the editor is "Umbraco.Void". When a suffix is provided, /// it is appended to the alias. Eg if the suffix is "Foo" the alias is "Umbraco.Void.Foo". - public VoidEditor(string aliasSuffix, ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public VoidEditor(string aliasSuffix, ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { Alias = "Umbraco.Void"; if (string.IsNullOrWhiteSpace(aliasSuffix)) return; @@ -32,10 +32,10 @@ namespace Umbraco.Core.PropertyEditors /// /// Initializes a new instance of the class. /// - /// A logger. + /// A logger factory. /// The alias of the editor is "Umbraco.Void". - public VoidEditor(ILogger logger, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : this(null, logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) + public VoidEditor(ILoggerFactory loggerFactory, IDataTypeService dataTypeService, ILocalizationService localizationService, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) + : this(null, loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) { } } } diff --git a/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs b/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs index 1e798da3b2..4c1482c82c 100644 --- a/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs +++ b/src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.PublishedCache { @@ -23,11 +23,11 @@ namespace Umbraco.Web.PublishedCache private readonly IMediaTypeService _mediaTypeService; private readonly IMemberTypeService _memberTypeService; private readonly IPublishedContentTypeFactory _publishedContentTypeFactory; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); // default ctor - public PublishedContentTypeCache(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, IPublishedContentTypeFactory publishedContentTypeFactory, ILogger logger) + public PublishedContentTypeCache(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, IPublishedContentTypeFactory publishedContentTypeFactory, ILogger logger) { _contentTypeService = contentTypeService; _mediaTypeService = mediaTypeService; @@ -37,7 +37,7 @@ namespace Umbraco.Web.PublishedCache } // for unit tests ONLY - internal PublishedContentTypeCache(ILogger logger, IPublishedContentTypeFactory publishedContentTypeFactory) + internal PublishedContentTypeCache(ILogger logger, IPublishedContentTypeFactory publishedContentTypeFactory) { _logger = logger; _publishedContentTypeFactory = publishedContentTypeFactory; @@ -50,7 +50,7 @@ namespace Umbraco.Web.PublishedCache /// public void ClearAll() { - _logger.Debug("Clear all."); + _logger.LogDebug("Clear all."); try { @@ -72,7 +72,7 @@ namespace Umbraco.Web.PublishedCache /// An identifier. public void ClearContentType(int id) { - _logger.Debug("Clear content type w/id {ContentTypeId}", id); + _logger.LogDebug("Clear content type w/id {ContentTypeId}", id); try { @@ -107,7 +107,7 @@ namespace Umbraco.Web.PublishedCache /// A data type identifier. public void ClearDataType(int id) { - _logger.Debug("Clear data type w/id {DataTypeId}.", id); + _logger.LogDebug("Clear data type w/id {DataTypeId}.", id); // there is no recursion to handle here because a PublishedContentType contains *all* its // properties ie both its own properties and those that were inherited (it's based upon an diff --git a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs index ac8d0980c4..8f68ec0a64 100644 --- a/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs +++ b/src/Umbraco.Infrastructure/Routing/ContentFinderByConfigured404.cs @@ -1,9 +1,10 @@ -using Examine; using System.Globalization; using System.Linq; +using Examine; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -14,16 +15,20 @@ namespace Umbraco.Web.Routing /// public class ContentFinderByConfigured404 : IContentLastChanceFinder { - private readonly ILogger _logger; + 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; } @@ -34,7 +39,7 @@ namespace Umbraco.Web.Routing /// A value indicating whether an Umbraco document was found and assigned. public bool TryFindContent(IPublishedRequest frequest) { - _logger.Debug("Looking for a page to handle 404."); + _logger.LogDebug("Looking for a page to handle 404."); // try to find a culture as best as we can var errorCulture = CultureInfo.CurrentUICulture; @@ -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); @@ -72,17 +77,17 @@ namespace Umbraco.Web.Routing if (error404.HasValue) { - _logger.Debug("Got id={ErrorNodeId}.", error404.Value); + _logger.LogDebug("Got id={ErrorNodeId}.", error404.Value); content = frequest.UmbracoContext.Content.GetById(error404.Value); - _logger.Debug(content == null + _logger.LogDebug(content == null ? "Could not find content with that id." : "Found corresponding content."); } else { - _logger.Debug("Got nothing."); + _logger.LogDebug("Got nothing."); } frequest.PublishedContent = content; diff --git a/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs index 335e1f868a..ae50baa5b3 100644 --- a/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs +++ b/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs @@ -1,10 +1,11 @@ using System; using System.Globalization; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Composing; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Core.Xml; @@ -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) @@ -61,13 +62,13 @@ namespace Umbraco.Web.Routing } /// - /// Returns the content id based on the configured IContentErrorPage section + /// Returns the content id based on the configured ContentErrorPage section. /// /// /// /// /// - 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; @@ -107,7 +108,7 @@ namespace Umbraco.Web.Routing } catch (Exception ex) { - Current.Logger.Error(ex, "Could not parse xpath expression: {ContentXPath}", errorPage.ContentXPath); + Current.Logger.LogError(ex, "Could not parse xpath expression: {ContentXPath}", errorPage.ContentXPath); return null; } } 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..601a12ac1c 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs @@ -1,11 +1,12 @@ using System; using Examine; +using Microsoft.Extensions.Options; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.Grid; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Dashboards; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; @@ -18,7 +19,6 @@ using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Templates; using Umbraco.Core.Persistence; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; @@ -29,6 +29,7 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Sync; +using Umbraco.Core.Templates; using Umbraco.Examine; using Umbraco.Infrastructure.Examine; using Umbraco.Infrastructure.Media; @@ -41,6 +42,7 @@ using Umbraco.Web.Features; using Umbraco.Web.HealthCheck; using Umbraco.Web.HealthCheck.NotificationMethods; using Umbraco.Web.Install; +using Umbraco.Web.Media; using Umbraco.Web.Media.EmbedProviders; using Umbraco.Web.Migrations.PostMigrations; using Umbraco.Web.Models.PublishedContent; @@ -55,6 +57,8 @@ using Umbraco.Web.Templates; using Umbraco.Web.Trees; using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator; using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; +using Microsoft.Extensions.Logging; + namespace Umbraco.Core.Runtime { @@ -124,7 +128,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 @@ -145,6 +149,7 @@ namespace Umbraco.Core.Runtime factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), + factory.GetInstance>(), factory.GetInstance(), true, new DatabaseServerMessengerOptions(), factory.GetInstance(), @@ -163,7 +168,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(); @@ -201,13 +206,6 @@ namespace Umbraco.Core.Runtime // Config manipulator composition.RegisterUnique(); - - // register the http context and umbraco context accessors - // we *should* use the HttpContextUmbracoContextAccessor, however there are cases when - // we have no http context, eg when booting Umbraco or in background threads, so instead - // let's use an hybrid accessor that can fall back to a ThreadStatic context. - composition.RegisterUnique(); - // register the umbraco context factory // composition.RegisterUnique(); composition.RegisterUnique(); @@ -350,7 +348,6 @@ namespace Umbraco.Core.Runtime return new PublishedContentQuery(umbCtx.UmbracoContext.PublishedSnapshot, factory.GetInstance(), factory.GetInstance()); }, Lifetime.Request); - composition.RegisterUnique(); // register the http context and umbraco context accessors @@ -369,6 +366,8 @@ namespace Umbraco.Core.Runtime // Register noop versions for examine to be overridden by examine composition.RegisterUnique(); composition.RegisterUnique(); + + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 2f9766e5c2..4f921aa0c7 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -2,9 +2,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using Microsoft.Extensions.Logging; +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,17 +27,18 @@ 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, + ILoggerFactory loggerFactory, IProfiler profiler, IUmbracoBootPermissionChecker umbracoBootPermissionChecker, IHostingEnvironment hostingEnvironment, @@ -41,40 +46,37 @@ 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; + RuntimeLoggerFactory = loggerFactory; _umbracoBootPermissionChecker = umbracoBootPermissionChecker; - _requestCache = requestCache; - Logger = logger; + Logger = loggerFactory.CreateLogger(); 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 - }; } /// /// Gets the logger. /// - protected ILogger Logger { get; } + private ILogger Logger { get; } + + public ILoggerFactory RuntimeLoggerFactory { get; } protected IBackOfficeInfo BackOfficeInfo { get; } @@ -88,7 +90,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 +101,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; @@ -134,12 +137,12 @@ namespace Umbraco.Core.Runtime "Boot failed.")) { - Logger.Info("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.", + Logger.LogInformation("Booting site '{HostingSiteName}', app '{HostingApplicationId}', path '{HostingPhysicalPath}', server '{MachineName}'.", HostingEnvironment?.SiteName, HostingEnvironment?.ApplicationId, HostingEnvironment?.ApplicationPhysicalPath, NetworkHelper.MachineName); - Logger.Debug("Runtime: {Runtime}", GetType().FullName); + Logger.LogDebug("Runtime: {Runtime}", GetType().FullName); AppDomain.CurrentDomain.SetData("DataDirectory", HostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data)); @@ -164,31 +167,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), RuntimeLoggerFactory.CreateLogger(), ProfilingLogger); + + // re-create the state object with the essential services + _state = new RuntimeState(_globalSettings, UmbracoVersion, databaseFactory, RuntimeLoggerFactory.CreateLogger()); // 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, RuntimeLoggerFactory, 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 +248,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 +259,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, @@ -278,7 +279,7 @@ namespace Umbraco.Core.Runtime var msg = "Unhandled exception in AppDomain"; if (isTerminating) msg += " (terminating)"; msg += "."; - Logger.Error(exception, msg); + Logger.LogError(exception, msg); }; } @@ -293,7 +294,7 @@ namespace Umbraco.Core.Runtime enableDisableAttributes = typeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute)); } - var composers = new Composers(composition, composerTypes, enableDisableAttributes, ProfilingLogger); + var composers = new Composers(composition, composerTypes, enableDisableAttributes, RuntimeLoggerFactory.CreateLogger(), ProfilingLogger); composers.Compose(); } @@ -313,31 +314,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); + Logger.LogDebug("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; + Logger.LogDebug("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 +372,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 +384,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(RuntimeLoggerFactory.CreateLogger(), RuntimeLoggerFactory, 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/MainDomSemaphoreLock.cs b/src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs index 419a1781a2..eed13f5060 100644 --- a/src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/MainDomSemaphoreLock.cs @@ -1,8 +1,8 @@ using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; namespace Umbraco.Core.Runtime { @@ -16,10 +16,10 @@ namespace Umbraco.Core.Runtime // event wait handle used to notify current main domain that it should // release the lock because a new domain wants to be the main domain private readonly EventWaitHandle _signal; - private readonly ILogger _logger; + private readonly ILogger _logger; private IDisposable _lockRelease; - public MainDomSemaphoreLock(ILogger logger, IHostingEnvironment hostingEnvironment) + public MainDomSemaphoreLock(ILogger logger, IHostingEnvironment hostingEnvironment) { var lockName = "UMBRACO-" + MainDom.GetMainDomId(hostingEnvironment) + "-MAINDOM-LCK"; _systemLock = new SystemLock(lockName); @@ -52,7 +52,7 @@ namespace Umbraco.Core.Runtime } catch (TimeoutException ex) { - _logger.Error(ex); + _logger.LogError(ex.Message); return Task.FromResult(false); } finally 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..0f29dfe36c 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -6,9 +6,10 @@ using System.Linq; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Mappers; @@ -21,7 +22,7 @@ namespace Umbraco.Core.Runtime private string _lockId; private const string MainDomKeyPrefix = "Umbraco.Core.Runtime.SqlMainDom"; private const string UpdatedSuffix = "_updated"; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IHostingEnvironment _hostingEnvironment; private IUmbracoDatabase _db; private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); @@ -31,16 +32,16 @@ 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, ILoggerFactory loggerFactory, 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(); _logger = logger; _hostingEnvironment = hostingEnvironment; - _dbFactory = new UmbracoDatabaseFactory(_logger, + _dbFactory = new UmbracoDatabaseFactory(loggerFactory.CreateLogger(), + loggerFactory, globalSettings, connectionStrings, - Constants.System.UmbracoConnectionName, new Lazy(() => new MapperCollection(Enumerable.Empty())), dbProviderFactoryCreator); @@ -60,7 +61,7 @@ namespace Umbraco.Core.Runtime _sqlServerSyntax = sqlServerSyntaxProvider; - _logger.Debug("Acquiring lock..."); + _logger.LogDebug("Acquiring lock..."); var tempId = Guid.NewGuid().ToString(); @@ -78,7 +79,7 @@ namespace Umbraco.Core.Runtime { if (IsLockTimeoutException(ex)) { - _logger.Error(ex, "Sql timeout occurred, could not acquire MainDom."); + _logger.LogError(ex, "Sql timeout occurred, could not acquire MainDom."); _errorDuringAcquiring = true; return false; } @@ -93,7 +94,7 @@ namespace Umbraco.Core.Runtime // if we've inserted, then there was no MainDom so we can instantly acquire InsertLockRecord(_lockId, db); // so update with our appdomain id - _logger.Debug("Acquired with ID {LockId}", _lockId); + _logger.LogDebug("Acquired with ID {LockId}", _lockId); return true; } @@ -103,7 +104,7 @@ namespace Umbraco.Core.Runtime catch (Exception ex) { // unexpected - _logger.Error(ex, "Unexpected error, cannot acquire MainDom"); + _logger.LogError(ex, "Unexpected error, cannot acquire MainDom"); _errorDuringAcquiring = true; return false; } @@ -120,7 +121,7 @@ namespace Umbraco.Core.Runtime { if (_errorDuringAcquiring) { - _logger.Warn("Could not acquire MainDom, listening is canceled."); + _logger.LogWarning("Could not acquire MainDom, listening is canceled."); return Task.CompletedTask; } @@ -180,13 +181,13 @@ namespace Umbraco.Core.Runtime { // we are no longer main dom, another one has come online, exit _mainDomChanging = true; - _logger.Debug("Detected new booting application, releasing MainDom lock."); + _logger.LogDebug("Detected new booting application, releasing MainDom lock."); return; } } catch (Exception ex) { - _logger.Error(ex, "Unexpected error during listening."); + _logger.LogError(ex, "Unexpected error during listening."); // We need to keep on listening unless we've been notified by our own AppDomain to shutdown since // we don't want to shutdown resources controlled by MainDom inadvertently. We'll just keep listening otherwise. @@ -260,7 +261,7 @@ namespace Umbraco.Core.Runtime // so now we update the row with our appdomain id InsertLockRecord(_lockId, db); - _logger.Debug("Acquired with ID {LockId}", _lockId); + _logger.LogDebug("Acquired with ID {LockId}", _lockId); return true; } else if (mainDomRows.Count == 1 && !mainDomRows[0].Value.StartsWith(tempId)) @@ -269,7 +270,7 @@ namespace Umbraco.Core.Runtime // another new AppDomain has come online and is wanting to take over. In that case, we will not // acquire. - _logger.Debug("Cannot acquire, another booting application detected."); + _logger.LogDebug("Cannot acquire, another booting application detected."); return false; } } @@ -277,12 +278,12 @@ namespace Umbraco.Core.Runtime { if (IsLockTimeoutException(ex as SqlException)) { - _logger.Error(ex, "Sql timeout occurred, waiting for existing MainDom is canceled."); + _logger.LogError(ex, "Sql timeout occurred, waiting for existing MainDom is canceled."); _errorDuringAcquiring = true; return false; } // unexpected - _logger.Error(ex, "Unexpected error, waiting for existing MainDom is canceled."); + _logger.LogError(ex, "Unexpected error, waiting for existing MainDom is canceled."); _errorDuringAcquiring = true; return false; } @@ -303,7 +304,7 @@ namespace Umbraco.Core.Runtime // which isn't ideal. // So... we're going to 'just' take over, if the writelock works then we'll assume we're ok - _logger.Debug("Timeout elapsed, assuming orphan row, acquiring MainDom."); + _logger.LogDebug("Timeout elapsed, assuming orphan row, acquiring MainDom."); using var transaction = db.GetTransaction(IsolationLevel.ReadCommitted); @@ -313,7 +314,7 @@ namespace Umbraco.Core.Runtime // so now we update the row with our appdomain id InsertLockRecord(_lockId, db); - _logger.Debug("Acquired with ID {LockId}", _lockId); + _logger.LogDebug("Acquired with ID {LockId}", _lockId); return true; } catch (Exception ex) @@ -321,11 +322,11 @@ namespace Umbraco.Core.Runtime if (IsLockTimeoutException(ex as SqlException)) { // something is wrong, we cannot acquire, not much we can do - _logger.Error(ex, "Sql timeout occurred, could not forcibly acquire MainDom."); + _logger.LogError(ex, "Sql timeout occurred, could not forcibly acquire MainDom."); _errorDuringAcquiring = true; return false; } - _logger.Error(ex, "Unexpected error, could not forcibly acquire MainDom."); + _logger.LogError(ex, "Unexpected error, could not forcibly acquire MainDom."); _errorDuringAcquiring = true; return false; } @@ -398,18 +399,18 @@ namespace Umbraco.Core.Runtime // Otherwise, if we are just shutting down, we want to just delete the row. if (_mainDomChanging) { - _logger.Debug("Releasing MainDom, updating row, new application is booting."); + _logger.LogDebug("Releasing MainDom, updating row, new application is booting."); var count = db.Execute($"UPDATE umbracoKeyValue SET [value] = [value] + '{UpdatedSuffix}' WHERE [key] = @key", new { key = MainDomKey }); } else { - _logger.Debug("Releasing MainDom, deleting row, application is shutting down."); + _logger.LogDebug("Releasing MainDom, deleting row, application is shutting down."); var count = db.Execute("DELETE FROM umbracoKeyValue WHERE [key] = @key", new { key = MainDomKey }); } } catch (Exception ex) { - _logger.Error(ex, "Unexpected error during dipsose."); + _logger.LogError(ex, "Unexpected error during dipsose."); } finally { 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..cb2358d083 100644 --- a/src/Umbraco.Infrastructure/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/RuntimeState.cs @@ -1,11 +1,10 @@ using System; using System.Threading; using Semver; -using Umbraco.Core.Collections; +using Microsoft.Extensions.Logging; 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.LogDebug("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.LogDebug("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.LogDebug("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.LogWarning(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.LogDebug("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 @@ -162,7 +172,7 @@ namespace Umbraco.Core FinalMigrationState = upgrader.Plan.FinalState; } - logger.Debug("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", FinalMigrationState, CurrentMigrationState ?? ""); + logger.LogDebug("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", FinalMigrationState, CurrentMigrationState ?? ""); return CurrentMigrationState == FinalMigrationState; } diff --git a/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs b/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs index a9fff229f2..fbc68daca3 100644 --- a/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs +++ b/src/Umbraco.Infrastructure/Scheduling/BackgroundTaskRunner.cs @@ -2,10 +2,10 @@ using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Events; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; namespace Umbraco.Web.Scheduling { @@ -80,7 +80,7 @@ namespace Umbraco.Web.Scheduling private readonly string _logPrefix; private readonly BackgroundTaskRunnerOptions _options; - private readonly ILogger _logger; + private readonly ILogger> _logger; private readonly IApplicationShutdownRegistry _applicationShutdownRegistry; private readonly object _locker = new object(); @@ -105,7 +105,7 @@ namespace Umbraco.Web.Scheduling /// A logger. /// The application shutdown registry /// An optional main domain hook. - public BackgroundTaskRunner(ILogger logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) + public BackgroundTaskRunner(ILogger> logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) : this(typeof(T).FullName, new BackgroundTaskRunnerOptions(), logger, applicationShutdownRegistry, hook) { } @@ -116,7 +116,7 @@ namespace Umbraco.Web.Scheduling /// A logger. /// The application shutdown registry /// An optional main domain hook. - public BackgroundTaskRunner(string name, ILogger logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) + public BackgroundTaskRunner(string name, ILogger> logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) : this(name, new BackgroundTaskRunnerOptions(), logger, applicationShutdownRegistry, hook) { } @@ -127,7 +127,7 @@ namespace Umbraco.Web.Scheduling /// A logger. /// The application shutdown registry /// An optional main domain hook. - public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) + public BackgroundTaskRunner(BackgroundTaskRunnerOptions options, ILogger> logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) : this(typeof(T).FullName, options, logger, applicationShutdownRegistry, hook) { } @@ -139,7 +139,7 @@ namespace Umbraco.Web.Scheduling /// A logger. /// The application shutdown registry /// An optional main domain hook. - public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) + public BackgroundTaskRunner(string name, BackgroundTaskRunnerOptions options, ILogger> logger, IApplicationShutdownRegistry applicationShutdownRegistry, MainDomHook hook = null) { _options = options ?? throw new ArgumentNullException(nameof(options)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -245,7 +245,7 @@ namespace Umbraco.Web.Scheduling throw new InvalidOperationException("The task runner has completed."); // add task - _logger.Debug("{LogPrefix} Task Added {TaskType}", _logPrefix , task.GetType().FullName); + _logger.LogDebug("{LogPrefix} Task Added {TaskType}", _logPrefix , task.GetType().FullName); _tasks.Post(task); // start @@ -265,12 +265,12 @@ namespace Umbraco.Web.Scheduling { if (_completed) { - _logger.Debug("{LogPrefix} Task cannot be added {TaskType}, the task runner has already shutdown", _logPrefix, task.GetType().FullName); + _logger.LogDebug("{LogPrefix} Task cannot be added {TaskType}, the task runner has already shutdown", _logPrefix, task.GetType().FullName); return false; } // add task - _logger.Debug("{LogPrefix} Task added {TaskType}", _logPrefix, task.GetType().FullName); + _logger.LogDebug("{LogPrefix} Task added {TaskType}", _logPrefix, task.GetType().FullName); _tasks.Post(task); // start @@ -327,7 +327,7 @@ namespace Umbraco.Web.Scheduling _shutdownToken = _shutdownTokenSource.Token; _runningTask = Task.Run(async () => await Pump().ConfigureAwait(false), _shutdownToken); - _logger.Debug("{LogPrefix} Starting", _logPrefix); + _logger.LogDebug("{LogPrefix} Starting", _logPrefix); } /// @@ -348,7 +348,7 @@ namespace Umbraco.Web.Scheduling var hasTasks = TaskCount > 0; if (!force && hasTasks) - _logger.Info("{LogPrefix} Waiting for tasks to complete", _logPrefix); + _logger.LogInformation("{LogPrefix} Waiting for tasks to complete", _logPrefix); // complete the queue // will stop waiting on the queue or on a latch @@ -414,7 +414,7 @@ namespace Umbraco.Web.Scheduling } catch (Exception ex) { - _logger.Error(ex, "{LogPrefix} Task runner exception", _logPrefix); + _logger.LogError(ex, "{LogPrefix} Task runner exception", _logPrefix); } } } @@ -446,7 +446,7 @@ namespace Umbraco.Web.Scheduling if (_shutdownToken.IsCancellationRequested == false && TaskCount > 0) continue; // if we really have nothing to do, stop - _logger.Debug("{LogPrefix} Stopping", _logPrefix); + _logger.LogDebug("{LogPrefix} Stopping", _logPrefix); if (_options.PreserveRunningTask == false) _runningTask = null; @@ -573,7 +573,7 @@ namespace Umbraco.Web.Scheduling catch (Exception ex) { - _logger.Error(ex, "{LogPrefix} Task has failed", _logPrefix); + _logger.LogError(ex, "{LogPrefix} Task has failed", _logPrefix); } } @@ -607,7 +607,7 @@ namespace Umbraco.Web.Scheduling private void OnEvent(TypedEventHandler, TArgs> handler, string name, TArgs e) { - _logger.Debug("{LogPrefix} OnEvent {EventName}", _logPrefix, name); + _logger.LogDebug("{LogPrefix} OnEvent {EventName}", _logPrefix, name); if (handler == null) return; @@ -617,7 +617,7 @@ namespace Umbraco.Web.Scheduling } catch (Exception ex) { - _logger.Error(ex, "{LogPrefix} {Name} exception occurred", _logPrefix, name); + _logger.LogError(ex, "{LogPrefix} {Name} exception occurred", _logPrefix, name); } } @@ -704,7 +704,7 @@ namespace Umbraco.Web.Scheduling if (_terminating == false) { _terminating = true; - _logger.Info("{LogPrefix} Terminating {Immediate}", _logPrefix, immediate ? immediate.ToString() : string.Empty); + _logger.LogInformation("{LogPrefix} Terminating {Immediate}", _logPrefix, immediate ? immediate.ToString() : string.Empty); onTerminating = true; } } @@ -789,7 +789,7 @@ namespace Umbraco.Web.Scheduling /// private void StopImmediate() { - _logger.Info("{LogPrefix} Canceling tasks", _logPrefix); + _logger.LogInformation("{LogPrefix} Canceling tasks", _logPrefix); try { Shutdown(true, true); // cancel all tasks, wait for the current one to end @@ -823,7 +823,7 @@ namespace Umbraco.Web.Scheduling terminatedSource = _terminatedSource; } - _logger.Info("{LogPrefix} Tasks {TaskStatus}, terminated", + _logger.LogInformation("{LogPrefix} Tasks {TaskStatus}, terminated", _logPrefix, immediate ? "cancelled" : "completed"); diff --git a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs index adae7b3828..6198e7845d 100644 --- a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs +++ b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs @@ -2,11 +2,12 @@ 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; using Umbraco.Web.HealthCheck; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.Scheduling { @@ -16,8 +17,9 @@ namespace Umbraco.Web.Scheduling private readonly HealthCheckCollection _healthChecks; private readonly HealthCheckNotificationMethodCollection _notifications; private readonly IScopeProvider _scopeProvider; - private readonly IProfilingLogger _logger; - private readonly IHealthChecksSettings _healthChecksSettingsConfig; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; + private readonly HealthChecksSettings _healthChecksSettings; private readonly IServerRegistrar _serverRegistrar; private readonly IRuntimeState _runtimeState; @@ -28,8 +30,9 @@ namespace Umbraco.Web.Scheduling HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, IMainDom mainDom, - IProfilingLogger logger, - IHealthChecksSettings healthChecksSettingsConfig, + IProfilingLogger profilingLogger , + ILogger logger, + HealthChecksSettings healthChecksSettings, IServerRegistrar serverRegistrar, IRuntimeState runtimeState, IScopeProvider scopeProvider) @@ -40,8 +43,9 @@ namespace Umbraco.Web.Scheduling _mainDom = mainDom; _scopeProvider = scopeProvider; _runtimeState = runtimeState; + _profilingLogger = profilingLogger ; _logger = logger; - _healthChecksSettingsConfig = healthChecksSettingsConfig; + _healthChecksSettings = healthChecksSettings; _serverRegistrar = serverRegistrar; _runtimeState = runtimeState; } @@ -54,17 +58,17 @@ namespace Umbraco.Web.Scheduling switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Replica: - _logger.Debug("Does not run on replica servers."); + _logger.LogDebug("Does not run on replica servers."); return true; // DO repeat, server role can change case ServerRole.Unknown: - _logger.Debug("Does not run on servers with unknown role."); + _logger.LogDebug("Does not run on servers with unknown role."); return true; // DO repeat, server role can change } // ensure we do not run if not main domain, but do NOT lock it if (_mainDom.IsMainDom == false) { - _logger.Debug("Does not run if not MainDom."); + _logger.LogDebug("Does not run if not MainDom."); return false; // do NOT repeat, going down } @@ -72,9 +76,9 @@ namespace Umbraco.Web.Scheduling // checks can be making service/database calls so we want to ensure the CallContext/Ambient scope // isn't used since that can be problematic. using (var scope = _scopeProvider.CreateScope()) - using (_logger.DebugDuration("Health checks executing", "Health checks complete")) + using (_profilingLogger.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..c1b0b2e6d3 100644 --- a/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs +++ b/src/Umbraco.Infrastructure/Scheduling/LogScrubber.cs @@ -1,37 +1,41 @@ 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; using Umbraco.Core.Services; using Umbraco.Core.Sync; +using Microsoft.Extensions.Logging; 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 IProfilingLogger _logger; + private readonly LoggingSettings _settings; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _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 profilingLogger , ILogger logger) : base(runner, delayMilliseconds, periodMilliseconds) { _mainDom = mainDom; _serverRegistrar = serverRegistrar; _auditService = auditService; - _settings = settings; + _settings = settings.Value; _scopeProvider = scopeProvider; + _profilingLogger = profilingLogger ; _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 @@ -41,7 +45,7 @@ namespace Umbraco.Web.Scheduling } catch (Exception ex) { - _logger.Error(ex, "Unable to locate a log scrubbing maximum age. Defaulting to 24 hours."); + _logger.LogError(ex, "Unable to locate a log scrubbing maximum age. Defaulting to 24 hours."); } return maximumAge; @@ -58,23 +62,23 @@ namespace Umbraco.Web.Scheduling switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Replica: - _logger.Debug("Does not run on replica servers."); + _logger.LogDebug("Does not run on replica servers."); return true; // DO repeat, server role can change case ServerRole.Unknown: - _logger.Debug("Does not run on servers with unknown role."); + _logger.LogDebug("Does not run on servers with unknown role."); return true; // DO repeat, server role can change } // ensure we do not run if not main domain, but do NOT lock it if (_mainDom.IsMainDom == false) { - _logger.Debug("Does not run if not MainDom."); + _logger.LogDebug("Does not run if not MainDom."); return false; // do NOT repeat, going down } // Ensure we use an explicit scope since we are running on a background thread. using (var scope = _scopeProvider.CreateScope()) - using (_logger.DebugDuration("Log scrubbing executing", "Log scrubbing complete")) + using (_profilingLogger.DebugDuration("Log scrubbing executing", "Log scrubbing complete")) { _auditService.CleanLogs(GetLogScrubbingMaximumAge(_settings)); scope.Complete(); diff --git a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs index 6ec0250d90..81dd8f92af 100644 --- a/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/Scheduling/ScheduledPublishing.cs @@ -1,26 +1,27 @@ using System; using System.Linq; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Sync; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.Scheduling { public class ScheduledPublishing : RecurringTaskBase { private readonly IContentService _contentService; - private readonly ILogger _logger; + private readonly ILogger _logger; 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; @@ -42,24 +44,24 @@ namespace Umbraco.Web.Scheduling switch (_serverRegistrar.GetCurrentServerRole()) { case ServerRole.Replica: - _logger.Debug("Does not run on replica servers."); + _logger.LogDebug("Does not run on replica servers."); return true; // DO repeat, server role can change case ServerRole.Unknown: - _logger.Debug("Does not run on servers with unknown role."); + _logger.LogDebug("Does not run on servers with unknown role."); return true; // DO repeat, server role can change } // ensure we do not run if not main domain, but do NOT lock it if (_mainDom.IsMainDom == false) { - _logger.Debug("Does not run if not MainDom."); + _logger.LogDebug("Does not run if not MainDom."); return false; // do NOT repeat, going down } // do NOT run publishing if not properly running if (_runtime.Level != RuntimeLevel.Run) { - _logger.Debug("Does not run if run level is not Run."); + _logger.LogDebug("Does not run if run level is not Run."); return true; // repeat/wait } @@ -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 @@ -83,7 +86,7 @@ namespace Umbraco.Web.Scheduling // run var result = _contentService.PerformScheduledPublish(DateTime.Now); foreach (var grouped in result.GroupBy(x => x.Result)) - _logger.Info( + _logger.LogInformation( "Scheduled publishing result: '{StatusCount}' items with status {Status}", grouped.Count(), grouped.Key); } @@ -98,7 +101,7 @@ namespace Umbraco.Web.Scheduling catch (Exception ex) { // important to catch *everything* to ensure the task repeats - _logger.Error(ex, "Failed."); + _logger.LogError(ex, "Failed."); } return true; // repeat diff --git a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs index a5850719ab..c96071ff04 100644 --- a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs +++ b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs @@ -3,12 +3,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging; +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 +19,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; @@ -30,17 +31,20 @@ namespace Umbraco.Web.Scheduling private readonly IServerRegistrar _serverRegistrar; private readonly IContentService _contentService; private readonly IAuditService _auditService; - private readonly IProfilingLogger _logger; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IApplicationShutdownRegistry _applicationShutdownRegistry; private readonly IScopeProvider _scopeProvider; 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; @@ -56,11 +60,12 @@ namespace Umbraco.Web.Scheduling public SchedulerComponent(IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar, IContentService contentService, IAuditService auditService, HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications, - IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger logger, - IApplicationShutdownRegistry applicationShutdownRegistry, IHealthChecksSettings healthChecksSettingsConfig, + IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger profilingLogger , ILoggerFactory loggerFactory, + 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; @@ -68,28 +73,32 @@ namespace Umbraco.Web.Scheduling _contentService = contentService; _auditService = auditService; _scopeProvider = scopeProvider; - _logger = logger; + _profilingLogger = profilingLogger ; + _loggerFactory = loggerFactory; + _logger = loggerFactory.CreateLogger(); _applicationShutdownRegistry = applicationShutdownRegistry; _umbracoContextFactory = umbracoContextFactory; _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; } public void Initialize() { + var logger = _loggerFactory.CreateLogger>(); // backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly - _keepAliveRunner = new BackgroundTaskRunner("KeepAlive", _logger, _applicationShutdownRegistry); - _publishingRunner = new BackgroundTaskRunner("ScheduledPublishing", _logger, _applicationShutdownRegistry); - _scrubberRunner = new BackgroundTaskRunner("LogScrubber", _logger, _applicationShutdownRegistry); - _fileCleanupRunner = new BackgroundTaskRunner("TempFileCleanup", _logger, _applicationShutdownRegistry); - _healthCheckRunner = new BackgroundTaskRunner("HealthCheckNotifier", _logger, _applicationShutdownRegistry); + _keepAliveRunner = new BackgroundTaskRunner("KeepAlive", logger, _applicationShutdownRegistry); + _publishingRunner = new BackgroundTaskRunner("ScheduledPublishing", logger, _applicationShutdownRegistry); + _scrubberRunner = new BackgroundTaskRunner("LogScrubber", logger, _applicationShutdownRegistry); + _fileCleanupRunner = new BackgroundTaskRunner("TempFileCleanup", logger, _applicationShutdownRegistry); + _healthCheckRunner = new BackgroundTaskRunner("HealthCheckNotifier", logger, _applicationShutdownRegistry); // we will start the whole process when a successful request is made _requestAccessor.RouteAttempt += RegisterBackgroundTasksOnce; @@ -116,7 +125,7 @@ namespace Umbraco.Web.Scheduling { LazyInitializer.EnsureInitialized(ref _tasks, ref _started, ref _locker, () => { - _logger.Debug("Initializing the scheduler"); + _logger.LogDebug("Initializing the scheduler"); var tasks = new List(); @@ -129,19 +138,19 @@ 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)); + tasks.Add(RegisterHealthCheckNotifier(healthCheckConfig, _healthChecks, _notifications, _profilingLogger)); return tasks.ToArray(); }); } - 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), _loggerFactory.CreateLogger(), _profilingLogger, _serverRegistrar); _keepAliveRunner.TryAdd(task); return task; } @@ -150,12 +159,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, _loggerFactory.CreateLogger(), _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 +185,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, _loggerFactory.CreateLogger(), _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, _profilingLogger, _loggerFactory.CreateLogger()); _scrubberRunner.TryAdd(task); return task; } @@ -209,7 +218,7 @@ namespace Umbraco.Web.Scheduling var task = new TempFileCleanup(_fileCleanupRunner, DefaultDelayMilliseconds, OneHourMilliseconds, tempFolderPaths.Select(x=>new DirectoryInfo(x)), TimeSpan.FromDays(1), //files that are over a day old - _mainDom, _logger); + _mainDom, _profilingLogger, _loggerFactory.CreateLogger()); _scrubberRunner.TryAdd(task); return task; } diff --git a/src/Umbraco.Infrastructure/Scheduling/SimpleTask.cs b/src/Umbraco.Infrastructure/Scheduling/SimpleTask.cs new file mode 100644 index 0000000000..a8603915b0 --- /dev/null +++ b/src/Umbraco.Infrastructure/Scheduling/SimpleTask.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Umbraco.Web.Scheduling +{ + /// + /// A simple task that executes a delegate synchronously + /// + internal class SimpleTask : IBackgroundTask + { + private readonly Action _action; + + public SimpleTask(Action action) + { + _action = action; + } + + public bool IsAsync => false; + + public void Run() => _action(); + + public Task RunAsync(CancellationToken token) + { + throw new NotImplementedException(); + } + + public void Dispose() + { + } + } +} diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index 3b17ae876d..87986a6318 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -1,12 +1,12 @@ using System; using System.Data; +using Microsoft.Extensions.Logging; 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,9 +17,9 @@ 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 ILogger _logger; private readonly ITypeFinder _typeFinder; private readonly IsolationLevel _isolationLevel; @@ -39,9 +39,9 @@ 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, + ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, IScopeContext scopeContext, bool detachable, IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, @@ -118,9 +118,9 @@ 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, + ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, bool detachable, IScopeContext scopeContext, IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, @@ -132,9 +132,9 @@ 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, + ILogger logger, ITypeFinder typeFinder, FileSystems fileSystems, Scope parent, IsolationLevel isolationLevel = IsolationLevel.Unspecified, RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, @@ -323,7 +323,7 @@ namespace Umbraco.Core.Scoping if (completed.HasValue == false || completed.Value == false) { if (LogUncompletedScopes) - _logger.Debug("Uncompleted Child Scope at\r\n {StackTrace}", Environment.StackTrace); + _logger.LogDebug("Uncompleted Child Scope at\r\n {StackTrace}", Environment.StackTrace); _completed = false; } diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index 610f308b96..52c096b224 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.Logging; +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; @@ -22,20 +21,22 @@ namespace Umbraco.Core.Scoping /// internal class ScopeProvider : IScopeProvider, IScopeAccessor { - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; 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, ILoggerFactory loggerFactory, ITypeFinder typeFinder, IRequestCache requestCache) { DatabaseFactory = databaseFactory; _fileSystems = fileSystems; - _coreDebugSettings = coreDebugSettings; + _coreDebugSettings = coreDebugSettings.Value; _mediaFileSystem = mediaFileSystem; _logger = logger; + _loggerFactory = loggerFactory; _typeFinder = typeFinder; _requestCache = requestCache; // take control of the FileSystems @@ -93,7 +94,7 @@ namespace Umbraco.Core.Scoping { // first, null-register the existing value var ambientScope = CallContext.GetData(ScopeItemKey); - + if (ambientScope != null) RegisterContext(ambientScope, null); // then register the new value var scope = value as IScope; @@ -255,7 +256,7 @@ namespace Umbraco.Core.Scoping IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null) { - return new Scope(this, _coreDebugSettings, _mediaFileSystem, _logger, _typeFinder, _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems); + return new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _typeFinder, _fileSystems, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems); } /// @@ -311,13 +312,13 @@ namespace Umbraco.Core.Scoping { var ambientContext = AmbientContext; var newContext = ambientContext == null ? new ScopeContext() : null; - var scope = new Scope(this, _coreDebugSettings, _mediaFileSystem, _logger, _typeFinder, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); + var scope = new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _typeFinder, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); // assign only if scope creation did not throw! SetAmbient(scope, newContext ?? ambientContext); return scope; } - var nested = new Scope(this, _coreDebugSettings, _mediaFileSystem, _logger, _typeFinder, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); + var nested = new Scope(this, _coreDebugSettings, _mediaFileSystem, _loggerFactory.CreateLogger(), _typeFinder, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); SetAmbient(nested, AmbientContext); return nested; } diff --git a/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs b/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs index 1946e2041b..3f50c0b38c 100644 --- a/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs +++ b/src/Umbraco.Infrastructure/Search/BackgroundIndexRebuilder.cs @@ -3,6 +3,7 @@ using System.Threading; using Umbraco.Core.Logging; using Umbraco.Examine; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Hosting; using Umbraco.Web.Scheduling; @@ -12,19 +13,24 @@ 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; private readonly IMainDom _mainDom; - private readonly IProfilingLogger _logger; + // TODO: Remove unused ProfilingLogger? + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IApplicationShutdownRegistry _hostingEnvironment; private static BackgroundTaskRunner _rebuildOnStartupRunner; - public BackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger logger, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) + public BackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger profilingLogger , ILoggerFactory loggerFactory, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) { _mainDom = mainDom; - _logger = logger; + _profilingLogger = profilingLogger ; + _loggerFactory = loggerFactory; + _logger = loggerFactory.CreateLogger(); _hostingEnvironment = hostingEnvironment; _indexRebuilder = indexRebuilder; } @@ -34,7 +40,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 @@ -42,17 +48,17 @@ namespace Umbraco.Web.Search { if (_rebuildOnStartupRunner != null && _rebuildOnStartupRunner.IsRunning) { - _logger.Warn("Call was made to RebuildIndexes but the task runner for rebuilding is already running"); + _logger.LogWarning("Call was made to RebuildIndexes but the task runner for rebuilding is already running"); return; } - _logger.Info("Starting initialize async background thread."); + _logger.LogInformation("Starting initialize async background thread."); //do the rebuild on a managed background thread - var task = new RebuildOnStartupTask(_mainDom, _indexRebuilder, _logger, onlyEmptyIndexes, waitMilliseconds); + var task = new RebuildOnStartupTask(_mainDom, _indexRebuilder, _loggerFactory.CreateLogger(), onlyEmptyIndexes, waitMilliseconds); _rebuildOnStartupRunner = new BackgroundTaskRunner( "RebuildIndexesOnStartup", - _logger, _hostingEnvironment); + _loggerFactory.CreateLogger>(), _hostingEnvironment); _rebuildOnStartupRunner.TryAdd(task); } @@ -66,12 +72,12 @@ namespace Umbraco.Web.Search private readonly IMainDom _mainDom; private readonly IndexRebuilder _indexRebuilder; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly bool _onlyEmptyIndexes; private readonly int _waitMilliseconds; public RebuildOnStartupTask(IMainDom mainDom, - IndexRebuilder indexRebuilder, ILogger logger, bool onlyEmptyIndexes, int waitMilliseconds = 0) + IndexRebuilder indexRebuilder, ILogger logger, bool onlyEmptyIndexes, int waitMilliseconds = 0) { _mainDom = mainDom; _indexRebuilder = indexRebuilder ?? throw new ArgumentNullException(nameof(indexRebuilder)); @@ -95,7 +101,7 @@ namespace Umbraco.Web.Search } catch (Exception ex) { - _logger.Error(ex, "Failed to rebuild empty indexes."); + _logger.LogError(ex, "Failed to rebuild empty indexes."); } } diff --git a/src/Umbraco.Infrastructure/Search/ExamineComponent.cs b/src/Umbraco.Infrastructure/Search/ExamineComponent.cs index 35a8804ecb..46332aa730 100644 --- a/src/Umbraco.Infrastructure/Search/ExamineComponent.cs +++ b/src/Umbraco.Infrastructure/Search/ExamineComponent.cs @@ -5,6 +5,7 @@ using System.Linq; using Examine; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Scoping; @@ -13,9 +14,13 @@ using Umbraco.Core.Services.Changes; using Umbraco.Core.Sync; using Umbraco.Web.Cache; using Umbraco.Examine; +using Microsoft.Extensions.Logging; +using Umbraco.Web.Scheduling; namespace Umbraco.Web.Search { + + public sealed class ExamineComponent : Umbraco.Core.Composing.IComponent { private readonly IExamineManager _examineManager; @@ -24,13 +29,13 @@ 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; - private readonly IProfilingLogger _logger; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; private readonly IUmbracoIndexesCreator _indexCreator; - + private readonly BackgroundTaskRunner _indexItemTaskRunner; // the default enlist priority is 100 // enlist with a lower priority to ensure that anything "default" runs after us @@ -39,13 +44,15 @@ namespace Umbraco.Web.Search public ExamineComponent(IMainDom mainDom, IExamineManager examineManager, IProfilingLogger profilingLogger, + ILoggerFactory loggerFactory, IScopeProvider scopeProvider, IUmbracoIndexesCreator indexCreator, ServiceContext services, IContentValueSetBuilder contentValueSetBuilder, IPublishedContentValueSetBuilder publishedContentValueSetBuilder, IValueSetBuilder mediaValueSetBuilder, IValueSetBuilder memberValueSetBuilder, - BackgroundIndexRebuilder backgroundIndexRebuilder) + BackgroundIndexRebuilder backgroundIndexRebuilder, + IApplicationShutdownRegistry applicationShutdownRegistry) { _services = services; _scopeProvider = scopeProvider; @@ -56,8 +63,10 @@ namespace Umbraco.Web.Search _memberValueSetBuilder = memberValueSetBuilder; _backgroundIndexRebuilder = backgroundIndexRebuilder; _mainDom = mainDom; - _logger = profilingLogger; + _profilingLogger = profilingLogger; + _logger = loggerFactory.CreateLogger(); _indexCreator = indexCreator; + _indexItemTaskRunner = new BackgroundTaskRunner(loggerFactory.CreateLogger>(), applicationShutdownRegistry); } public void Initialize() @@ -65,7 +74,7 @@ namespace Umbraco.Web.Search //let's deal with shutting down Examine with MainDom var examineShutdownRegistered = _mainDom.Register(() => { - using (_logger.TraceDuration("Examine shutting down")) + using (_profilingLogger.TraceDuration("Examine shutting down")) { _examineManager.Dispose(); } @@ -73,7 +82,7 @@ namespace Umbraco.Web.Search if (!examineShutdownRegistered) { - _logger.Info("Examine shutdown not registered, this AppDomain is not the MainDom, Examine will be disabled"); + _logger.LogInformation("Examine shutdown not registered, this AppDomain is not the MainDom, Examine will be disabled"); //if we could not register the shutdown examine ourselves, it means we are not maindom! in this case all of examine should be disabled! Suspendable.ExamineEvents.SuspendIndexers(_logger); @@ -84,11 +93,11 @@ namespace Umbraco.Web.Search foreach(var index in _indexCreator.Create()) _examineManager.AddIndex(index); - _logger.Debug("Examine shutdown registered with MainDom"); + _logger.LogDebug("Examine shutdown registered with MainDom"); var registeredIndexers = _examineManager.Indexes.OfType().Count(x => x.EnableDefaultEventHandler); - _logger.Info("Adding examine event handlers for {RegisteredIndexers} index providers.", registeredIndexers); + _logger.LogInformation("Adding examine event handlers for {RegisteredIndexers} index providers.", registeredIndexers); // don't bind event handlers if we're not suppose to listen if (registeredIndexers == 0) @@ -104,7 +113,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 @@ -557,12 +572,18 @@ namespace Umbraco.Web.Search } } + /// + /// An action that will execute at the end of the Scope being completed + /// private abstract class DeferedAction { public virtual void Execute() { } } + /// + /// Re-indexes an item on a background thread + /// private class DeferedReIndexForContent : DeferedAction { private readonly ExamineComponent _examineComponent; @@ -583,41 +604,32 @@ namespace Umbraco.Web.Search public static void Execute(ExamineComponent examineComponent, IContent content, bool isPublished) { - // TODO: This is ugly, it is going to build the value set 3x and for 2 of those times it will be the same value - // set. We can do better. - - // TODO: We are .ToList() ing each of the calls to GetValueSets here. This is currently required but isn't the way - // that this was intended to work. Ideally, the IEnumerable package gets passed to Examine and it is only iterated/executed - // when the indexing takes place which would occur on a background thread. This is problematic with how the ContentValueSetBuilder - // in combination with UmbracoContentIndex.PerformIndexItems works because (at least what I've come to believe) we are using yield - // return in the GetValueSets call in combination with trying to lazily resolve the enumerable but because we GroupBy in - // UmbracoContentIndex.PerformIndexItems it's eagerly executed but then lazily executed again on the background thread and I believe - // that in doing this when the call is made to _userService.GetProfilesById it's trying to resolve a scope from an AsyncLocal instance - // that has already been disposed higher up it's chain. I 'think' to how the eager/lazy enumeration happens with yield return that it's - // capturing a scope/AsyncLocal instance that it shouldn't really be using. - - // TODO: We don't want these value sets to be eagerly built in this thread since this is most likely going to be a request thread. - // This is why the lazy execution of the Enumerable had the intended affect of executing only when requested on the background thread. - // This could still be acheived: Either we have a custom Enumerable/Enumerator to do this, or we simply call the below code - // on a background thread... which would be much easier! - - // TODO: I think this is an issue in v8 too! - - foreach (var index in examineComponent._examineManager.Indexes.OfType() - //filter the indexers - .Where(x => isPublished || !x.PublishedValuesOnly) - .Where(x => x.EnableDefaultEventHandler)) + // perform the ValueSet lookup on a background thread + examineComponent._indexItemTaskRunner.Add(new SimpleTask(() => { - //for content we have a different builder for published vs unpublished - var builder = index.PublishedValuesOnly - ? examineComponent._publishedContentValueSetBuilder - : (IValueSetBuilder)examineComponent._contentValueSetBuilder; + // for content we have a different builder for published vs unpublished + // we don't want to build more value sets than is needed so we'll lazily build 2 one for published one for non-published + var builders = new Dictionary>> + { + [true] = new Lazy>(() => examineComponent._publishedContentValueSetBuilder.GetValueSets(content).ToList()), + [false] = new Lazy>(() => examineComponent._contentValueSetBuilder.GetValueSets(content).ToList()) + }; - index.IndexItems(builder.GetValueSets(content).ToList()); - } + foreach (var index in examineComponent._examineManager.Indexes.OfType() + //filter the indexers + .Where(x => isPublished || !x.PublishedValuesOnly) + .Where(x => x.EnableDefaultEventHandler)) + { + var valueSet = builders[index.PublishedValuesOnly].Value; + index.IndexItems(valueSet); + } + })); } } + /// + /// Re-indexes an item on a background thread + /// private class DeferedReIndexForMedia : DeferedAction { private readonly ExamineComponent _examineComponent; @@ -638,18 +650,25 @@ namespace Umbraco.Web.Search public static void Execute(ExamineComponent examineComponent, IMedia media, bool isPublished) { - var valueSet = examineComponent._mediaValueSetBuilder.GetValueSets(media).ToList(); - - foreach (var index in examineComponent._examineManager.Indexes.OfType() - //filter the indexers - .Where(x => isPublished || !x.PublishedValuesOnly) - .Where(x => x.EnableDefaultEventHandler)) + // perform the ValueSet lookup on a background thread + examineComponent._indexItemTaskRunner.Add(new SimpleTask(() => { - index.IndexItems(valueSet); - } + var valueSet = examineComponent._mediaValueSetBuilder.GetValueSets(media).ToList(); + + foreach (var index in examineComponent._examineManager.Indexes.OfType() + //filter the indexers + .Where(x => isPublished || !x.PublishedValuesOnly) + .Where(x => x.EnableDefaultEventHandler)) + { + index.IndexItems(valueSet); + } + })); } } + /// + /// Re-indexes an item on a background thread + /// private class DeferedReIndexForMember : DeferedAction { private readonly ExamineComponent _examineComponent; @@ -668,13 +687,17 @@ namespace Umbraco.Web.Search public static void Execute(ExamineComponent examineComponent, IMember member) { - var valueSet = examineComponent._memberValueSetBuilder.GetValueSets(member).ToList(); - foreach (var index in examineComponent._examineManager.Indexes.OfType() - //filter the indexers - .Where(x => x.EnableDefaultEventHandler)) + // perform the ValueSet lookup on a background thread + examineComponent._indexItemTaskRunner.Add(new SimpleTask(() => { - index.IndexItems(valueSet); - } + var valueSet = examineComponent._memberValueSetBuilder.GetValueSets(member).ToList(); + foreach (var index in examineComponent._examineManager.Indexes.OfType() + //filter the indexers + .Where(x => x.EnableDefaultEventHandler)) + { + index.IndexItems(valueSet); + } + })); } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs index 7d3be1d52b..77c7b6610f 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/AuditService.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; 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; @@ -18,9 +17,9 @@ namespace Umbraco.Core.Services.Implement private readonly IAuditRepository _auditRepository; private readonly IAuditEntryRepository _auditEntryRepository; - public AuditService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public AuditService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IAuditRepository auditRepository, IAuditEntryRepository auditEntryRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _auditRepository = auditRepository; _auditEntryRepository = auditEntryRepository; diff --git a/src/Umbraco.Infrastructure/Services/Implement/ConsentService.cs b/src/Umbraco.Infrastructure/Services/Implement/ConsentService.cs index acc4683d64..1f33d1fe58 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ConsentService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ConsentService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -18,8 +18,8 @@ namespace Umbraco.Core.Services.Implement /// /// Initializes a new instance of the class. /// - public ConsentService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IConsentRepository consentRepository) - : base(provider, logger, eventMessagesFactory) + public ConsentService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IConsentRepository consentRepository) + : base(provider, loggerFactory, eventMessagesFactory) { _consentRepository = consentRepository; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs index 4cd85bc408..b796f9b686 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Querying; @@ -29,16 +29,17 @@ namespace Umbraco.Core.Services.Implement private readonly ILanguageRepository _languageRepository; private readonly Lazy _propertyValidationService; private readonly IShortStringHelper _shortStringHelper; + private readonly ILogger _logger; private IQuery _queryNotTrashed; #region Constructors - public ContentService(IScopeProvider provider, ILogger logger, + public ContentService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDocumentRepository documentRepository, IEntityRepository entityRepository, IAuditRepository auditRepository, IContentTypeRepository contentTypeRepository, IDocumentBlueprintRepository documentBlueprintRepository, ILanguageRepository languageRepository, Lazy propertyValidationService, IShortStringHelper shortStringHelper) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _documentRepository = documentRepository; _entityRepository = entityRepository; @@ -48,6 +49,7 @@ namespace Umbraco.Core.Services.Implement _languageRepository = languageRepository; _propertyValidationService = propertyValidationService; _shortStringHelper = shortStringHelper; + _logger = loggerFactory.CreateLogger(); } #endregion @@ -1417,7 +1419,7 @@ namespace Umbraco.Core.Services.Implement var result = CommitDocumentChangesInternal(scope, d, saveEventArgs, allLangs.Value, d.WriterId); if (result.Success == false) - Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); + _logger.LogError(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); results.Add(result); } @@ -1427,7 +1429,7 @@ namespace Umbraco.Core.Services.Implement d.ContentSchedule.Clear(ContentScheduleAction.Expire, date); var result = Unpublish(d, userId: d.WriterId); if (result.Success == false) - Logger.Error(null, "Failed to unpublish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); + _logger.LogError(null, "Failed to unpublish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); results.Add(result); } } @@ -1481,7 +1483,7 @@ namespace Umbraco.Core.Services.Implement var impact = CultureImpact.Explicit(culture, IsDefaultCulture(allLangs.Value, culture)); var tryPublish = d.PublishCulture(impact) && _propertyValidationService.Value.IsPropertyDataValid(d, out invalidProperties, impact); if (invalidProperties != null && invalidProperties.Length > 0) - Logger.Warn("Scheduled publishing will fail for document {DocumentId} and culture {Culture} because of invalid properties {InvalidProperties}", + _logger.LogWarning("Scheduled publishing will fail for document {DocumentId} and culture {Culture} because of invalid properties {InvalidProperties}", d.Id, culture, string.Join(",", invalidProperties.Select(x => x.Alias))); publishing &= tryPublish; //set the culture to be published @@ -1498,7 +1500,7 @@ namespace Umbraco.Core.Services.Implement result = CommitDocumentChangesInternal(scope, d, saveEventArgs, allLangs.Value, d.WriterId); if (result.Success == false) - Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); + _logger.LogError(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); results.Add(result); } @@ -1512,7 +1514,7 @@ namespace Umbraco.Core.Services.Implement : SaveAndPublish(d, userId: d.WriterId); if (result.Success == false) - Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); + _logger.LogError(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); results.Add(result); } @@ -2635,7 +2637,7 @@ namespace Umbraco.Core.Services.Implement // raise Publishing event if (scope.Events.DispatchCancelable(Publishing, this, savingEventArgs.ToContentPublishingEventArgs())) { - Logger.Info("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "publishing was cancelled"); + _logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "publishing was cancelled"); return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, content); } @@ -2687,7 +2689,7 @@ namespace Umbraco.Core.Services.Implement // either because it is 'publishing' or because it already has a published version if (content.PublishedState != PublishedState.Publishing && content.PublishedVersionId == 0) { - Logger.Info("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document does not have published values"); + _logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document does not have published values"); return new PublishResult(PublishResultType.FailedPublishNothingToPublish, evtMsgs, content); } @@ -2700,20 +2702,20 @@ namespace Umbraco.Core.Services.Implement { case ContentStatus.Expired: if (!variesByCulture) - Logger.Info("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document has expired"); + _logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document has expired"); else - Logger.Info("Document {ContentName} (id={ContentId}) culture {Culture} cannot be published: {Reason}", content.Name, content.Id, culture, "document culture has expired"); + _logger.LogInformation("Document {ContentName} (id={ContentId}) culture {Culture} cannot be published: {Reason}", content.Name, content.Id, culture, "document culture has expired"); return new PublishResult(!variesByCulture ? PublishResultType.FailedPublishHasExpired : PublishResultType.FailedPublishCultureHasExpired, evtMsgs, content); case ContentStatus.AwaitingRelease: if (!variesByCulture) - Logger.Info("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document is awaiting release"); + _logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document is awaiting release"); else - Logger.Info("Document {ContentName} (id={ContentId}) culture {Culture} cannot be published: {Reason}", content.Name, content.Id, culture, "document is culture awaiting release"); + _logger.LogInformation("Document {ContentName} (id={ContentId}) culture {Culture} cannot be published: {Reason}", content.Name, content.Id, culture, "document is culture awaiting release"); return new PublishResult(!variesByCulture ? PublishResultType.FailedPublishAwaitingRelease : PublishResultType.FailedPublishCultureAwaitingRelease, evtMsgs, content); case ContentStatus.Trashed: - Logger.Info("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document is trashed"); + _logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "document is trashed"); return new PublishResult(PublishResultType.FailedPublishIsTrashed, evtMsgs, content); } } @@ -2726,7 +2728,7 @@ namespace Umbraco.Core.Services.Implement var pathIsOk = content.ParentId == Constants.System.Root || IsPathPublished(GetParent(content)); if (!pathIsOk) { - Logger.Info("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "parent is not published"); + _logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "parent is not published"); return new PublishResult(PublishResultType.FailedPublishPathNotPublished, evtMsgs, content); } } @@ -2763,11 +2765,11 @@ namespace Umbraco.Core.Services.Implement return new PublishResult(PublishResultType.FailedPublishNothingToPublish, evtMsgs, content); if (culturesUnpublishing.Count > 0) - Logger.Info("Document {ContentName} (id={ContentId}) cultures: {Cultures} have been unpublished.", + _logger.LogInformation("Document {ContentName} (id={ContentId}) cultures: {Cultures} have been unpublished.", content.Name, content.Id, string.Join(",", culturesUnpublishing)); if (culturesPublishing.Count > 0) - Logger.Info("Document {ContentName} (id={ContentId}) cultures: {Cultures} have been published.", + _logger.LogInformation("Document {ContentName} (id={ContentId}) cultures: {Cultures} have been published.", content.Name, content.Id, string.Join(",", culturesPublishing)); if (culturesUnpublishing.Count > 0 && culturesPublishing.Count > 0) @@ -2779,7 +2781,7 @@ namespace Umbraco.Core.Services.Implement return new PublishResult(PublishResultType.SuccessPublishCulture, evtMsgs, content); } - Logger.Info("Document {ContentName} (id={ContentId}) has been published.", content.Name, content.Id); + _logger.LogInformation("Document {ContentName} (id={ContentId}) has been published.", content.Name, content.Id); return new PublishResult(evtMsgs, content); } @@ -2795,7 +2797,7 @@ namespace Umbraco.Core.Services.Implement // raise Unpublishing event if (scope.Events.DispatchCancelable(Unpublishing, this, new PublishEventArgs(content, evtMsgs))) { - Logger.Info("Document {ContentName} (id={ContentId}) cannot be unpublished: unpublishing was cancelled.", content.Name, content.Id); + _logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be unpublished: unpublishing was cancelled.", content.Name, content.Id); return new PublishResult(PublishResultType.FailedUnpublishCancelledByEvent, evtMsgs, content); } @@ -2827,12 +2829,12 @@ namespace Umbraco.Core.Services.Implement foreach (var p in pastReleases) content.ContentSchedule.Remove(p); if (pastReleases.Count > 0) - Logger.Info("Document {ContentName} (id={ContentId}) had its release date removed, because it was unpublished.", content.Name, content.Id); + _logger.LogInformation("Document {ContentName} (id={ContentId}) had its release date removed, because it was unpublished.", content.Name, content.Id); // change state to unpublishing content.PublishedState = PublishedState.Unpublishing; - Logger.Info("Document {ContentName} (id={ContentId}) has been unpublished.", content.Name, content.Id); + _logger.LogInformation("Document {ContentName} (id={ContentId}) has been unpublished.", content.Name, content.Id); return attempt; } @@ -3164,7 +3166,7 @@ namespace Umbraco.Core.Services.Implement if (rollbackSaveResult.Success == false) { //Log the error/warning - Logger.Error("User '{UserId}' was unable to rollback content '{ContentId}' to version '{VersionId}'", userId, id, versionId); + _logger.LogError("User '{UserId}' was unable to rollback content '{ContentId}' to version '{VersionId}'", userId, id, versionId); } else { @@ -3173,7 +3175,7 @@ namespace Umbraco.Core.Services.Implement scope.Events.Dispatch(RolledBack, this, rollbackEventArgs); //Logging & Audit message - Logger.Info("User '{UserId}' rolled back content '{ContentId}' to version '{VersionId}'", userId, id, versionId); + _logger.LogInformation("User '{UserId}' rolled back content '{ContentId}' to version '{VersionId}'", userId, id, versionId); Audit(AuditType.RollBack, userId, id, $"Content '{content.Name}' was rolled back to version '{versionId}'"); } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeService.cs index 206f11e5b0..ab7e70e852 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeService.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -14,9 +14,9 @@ namespace Umbraco.Core.Services.Implement /// public class ContentTypeService : ContentTypeServiceBase, IContentTypeService { - public ContentTypeService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IContentService contentService, + public ContentTypeService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IContentService contentService, IContentTypeRepository repository, IAuditRepository auditRepository, IDocumentTypeContainerRepository entityContainerRepository, IEntityRepository entityRepository) - : base(provider, logger, eventMessagesFactory, repository, auditRepository, entityContainerRepository, entityRepository) + : base(provider, loggerFactory, eventMessagesFactory, repository, auditRepository, entityContainerRepository, entityRepository) { ContentService = contentService; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBase.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBase.cs index 26298f171c..7067e27f59 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBase.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBase.cs @@ -1,13 +1,13 @@ -using Umbraco.Core.Events; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Events; using Umbraco.Core.Scoping; namespace Umbraco.Core.Services.Implement { public abstract class ContentTypeServiceBase : ScopeRepositoryService { - protected ContentTypeServiceBase(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory) - : base(provider, logger, eventMessagesFactory) + protected ContentTypeServiceBase(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { } } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs index a08bc3cd96..3241fa9d0e 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs @@ -1,5 +1,5 @@ -using Umbraco.Core.Events; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Scoping; using Umbraco.Core.Services.Changes; @@ -10,8 +10,8 @@ namespace Umbraco.Core.Services.Implement where TItem : class, IContentTypeComposition where TService : class, IContentTypeBaseService { - protected ContentTypeServiceBase(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory) - : base(provider, logger, eventMessagesFactory) + protected ContentTypeServiceBase(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { } protected abstract TService This { get; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index 9cd911e8d4..a3e3687b10 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Repositories; @@ -22,9 +22,9 @@ namespace Umbraco.Core.Services.Implement private readonly IEntityContainerRepository _containerRepository; private readonly IEntityRepository _entityRepository; - protected ContentTypeServiceBase(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + protected ContentTypeServiceBase(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, TRepository repository, IAuditRepository auditRepository, IEntityContainerRepository containerRepository, IEntityRepository entityRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { Repository = repository; _auditRepository = auditRepository; @@ -508,15 +508,15 @@ namespace Umbraco.Core.Services.Implement // delete content DeleteItemsOfTypes(descendantsAndSelf.Select(x => x.Id)); - + // Next find all other document types that have a reference to this content type var referenceToAllowedContentTypes = GetAll().Where(q => q.AllowedContentTypes.Any(p=>p.Id.Value==item.Id)); foreach (var reference in referenceToAllowedContentTypes) - { - reference.AllowedContentTypes = reference.AllowedContentTypes.Where(p => p.Id.Value != item.Id); + { + reference.AllowedContentTypes = reference.AllowedContentTypes.Where(p => p.Id.Value != item.Id); var changedRef = new List>() { new ContentTypeChange(reference, ContentTypeChangeTypes.RefreshMain) }; // Fire change event - OnChanged(scope, changedRef.ToEventArgs()); + OnChanged(scope, changedRef.ToEventArgs()); } // finally delete the content type @@ -525,7 +525,7 @@ namespace Umbraco.Core.Services.Implement // (contents of any descendant type have been deleted but // contents of any composed (impacted) type remain but // need to have their property data cleared) - Repository.Delete(item); + Repository.Delete(item); //... var changes = descendantsAndSelf.Select(x => new ContentTypeChange(x, ContentTypeChangeTypes.Remove)) diff --git a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs index 08bed264ae..eb6a94c4ee 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories; @@ -30,11 +30,11 @@ namespace Umbraco.Core.Services.Implement private readonly ILocalizationService _localizationService; private readonly IShortStringHelper _shortStringHelper; - public DataTypeService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public DataTypeService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDataTypeRepository dataTypeRepository, IDataTypeContainerRepository dataTypeContainerRepository, IAuditRepository auditRepository, IEntityRepository entityRepository, IContentTypeRepository contentTypeRepository, IIOHelper ioHelper, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _dataTypeRepository = dataTypeRepository; _dataTypeContainerRepository = dataTypeContainerRepository; @@ -324,7 +324,7 @@ namespace Umbraco.Core.Services.Implement .Where(x => x.Editor is MissingPropertyEditor); foreach (var dataType in dataTypesWithMissingEditors) { - dataType.Editor = new LabelPropertyEditor(Logger, _ioHelper, this, _localizedTextService, _localizationService, _shortStringHelper); + dataType.Editor = new LabelPropertyEditor(LoggerFactory, _ioHelper, this, _localizedTextService, _localizationService, _shortStringHelper); } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/DomainService.cs b/src/Umbraco.Infrastructure/Services/Implement/DomainService.cs index 32decb56d5..7bdce6f6cb 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/DomainService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/DomainService.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -11,9 +11,9 @@ namespace Umbraco.Core.Services.Implement { private readonly IDomainRepository _domainRepository; - public DomainService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public DomainService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDomainRepository domainRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _domainRepository = domainRepository; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/EntityService.cs b/src/Umbraco.Infrastructure/Services/Implement/EntityService.cs index 8436f56457..ccfbe4aacd 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/EntityService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/EntityService.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; @@ -21,8 +21,8 @@ namespace Umbraco.Core.Services.Implement private IQuery _queryRootEntity; private readonly IIdKeyMap _idKeyMap; - public EntityService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IIdKeyMap idKeyMap, IEntityRepository entityRepository) - : base(provider, logger, eventMessagesFactory) + public EntityService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IIdKeyMap idKeyMap, IEntityRepository entityRepository) + : base(provider, loggerFactory, eventMessagesFactory) { _idKeyMap = idKeyMap; _entityRepository = entityRepository; diff --git a/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs b/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs index c872cf6abb..e4a3f3638e 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models.Identity; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -12,9 +12,9 @@ namespace Umbraco.Core.Services.Implement { private readonly IExternalLoginRepository _externalLoginRepository; - public ExternalLoginService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public ExternalLoginService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IExternalLoginRepository externalLoginRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _externalLoginRepository = externalLoginRepository; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/FileService.cs b/src/Umbraco.Infrastructure/Services/Implement/FileService.cs index 188fad4c7b..e1f4a017b3 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/FileService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/FileService.cs @@ -3,12 +3,14 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; 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; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; @@ -29,17 +31,17 @@ 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"; private const string PartialViewMacroHeader = "@inherits Umbraco.Web.Common.Macros.PartialViewMacroPage"; - public FileService(IScopeProvider uowProvider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public FileService(IScopeProvider uowProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IStylesheetRepository stylesheetRepository, IScriptRepository scriptRepository, ITemplateRepository templateRepository, IPartialViewRepository partialViewRepository, IPartialViewMacroRepository partialViewMacroRepository, - IAuditRepository auditRepository, IShortStringHelper shortStringHelper, IGlobalSettings globalSettings, IHostingEnvironment hostingEnvironment) - : base(uowProvider, logger, eventMessagesFactory) + IAuditRepository auditRepository, IShortStringHelper shortStringHelper, IOptions globalSettings, IHostingEnvironment hostingEnvironment) + : base(uowProvider, loggerFactory, eventMessagesFactory) { _stylesheetRepository = stylesheetRepository; _scriptRepository = scriptRepository; @@ -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/LocalizationService.cs b/src/Umbraco.Infrastructure/Services/Implement/LocalizationService.cs index 251261cfc8..07fa0e1e77 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/LocalizationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/LocalizationService.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -18,9 +18,9 @@ namespace Umbraco.Core.Services.Implement private readonly ILanguageRepository _languageRepository; private readonly IAuditRepository _auditRepository; - public LocalizationService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public LocalizationService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDictionaryRepository dictionaryRepository, IAuditRepository auditRepository, ILanguageRepository languageRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _dictionaryRepository = dictionaryRepository; _auditRepository = auditRepository; diff --git a/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs b/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs index 4f5121def7..4d12f111e3 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs @@ -4,7 +4,7 @@ using System.Globalization; using System.Linq; using System.Xml.Linq; using System.Xml.XPath; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Services.Implement { @@ -12,7 +12,7 @@ namespace Umbraco.Core.Services.Implement public class LocalizedTextService : ILocalizedTextService { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly Lazy _fileSources; private readonly IDictionary>> _dictionarySource; private readonly IDictionary> _xmlSource; @@ -22,7 +22,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// - public LocalizedTextService(Lazy fileSources, ILogger logger) + public LocalizedTextService(Lazy fileSources, ILogger logger) { if (logger == null) throw new ArgumentNullException("logger"); _logger = logger; @@ -35,7 +35,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// - public LocalizedTextService(IDictionary> source, ILogger logger) + public LocalizedTextService(IDictionary> source, ILogger logger) { if (source == null) throw new ArgumentNullException("source"); if (logger == null) throw new ArgumentNullException("logger"); @@ -48,7 +48,7 @@ namespace Umbraco.Core.Services.Implement /// /// /// - public LocalizedTextService(IDictionary>> source, ILogger logger) + public LocalizedTextService(IDictionary>> source, ILogger logger) { _dictionarySource = source ?? throw new ArgumentNullException(nameof(source)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -104,7 +104,7 @@ namespace Umbraco.Core.Services.Implement { if (xmlSource.ContainsKey(culture) == false) { - _logger.Warn("The culture specified {Culture} was not found in any configured sources for this service", culture); + _logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture); return result; } @@ -124,7 +124,7 @@ namespace Umbraco.Core.Services.Implement { if (_dictionarySource.ContainsKey(culture) == false) { - _logger.Warn("The culture specified {Culture} was not found in any configured sources for this service", culture); + _logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture); return result; } @@ -207,7 +207,7 @@ namespace Umbraco.Core.Services.Implement { if (_dictionarySource.ContainsKey(culture) == false) { - _logger.Warn("The culture specified {Culture} was not found in any configured sources for this service", culture); + _logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture); return "[" + key + "]"; } @@ -245,7 +245,7 @@ namespace Umbraco.Core.Services.Implement { if (xmlSource.ContainsKey(culture) == false) { - _logger.Warn("The culture specified {Culture} was not found in any configured sources for this service", culture); + _logger.LogWarning("The culture specified {Culture} was not found in any configured sources for this service", culture); return "[" + key + "]"; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextServiceFileSources.cs b/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextServiceFileSources.cs index 77bc82f092..b4c49b9509 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextServiceFileSources.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/LocalizedTextServiceFileSources.cs @@ -8,7 +8,7 @@ using System.Xml.Linq; using Umbraco.Composing; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Services.Implement { @@ -17,7 +17,7 @@ namespace Umbraco.Core.Services.Implement /// public class LocalizedTextServiceFileSources { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IAppPolicyCache _cache; private readonly IEnumerable _supplementFileSources; private readonly DirectoryInfo _fileSourceFolder; @@ -37,7 +37,7 @@ namespace Umbraco.Core.Services.Implement /// /// public LocalizedTextServiceFileSources( - ILogger logger, + ILogger logger, AppCaches appCaches, DirectoryInfo fileSourceFolder, IEnumerable supplementFileSources) @@ -51,7 +51,7 @@ namespace Umbraco.Core.Services.Implement if (fileSourceFolder.Exists == false) { - Current.Logger.Warn("The folder does not exist: {FileSourceFolder}, therefore no sources will be discovered", fileSourceFolder.FullName); + _logger.LogWarning("The folder does not exist: {FileSourceFolder}, therefore no sources will be discovered", fileSourceFolder.FullName); } else { @@ -99,7 +99,7 @@ namespace Umbraco.Core.Services.Implement } catch (CultureNotFoundException) { - Current.Logger.Warn("The culture {CultureValue} found in the file {CultureFile} is not a valid culture", cultureVal, fileInfo.FullName); + _logger.LogWarning("The culture {CultureValue} found in the file {CultureFile} is not a valid culture", cultureVal, fileInfo.FullName); //If the culture in the file is invalid, we'll just hope the file name is a valid culture below, otherwise // an exception will be thrown. } @@ -140,7 +140,7 @@ namespace Umbraco.Core.Services.Implement /// /// Constructor /// - public LocalizedTextServiceFileSources(ILogger logger, AppCaches appCaches, DirectoryInfo fileSourceFolder) + public LocalizedTextServiceFileSources(ILogger logger, AppCaches appCaches, DirectoryInfo fileSourceFolder) : this(logger, appCaches, fileSourceFolder, Enumerable.Empty()) { } @@ -206,7 +206,7 @@ namespace Umbraco.Core.Services.Implement } catch (Exception ex) { - _logger.Error(ex, "Could not load file into XML {File}", supplementaryFile.File.FullName); + _logger.LogError(ex, "Could not load file into XML {File}", supplementaryFile.File.FullName); continue; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/MacroService.cs b/src/Umbraco.Infrastructure/Services/Implement/MacroService.cs index a6631aae4c..98bc633fa9 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MacroService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MacroService.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -17,9 +17,9 @@ namespace Umbraco.Core.Services.Implement private readonly IMacroRepository _macroRepository; private readonly IAuditRepository _auditRepository; - public MacroService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public MacroService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IMacroRepository macroRepository, IAuditRepository auditRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _macroRepository = macroRepository; _auditRepository = auditRepository; diff --git a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs index 5e9854ad9e..0672c3218f 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs @@ -4,9 +4,9 @@ using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Querying; @@ -32,10 +32,10 @@ namespace Umbraco.Core.Services.Implement #region Constructors - public MediaService(IScopeProvider provider, IMediaFileSystem mediaFileSystem, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public MediaService(IScopeProvider provider, IMediaFileSystem mediaFileSystem, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IMediaRepository mediaRepository, IAuditRepository auditRepository, IMediaTypeRepository mediaTypeRepository, IEntityRepository entityRepository, IShortStringHelper shortStringHelper) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _mediaFileSystem = mediaFileSystem; _mediaRepository = mediaRepository; diff --git a/src/Umbraco.Infrastructure/Services/Implement/MediaTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/MediaTypeService.cs index 8cb69a655d..73ce6822a1 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MediaTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MediaTypeService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -10,10 +10,10 @@ namespace Umbraco.Core.Services.Implement { public class MediaTypeService : ContentTypeServiceBase, IMediaTypeService { - public MediaTypeService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMediaService mediaService, + public MediaTypeService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IMediaService mediaService, IMediaTypeRepository mediaTypeRepository, IAuditRepository auditRepository, IMediaTypeContainerRepository entityContainerRepository, IEntityRepository entityRepository) - : base(provider, logger, eventMessagesFactory, mediaTypeRepository, auditRepository, entityContainerRepository, entityRepository) + : base(provider, loggerFactory, eventMessagesFactory, mediaTypeRepository, auditRepository, entityContainerRepository, entityRepository) { MediaService = mediaService; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/MemberGroupService.cs b/src/Umbraco.Infrastructure/Services/Implement/MemberGroupService.cs index 308080bbf4..9947e50661 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MemberGroupService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MemberGroupService.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; @@ -14,9 +14,9 @@ namespace Umbraco.Core.Services.Implement { private readonly IMemberGroupRepository _memberGroupRepository; - public MemberGroupService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public MemberGroupService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IMemberGroupRepository memberGroupRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _memberGroupRepository = memberGroupRepository; //Proxy events! diff --git a/src/Umbraco.Infrastructure/Services/Implement/MemberService.cs b/src/Umbraco.Infrastructure/Services/Implement/MemberService.cs index 5143cd6203..4ae0458910 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MemberService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MemberService.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Querying; @@ -28,9 +28,9 @@ namespace Umbraco.Core.Services.Implement #region Constructor - public MemberService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberGroupService memberGroupService, + public MemberService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IMemberGroupService memberGroupService, IMemberRepository memberRepository, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, IAuditRepository auditRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _memberRepository = memberRepository; _memberTypeRepository = memberTypeRepository; @@ -435,15 +435,10 @@ namespace Umbraco.Core.Services.Implement /// public IMember GetByUsername(string username) { - // TODO: Somewhere in here, whether at this level or the repository level, we need to add - // a caching mechanism since this method is used by all the membership providers and could be - // called quite a bit when dealing with members. - using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { - scope.ReadLock(Constants.Locks.MemberTree); - var query = Query().Where(x => x.Username.Equals(username)); - return _memberRepository.Get(query).FirstOrDefault(); + scope.ReadLock(Constants.Locks.MemberTree); + return _memberRepository.GetByUsername(username); } } @@ -793,12 +788,17 @@ namespace Umbraco.Core.Services.Implement #region Save - /// - /// Saves an - /// - /// to Save - /// Optional parameter to raise events. - /// Default is True otherwise set to False to not raise events + /// + public void SetLastLogin(string username, DateTime date) + { + using (var scope = ScopeProvider.CreateScope()) + { + _memberRepository.SetLastLogin(username, date); + scope.Complete(); + } + } + + /// public void Save(IMember member, bool raiseEvents = true) { //trimming username and email to make sure we have no trailing space @@ -834,12 +834,7 @@ namespace Umbraco.Core.Services.Implement } } - /// - /// Saves a list of objects - /// - /// to save - /// Optional parameter to raise events. - /// Default is True otherwise set to False to not raise events + /// public void Save(IEnumerable members, bool raiseEvents = true) { var membersA = members.ToArray(); @@ -986,7 +981,7 @@ namespace Umbraco.Core.Services.Implement return result.Select(x => x.Id).Distinct(); } } - + public IEnumerable GetMembersInRole(string roleName) { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) diff --git a/src/Umbraco.Infrastructure/Services/Implement/MemberTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/MemberTypeService.cs index 05f32dc99c..b3c443b9a4 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MemberTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MemberTypeService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -12,9 +12,9 @@ namespace Umbraco.Core.Services.Implement { private readonly IMemberTypeRepository _memberTypeRepository; - public MemberTypeService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberService memberService, + public MemberTypeService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IMemberService memberService, IMemberTypeRepository memberTypeRepository, IAuditRepository auditRepository, IEntityRepository entityRepository) - : base(provider, logger, eventMessagesFactory, memberTypeRepository, auditRepository, null, entityRepository) + : base(provider, loggerFactory, eventMessagesFactory, memberTypeRepository, auditRepository, null, entityRepository) { MemberService = memberService; _memberTypeRepository = memberTypeRepository; diff --git a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs index cf53fb34cd..7964cd273e 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs @@ -3,14 +3,13 @@ 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 Microsoft.Extensions.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; @@ -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 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)); @@ -510,7 +509,7 @@ namespace Umbraco.Core.Services.Implement { ThreadPool.QueueUserWorkItem(state => { - _logger.Debug("Begin processing notifications."); + _logger.LogDebug("Begin processing notifications."); while (true) { NotificationRequest request; @@ -519,11 +518,11 @@ namespace Umbraco.Core.Services.Implement try { _emailSender.SendAsync(request.Mail).GetAwaiter().GetResult(); - _logger.Debug("Notification '{Action}' sent to {Username} ({Email})", request.Action, request.UserName, request.Email); + _logger.LogDebug("Notification '{Action}' sent to {Username} ({Email})", request.Action, request.UserName, request.Email); } catch (Exception ex) { - _logger.Error(ex, "An error occurred sending notification"); + _logger.LogError(ex, "An error occurred sending notification"); } finally { @@ -538,7 +537,7 @@ namespace Umbraco.Core.Services.Implement } } - _logger.Debug("Done processing notifications."); + _logger.LogDebug("Done processing notifications."); }); } 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/PublicAccessService.cs b/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs index f2af6cf424..2143d638fe 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -13,9 +13,9 @@ namespace Umbraco.Core.Services.Implement { private readonly IPublicAccessRepository _publicAccessRepository; - public PublicAccessService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public PublicAccessService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IPublicAccessRepository publicAccessRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _publicAccessRepository = publicAccessRepository; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/RedirectUrlService.cs b/src/Umbraco.Infrastructure/Services/Implement/RedirectUrlService.cs index 80816961fc..bc629044bd 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/RedirectUrlService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/RedirectUrlService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -12,9 +12,9 @@ namespace Umbraco.Core.Services.Implement { private readonly IRedirectUrlRepository _redirectUrlRepository; - public RedirectUrlService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public RedirectUrlService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IRedirectUrlRepository redirectUrlRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _redirectUrlRepository = redirectUrlRepository; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/RelationService.cs b/src/Umbraco.Infrastructure/Services/Implement/RelationService.cs index c629466edf..f00478b668 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/RelationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/RelationService.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Repositories; @@ -17,9 +17,9 @@ namespace Umbraco.Core.Services.Implement private readonly IRelationTypeRepository _relationTypeRepository; private readonly IAuditRepository _auditRepository; - public RelationService(IScopeProvider uowProvider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IEntityService entityService, + public RelationService(IScopeProvider uowProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IEntityService entityService, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository, IAuditRepository auditRepository) - : base(uowProvider, logger, eventMessagesFactory) + : base(uowProvider, loggerFactory, eventMessagesFactory) { _relationRepository = relationRepository; _relationTypeRepository = relationTypeRepository; @@ -172,6 +172,18 @@ namespace Umbraco.Core.Services.Implement } } + /// + public IRelation GetByParentAndChildId(int parentId, int childId, IRelationType relationType) + { + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + { + var query = Query().Where(x => x.ParentId == parentId && + x.ChildId == childId && + x.RelationTypeId == relationType.Id); + return _relationRepository.Get(query).FirstOrDefault(); + } + } + /// public IEnumerable GetByRelationTypeName(string relationTypeName) { @@ -193,7 +205,7 @@ namespace Umbraco.Core.Services.Implement public IEnumerable GetByRelationTypeAlias(string relationTypeAlias) { var relationType = GetRelationType(relationTypeAlias); - + return relationType == null ? Enumerable.Empty() : GetRelationsByListOfTypeIds(new[] { relationType.Id }); @@ -296,7 +308,7 @@ namespace Umbraco.Core.Services.Implement /// public IEnumerable> GetEntitiesFromRelations(IEnumerable relations) { - //TODO: Argh! N+1 + //TODO: Argh! N+1 foreach (var relation in relations) { diff --git a/src/Umbraco.Infrastructure/Services/Implement/RepositoryService.cs b/src/Umbraco.Infrastructure/Services/Implement/RepositoryService.cs index 88cbc1db76..3be66fea27 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/RepositoryService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/RepositoryService.cs @@ -1,6 +1,6 @@ using System; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Scoping; @@ -11,15 +11,15 @@ namespace Umbraco.Core.Services.Implement /// public abstract class RepositoryService : IService { - protected ILogger Logger { get; } protected IEventMessagesFactory EventMessagesFactory { get; } protected IScopeProvider ScopeProvider { get; } + protected ILoggerFactory LoggerFactory { get; } - protected RepositoryService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory) + protected RepositoryService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory) { - Logger = logger ?? throw new ArgumentNullException(nameof(logger)); EventMessagesFactory = eventMessagesFactory ?? throw new ArgumentNullException(nameof(eventMessagesFactory)); ScopeProvider = provider ?? throw new ArgumentNullException(nameof(provider)); + LoggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); } protected IQuery Query() => ScopeProvider.SqlContext.Query(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/ScopeRepositoryService.cs b/src/Umbraco.Infrastructure/Services/Implement/ScopeRepositoryService.cs index d7303991b5..9e1cf94b19 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ScopeRepositoryService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ScopeRepositoryService.cs @@ -1,5 +1,5 @@ -using Umbraco.Core.Events; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Events; using Umbraco.Core.Scoping; namespace Umbraco.Core.Services.Implement @@ -7,8 +7,8 @@ namespace Umbraco.Core.Services.Implement // TODO: that one does not add anything = kill public abstract class ScopeRepositoryService : RepositoryService { - protected ScopeRepositoryService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory) - : base(provider, logger, eventMessagesFactory) + protected ScopeRepositoryService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { } } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs index 6a092b159f..6e5316272b 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Events; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; @@ -27,11 +27,11 @@ namespace Umbraco.Core.Services.Implement /// Initializes a new instance of the class. /// /// A UnitOfWork provider. - /// A logger. + /// A logger factory /// - public ServerRegistrationService(IScopeProvider scopeProvider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public ServerRegistrationService(IScopeProvider scopeProvider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IServerRegistrationRepository serverRegistrationRepository, IHostingEnvironment hostingEnvironment) - : base(scopeProvider, logger, eventMessagesFactory) + : base(scopeProvider, loggerFactory, eventMessagesFactory) { _serverRegistrationRepository = serverRegistrationRepository; _hostingEnvironment = hostingEnvironment; diff --git a/src/Umbraco.Infrastructure/Services/Implement/TagService.cs b/src/Umbraco.Infrastructure/Services/Implement/TagService.cs index e888258067..a5161b22d6 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/TagService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/TagService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Scoping; @@ -18,9 +18,9 @@ namespace Umbraco.Core.Services.Implement { private readonly ITagRepository _tagRepository; - public TagService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, + public TagService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, ITagRepository tagRepository) - : base(provider, logger, eventMessagesFactory) + : base(provider, loggerFactory, eventMessagesFactory) { _tagRepository = tagRepository; } diff --git a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs index faf7889fbf..a6b55a1dc3 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/UserService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/UserService.cs @@ -4,9 +4,11 @@ using System.Data.Common; using System.Globalization; using System.Linq; using System.Linq.Expressions; +using Microsoft.Extensions.Logging; +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; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; @@ -22,17 +24,19 @@ 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; + private readonly ILogger _logger; - public UserService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IRuntimeState runtimeState, - IUserRepository userRepository, IUserGroupRepository userGroupRepository, IGlobalSettings globalSettings) - : base(provider, logger, eventMessagesFactory) + public UserService(IScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IRuntimeState runtimeState, + IUserRepository userRepository, IUserGroupRepository userGroupRepository, IOptions globalSettings) + : base(provider, loggerFactory, eventMessagesFactory) { _userRepository = userRepository; _userGroupRepository = userGroupRepository; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _isUpgrading = runtimeState.Level == RuntimeLevel.Install || runtimeState.Level == RuntimeLevel.Upgrade; + _logger = loggerFactory.CreateLogger(); } #region Implementation of IMembershipUserService @@ -252,6 +256,13 @@ namespace Umbraco.Core.Services.Implement } } + // explicit implementation because we don't need it now but due to the way that the members membership provider is put together + // this method must exist in this service as an implementation (legacy) + void IMembershipMemberService.SetLastLogin(string username, DateTime date) + { + throw new NotSupportedException("This method is not implemented or supported for users"); + } + /// /// Saves an /// @@ -291,7 +302,7 @@ namespace Umbraco.Core.Services.Implement // if we are upgrading and an exception occurs, log and swallow it if (_isUpgrading == false) throw; - Logger.Warn(ex, "An error occurred attempting to save a user instance during upgrade, normally this warning can be ignored"); + _logger.LogWarning(ex, "An error occurred attempting to save a user instance during upgrade, normally this warning can be ignored"); // we don't want the uow to rollback its scope! scope.Complete(); @@ -939,7 +950,7 @@ namespace Umbraco.Core.Services.Implement { var nodeIds = path.GetIdsFromPathReversed(); - if (nodeIds.Length == 0) + if (nodeIds.Length == 0 || user is null) return EntityPermissionSet.Empty(); //collect all permissions structures for all nodes for all groups belonging to the user diff --git a/src/Umbraco.Infrastructure/Suspendable.cs b/src/Umbraco.Infrastructure/Suspendable.cs index 7287d1c364..e03931d0d7 100644 --- a/src/Umbraco.Infrastructure/Suspendable.cs +++ b/src/Umbraco.Infrastructure/Suspendable.cs @@ -1,6 +1,6 @@ -using Umbraco.Composing; +using Microsoft.Extensions.Logging; +using Umbraco.Composing; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Examine; using Umbraco.Web.Cache; using Umbraco.Web.Search; @@ -30,7 +30,7 @@ namespace Umbraco.Web public static void SuspendDocumentCache() { - Current.Logger.Info(typeof (PageCacheRefresher), "Suspend document cache."); + Current.Logger.LogInformation("Suspend document cache."); _suspended = true; } @@ -38,7 +38,7 @@ namespace Umbraco.Web { _suspended = false; - Current.Logger.Info(typeof (PageCacheRefresher), "Resume document cache (reload:{Tried}).", _tried); + Current.Logger.LogInformation("Resume document cache (reload:{Tried}).", _tried); if (_tried == false) return; _tried = false; @@ -66,7 +66,7 @@ namespace Umbraco.Web public static void SuspendIndexers(ILogger logger) { - logger.Info(typeof (ExamineEvents), "Suspend indexers."); + logger.LogInformation("Suspend indexers."); _suspended = true; } @@ -74,7 +74,7 @@ namespace Umbraco.Web { _suspended = false; - logger.Info(typeof (ExamineEvents), "Resume indexers (rebuild:{Tried}).", _tried); + Current.Logger.LogInformation("Resume indexers (rebuild:{Tried}).", _tried); if (_tried == false) return; _tried = false; @@ -91,13 +91,13 @@ namespace Umbraco.Web public static void Suspend() { - Current.Logger.Info(typeof (ScheduledPublishing), "Suspend scheduled publishing."); + Current.Logger.LogInformation("Suspend scheduled publishing."); _suspended = true; } public static void Resume() { - Current.Logger.Info(typeof (ScheduledPublishing), "Resume scheduled publishing."); + Current.Logger.LogInformation("Resume scheduled publishing."); _suspended = false; } } diff --git a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs index 2f6bb61e42..16a83f45fe 100644 --- a/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Infrastructure/Sync/DatabaseServerMessenger.cs @@ -8,6 +8,7 @@ using System.Threading; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NPoco; +using Microsoft.Extensions.Logging; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Logging; @@ -47,7 +48,7 @@ namespace Umbraco.Core.Sync public DatabaseServerMessengerOptions Options { get; } public DatabaseServerMessenger( - IMainDom mainDom, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, IServerRegistrar serverRegistrar, + IMainDom mainDom, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, ILogger logger, IServerRegistrar serverRegistrar, bool distributedEnabled, DatabaseServerMessengerOptions options, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers) : base(distributedEnabled) { @@ -58,7 +59,7 @@ namespace Umbraco.Core.Sync _serverRegistrar = serverRegistrar; _hostingEnvironment = hostingEnvironment; _cacheRefreshers = cacheRefreshers; - Logger = proflog; + Logger = logger; Options = options ?? throw new ArgumentNullException(nameof(options)); _lastPruned = _lastSync = DateTime.UtcNow; _syncIdle = new ManualResetEvent(true); @@ -72,7 +73,7 @@ namespace Umbraco.Core.Sync + "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique } - protected ILogger Logger { get; } + protected ILogger Logger { get; } protected IScopeProvider ScopeProvider { get; } @@ -151,7 +152,7 @@ namespace Umbraco.Core.Sync var idle =_syncIdle.WaitOne(5000); if (idle == false) { - Logger.Warn("The wait lock timed out, application is shutting down. The current instruction batch will be re-processed."); + Logger.LogWarning("The wait lock timed out, application is shutting down. The current instruction batch will be re-processed."); } }, weight); @@ -187,7 +188,7 @@ namespace Umbraco.Core.Sync { // we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new // server and it will need to rebuild it's own caches, eg Lucene or the xml cache file. - Logger.Warn("No last synced Id found, this generally means this is a new server/install." + Logger.LogWarning("No last synced Id found, this generally means this is a new server/install." + " The server will build its caches and indexes, and then adjust its last synced Id to the latest found in" + " the database and maintain cache updates based on that Id."); @@ -201,7 +202,7 @@ namespace Umbraco.Core.Sync if (count > Options.MaxProcessingInstructionCount) { //too many instructions, proceed to cold boot - Logger.Warn( + Logger.LogWarning( "The instruction count ({InstructionCount}) exceeds the specified MaxProcessingInstructionCount ({MaxProcessingInstructionCount})." + " The server will skip existing instructions, rebuild its caches and indexes entirely, adjust its last synced Id" + " to the latest found in the database and maintain cache updates based on that Id.", @@ -361,7 +362,7 @@ namespace Umbraco.Core.Sync } catch (JsonException ex) { - Logger.Error(ex, "Failed to deserialize instructions ({DtoId}: '{DtoInstructions}').", + Logger.LogError(ex, "Failed to deserialize instructions ({DtoId}: '{DtoInstructions}').", dto.Id, dto.Instructions); @@ -377,7 +378,7 @@ namespace Umbraco.Core.Sync //if they couldn't be all processed (i.e. we're shutting down) then exit if (success == false) { - Logger.Info("The current batch of instructions was not processed, app is shutting down"); + Logger.LogInformation("The current batch of instructions was not processed, app is shutting down"); break; } @@ -419,7 +420,7 @@ namespace Umbraco.Core.Sync //} catch (Exception ex) { - Logger.Error( + Logger.LogError( ex, "DISTRIBUTED CACHE IS NOT UPDATED. Failed to execute instructions ({DtoId}: '{DtoInstructions}'). Instruction is being skipped/ignored", dto.Id, diff --git a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs index b65254b181..d115bc7595 100644 --- a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs +++ b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs @@ -4,7 +4,7 @@ using System.Linq; using Newtonsoft.Json; using Umbraco.Composing; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; namespace Umbraco.Core.Sync { @@ -157,7 +157,7 @@ namespace Umbraco.Core.Sync { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); - Current.Logger.Debug("Invoking refresher {RefresherType} on local server for message type RefreshByPayload", refresher.GetType()); + Current.Logger.LogDebug("Invoking refresher {RefresherType} on local server for message type RefreshByPayload", refresher.GetType()); var payloadRefresher = refresher as IPayloadCacheRefresher; if (payloadRefresher == null) @@ -179,7 +179,7 @@ namespace Umbraco.Core.Sync { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); - Current.Logger.Debug("Invoking refresher {RefresherType} on local server for message type {MessageType}", refresher.GetType(), messageType); + Current.Logger.LogDebug("Invoking refresher {RefresherType} on local server for message type {MessageType}", refresher.GetType(), messageType); switch (messageType) { @@ -240,7 +240,7 @@ namespace Umbraco.Core.Sync { if (refresher == null) throw new ArgumentNullException(nameof(refresher)); - Current.Logger.Debug("Invoking refresher {RefresherType} on local server for message type {MessageType}", refresher.GetType(), messageType); + Current.Logger.LogDebug("Invoking refresher {RefresherType} on local server for message type {MessageType}", refresher.GetType(), messageType); var typedRefresher = refresher as ICacheRefresher; @@ -276,7 +276,7 @@ namespace Umbraco.Core.Sync //{ // if (refresher == null) throw new ArgumentNullException("refresher"); - // Current.Logger.Debug("Invoking refresher {0} on local server for message type Notify", + // Current.Logger.LogDebug("Invoking refresher {0} on local server for message type Notify", // () => refresher.GetType()); // refresher.Notify(payload); 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..d8fbbd7fbd 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -10,38 +10,40 @@ - - + + - - - + + + + - - - - + + + + - + - + - - + + + - - + + - - + + @@ -90,6 +92,9 @@ <_Parameter1>Umbraco.Tests.UnitTests + + <_Parameter1>DynamicProxyGenAssembly2 + 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/PreviewInitialize.js b/src/Umbraco.Infrastructure/WebAssets/PreviewInitialize.js index 764e354d5f..45ee39eefc 100644 --- a/src/Umbraco.Infrastructure/WebAssets/PreviewInitialize.js +++ b/src/Umbraco.Infrastructure/WebAssets/PreviewInitialize.js @@ -8,7 +8,6 @@ 'js/umbraco.services.js', 'js/umbraco.interceptors.js', 'ServerVariables', - 'lib/signalr/jquery.signalR.js', - 'BackOffice/signalr/hubs', + 'lib/signalr/signalr.min.js', 'js/umbraco.preview.js' ] 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..023911d518 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..0e4cd4f49a 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..c615559920 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 ModelsBuilderSettings _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..4ccdc1b362 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..9a735631ff 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..3adbc0df2c 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 ModelsBuilderSettings _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..aa7ab40ba5 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(ModelsBuilderSettings 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 ModelsBuilderSettings 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..bc97118ee4 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 ModelsBuilderSettings _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..43771eb46a 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(ModelsBuilderSettings 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..837bf18dae 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 ModelsBuilderSettings _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..bc61f2eaee 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs @@ -6,91 +6,60 @@ 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(); 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) + { + return factory.GetInstance(); + // 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..b8488e0852 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 Microsoft.Extensions.Logging; 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 { @@ -14,8 +19,8 @@ namespace Umbraco.ModelsBuilder.Embedded { private static Mutex _mutex; private static int _req; - private readonly ILogger _logger; - private readonly IModelsBuilderConfig _config; + private readonly ILogger _logger; + private readonly ModelsBuilderSettings _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; @@ -65,11 +70,11 @@ namespace Umbraco.ModelsBuilder.Embedded private void RequestModelsGeneration(object sender, EventArgs args) { //HttpContext.Current.Items[this] = true; - _logger.Debug("Requested to generate models."); + _logger.LogDebug("Requested to generate models."); 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; @@ -79,22 +84,22 @@ namespace Umbraco.ModelsBuilder.Embedded try { - _logger.Debug("Generate models..."); + _logger.LogDebug("Generate models..."); const int timeout = 2 * 60 * 1000; // 2 mins _mutex.WaitOne(timeout); // wait until it is safe, and acquire - _logger.Info("Generate models now."); + _logger.LogInformation("Generate models now."); GenerateModels(); _mbErrors.Clear(); - _logger.Info("Generated."); + _logger.LogInformation("Generated."); } catch (TimeoutException) { - _logger.Warn("Timeout, models were NOT generated."); + _logger.LogWarning("Timeout, models were NOT generated."); } catch (Exception e) { _mbErrors.Report("Failed to build Live models.", e); - _logger.Error("Failed to generate models.", e); + _logger.LogError("Failed to generate models.", e); } finally { @@ -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..dca2fda0dc 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 ModelsBuilderSettings _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..92e0604a16 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 ModelsBuilderSettings _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..e52e438b43 100644 --- a/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs +++ b/src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs @@ -8,66 +8,66 @@ 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 Microsoft.Extensions.Logging; 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 private bool _pendingRebuild; - private readonly IProfilingLogger _logger; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; 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 ModelsBuilderSettings _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, + IProfilingLogger profilingLogger, + ILogger logger, + IOptions config, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, - IIOHelper ioHelper) + IPublishedValueFallback publishedValueFallback) { _umbracoServices = umbracoServices; + _profilingLogger = profilingLogger; _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 +113,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 +158,6 @@ namespace Umbraco.ModelsBuilder.Embedded #endregion #region Compilation - // deadlock note // // when RazorBuildProvider_CodeGenerationStarted runs, the thread has Monitor.Enter-ed the BuildManager @@ -188,37 +187,38 @@ 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() { - _logger.Debug("Resetting models."); + _logger.LogDebug("Resetting models."); try { @@ -227,14 +227,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 +245,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; } } @@ -265,7 +260,7 @@ namespace Umbraco.ModelsBuilder.Embedded internal Infos EnsureModels() { if (_debugLevel > 0) - _logger.Debug("Ensuring models."); + _logger.LogDebug("Ensuring models."); // don't use an upgradeable lock here because only 1 thread at a time could enter it try @@ -280,12 +275,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(); @@ -297,7 +292,7 @@ namespace Umbraco.ModelsBuilder.Embedded // either they haven't been loaded from the cache yet // or they have been reseted and are pending a rebuild - using (_logger.DebugDuration("Get models.", "Got models.")) + using (_profilingLogger.DebugDuration("Get models.", "Got models.")) { try { @@ -308,9 +303,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(); @@ -319,13 +311,12 @@ namespace Umbraco.ModelsBuilder.Embedded { try { - _logger.Error("Failed to build models.", e); - _logger.Warn("Running without models."); // be explicit + _logger.LogError(e, "Failed to build models."); + _logger.LogWarning("Running without models."); // be explicit _errors.Report("Failed to build PureLive models.", e); } finally { - _modelsAssembly = null; _infos = new Infos { ModelInfos = null, ModelTypeMap = new Dictionary() }; } } @@ -342,14 +333,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); @@ -365,13 +378,13 @@ namespace Umbraco.ModelsBuilder.Embedded if (!forceRebuild) { - _logger.Debug("Looking for cached models."); + _logger.LogDebug("Looking for cached models."); if (File.Exists(modelsHashFile) && File.Exists(projFile)) { var cachedHash = File.ReadAllText(modelsHashFile); if (currentHash != cachedHash) { - _logger.Debug("Found obsolete cached models."); + _logger.LogDebug("Found obsolete cached models."); forceRebuild = true; } @@ -379,7 +392,7 @@ namespace Umbraco.ModelsBuilder.Embedded } else { - _logger.Debug("Could not find cached models."); + _logger.LogDebug("Could not find cached models."); forceRebuild = true; } } @@ -392,23 +405,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}."); + _logger.LogDebug($"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) { @@ -418,20 +424,18 @@ namespace Umbraco.ModelsBuilder.Embedded // with the "same but different" version of the assembly in memory _skipver = assembly.GetName().Version.Revision; - _logger.Debug("Loading cached models (dll)."); + _logger.LogDebug("Loading cached models (dll)."); return assembly; } - _logger.Debug("Cached models dll cannot be loaded (invalid assembly)."); + _logger.LogDebug("Cached models dll cannot be loaded (invalid assembly)."); } else if (!File.Exists(dllPath)) - _logger.Debug("Cached models dll does not exist."); + _logger.LogDebug("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."); + _logger.LogDebug("Cached models dll is marked for deletion."); else - _logger.Debug("Cached models dll cannot be loaded (why?)."); + _logger.LogDebug("Cached models dll cannot be loaded (why?)."); } // must reset the version in the file else it would keep growing @@ -444,16 +448,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 { @@ -461,12 +464,12 @@ namespace Umbraco.ModelsBuilder.Embedded throw; } - _logger.Debug("Loading cached models (source)."); + _logger.LogDebug("Loading cached models (source)."); return assembly; } // need to rebuild - _logger.Debug("Rebuilding models."); + _logger.LogDebug("Rebuilding models."); // generate code, save var code = GenerateModelsCode(typeModels); @@ -490,9 +493,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 { @@ -500,13 +506,44 @@ namespace Umbraco.ModelsBuilder.Embedded throw; } - _logger.Debug("Done rebuilding."); + _logger.LogDebug("Done rebuilding."); 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."); + _logger.LogDebug("Failed to compile."); // the dll file reference still points to the previous dll, which is obsolete // now and will be deleted by ASP.NET eventually, so better clear that reference. @@ -523,7 +560,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 +572,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 +597,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 +611,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 +689,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; } } @@ -672,7 +710,7 @@ namespace Umbraco.ModelsBuilder.Embedded //if (_building && OurFiles.Contains(changed)) //{ - // //_logger.Info("Ignoring files self-changes."); + // //_logger.LogInformation("Ignoring files self-changes."); // return; //} @@ -680,7 +718,7 @@ namespace Umbraco.ModelsBuilder.Embedded if (OurFiles.Contains(changed)) return; - _logger.Info("Detected files changes."); + _logger.LogInformation("Detected files changes."); lock (SyncRoot) // don't reset while being locked ResetModels(); 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/ContentStore.cs b/src/Umbraco.PublishedCache.NuCache/ContentStore.cs index 48bb2c4069..e33381d858 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentStore.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentStore.cs @@ -5,9 +5,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CSharpTest.Net.Collections; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Exceptions; -using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Scoping; using Umbraco.Web.PublishedCache.NuCache.Snap; @@ -35,18 +35,19 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; private readonly IVariationContextAccessor _variationContextAccessor; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly ConcurrentDictionary> _contentNodes; private LinkedNode _root; // We must keep separate dictionaries for by id and by alias because we track these in snapshot/layers // and it is possible that the alias of a content type can be different for the same id in another layer // whereas the GUID -> INT cross reference can never be different - private readonly ConcurrentDictionary> _contentTypesById; + private readonly ConcurrentDictionary> _contentTypesById; private readonly ConcurrentDictionary> _contentTypesByAlias; private readonly ConcurrentDictionary _contentTypeKeyToIdMap; private readonly ConcurrentDictionary _contentKeyToIdMap; - private readonly ILogger _logger; private readonly IPublishedModelFactory _publishedModelFactory; private BPlusTree _localDb; private readonly ConcurrentQueue _genObjs; @@ -68,12 +69,14 @@ namespace Umbraco.Web.PublishedCache.NuCache IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, ILogger logger, + ILoggerFactory loggerFactory, IPublishedModelFactory publishedModelFactory, BPlusTree localDb = null) { _publishedSnapshotAccessor = publishedSnapshotAccessor; _variationContextAccessor = variationContextAccessor; _logger = logger; + _loggerFactory = loggerFactory; _publishedModelFactory = publishedModelFactory; _localDb = localDb; @@ -253,7 +256,7 @@ namespace Umbraco.Web.PublishedCache.NuCache catch (Exception ex) { /* TBD: May already be throwing so don't throw again */ - _logger.Error(ex, "Error trying to release DB"); + _logger.LogError(ex, "Error trying to release DB"); } finally { @@ -264,7 +267,7 @@ namespace Umbraco.Web.PublishedCache.NuCache } catch (Exception ex) { - _logger.Error(ex, "Error trying to lock"); + _logger.LogError(ex, "Error trying to lock"); throw; } finally @@ -521,7 +524,7 @@ namespace Umbraco.Web.PublishedCache.NuCache parent = GetParentLink(kit.Node, null); if (parent == null) { - _logger.Warn($"Skip item id={kit.Node.Id}, could not find parent id={kit.Node.ParentContentId}."); + _logger.LogWarning($"Skip item id={kit.Node.Id}, could not find parent id={kit.Node.ParentContentId}."); return false; } @@ -530,21 +533,21 @@ namespace Umbraco.Web.PublishedCache.NuCache // because the data sort operation is by path. if (parent.Value == null) { - _logger.Warn($"Skip item id={kit.Node.Id}, no Data assigned for linked node with path {kit.Node.Path} and parent id {kit.Node.ParentContentId}. This can indicate data corruption for the Path value for node {kit.Node.Id}. See the Health Check dashboard in Settings to resolve data integrity issues."); + _logger.LogWarning($"Skip item id={kit.Node.Id}, no Data assigned for linked node with path {kit.Node.Path} and parent id {kit.Node.ParentContentId}. This can indicate data corruption for the Path value for node {kit.Node.Id}. See the Health Check dashboard in Settings to resolve data integrity issues."); return false; } // make sure the kit is valid if (kit.DraftData == null && kit.PublishedData == null) { - _logger.Warn($"Skip item id={kit.Node.Id}, both draft and published data are null."); + _logger.LogWarning($"Skip item id={kit.Node.Id}, both draft and published data are null."); return false; } // unknown = bad if (_contentTypesById.TryGetValue(kit.ContentTypeId, out var link) == false || link.Value == null) { - _logger.Warn($"Skip item id={kit.Node.Id}, could not find content type id={kit.ContentTypeId}."); + _logger.LogWarning($"Skip item id={kit.Node.Id}, could not find content type id={kit.ContentTypeId}."); return false; } @@ -601,7 +604,7 @@ namespace Umbraco.Web.PublishedCache.NuCache throw new ArgumentException("Kit content cannot have children.", nameof(kit)); // ReSharper restore LocalizableElement - _logger.Debug("Set content ID: {KitNodeId}", kit.Node.Id); + _logger.LogDebug("Set content ID: {KitNodeId}", kit.Node.Id); // get existing _contentNodes.TryGetValue(kit.Node.Id, out var link); @@ -720,7 +723,7 @@ namespace Umbraco.Web.PublishedCache.NuCache previousNode = null; // there is no previous sibling } - _logger.Debug($"Set {thisNode.Id} with parent {thisNode.ParentContentId}"); + _logger.LogDebug($"Set {thisNode.Id} with parent {thisNode.ParentContentId}"); SetValueLocked(_contentNodes, thisNode.Id, thisNode); // if we are initializing from the database source ensure the local db is updated @@ -777,7 +780,7 @@ namespace Umbraco.Web.PublishedCache.NuCache ok = false; continue; // skip that one } - _logger.Debug($"Set {kit.Node.Id} with parent {kit.Node.ParentContentId}"); + _logger.LogDebug($"Set {kit.Node.Id} with parent {kit.Node.ParentContentId}"); SetValueLocked(_contentNodes, kit.Node.Id, kit.Node); if (_localDb != null) RegisterChange(kit.Node.Id, kit); @@ -866,7 +869,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (link?.Value == null) return false; var content = link.Value; - _logger.Debug("Clear content ID: {ContentId}", content.Id); + _logger.LogDebug("Clear content ID: {ContentId}", content.Id); // clear the entire branch ClearBranchLocked(content); @@ -1059,7 +1062,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var parent = parentLink.Value; // We are doing a null check here but this should no longer be possible because we have a null check in BuildKit - // for the parent.Value property and we'll output a warning. However I'll leave this additional null check in place. + // for the parent.Value property and we'll output a warning. However I'll leave this additional null check in place. // see https://github.com/umbraco/Umbraco-CMS/issues/7868 if (parent == null) throw new PanicException($"A null Value was returned on the {nameof(parentLink)} LinkedNode with id={content.ParentContentId}, potentially your database paths are corrupted."); @@ -1308,7 +1311,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (_nextGen == false && _genObj != null) return new Snapshot(this, _genObj.GetGenRef() #if DEBUG - , _logger + , _loggerFactory.CreateLogger() #endif ); @@ -1344,7 +1347,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var snapshot = new Snapshot(this, _genObj.GetGenRef() #if DEBUG - , _logger + , _loggerFactory.CreateLogger() #endif ); @@ -1358,7 +1361,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public Snapshot LiveSnapshot => new Snapshot(this, _liveGen #if DEBUG - , _logger + , _loggerFactory.CreateLogger() #endif ); @@ -1393,14 +1396,14 @@ namespace Umbraco.Web.PublishedCache.NuCache { // see notes in CreateSnapshot #if DEBUG - _logger.Debug("Collect."); + _logger.LogDebug("Collect."); #endif while (_genObjs.TryPeek(out var genObj) && (genObj.Count == 0 || genObj.WeakGenRef.IsAlive == false)) { _genObjs.TryDequeue(out genObj); // cannot fail since TryPeek has succeeded _floorGen = genObj.Gen; #if DEBUG - //_logger.Debug("_floorGen=" + _floorGen + ", _liveGen=" + _liveGen); + //_logger.LogDebug("_floorGen=" + _floorGen + ", _liveGen=" + _liveGen); #endif } @@ -1438,7 +1441,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var link = kvp.Value; #if DEBUG - //_logger.Debug("Collect id:" + kvp.Key + ", gen:" + link.Gen + + //_logger.LogDebug("Collect id:" + kvp.Key + ", gen:" + link.Gen + // ", nxt:" + (link.Next == null ? "null" : "link") + // ", val:" + (link.Value == null ? "null" : "value")); #endif @@ -1546,7 +1549,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly GenRef _genRef; private long _gen; #if DEBUG - private readonly ILogger _logger; + private readonly ILogger _logger; #endif //private static int _count; @@ -1554,7 +1557,7 @@ namespace Umbraco.Web.PublishedCache.NuCache internal Snapshot(ContentStore store, GenRef genRef #if DEBUG - , ILogger logger + , ILogger logger #endif ) { @@ -1566,13 +1569,13 @@ namespace Umbraco.Web.PublishedCache.NuCache #if DEBUG _logger = logger; - _logger.Debug("Creating snapshot."); + _logger.LogDebug("Creating snapshot."); #endif } internal Snapshot(ContentStore store, long gen #if DEBUG - , ILogger logger + , ILogger logger #endif ) { @@ -1581,7 +1584,7 @@ namespace Umbraco.Web.PublishedCache.NuCache #if DEBUG _logger = logger; - _logger.Debug("Creating live."); + _logger.LogDebug("Creating live."); #endif } @@ -1669,7 +1672,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { if (_gen < 0) return; #if DEBUG - _logger.Debug("Dispose snapshot ({Snapshot})", _genRef?.GenObj.Count.ToString() ?? "live"); + _logger.LogDebug("Dispose snapshot ({Snapshot})", _genRef?.GenObj.Count.ToString() ?? "live"); #endif _gen = -1; if (_genRef != null) diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/BTree.cs index 00e7fd34d1..99d0e9da38 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,16 +40,15 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource return tree; } - private static int GetBlockSize(INuCacheSettings settings) + private static int GetBlockSize(NuCacheSettings settings) { var blockSize = 4096; var appSetting = settings.BTreeBlockSize; - if (appSetting == null) + if (!appSetting.HasValue) return blockSize; - if (!int.TryParse(appSetting, out blockSize)) - throw new ConfigurationErrorsException($"Invalid block size value \"{appSetting}\": not a number."); + blockSize = appSetting.Value; var bit = 0; for (var i = blockSize; i != 1; i >>= 1) diff --git a/src/Umbraco.PublishedCache.NuCache/DataSource/DatabaseDataSource.cs b/src/Umbraco.PublishedCache.NuCache/DataSource/DatabaseDataSource.cs index 3fedfbb7eb..bdcd8fe3e3 100644 --- a/src/Umbraco.PublishedCache.NuCache/DataSource/DatabaseDataSource.cs +++ b/src/Umbraco.PublishedCache.NuCache/DataSource/DatabaseDataSource.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using NPoco; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Scoping; @@ -21,9 +21,9 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource { private const int PageSize = 500; - private readonly ILogger _logger; + private readonly ILogger _logger; - public DatabaseDataSource(ILogger logger) + public DatabaseDataSource(ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } @@ -215,7 +215,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource { if (Debugger.IsAttached) throw new InvalidOperationException("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); - _logger.Warn("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); + _logger.LogWarning("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); } else { @@ -242,7 +242,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource { if (Debugger.IsAttached) throw new InvalidOperationException("Missing cmsContentNu published content for node " + dto.Id + ", consider rebuilding."); - _logger.Warn("Missing cmsContentNu published content for node {NodeId}, consider rebuilding.", dto.Id); + _logger.LogWarning("Missing cmsContentNu published content for node {NodeId}, consider rebuilding.", dto.Id); } else { diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index 815fe0a168..688515ad33 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -6,11 +6,14 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CSharpTest.Net.Collections; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; 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; @@ -39,13 +42,15 @@ namespace Umbraco.Web.PublishedCache.NuCache { private readonly ServiceContext _serviceContext; private readonly IPublishedContentTypeFactory _publishedContentTypeFactory; + private readonly IProfilingLogger _profilingLogger; private readonly IScopeProvider _scopeProvider; private readonly IDataSource _dataSource; - private readonly IProfilingLogger _logger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; 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 +58,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; @@ -81,17 +86,21 @@ namespace Umbraco.Web.PublishedCache.NuCache public PublishedSnapshotService(PublishedSnapshotServiceOptions options, IMainDom mainDom, IRuntimeState runtime, ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, - IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IProfilingLogger logger, IScopeProvider scopeProvider, + IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, + IProfilingLogger profilingLogger, + ILoggerFactory loggerFactory, + 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) @@ -99,19 +108,21 @@ namespace Umbraco.Web.PublishedCache.NuCache _serviceContext = serviceContext; _publishedContentTypeFactory = publishedContentTypeFactory; + _profilingLogger = profilingLogger; _dataSource = dataSource; - _logger = logger; + _loggerFactory = loggerFactory; + _logger = _loggerFactory.CreateLogger(); _scopeProvider = scopeProvider; _documentRepository = documentRepository; _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 @@ -145,17 +156,17 @@ namespace Umbraco.Web.PublishedCache.NuCache // stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to // figure out whether it can read the databases or it should populate them from sql - _logger.Info("Creating the content store, localContentDbExists? {LocalContentDbExists}", _localContentDbExists); - _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, publishedModelFactory, _localContentDb); - _logger.Info("Creating the media store, localMediaDbExists? {LocalMediaDbExists}", _localMediaDbExists); - _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, publishedModelFactory, _localMediaDb); + _logger.LogInformation("Creating the content store, localContentDbExists? {LocalContentDbExists}", _localContentDbExists); + _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, publishedModelFactory, _localContentDb); + _logger.LogInformation("Creating the media store, localMediaDbExists? {LocalMediaDbExists}", _localMediaDbExists); + _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, publishedModelFactory, _localMediaDb); } else { - _logger.Info("Creating the content store (local db ignored)"); - _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, publishedModelFactory); - _logger.Info("Creating the media store (local db ignored)"); - _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, publishedModelFactory); + _logger.LogInformation("Creating the content store (local db ignored)"); + _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, publishedModelFactory); + _logger.LogInformation("Creating the media store (local db ignored)"); + _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _loggerFactory.CreateLogger("ContentStore"), _loggerFactory, publishedModelFactory); } _domainStore = new SnapDictionary(); @@ -201,7 +212,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _localContentDb = BTree.GetTree(localContentDbPath, _localContentDbExists, _config); _localMediaDb = BTree.GetTree(localMediaDbPath, _localMediaDbExists, _config); - _logger.Info("Registered with MainDom, localContentDbExists? {LocalContentDbExists}, localMediaDbExists? {LocalMediaDbExists}", _localContentDbExists, _localMediaDbExists); + _logger.LogInformation("Registered with MainDom, localContentDbExists? {LocalContentDbExists}, localMediaDbExists? {LocalMediaDbExists}", _localContentDbExists, _localMediaDbExists); } /// @@ -212,19 +223,19 @@ namespace Umbraco.Web.PublishedCache.NuCache /// private void MainDomRelease() { - _logger.Debug("Releasing from MainDom..."); + _logger.LogDebug("Releasing from MainDom..."); lock (_storesLock) { - _logger.Debug("Releasing content store..."); + _logger.LogDebug("Releasing content store..."); _contentStore?.ReleaseLocalDb(); //null check because we could shut down before being assigned _localContentDb = null; - _logger.Debug("Releasing media store..."); + _logger.LogDebug("Releasing media store..."); _mediaStore?.ReleaseLocalDb(); //null check because we could shut down before being assigned _localMediaDb = null; - _logger.Info("Released from MainDom"); + _logger.LogInformation("Released from MainDom"); } } @@ -243,14 +254,14 @@ namespace Umbraco.Web.PublishedCache.NuCache { okContent = LockAndLoadContent(scope => LoadContentFromLocalDbLocked(true)); if (!okContent) - _logger.Warn("Loading content from local db raised warnings, will reload from database."); + _logger.LogWarning("Loading content from local db raised warnings, will reload from database."); } if (_localMediaDbExists) { okMedia = LockAndLoadMedia(scope => LoadMediaFromLocalDbLocked(true)); if (!okMedia) - _logger.Warn("Loading media from local db raised warnings, will reload from database."); + _logger.LogWarning("Loading media from local db raised warnings, will reload from database."); } if (!okContent) @@ -263,7 +274,7 @@ namespace Umbraco.Web.PublishedCache.NuCache } catch (Exception ex) { - _logger.Fatal(ex, "Panic, exception while loading cache data."); + _logger.LogCritical(ex, "Panic, exception while loading cache data."); throw; } @@ -406,7 +417,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _contentStore.SetAllContentTypesLocked(contentTypes); - using (_logger.TraceDuration("Loading content from database")) + using (_profilingLogger.TraceDuration("Loading content from database")) { // beware! at that point the cache is inconsistent, // assuming we are going to SetAll content items! @@ -425,7 +436,7 @@ namespace Umbraco.Web.PublishedCache.NuCache .Select(x => _publishedContentTypeFactory.CreateContentType(x)); _contentStore.SetAllContentTypesLocked(contentTypes); - using (_logger.TraceDuration("Loading content from local cache file")) + using (_profilingLogger.TraceDuration("Loading content from local cache file")) { // beware! at that point the cache is inconsistent, // assuming we are going to SetAll content items! @@ -477,14 +488,14 @@ namespace Umbraco.Web.PublishedCache.NuCache .Select(x => _publishedContentTypeFactory.CreateContentType(x)); _mediaStore.SetAllContentTypesLocked(mediaTypes); - using (_logger.TraceDuration("Loading media from database")) + using (_profilingLogger.TraceDuration("Loading media from database")) { // beware! at that point the cache is inconsistent, // assuming we are going to SetAll content items! _localMediaDb?.Clear(); - _logger.Debug("Loading media from database..."); + _logger.LogDebug("Loading media from database..."); // IMPORTANT GetAllMediaSources sorts kits by level + parentId + sortOrder var kits = _dataSource.GetAllMediaSources(scope); return onStartup ? _mediaStore.SetAllFastSortedLocked(kits, true) : _mediaStore.SetAllLocked(kits); @@ -497,7 +508,7 @@ namespace Umbraco.Web.PublishedCache.NuCache .Select(x => _publishedContentTypeFactory.CreateContentType(x)); _mediaStore.SetAllContentTypesLocked(mediaTypes); - using (_logger.TraceDuration("Loading media from local cache file")) + using (_profilingLogger.TraceDuration("Loading media from local cache file")) { // beware! at that point the cache is inconsistent, // assuming we are going to SetAll content items! @@ -532,7 +543,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // Update: We will still return false here even though the above mentioned race condition has been fixed since we now // lock the entire operation of creating/populating the cache file with the same lock as releasing/closing the cache file - _logger.Info($"Tried to load {entityType} from the local cache file but it was empty."); + _logger.LogInformation($"Tried to load {entityType} from the local cache file but it was empty."); return false; } @@ -709,7 +720,7 @@ namespace Umbraco.Web.PublishedCache.NuCache foreach (var payload in payloads) { - _logger.Debug("Notified {ChangeTypes} for content {ContentId}", payload.ChangeTypes, payload.Id); + _logger.LogDebug("Notified {ChangeTypes} for content {ContentId}", payload.ChangeTypes, payload.Id); if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll)) { @@ -802,7 +813,7 @@ namespace Umbraco.Web.PublishedCache.NuCache foreach (var payload in payloads) { - _logger.Debug("Notified {ChangeTypes} for media {MediaId}", payload.ChangeTypes, payload.Id); + _logger.LogDebug("Notified {ChangeTypes} for media {MediaId}", payload.ChangeTypes, payload.Id); if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll)) { @@ -873,7 +884,7 @@ namespace Umbraco.Web.PublishedCache.NuCache return; foreach (var payload in payloads) - _logger.Debug("Notified {ChangeTypes} for {ItemType} {ItemId}", payload.ChangeTypes, payload.ItemType, payload.Id); + _logger.LogDebug("Notified {ChangeTypes} for {ItemType} {ItemId}", payload.ChangeTypes, payload.ItemType, payload.Id); Notify(_contentStore, payloads, RefreshContentTypesLocked); Notify(_mediaStore, payloads, RefreshMediaTypesLocked); @@ -957,7 +968,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var idsA = payloads.Select(x => x.Id).ToArray(); foreach (var payload in payloads) - _logger.Debug("Notified {RemovedStatus} for data type {DataTypeId}", + _logger.LogDebug("Notified {RemovedStatus} for data type {DataTypeId}", payload.Removed ? "Removed" : "Refreshed", payload.Id); @@ -1229,14 +1240,14 @@ namespace Umbraco.Web.PublishedCache.NuCache var snapshotCache = new DictionaryAppCache(); - var memberTypeCache = new PublishedContentTypeCache(null, null, _serviceContext.MemberTypeService, _publishedContentTypeFactory, _logger); + var memberTypeCache = new PublishedContentTypeCache(null, null, _serviceContext.MemberTypeService, _publishedContentTypeFactory, _loggerFactory.CreateLogger()); var defaultCulture = _defaultCultureAccessor.DefaultCulture; var domainCache = new DomainCache(domainSnap, defaultCulture); 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, @@ -1490,7 +1501,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Rebuild() { - _logger.Debug("Rebuilding..."); + _logger.LogDebug("Rebuilding..."); using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) { scope.ReadLock(Constants.Locks.ContentTree); diff --git a/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj b/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj index 4a7733a810..edb68c6b93 100644 --- a/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj +++ b/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj @@ -24,9 +24,15 @@ <_Parameter1>Umbraco.Tests + + <_Parameter1>Umbraco.Tests.Integration + <_Parameter1>Umbraco.Tests.Benchmarks + + <_Parameter1>DynamicProxyGenAssembly2 + diff --git a/src/Umbraco.TestData/Umbraco.TestData.csproj b/src/Umbraco.TestData/Umbraco.TestData.csproj index 052acd64ef..a21251130e 100644 --- a/src/Umbraco.TestData/Umbraco.TestData.csproj +++ b/src/Umbraco.TestData/Umbraco.TestData.csproj @@ -66,7 +66,7 @@ - 28.4.4 + 31.0.3 5.2.7 diff --git a/src/Umbraco.TestData/UmbracoTestDataController.cs b/src/Umbraco.TestData/UmbracoTestDataController.cs index 09f9177982..33c361df2d 100644 --- a/src/Umbraco.TestData/UmbracoTestDataController.cs +++ b/src/Umbraco.TestData/UmbracoTestDataController.cs @@ -33,8 +33,8 @@ namespace Umbraco.TestData private readonly PropertyEditorCollection _propertyEditors; private readonly IShortStringHelper _shortStringHelper; - public UmbracoTestDataController(IScopeProvider scopeProvider, PropertyEditorCollection propertyEditors, IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, IShortStringHelper shortStringHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, logger, profilingLogger) + public UmbracoTestDataController(IScopeProvider scopeProvider, PropertyEditorCollection propertyEditors, IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IShortStringHelper shortStringHelper) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) { _scopeProvider = scopeProvider; _propertyEditors = propertyEditors; diff --git a/src/Umbraco.Tests.AcceptanceTest/README.md b/src/Umbraco.Tests.AcceptanceTest/README.md index e8699b0733..f4edaa92ea 100644 --- a/src/Umbraco.Tests.AcceptanceTest/README.md +++ b/src/Umbraco.Tests.AcceptanceTest/README.md @@ -1,35 +1,36 @@ -# Umbraco Acceptance Tests - -### Prerequisite -- 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. - -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. - -The file need the following content: -``` -{ - "username": "", - "password": "" -} -``` -Replace the `` and `` placeholders with correct info. - - - -### Executing tests - -There exists two npm scripts, that can be used to execute the test. - -1. `npm run test` - - Executes the tests headless. -1. `npm run ui` - - Executes the tests in a browser handled by a cypress application. - - In case of errors it is recommended to use the UI to debug. +# Umbraco Acceptance Tests + +### 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. + +### Getting started +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. + +The script will ask you to enter the username and password for a superadmin user of your Umbraco CMS. + +### Executing tests +There are two npm scripts that can be used to execute the test: + +1. `npm run test` + - Executes the tests headless. +1. `npm run ui` + - Executes the tests in a browser handled by a cypress application. + + In case of errors it is recommended to use the UI to debug. + +### Enviroment Configuration + +The enviroment configuration is begin setup by the npm installation script. +This results in the creation of this file: `cypress.env.json`. +This file is already added to `.gitignore` and can contain values that are different for each developer machine. + +The file has the following content: +``` +{ + "username": "", + "password": "" +} +``` +You can change this if you like or run the config script to reset the values, type "npm run config" in your terminal. diff --git a/src/Umbraco.Tests.AcceptanceTest/config.js b/src/Umbraco.Tests.AcceptanceTest/config.js new file mode 100644 index 0000000000..5297cbccbc --- /dev/null +++ b/src/Umbraco.Tests.AcceptanceTest/config.js @@ -0,0 +1,49 @@ +const prompt = require('prompt'); +const fs = require('fs'); + +const properties = [ + { + description: 'Enter your superadmin username/email', + name: 'username', + required: true + }, + { + description: 'Enter your superadmin password', + name: 'password', + hidden: true, + required: true + }, + { + description: 'Enter CMS URL, or leave empty for default(https://localhost:44331)', + name: 'baseUrl' + } +]; + + +const configPath = './cypress.env.json' + +console.log("Configure your test enviroment") + +prompt.start(); + +prompt.get(properties, function (error, result) { + if (error) { return onError(error); } + +var fileContent = `{ + "username": "${result.username}", + "password": "${result.password}"${ + result.baseUrl && `, + "baseUrl": "${result.baseUrl}"` + } +}`; + + fs.writeFile(configPath, fileContent, function (error) { + if (error) return console.error(error); + console.log('Configuration saved'); + }); +}); + +function onError(error) { + console.error(error); + return true; +} 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/cypress/plugins/index.js b/src/Umbraco.Tests.AcceptanceTest/cypress/plugins/index.js index aa9918d215..59283feec5 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/plugins/index.js +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/plugins/index.js @@ -18,4 +18,11 @@ module.exports = (on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config + const baseUrl = config.env.baseUrl || null; + + if (baseUrl) { + config.baseUrl = baseUrl; + } + + return config; } diff --git a/src/Umbraco.Tests.AcceptanceTest/package.json b/src/Umbraco.Tests.AcceptanceTest/package.json index 867b7f5cf3..e845681f18 100644 --- a/src/Umbraco.Tests.AcceptanceTest/package.json +++ b/src/Umbraco.Tests.AcceptanceTest/package.json @@ -1,13 +1,16 @@ { "scripts": { + "postinstall": "node postinstall.js", + "config": "node config.js", "test": "npx cypress run", "ui": "npx cypress open" }, "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", + "prompt": "^1.0.0" }, "dependencies": { "typescript": "^3.9.2" diff --git a/src/Umbraco.Tests.AcceptanceTest/postinstall.js b/src/Umbraco.Tests.AcceptanceTest/postinstall.js new file mode 100644 index 0000000000..6117ac84f0 --- /dev/null +++ b/src/Umbraco.Tests.AcceptanceTest/postinstall.js @@ -0,0 +1,14 @@ +const fs = require('fs'); + +const configPath = './cypress.env.json'; + +try { + if (fs.existsSync(configPath)) { + //file exists + console.log("Skips configuration as file already exists, run 'npm run config' to change your configuration."); + } else { + require('./config.js'); + } +} catch(err) { + console.error(err) +} diff --git a/src/Umbraco.Tests.Benchmarks/Config/QuickRunConfigAttribute.cs b/src/Umbraco.Tests.Benchmarks/Config/QuickRunConfigAttribute.cs index 52d670de3c..0e87bfb584 100644 --- a/src/Umbraco.Tests.Benchmarks/Config/QuickRunConfigAttribute.cs +++ b/src/Umbraco.Tests.Benchmarks/Config/QuickRunConfigAttribute.cs @@ -1,7 +1,7 @@ using System; using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Horology; using BenchmarkDotNet.Jobs; +using Perfolizer.Horology; namespace Umbraco.Tests.Benchmarks.Config { diff --git a/src/Umbraco.Tests.Benchmarks/Config/QuickRunWithMemoryDiagnoserConfigAttribute.cs b/src/Umbraco.Tests.Benchmarks/Config/QuickRunWithMemoryDiagnoserConfigAttribute.cs index 381efc9139..73e4fd6de2 100644 --- a/src/Umbraco.Tests.Benchmarks/Config/QuickRunWithMemoryDiagnoserConfigAttribute.cs +++ b/src/Umbraco.Tests.Benchmarks/Config/QuickRunWithMemoryDiagnoserConfigAttribute.cs @@ -14,7 +14,7 @@ namespace Umbraco.Tests.Benchmarks.Config /// public QuickRunWithMemoryDiagnoserConfigAttribute() { - Config.Add(new MemoryDiagnoser()); + Config.Add(MemoryDiagnoser.Default); } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs index d63f586be3..02696b9b7b 100644 --- a/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs +++ b/src/Umbraco.Tests.Benchmarks/CtorInvokeBenchmarks.cs @@ -5,8 +5,8 @@ using System.Reflection.Emit; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; -using BenchmarkDotNet.Horology; using BenchmarkDotNet.Jobs; +using Perfolizer.Horology; using Umbraco.Core; namespace Umbraco.Tests.Benchmarks @@ -26,7 +26,7 @@ namespace Umbraco.Tests.Benchmarks { public Config() { - Add(new MemoryDiagnoser()); + Add(MemoryDiagnoser.Default); //Add(ExecutionValidator.FailOnError); //The 'quick and dirty' settings, so it runs a little quicker diff --git a/src/Umbraco.Tests.Benchmarks/SqlTemplatesBenchmark.cs b/src/Umbraco.Tests.Benchmarks/SqlTemplatesBenchmark.cs index 0f563d826d..22912af9ff 100644 --- a/src/Umbraco.Tests.Benchmarks/SqlTemplatesBenchmark.cs +++ b/src/Umbraco.Tests.Benchmarks/SqlTemplatesBenchmark.cs @@ -31,7 +31,7 @@ namespace Umbraco.Tests.Benchmarks { public Config() { - Add(new MemoryDiagnoser()); + Add(MemoryDiagnoser.Default); } } diff --git a/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs index 1571f63500..203e19fc6e 100644 --- a/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs +++ b/src/Umbraco.Tests.Benchmarks/TypeFinderBenchmarks.cs @@ -1,8 +1,9 @@ using BenchmarkDotNet.Attributes; using System; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Tests.Benchmarks.Config; namespace Umbraco.Tests.Benchmarks @@ -15,18 +16,17 @@ namespace Umbraco.Tests.Benchmarks [Benchmark(Baseline = true)] public void WithGetReferencingAssembliesCheck() { - var typeFinder1 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); + var typeFinder1 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); var found = typeFinder1.FindClassesOfType().Count(); } [Benchmark] public void WithoutGetReferencingAssembliesCheck() { - var typeFinder2 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); + var typeFinder2 = new TypeFinder(new NullLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); typeFinder2.QueryWithReferencingAssemblies = false; var found = typeFinder2.FindClassesOfType().Count(); } - } } diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index 84ec535b9d..f49367ef77 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -36,6 +36,9 @@ 7.3 + + C:\Users\Berg\.nuget\packages\perfolizer\0.2.1\lib\netstandard2.0\Perfolizer.dll + @@ -95,7 +98,16 @@ - 0.11.3 + 0.12.1 + + + 3.1.8 + + + 3.1.8 + + + 0.2.1 diff --git a/src/Umbraco.Tests.Common/Builders/BuilderBase.cs b/src/Umbraco.Tests.Common/Builders/BuilderBase.cs index d8fc048d1b..bb8255bbc0 100644 --- a/src/Umbraco.Tests.Common/Builders/BuilderBase.cs +++ b/src/Umbraco.Tests.Common/Builders/BuilderBase.cs @@ -1,7 +1,19 @@ +using System; + namespace Umbraco.Tests.Common.Builders { public abstract class BuilderBase { public abstract T Build(); + + protected static string RandomAlias(string alias, bool randomizeAliases) + { + if (randomizeAliases) + { + return string.Concat(alias, Guid.NewGuid().ToString("N")); + } + + return alias; + } } } diff --git a/src/Umbraco.Tests.Common/Builders/ContentBuilder.cs b/src/Umbraco.Tests.Common/Builders/ContentBuilder.cs index c9aaa4e908..9f30005c55 100644 --- a/src/Umbraco.Tests.Common/Builders/ContentBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/ContentBuilder.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; using System.Globalization; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders.Interfaces; +using Umbraco.Tests.Common.Builders.Extensions; +using Umbraco.Tests.Testing; +using Umbraco.Core; namespace Umbraco.Tests.Common.Builders { @@ -20,7 +23,8 @@ namespace Umbraco.Tests.Common.Builders IWithLevelBuilder, IWithPathBuilder, IWithSortOrderBuilder, - IWithCultureInfoBuilder + IWithCultureInfoBuilder, + IWithPropertyValues { private ContentTypeBuilder _contentTypeBuilder; private GenericDictionaryBuilder _propertyDataBuilder; @@ -30,6 +34,7 @@ namespace Umbraco.Tests.Common.Builders private DateTime? _createDate; private DateTime? _updateDate; private int? _parentId; + private IContent _parent; private string _name; private int? _creatorId; private int? _level; @@ -39,6 +44,9 @@ namespace Umbraco.Tests.Common.Builders private CultureInfo _cultureInfo; private IContentType _contentType; private IDictionary _cultureNames = new Dictionary(); + private object _propertyValues; + private string _propertyValuesCulture; + private string _propertyValuesSegment; public ContentTypeBuilder AddContentType() { @@ -48,70 +56,21 @@ namespace Umbraco.Tests.Common.Builders return builder; } - public override Content Build() + public ContentBuilder WithParent(IContent parent) { - var id = _id ?? 1; - var key = _key ?? Guid.NewGuid(); - var parentId = _parentId ?? -1; - var createDate = _createDate ?? DateTime.Now; - var updateDate = _updateDate ?? DateTime.Now; - var name = _name ?? Guid.NewGuid().ToString(); - var creatorId = _creatorId ?? 1; - var level = _level ?? 1; - var path = _path ?? $"-1,{id}"; - var sortOrder = _sortOrder ?? 0; - var trashed = _trashed ?? false; - var culture = _cultureInfo?.Name ?? null; - - if (_contentTypeBuilder is null && _contentType is null) - { - throw new InvalidOperationException("A member cannot be constructed without providing a member type. Use AddContentType() or WithContentType()."); - } - - var contentType = _contentType ?? _contentTypeBuilder.Build(); - - var content = new Content(name, parentId, contentType, culture) - { - Id = id, - Key = key, - CreateDate = createDate, - UpdateDate = updateDate, - CreatorId = creatorId, - Level = level, - Path = path, - SortOrder = sortOrder, - Trashed = trashed, - }; - - foreach (var cultureName in _cultureNames) - { - content.SetCultureName(cultureName.Value, cultureName.Key); - } - - - if (_propertyDataBuilder != null) - { - var propertyData = _propertyDataBuilder.Build(); - foreach (var kvp in propertyData) - { - content.SetValue(kvp.Key, kvp.Value); - } - - content.ResetDirtyProperties(false); - } - - return content; + _parentId = null; + _parent = parent; + return this; } public ContentBuilder WithContentType(IContentType contentType) { _contentTypeBuilder = null; _contentType = contentType; - return this; } - public ContentBuilder WithCultureName(string culture, string name) + public ContentBuilder WithCultureName(string culture, string name = "") { if (string.IsNullOrWhiteSpace(name)) { @@ -135,6 +94,245 @@ namespace Umbraco.Tests.Common.Builders return builder; } + public override Content Build() + { + var id = _id ?? 0; + var key = _key ?? Guid.NewGuid(); + var parentId = _parentId ?? -1; + var parent = _parent ?? null; + var createDate = _createDate ?? DateTime.Now; + var updateDate = _updateDate ?? DateTime.Now; + var name = _name ?? Guid.NewGuid().ToString(); + var creatorId = _creatorId ?? 0; + var level = _level ?? 1; + var path = _path ?? $"-1,{id}"; + var sortOrder = _sortOrder ?? 0; + var trashed = _trashed ?? false; + var culture = _cultureInfo?.Name ?? null; + var propertyValues = _propertyValues ?? null; + var propertyValuesCulture = _propertyValuesCulture ?? null; + var propertyValuesSegment = _propertyValuesSegment ?? null; + + if (_contentTypeBuilder is null && _contentType is null) + { + throw new InvalidOperationException("A content item cannot be constructed without providing a content type. Use AddContentType() or WithContentType()."); + } + + var contentType = _contentType ?? _contentTypeBuilder.Build(); + + Content content; + if (parent != null) + { + content = new Content(name, parent, contentType, culture); + } + else + { + content = new Content(name, parentId, contentType, culture); + } + + content.Id = id; + content.Key = key; + content.CreateDate = createDate; + content.UpdateDate = updateDate; + content.CreatorId = creatorId; + content.Level = level; + content.Path = path; + content.SortOrder = sortOrder; + content.Trashed = trashed; + + foreach (var cultureName in _cultureNames) + { + content.SetCultureName(cultureName.Value, cultureName.Key); + } + + if (_propertyDataBuilder != null || propertyValues != null) + { + if (_propertyDataBuilder != null) + { + var propertyData = _propertyDataBuilder.Build(); + foreach (var keyValuePair in propertyData) + { + content.SetValue(keyValuePair.Key, keyValuePair.Value); + } + } + else + { + content.PropertyValues(propertyValues, propertyValuesCulture, propertyValuesSegment); + } + + content.ResetDirtyProperties(false); + } + + return content; + } + + public static Content CreateBasicContent(IContentType contentType) + { + return new ContentBuilder() + .WithContentType(contentType) + .WithName("Home") + .Build(); + } + + public static Content CreateSimpleContent(IContentType contentType) + { + return new ContentBuilder() + .WithContentType(contentType) + .WithName("Home") + .WithPropertyValues(new + { + title = "Welcome to our Home page", + bodyText = "This is the welcome message on the first page", + author = "John Doe" + }) + .Build(); + } + + public static Content CreateSimpleContent(IContentType contentType, string name, int parentId = -1, string culture = null, string segment = null) + { + return new ContentBuilder() + .WithContentType(contentType) + .WithName(name) + .WithParentId(parentId) + .WithPropertyValues(new + { + title = "Welcome to our Home page", + bodyText = "This is the welcome message on the first page", + author = "John Doe" + }, culture, segment) + .Build(); + } + + public static Content CreateSimpleContent(IContentType contentType, string name, IContent parent, string culture = null, string segment = null, bool setPropertyValues = true) + { + var builder = new ContentBuilder() + .WithContentType(contentType) + .WithName(name) + .WithParent(parent); + + + if (!(culture is null)) + { + builder = builder.WithCultureName(culture, name); + } + + if (setPropertyValues) + { + builder = builder.WithPropertyValues(new + { + title = name + " Subpage", + bodyText = "This is a subpage", + author = "John Doe" + }, culture, segment); + } + + var content = builder.Build(); + + content.ResetDirtyProperties(false); + + return content; + } + + public static IEnumerable CreateTextpageContent(IContentType contentType, int parentId, int amount) + { + var list = new List(); + + for (int i = 0; i < amount; i++) + { + var name = "Textpage No-" + i; + var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 }; + object obj = + new + { + title = name + " title", + bodyText = string.Format("This is a textpage based on the {0} ContentType", contentType.Alias), + keywords = "text,page,meta", + description = "This is the meta description for a textpage" + }; + + content.PropertyValues(obj); + + content.ResetDirtyProperties(false); + + list.Add(content); + } + + return list; + } + public static Content CreateTextpageContent(IContentType contentType, string name, int parentId) + { + return new ContentBuilder() + .WithId(0) + .WithContentType(contentType) + .WithName(name) + .WithParentId(parentId) + .WithPropertyValues(new + { + title = name + " textpage", + bodyText = string.Format("This is a textpage based on the {0} ContentType", contentType.Alias), + keywords = "text,page,meta", + description = "This is the meta description for a textpage" + }) + .Build(); + } + + public static IEnumerable CreateMultipleTextpageContent(IContentType contentType, int parentId, int amount) + { + var list = new List(); + + for (var i = 0; i < amount; i++) + { + var name = "Textpage No-" + i; + var content = new ContentBuilder() + .WithName(name) + .WithParentId(parentId) + .WithContentType(contentType) + .WithPropertyValues(new + { + title = name + " title", + bodyText = $"This is a textpage based on the {contentType.Alias} ContentType", + keywords = "text,page,meta", + description = "This is the meta description for a textpage" + }) + .Build(); + + list.Add(content); + } + + return list; + } + + public static Content CreateAllTypesContent(IContentType contentType, string name, int parentId) + { + var content = new ContentBuilder() + .WithName(name) + .WithParentId(parentId) + .WithContentType(contentType) + .Build(); + + content.SetValue("isTrue", true); + content.SetValue("number", 42); + content.SetValue("bodyText", "Lorem Ipsum Body Text Test"); + content.SetValue("singleLineText", "Single Line Text Test"); + content.SetValue("multilineText", "Multiple lines \n in one box"); + content.SetValue("upload", "/media/1234/koala.jpg"); + content.SetValue("label", "Non-editable label"); + content.SetValue("dateTime", DateTime.Now.AddDays(-20)); + content.SetValue("colorPicker", "black"); + content.SetValue("ddlMultiple", "1234,1235"); + content.SetValue("rbList", "random"); + content.SetValue("date", DateTime.Now.AddDays(-10)); + content.SetValue("ddl", "1234"); + content.SetValue("chklist", "randomc"); + content.SetValue("contentPicker", Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")).ToString()); + content.SetValue("mediaPicker", Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")).ToString()); + content.SetValue("memberPicker", Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")).ToString()); + content.SetValue("multiUrlPicker", "[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]"); + content.SetValue("tags", "this,is,tags"); + + return content; + } + int? IWithIdBuilder.Id { get => _id; @@ -194,15 +392,35 @@ namespace Umbraco.Tests.Common.Builders get => _sortOrder; set => _sortOrder = value; } + int? IWithParentIdBuilder.ParentId { get => _parentId; set => _parentId = value; } + CultureInfo IWithCultureInfoBuilder.CultureInfo { get => _cultureInfo; set => _cultureInfo = value; } + + object IWithPropertyValues.PropertyValues + { + get => _propertyValues; + set => _propertyValues = value; + } + + string IWithPropertyValues.PropertyValuesCulture + { + get => _propertyValuesCulture; + set => _propertyValuesCulture = value; + } + + string IWithPropertyValues.PropertyValuesSegment + { + get => _propertyValuesSegment; + set => _propertyValuesSegment = value; + } } } diff --git a/src/Umbraco.Tests.Common/Builders/ContentTypeBaseBuilder.cs b/src/Umbraco.Tests.Common/Builders/ContentTypeBaseBuilder.cs index d9838cbd50..aab18d70af 100644 --- a/src/Umbraco.Tests.Common/Builders/ContentTypeBaseBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/ContentTypeBaseBuilder.cs @@ -15,6 +15,7 @@ namespace Umbraco.Tests.Common.Builders IWithAliasBuilder, IWithNameBuilder, IWithParentIdBuilder, + IWithParentContentTypeBuilder, IWithPathBuilder, IWithLevelBuilder, IWithSortOrderBuilder, @@ -32,6 +33,7 @@ namespace Umbraco.Tests.Common.Builders private string _alias; private string _name; private int? _parentId; + private IContentTypeComposition _parent; private int? _level; private string _path; private int? _sortOrder; @@ -43,7 +45,6 @@ namespace Umbraco.Tests.Common.Builders private string _thumbnail; private bool? _trashed; private bool? _isContainer; - protected ContentVariation? ContentVariation { get; set; } protected IShortStringHelper ShortStringHelper => new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); @@ -51,7 +52,7 @@ namespace Umbraco.Tests.Common.Builders { } - protected int GetId() => _id ?? 1; + protected int GetId() => _id ?? 0; protected Guid GetKey() => _key ?? Guid.NewGuid(); @@ -65,6 +66,8 @@ namespace Umbraco.Tests.Common.Builders protected int GetParentId() => _parentId ?? -1; + protected IContentTypeComposition GetParent() => _parent ?? null; + protected int GetLevel() => _level ?? 0; protected string GetPath() => _path ?? _path ?? $"-1,{GetId()}"; @@ -82,8 +85,6 @@ namespace Umbraco.Tests.Common.Builders protected bool GetTrashed() => _trashed ?? false; protected bool GetIsContainer() => _isContainer ?? false; - protected ContentVariation GetContentVariation() => ContentVariation ?? Core.Models.ContentVariation.Nothing; - protected void BuildPropertyGroups(ContentTypeCompositionBase contentType, IEnumerable propertyGroups) { @@ -93,8 +94,6 @@ namespace Umbraco.Tests.Common.Builders } } - - protected void BuildPropertyTypeIds(ContentTypeCompositionBase contentType, int? propertyTypeIdsIncrementingFrom) { if (propertyTypeIdsIncrementingFrom.HasValue) @@ -107,6 +106,23 @@ namespace Umbraco.Tests.Common.Builders } } + public static void EnsureAllIds(ContentTypeCompositionBase contentType, int seedId) + { + // Ensure everything has IDs (it will have if builder is used to create the object, but still useful to reset + // and ensure there are no clashes). + contentType.Id = seedId; + var itemid = seedId + 1; + foreach (var propertyGroup in contentType.PropertyGroups) + { + propertyGroup.Id = itemid++; + } + + foreach (var propertyType in contentType.PropertyTypes) + { + propertyType.Id = itemid++; + } + } + int? IWithIdBuilder.Id { get => _id; @@ -134,7 +150,21 @@ namespace Umbraco.Tests.Common.Builders int? IWithParentIdBuilder.ParentId { get => _parentId; - set => _parentId = value; + set + { + _parent = null; + _parentId = value; + } + } + + IContentTypeComposition IWithParentContentTypeBuilder.Parent + { + get => _parent; + set + { + _parentId = null; + _parent = value; + } } int? IWithLevelBuilder.Level diff --git a/src/Umbraco.Tests.Common/Builders/ContentTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/ContentTypeBuilder.cs index 7d51d26437..eb4192364f 100644 --- a/src/Umbraco.Tests.Common/Builders/ContentTypeBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/ContentTypeBuilder.cs @@ -1,13 +1,16 @@ using System.Collections.Generic; using System.Linq; +using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.Common.Builders.Interfaces; namespace Umbraco.Tests.Common.Builders { public class ContentTypeBuilder : ContentTypeBaseBuilder, - IWithPropertyTypeIdsIncrementingFrom, IBuildPropertyTypes + IWithPropertyTypeIdsIncrementingFrom, + IBuildPropertyTypes { private List> _propertyGroupBuilders = new List>(); private List> _noGroupPropertyTypeBuilders = new List>(); @@ -16,6 +19,7 @@ namespace Umbraco.Tests.Common.Builders private int? _propertyTypeIdsIncrementingFrom; private int? _defaultTemplateId; + private ContentVariation? _contentVariation; public ContentTypeBuilder() : base(null) { @@ -31,6 +35,12 @@ namespace Umbraco.Tests.Common.Builders return this; } + public ContentTypeBuilder WithContentVariation(ContentVariation contentVariation) + { + _contentVariation = contentVariation; + return this; + } + public PropertyGroupBuilder AddPropertyGroup() { var builder = new PropertyGroupBuilder(this); @@ -61,49 +71,401 @@ namespace Umbraco.Tests.Common.Builders public override IContentType Build() { - var contentType = new ContentType(ShortStringHelper, GetParentId()) + var contentVariation = _contentVariation ?? ContentVariation.Nothing; + + ContentType contentType; + var parent = GetParent(); + if (parent != null) { - Id = GetId(), - Key = GetKey(), - CreateDate = GetCreateDate(), - UpdateDate = GetUpdateDate(), - Alias = GetAlias(), - Name = GetName(), - Level = GetLevel(), - Path = GetPath(), - SortOrder = GetSortOrder(), - Description = GetDescription(), - Icon = GetIcon(), - Thumbnail = GetThumbnail(), - CreatorId = GetCreatorId(), - Trashed = GetTrashed(), - IsContainer = GetIsContainer(), - Variations = GetContentVariation(), - }; + contentType = new ContentType(ShortStringHelper, (IContentType)parent, GetAlias()); + } + else + { + contentType = new ContentType(ShortStringHelper, GetParentId()) + { + Alias = GetAlias(), + }; + } + + contentType.Id = GetId(); + contentType.Key = GetKey(); + contentType.CreateDate = GetCreateDate(); + contentType.UpdateDate = GetUpdateDate(); + contentType.Name = GetName(); + contentType.Level = GetLevel(); + contentType.Path = GetPath(); + contentType.SortOrder = GetSortOrder(); + contentType.Description = GetDescription(); + contentType.Icon = GetIcon(); + contentType.Thumbnail = GetThumbnail(); + contentType.CreatorId = GetCreatorId(); + contentType.Trashed = GetTrashed(); + contentType.IsContainer = GetIsContainer(); + + contentType.Variations = contentVariation; contentType.NoGroupPropertyTypes = _noGroupPropertyTypeBuilders.Select(x => x.Build()); BuildPropertyGroups(contentType, _propertyGroupBuilders.Select(x => x.Build())); BuildPropertyTypeIds(contentType, _propertyTypeIdsIncrementingFrom); - contentType.AllowedTemplates = _templateBuilders.Select(x => x.Build()); contentType.AllowedContentTypes = _allowedContentTypeBuilders.Select(x => x.Build()); + contentType.AllowedTemplates = _templateBuilders.Select(x => x.Build()); if (_defaultTemplateId.HasValue) { contentType.SetDefaultTemplate(contentType.AllowedTemplates .SingleOrDefault(x => x.Id == _defaultTemplateId.Value)); } - contentType.ResetDirtyProperties(false); return contentType; } - public ContentTypeBuilder WithContentVariation(ContentVariation contentVariation) + public static ContentType CreateBasicContentType(string alias = "basePage", string name = "Base Page", IContentType parent = null) { - ContentVariation = contentVariation; - return this; + var builder = new ContentTypeBuilder(); + return (ContentType)builder + .WithAlias(alias) + .WithName(name) + .WithParentContentType(parent) + .Build(); + } + + public static ContentType CreateSimpleContentType2(string alias, string name, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content") + { + var builder = CreateSimpleContentTypeHelper(alias, name, parent, randomizeAliases, propertyGroupName); + + builder.AddPropertyType() + .WithAlias(RandomAlias("gen", randomizeAliases)) + .WithName("Gen") + .WithSortOrder(1) + .WithDataTypeId(-88) + .WithMandatory(false) + .WithDescription(string.Empty) + .Done(); + + return (ContentType)builder.Build(); + }public static ContentType CreateSimpleContentType(string alias = null, string name = null, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content", bool mandatoryProperties = false, int defaultTemplateId = 0) + { + return (ContentType)CreateSimpleContentTypeHelper(alias, name, parent, randomizeAliases, propertyGroupName, mandatoryProperties, defaultTemplateId).Build(); + } + + public static ContentTypeBuilder CreateSimpleContentTypeHelper(string alias = null, string name = null, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content", bool mandatoryProperties = false, int defaultTemplateId = 0) + { + return new ContentTypeBuilder() + .WithAlias(alias ?? "simple") + .WithName(name ?? "Simple Page") + .WithParentContentType(parent) + .AddPropertyGroup() + .WithName(propertyGroupName) + .WithSortOrder(1) + .WithSupportsPublishing(true) + .AddPropertyType() + .WithAlias(RandomAlias("title", randomizeAliases)) + .WithName("Title") + .WithSortOrder(1) + .WithMandatory(mandatoryProperties) + .Done() + .AddPropertyType() + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.TinyMce) + .WithValueStorageType(ValueStorageType.Ntext) + .WithAlias(RandomAlias("bodyText", randomizeAliases)) + .WithName("Body text") + .WithSortOrder(2) + .WithDataTypeId(Constants.DataTypes.RichtextEditor) + .WithMandatory(mandatoryProperties) + .Done() + .AddPropertyType() + .WithAlias(RandomAlias("author", randomizeAliases)) + .WithName("Author") + .WithSortOrder(3) + .WithMandatory(mandatoryProperties) + .Done() + .Done() + .AddAllowedTemplate() + .WithId(defaultTemplateId) + .WithAlias("textPage") + .WithName("Textpage") + .Done() + .WithDefaultTemplateId(defaultTemplateId); + } + + public static ContentType CreateSimpleTagsContentType(string alias, string name, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content", int defaultTemplateId = 1) + { + var contentType = CreateSimpleContentType(alias, name, parent, randomizeAliases, propertyGroupName, defaultTemplateId: defaultTemplateId); + + var propertyType = new PropertyTypeBuilder() + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Tags) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithAlias(RandomAlias("tags", randomizeAliases)) + .WithName("Tags") + .WithDataTypeId(Constants.DataTypes.Tags) + .WithSortOrder(99) + .Build(); + contentType.AddPropertyType(propertyType); + + return contentType; + } + + public static ContentType CreateTextPageContentType(string alias = "textPage", string name = "Text Page", int defaultTemplateId = 1) + { + var builder = new ContentTypeBuilder(); + return (ContentType)builder + .WithAlias(alias) + .WithName(name) + .AddPropertyGroup() + .WithId(1) + .WithName("Content") + .WithSortOrder(1) + .WithSupportsPublishing(true) + .AddPropertyType() + .WithAlias("title") + .WithName("Title") + .WithSortOrder(1) + .Done() + .AddPropertyType() + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.TinyMce) + .WithValueStorageType(ValueStorageType.Ntext) + .WithAlias("bodyText") + .WithName("Body text") + .WithSortOrder(2) + .WithDataTypeId(Constants.DataTypes.RichtextEditor) + .Done() + .Done() + .AddPropertyGroup() + .WithId(2) + .WithName("Meta") + .WithSortOrder(2) + .WithSupportsPublishing(true) + .AddPropertyType() + .WithAlias("keywords") + .WithName("Keywords") + .WithSortOrder(1) + .Done() + .AddPropertyType() + .WithAlias("description") + .WithName("Description") + .WithSortOrder(2) + .Done() + .Done() + .AddAllowedTemplate() + .WithId(defaultTemplateId) + .WithAlias("textpage") + .WithName("Textpage") + .Done() + .WithDefaultTemplateId(defaultTemplateId) + .Build(); + } + + public static ContentType CreateMetaContentType(string alias = "meta", string name = "Meta") + { + var builder = new ContentTypeBuilder(); + return (ContentType)builder + .WithAlias(alias) + .WithName(name) + .WithDescription($"ContentType used for {name} tags") + .AddPropertyGroup() + .WithName(name) + .WithSortOrder(2) + .WithSupportsPublishing(true) + .AddPropertyType() + .WithAlias($"{alias}keywords") + .WithName($"{name} Keywords") + .WithSortOrder(1) + .Done() + .AddPropertyType() + .WithAlias($"{alias}description") + .WithName($"{name} Description") + .WithSortOrder(2) + .Done() + .Done() + .Build(); + } + + public static ContentType CreateContentMetaContentType() + { + var builder = new ContentTypeBuilder(); + return (ContentType)builder + .WithAlias("contentMeta") + .WithName("Content Meta") + .WithDescription($"ContentType used for Content Meta") + .AddPropertyGroup() + .WithName("Content") + .WithSortOrder(2) + .WithSupportsPublishing(true) + .AddPropertyType() + .WithAlias("title") + .WithName("Title") + .WithSortOrder(1) + .Done() + .Done() + .Build(); + } + + public static ContentType CreateAllTypesContentType(string alias, string name) + { + var builder = new ContentTypeBuilder(); + return (ContentType)builder + .WithAlias(alias) + .WithName(name) + .AddPropertyGroup() + .WithName("Content") + .WithSupportsPublishing(true) + .AddPropertyType() + .WithAlias("isTrue") + .WithName("Is True or False") + .WithDataTypeId(Constants.DataTypes.Boolean) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Boolean) + .WithValueStorageType(ValueStorageType.Integer) + .WithSortOrder(1) + .Done() + .AddPropertyType() + .WithAlias("number") + .WithName("Number") + .WithDataTypeId(-51) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Integer) + .WithValueStorageType(ValueStorageType.Integer) + .WithSortOrder(2) + .Done() + .AddPropertyType() + .WithAlias("bodyText") + .WithName("Body Text") + .WithDataTypeId(Constants.DataTypes.RichtextEditor) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.TinyMce) + .WithValueStorageType(ValueStorageType.Ntext) + .WithSortOrder(3) + .Done() + .AddPropertyType() + .WithAlias("singleLineText") + .WithName("Text String") + .WithDataTypeId(Constants.DataTypes.Textbox) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.TextBox) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithSortOrder(4) + .Done() + .AddPropertyType() + .WithAlias("multilineText") + .WithName("Multiple Text Strings") + .WithDataTypeId(Constants.DataTypes.Textarea) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.TextArea) + .WithValueStorageType(ValueStorageType.Ntext) + .WithSortOrder(5) + .Done() + .AddPropertyType() + .WithAlias("upload") + .WithName("Upload Field") + .WithDataTypeId(Constants.DataTypes.Upload) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.UploadField) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithSortOrder(6) + .Done() + .AddPropertyType() + .WithAlias("label") + .WithName("Label") + .WithDataTypeId(Constants.DataTypes.LabelString) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Label) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithSortOrder(7) + .Done() + .AddPropertyType() + .WithAlias("dateTime") + .WithName("Date Time") + .WithDataTypeId(Constants.DataTypes.DateTime) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.DateTime) + .WithValueStorageType(ValueStorageType.Date) + .WithSortOrder(8) + .Done() + .AddPropertyType() + .WithAlias("colorPicker") + .WithName("Color Picker") + .WithDataTypeId(-37) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.ColorPicker) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithSortOrder(9) + .Done() + .AddPropertyType() + .WithAlias("ddlMultiple") + .WithName("Dropdown List Multiple") + .WithDataTypeId(Constants.DataTypes.DropDownMultiple) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.DropDownListFlexible) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithSortOrder(11) + .Done() + .AddPropertyType() + .WithAlias("rbList") + .WithName("Radio Button List") + .WithDataTypeId(-40) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.RadioButtonList) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithSortOrder(12) + .Done() + .AddPropertyType() + .WithAlias("date") + .WithName("Date") + .WithDataTypeId(-36) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.DateTime) + .WithValueStorageType(ValueStorageType.Date) + .WithSortOrder(13) + .Done() + .AddPropertyType() + .WithAlias("ddl") + .WithName("Dropdown List") + .WithDataTypeId(Constants.DataTypes.DropDownSingle) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.DropDownListFlexible) + .WithValueStorageType(ValueStorageType.Integer) + .WithSortOrder(14) + .Done() + .AddPropertyType() + .WithAlias("chklist") + .WithName("Checkbox List") + .WithDataTypeId(-43) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.CheckBoxList) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithSortOrder(15) + .Done() + .AddPropertyType() + .WithAlias("contentPicker") + .WithName("Content Picker") + .WithDataTypeId(1046) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.ContentPicker) + .WithValueStorageType(ValueStorageType.Integer) + .WithSortOrder(16) + .Done() + .AddPropertyType() + .WithAlias("mediaPicker") + .WithName("Media Picker") + .WithDataTypeId(1048) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.MediaPicker) + .WithValueStorageType(ValueStorageType.Integer) + .WithSortOrder(17) + .Done() + .AddPropertyType() + .WithAlias("memberPicker") + .WithName("Member Picker") + .WithDataTypeId(1047) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.MemberPicker) + .WithValueStorageType(ValueStorageType.Integer) + .WithSortOrder(18) + .Done() + .AddPropertyType() + .WithAlias("multiUrlPicker") + .WithName("Multi URL Picker") + .WithDataTypeId(1050) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.MultiUrlPicker) + .WithValueStorageType(ValueStorageType.Nvarchar) + .WithSortOrder(19) + .Done() + .AddPropertyType() + .WithAlias("tags") + .WithName("Tags") + .WithDataTypeId(Constants.DataTypes.Tags) + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Tags) + .WithValueStorageType(ValueStorageType.Ntext) + .WithSortOrder(20) + .Done() + .Done() + .Build(); } int? IWithPropertyTypeIdsIncrementingFrom.PropertyTypeIdsIncrementingFrom @@ -111,6 +473,5 @@ namespace Umbraco.Tests.Common.Builders get => _propertyTypeIdsIncrementingFrom; set => _propertyTypeIdsIncrementingFrom = value; } - } } diff --git a/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs b/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs index 5e6b174f56..f7185d1620 100644 --- a/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/DataEditorBuilder.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; @@ -38,7 +39,7 @@ namespace Umbraco.Tests.Common.Builders var explicitValueEditor = _explicitValueEditorBuilder.Build(); return new DataEditor( - Mock.Of(), + NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Tests.Common/Builders/Extensions/BuilderExtensions.cs b/src/Umbraco.Tests.Common/Builders/Extensions/BuilderExtensions.cs index b5294d85fd..1af2dc5344 100644 --- a/src/Umbraco.Tests.Common/Builders/Extensions/BuilderExtensions.cs +++ b/src/Umbraco.Tests.Common/Builders/Extensions/BuilderExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders.Interfaces; namespace Umbraco.Tests.Common.Builders.Extensions @@ -76,6 +77,13 @@ namespace Umbraco.Tests.Common.Builders.Extensions return builder; } + public static T WithParentContentType(this T builder, IContentTypeComposition parent) + where T : IWithParentContentTypeBuilder + { + builder.Parent = parent; + return builder; + } + public static T WithTrashed(this T builder, bool trashed) where T : IWithTrashedBuilder { @@ -194,10 +202,26 @@ namespace Umbraco.Tests.Common.Builders.Extensions return builder; } - public static T WithCultureInfo(this T builder, string name) + public static T WithCultureInfo(this T builder, string cultureCode) where T : IWithCultureInfoBuilder { - builder.CultureInfo = CultureInfo.GetCultureInfo(name); + builder.CultureInfo = CultureInfo.GetCultureInfo(cultureCode); + return builder; + } + + public static T WithSupportsPublishing(this T builder, bool supportsPublishing) + where T : IWithSupportsPublishing + { + builder.SupportsPublishing = supportsPublishing; + return builder; + } + + public static T WithPropertyValues(this T builder, object propertyValues, string culture = null, string segment = null) + where T : IWithPropertyValues + { + builder.PropertyValues = propertyValues; + builder.PropertyValuesCulture = culture; + builder.PropertyValuesSegment = segment; return builder; } } diff --git a/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs deleted file mode 100644 index b1fe45f1f7..0000000000 --- a/src/Umbraco.Tests.Common/Builders/GlobalSettingsBuilder.cs +++ /dev/null @@ -1,251 +0,0 @@ -using Umbraco.Core.Configuration; - -namespace Umbraco.Tests.Common.Builders -{ - public class GlobalSettingsBuilder : GlobalSettingsBuilder - { - public GlobalSettingsBuilder() : base(null) - { - } - } - - public class GlobalSettingsBuilder : ChildBuilderBase - { - private string _configurationStatus; - private string _databaseFactoryServerVersion; - private string _defaultUiLanguage; - private bool? _disableElectionForSingleServer; - private bool? _hideTopLevelNodeFromPath; - private bool? _installEmptyDatabase; - private bool? _installMissingDatabase; - private bool? _isSmtpServerConfigured; - private string _path; - private string _registerType; - private string _reservedPaths; - private string _reservedUrls; - private int? _timeOutInMinutes; - private string _umbracoCssPath; - private string _umbracoMediaPath; - private string _umbracoPath; - private string _umbracoScriptsPath; - private string _mainDomLock; - private string _noNodesViewPath; - private bool? _useHttps; - private int? _versionCheckPeriod; - private readonly SmtpSettingsBuilder> _smtpSettingsBuilder; - - public GlobalSettingsBuilder(TParent parentBuilder) : base(parentBuilder) - { - _smtpSettingsBuilder = new SmtpSettingsBuilder>(this); - } - - public SmtpSettingsBuilder> AddSmtpSettings() => _smtpSettingsBuilder; - - public GlobalSettingsBuilder WithConfigurationStatus(string configurationStatus) - { - _configurationStatus = configurationStatus; - return this; - } - - public GlobalSettingsBuilder WithDatabaseFactoryServerVersion(string databaseFactoryServerVersion) - { - _databaseFactoryServerVersion = databaseFactoryServerVersion; - return this; - } - - public GlobalSettingsBuilder WithDefaultUiLanguage(string defaultUiLanguage) - { - _defaultUiLanguage = defaultUiLanguage; - return this; - } - - public GlobalSettingsBuilder WithDisableElectionForSingleServer(bool disableElectionForSingleServer) - { - _disableElectionForSingleServer = disableElectionForSingleServer; - return this; - } - - public GlobalSettingsBuilder WithHideTopLevelNodeFromPath(bool hideTopLevelNodeFromPath) - { - _hideTopLevelNodeFromPath = hideTopLevelNodeFromPath; - return this; - } - - public GlobalSettingsBuilder WithInstallEmptyDatabase(bool installEmptyDatabase) - { - _installEmptyDatabase = installEmptyDatabase; - return this; - } - - public GlobalSettingsBuilder WithInstallMissingDatabase(bool installMissingDatabase) - { - _installMissingDatabase = installMissingDatabase; - return this; - } - - public GlobalSettingsBuilder WithIsSmtpServerConfigured(bool isSmtpServerConfigured) - { - _isSmtpServerConfigured = isSmtpServerConfigured; - return this; - } - - public GlobalSettingsBuilder WithPath(string path) - { - _path = path; - return this; - } - - public GlobalSettingsBuilder WithRegisterType(string registerType) - { - _registerType = registerType; - return this; - } - - public GlobalSettingsBuilder WithReservedPaths(string reservedPaths) - { - _reservedPaths = reservedPaths; - return this; - } - - public GlobalSettingsBuilder WithReservedUrls(string reservedUrls) - { - _reservedUrls = reservedUrls; - return this; - } - - public GlobalSettingsBuilder WithUmbracoPath(string umbracoPath) - { - _umbracoPath = umbracoPath; - return this; - } - - public GlobalSettingsBuilder WithUseHttps(bool useHttps) - { - _useHttps = useHttps; - return this; - } - - public GlobalSettingsBuilder WithUmbracoCssPath(string umbracoCssPath) - { - _umbracoCssPath = umbracoCssPath; - return this; - } - - public GlobalSettingsBuilder WithUmbracoMediaPath(string umbracoMediaPath) - { - _umbracoMediaPath = umbracoMediaPath; - return this; - } - - public GlobalSettingsBuilder WithUmbracoScriptsPath(string umbracoScriptsPath) - { - _umbracoScriptsPath = umbracoScriptsPath; - return this; - } - - public GlobalSettingsBuilder WithMainDomLock(string mainDomLock) - { - _mainDomLock = mainDomLock; - return this; - } - - public GlobalSettingsBuilder WithNoNodesViewPath(string noNodesViewPath) - { - _noNodesViewPath = noNodesViewPath; - return this; - } - public GlobalSettingsBuilder WithVersionCheckPeriod(int versionCheckPeriod) - { - _versionCheckPeriod = versionCheckPeriod; - return this; - } - - public GlobalSettingsBuilder WithTimeOutInMinutes(int timeOutInMinutes) - { - _timeOutInMinutes = timeOutInMinutes; - return this; - } - - public override IGlobalSettings Build() - { - var configurationStatus = _configurationStatus ?? "9.0.0"; - var databaseFactoryServerVersion = _databaseFactoryServerVersion ?? null; - var defaultUiLanguage = _defaultUiLanguage ?? "en"; - var disableElectionForSingleServer = _disableElectionForSingleServer ?? false; - var hideTopLevelNodeFromPath = _hideTopLevelNodeFromPath ?? false; - var installEmptyDatabase = _installEmptyDatabase ?? false; - var installMissingDatabase = _installMissingDatabase ?? false; - var isSmtpServerConfigured = _isSmtpServerConfigured ?? false; - var path = _path ?? "/umbraco"; - var registerType = _registerType ?? null; - var reservedPaths = _reservedPaths ?? "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; - var reservedUrls = _reservedUrls ?? "~/config/splashes/noNodes.aspx,~/.well-known,"; - var umbracoPath = _umbracoPath ?? "~/umbraco"; - var useHttps = _useHttps ?? false; - var umbracoCssPath = _umbracoCssPath ?? "~/css"; - var umbracoMediaPath = _umbracoMediaPath ?? "~/media"; - var umbracoScriptsPath = _umbracoScriptsPath ?? "~/scripts"; - var versionCheckPeriod = _versionCheckPeriod ?? 0; - var timeOutInMinutes = _timeOutInMinutes ?? 20; - var smtpSettings = _smtpSettingsBuilder.Build(); - var mainDomLock = _mainDomLock ?? string.Empty; - var noNodesViewPath = _noNodesViewPath ?? "~/config/splashes/NoNodes.cshtml"; - - return new TestGlobalSettings - { - ConfigurationStatus = configurationStatus, - DatabaseFactoryServerVersion = databaseFactoryServerVersion, - DefaultUILanguage = defaultUiLanguage, - DisableElectionForSingleServer = disableElectionForSingleServer, - HideTopLevelNodeFromPath = hideTopLevelNodeFromPath, - InstallEmptyDatabase = installEmptyDatabase, - InstallMissingDatabase = installMissingDatabase, - IsSmtpServerConfigured = isSmtpServerConfigured, - Path = path, - RegisterType = registerType, - ReservedPaths = reservedPaths, - ReservedUrls = reservedUrls, - UmbracoPath = umbracoPath, - UseHttps = useHttps, - UmbracoCssPath = umbracoCssPath, - UmbracoMediaPath = umbracoMediaPath, - UmbracoScriptsPath = umbracoScriptsPath, - VersionCheckPeriod = versionCheckPeriod, - TimeOutInMinutes = timeOutInMinutes, - SmtpSettings = smtpSettings, - MainDomLock = mainDomLock, - NoNodesViewPath = noNodesViewPath, - }; - } - - private class TestGlobalSettings : IGlobalSettings - { - 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/Interfaces/IWithParentContentTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithParentContentTypeBuilder.cs new file mode 100644 index 0000000000..a9812654ef --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithParentContentTypeBuilder.cs @@ -0,0 +1,9 @@ +using Umbraco.Core.Models; + +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithParentContentTypeBuilder + { + IContentTypeComposition Parent { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithPropertyValues.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithPropertyValues.cs new file mode 100644 index 0000000000..c5a6c35724 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithPropertyValues.cs @@ -0,0 +1,11 @@ +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithPropertyValues + { + object PropertyValues { get; set; } + + string PropertyValuesCulture { get; set; } + + string PropertyValuesSegment { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/Interfaces/IWithSupportsPublishing.cs b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithSupportsPublishing.cs new file mode 100644 index 0000000000..03bf74aa06 --- /dev/null +++ b/src/Umbraco.Tests.Common/Builders/Interfaces/IWithSupportsPublishing.cs @@ -0,0 +1,9 @@ +using System; + +namespace Umbraco.Tests.Common.Builders.Interfaces +{ + public interface IWithSupportsPublishing + { + bool? SupportsPublishing { get; set; } + } +} diff --git a/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs b/src/Umbraco.Tests.Common/Builders/LanguageBuilder.cs index 88c8fa4639..4cd924fa3a 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; @@ -25,6 +24,7 @@ namespace Umbraco.Tests.Common.Builders { private DateTime? _createDate; private CultureInfo _cultureInfo; + private string _cultureName; private DateTime? _deleteDate; private int? _fallbackLanguageId; private int? _id; @@ -37,6 +37,12 @@ namespace Umbraco.Tests.Common.Builders { } + public LanguageBuilder WithCultureName(string cultureName) + { + _cultureName = cultureName; + return this; + } + public LanguageBuilder WithIsDefault(bool isDefault) { _isDefault = isDefault; @@ -58,6 +64,8 @@ namespace Umbraco.Tests.Common.Builders public override ILanguage Build() { var cultureInfo = _cultureInfo ?? CultureInfo.GetCultureInfo("en-US"); + var cultureName = _cultureName ?? cultureInfo.EnglishName; + var globalSettings = new GlobalSettings { DefaultUILanguage = cultureInfo.Name }; var key = _key ?? Guid.NewGuid(); var createDate = _createDate ?? DateTime.Now; var updateDate = _updateDate ?? DateTime.Now; @@ -66,10 +74,10 @@ 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, + CultureName = cultureName, IsoCode = cultureInfo.Name, Key = key, CreateDate = createDate, diff --git a/src/Umbraco.Tests.Common/Builders/MediaBuilder.cs b/src/Umbraco.Tests.Common/Builders/MediaBuilder.cs index e65f52f488..8a0c8c4b4a 100644 --- a/src/Umbraco.Tests.Common/Builders/MediaBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/MediaBuilder.cs @@ -1,6 +1,9 @@ using System; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders.Interfaces; +using Umbraco.Tests.Common.Builders.Extensions; +using Umbraco.Core; +using Umbraco.Tests.Testing; namespace Umbraco.Tests.Common.Builders { @@ -17,7 +20,8 @@ namespace Umbraco.Tests.Common.Builders IWithTrashedBuilder, IWithLevelBuilder, IWithPathBuilder, - IWithSortOrderBuilder + IWithSortOrderBuilder, + IWithPropertyValues { private MediaTypeBuilder _mediaTypeBuilder; private GenericDictionaryBuilder _propertyDataBuilder; @@ -33,36 +37,59 @@ namespace Umbraco.Tests.Common.Builders private string _path; private int? _sortOrder; private bool? _trashed; + private IMediaType _mediaType; + private object _propertyValues; + private string _propertyValuesCulture; + private string _propertyValuesSegment; public MediaTypeBuilder AddMediaType() { + _mediaType = null; var builder = new MediaTypeBuilder(this); _mediaTypeBuilder = builder; return builder; } + public MediaBuilder WithMediaType(IMediaType mediaType) + { + _mediaTypeBuilder = null; + _mediaType = mediaType; + + return this; + } + + public GenericDictionaryBuilder AddPropertyData() + { + var builder = new GenericDictionaryBuilder(this); + _propertyDataBuilder = builder; + return builder; + } + public override Media Build() { - var id = _id ?? 1; + var id = _id ?? 0; var key = _key ?? Guid.NewGuid(); var parentId = _parentId ?? -1; var createDate = _createDate ?? DateTime.Now; var updateDate = _updateDate ?? DateTime.Now; var name = _name ?? Guid.NewGuid().ToString(); - var creatorId = _creatorId ?? 1; + var creatorId = _creatorId ?? 0; var level = _level ?? 1; var path = _path ?? $"-1,{id}"; var sortOrder = _sortOrder ?? 0; var trashed = _trashed ?? false; + var propertyValues = _propertyValues ?? null; + var propertyValuesCulture = _propertyValuesCulture ?? null; + var propertyValuesSegment = _propertyValuesSegment ?? null; - if (_mediaTypeBuilder == null) + if (_mediaTypeBuilder is null && _mediaType is null) { - throw new InvalidOperationException("A member cannot be constructed without providing a member type. Use AddMediaType()."); + throw new InvalidOperationException("A media item cannot be constructed without providing a media type. Use AddMediaType() or WithMediaType()."); } - var memberType = _mediaTypeBuilder.Build(); + var mediaType = _mediaType ?? _mediaTypeBuilder.Build(); - var member = new Media(name, parentId, memberType) + var media = new Media(name, parentId, mediaType) { Id = id, Key = key, @@ -75,18 +102,89 @@ namespace Umbraco.Tests.Common.Builders Trashed = trashed, }; - if (_propertyDataBuilder != null) + if (_propertyDataBuilder != null || propertyValues != null) { - var propertyData = _propertyDataBuilder.Build(); - foreach (var kvp in propertyData) + if (_propertyDataBuilder != null) { - member.SetValue(kvp.Key, kvp.Value); + var propertyData = _propertyDataBuilder.Build(); + foreach (var keyValuePair in propertyData) + { + media.SetValue(keyValuePair.Key, keyValuePair.Value); + } + } + else + { + media.PropertyValues(propertyValues, propertyValuesCulture, propertyValuesSegment); } - member.ResetDirtyProperties(false); + media.ResetDirtyProperties(false); } - return member; + return media; + } + + public static Media CreateSimpleMedia(IMediaType mediaType, string name, int parentId) + { + return new MediaBuilder() + .WithName(name) + .WithMediaType(mediaType) + .WithParentId(parentId) + .WithPropertyValues(new + { + title = name + " Subpage", + bodyText = "This is a subpage", + author = "John Doe" + }) + .Build(); + } + + public static Media CreateMediaImage(IMediaType mediaType, int parentId) + { + return CreateMediaImage(mediaType, parentId, "/media/test-image.png"); + } + + public static Media CreateMediaImageWithCrop(IMediaType mediaType, int parentId) + { + return CreateMediaImage(mediaType, parentId, "{src: '/media/test-image.png', crops: []}"); + } + + private static Media CreateMediaImage(IMediaType mediaType, int parentId, string fileValue) + { + return new MediaBuilder() + .WithMediaType(mediaType) + .WithName("Test Image") + .WithParentId(parentId) + .AddPropertyData() + .WithKeyValue(Constants.Conventions.Media.File, fileValue) + .WithKeyValue(Constants.Conventions.Media.Width, "200") + .WithKeyValue(Constants.Conventions.Media.Height, "200") + .WithKeyValue(Constants.Conventions.Media.Bytes, "100") + .WithKeyValue(Constants.Conventions.Media.Extension, "png") + .Done() + .Build(); + } + + public static Media CreateMediaFolder(IMediaType mediaType, int parentId) + { + return new MediaBuilder() + .WithMediaType(mediaType) + .WithName("Test Folder") + .WithParentId(parentId) + .Build(); + } + + public static Media CreateMediaFile(IMediaType mediaType, int parentId) + { + return new MediaBuilder() + .WithMediaType(mediaType) + .WithName("Test File") + .WithParentId(parentId) + .AddPropertyData() + .WithKeyValue(Constants.Conventions.Media.File, "/media/test-file.txt") + .WithKeyValue(Constants.Conventions.Media.Bytes, "100") + .WithKeyValue(Constants.Conventions.Media.Extension, "png") + .Done() + .Build(); } int? IWithIdBuilder.Id @@ -153,5 +251,23 @@ namespace Umbraco.Tests.Common.Builders get => _parentId; set => _parentId = value; } + + object IWithPropertyValues.PropertyValues + { + get => _propertyValues; + set => _propertyValues = value; + } + + string IWithPropertyValues.PropertyValuesCulture + { + get => _propertyValuesCulture; + set => _propertyValuesCulture = value; + } + + string IWithPropertyValues.PropertyValuesSegment + { + get => _propertyValuesSegment; + set => _propertyValuesSegment = value; + } } } diff --git a/src/Umbraco.Tests.Common/Builders/MediaTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/MediaTypeBuilder.cs index 7ec3a3be4a..3cbb80bde4 100644 --- a/src/Umbraco.Tests.Common/Builders/MediaTypeBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/MediaTypeBuilder.cs @@ -81,24 +81,35 @@ namespace Umbraco.Tests.Common.Builders public override IMediaType Build() { - var mediaType = new MediaType(ShortStringHelper, GetParentId()) + MediaType mediaType; + var parent = GetParent(); + if (parent != null) { - Id = GetId(), - Key = GetKey(), - CreateDate = GetCreateDate(), - UpdateDate = GetUpdateDate(), - Alias = GetAlias(), - Name = GetName(), - Level = GetLevel(), - Path = GetPath(), - SortOrder = GetSortOrder(), - Description = GetDescription(), - Icon = GetIcon(), - Thumbnail = GetThumbnail(), - CreatorId = GetCreatorId(), - Trashed = GetTrashed(), - IsContainer = GetIsContainer(), - }; + mediaType = new MediaType(ShortStringHelper, (IMediaType)parent, GetAlias()); + } + else + { + mediaType = new MediaType(ShortStringHelper, GetParentId()) + { + Alias = GetAlias(), + }; + } + + mediaType.Id = GetId(); + mediaType.Key = GetKey(); + mediaType.CreateDate = GetCreateDate(); + mediaType.UpdateDate = GetUpdateDate(); + mediaType.Alias = GetAlias(); + mediaType.Name = GetName(); + mediaType.Level = GetLevel(); + mediaType.Path = GetPath(); + mediaType.SortOrder = GetSortOrder(); + mediaType.Description = GetDescription(); + mediaType.Icon = GetIcon(); + mediaType.Thumbnail = GetThumbnail(); + mediaType.CreatorId = GetCreatorId(); + mediaType.Trashed = GetTrashed(); + mediaType.IsContainer = GetIsContainer(); BuildPropertyGroups(mediaType, _propertyGroupBuilders.Select(x => x.Build())); BuildPropertyTypeIds(mediaType, _propertyTypeIdsIncrementingFrom); @@ -108,6 +119,134 @@ namespace Umbraco.Tests.Common.Builders return mediaType; } + public static MediaType CreateSimpleMediaType(string alias, string name, IMediaType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content") + { + var builder = new MediaTypeBuilder(); + var mediaType = builder + .WithAlias(alias) + .WithName(name) + .WithParentContentType(parent) + .AddPropertyGroup() + .WithName(propertyGroupName) + .WithSortOrder(1) + .AddPropertyType() + .WithAlias(RandomAlias("title", randomizeAliases)) + .WithName("Title") + .WithSortOrder(1) + .Done() + .AddPropertyType() + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.TinyMce) + .WithValueStorageType(ValueStorageType.Ntext) + .WithAlias(RandomAlias("bodyText", randomizeAliases)) + .WithName("Body text") + .WithSortOrder(2) + .WithDataTypeId(-87) + .Done() + .AddPropertyType() + .WithAlias(RandomAlias("author", randomizeAliases)) + .WithName("Author") + .WithSortOrder(3) + .Done() + .Done() + .Build(); + + // Ensure that nothing is marked as dirty + mediaType.ResetDirtyProperties(false); + + return (MediaType)mediaType; + } + + public static MediaType CreateImageMediaType(string alias = Constants.Conventions.MediaTypes.Image) + { + return CreateImageMediaType(alias ?? "Image", Constants.PropertyEditors.Aliases.UploadField, -90); + } + + public static MediaType CreateImageMediaTypeWithCrop(string alias = Constants.Conventions.MediaTypes.Image) + { + return CreateImageMediaType(alias ?? "Image", Constants.PropertyEditors.Aliases.ImageCropper, 1043); + } + + private static MediaType CreateImageMediaType(string alias, string imageFieldPropertyEditorAlias, int imageFieldDataTypeId) + { + var builder = new MediaTypeBuilder(); + var mediaType = builder + .WithAlias(alias) + .WithName("Image") + .AddPropertyGroup() + .WithName("Media") + .WithSortOrder(1) + .AddPropertyType() + .WithPropertyEditorAlias(imageFieldPropertyEditorAlias) + .WithAlias(Constants.Conventions.Media.File) + .WithName("File") + .WithSortOrder(1) + .WithDataTypeId(imageFieldDataTypeId) + .Done() + .AddPropertyType() + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Label) + .WithAlias(Constants.Conventions.Media.Width) + .WithName("Width") + .WithSortOrder(2) + .WithDataTypeId(Constants.System.DefaultLabelDataTypeId) + .Done() + .AddPropertyType() + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Label) + .WithAlias(Constants.Conventions.Media.Height) + .WithName("Height") + .WithSortOrder(3) + .WithDataTypeId(Constants.System.DefaultLabelDataTypeId) + .Done() + .AddPropertyType() + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Label) + .WithAlias(Constants.Conventions.Media.Bytes) + .WithName("Bytes") + .WithSortOrder(4) + .WithDataTypeId(Constants.System.DefaultLabelDataTypeId) + .Done() + .AddPropertyType() + .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Label) + .WithAlias(Constants.Conventions.Media.Extension) + .WithName("File Extension") + .WithSortOrder(5) + .WithDataTypeId(Constants.System.DefaultLabelDataTypeId) + .Done() + .Done() + .Build(); + + // Ensure that nothing is marked as dirty + mediaType.ResetDirtyProperties(false); + + return (MediaType)mediaType; + } + + public static MediaType CreateVideoMediaType() + { + var builder = new MediaTypeBuilder(); + var mediaType = builder + .WithAlias("video") + .WithName("Video") + .AddPropertyGroup() + .WithName("Media") + .WithSortOrder(1) + .AddPropertyType() + .WithAlias("title") + .WithName("Title") + .WithSortOrder(1) + .Done() + .AddPropertyType() + .WithAlias("videoFile") + .WithName("Video file") + .WithSortOrder(1) + .Done() + .Done() + .Build(); + + // Ensure that nothing is marked as dirty + mediaType.ResetDirtyProperties(false); + + return (MediaType)mediaType; + } + int? IWithPropertyTypeIdsIncrementingFrom.PropertyTypeIdsIncrementingFrom { get => _propertyTypeIdsIncrementingFrom; diff --git a/src/Umbraco.Tests.Common/Builders/MemberBuilder.cs b/src/Umbraco.Tests.Common/Builders/MemberBuilder.cs index ff954b741e..001956b66e 100644 --- a/src/Umbraco.Tests.Common/Builders/MemberBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/MemberBuilder.cs @@ -1,6 +1,8 @@ using System; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders.Interfaces; +using Umbraco.Tests.Common.Builders.Extensions; +using System.Collections.Generic; namespace Umbraco.Tests.Common.Builders { @@ -45,6 +47,7 @@ namespace Umbraco.Tests.Common.Builders private int? _sortOrder; private bool? _trashed; private int? _propertyIdsIncrementingFrom; + private IMemberType _memberType; public MemberBuilder WithPropertyIdsIncrementingFrom(int propertyIdsIncrementingFrom) { @@ -54,11 +57,20 @@ namespace Umbraco.Tests.Common.Builders public MemberTypeBuilder AddMemberType() { + _memberType = null; var builder = new MemberTypeBuilder(this); _memberTypeBuilder = builder; return builder; } + public MemberBuilder WithMemberType(IMemberType memberType) + { + _memberTypeBuilder = null; + _memberType = memberType; + + return this; + } + public GenericCollectionBuilder AddMemberGroups() { var builder = new GenericCollectionBuilder(this); @@ -82,12 +94,12 @@ namespace Umbraco.Tests.Common.Builders public override Member Build() { - var id = _id ?? 1; + var id = _id ?? 0; var key = _key ?? Guid.NewGuid(); var createDate = _createDate ?? DateTime.Now; var updateDate = _updateDate ?? DateTime.Now; var name = _name ?? Guid.NewGuid().ToString(); - var creatorId = _creatorId ?? 1; + var creatorId = _creatorId ?? 0; var level = _level ?? 1; var path = _path ?? $"-1,{id}"; var sortOrder = _sortOrder ?? 0; @@ -102,12 +114,12 @@ namespace Umbraco.Tests.Common.Builders var lastLoginDate = _lastLoginDate ?? DateTime.Now; var lastPasswordChangeDate = _lastPasswordChangeDate ?? DateTime.Now; - if (_memberTypeBuilder == null) + if (_memberTypeBuilder is null && _memberType is null) { - throw new InvalidOperationException("A member cannot be constructed without providing a member type. Use AddMemberType()."); + throw new InvalidOperationException("A member cannot be constructed without providing a member type. Use AddMemberType() or WithMemberType()."); } - var memberType = _memberTypeBuilder.Build(); + var memberType = _memberType ?? _memberTypeBuilder.Build(); var member = new Member(name, email, username, rawPasswordValue, memberType) { @@ -166,6 +178,84 @@ namespace Umbraco.Tests.Common.Builders return member; } + public static IEnumerable CreateSimpleMembers(IMemberType memberType, int amount, Action onCreating = null) + { + var list = new List(); + + for (int i = 0; i < amount; i++) + { + var name = "Member No-" + i; + + var builder = new MemberBuilder() + .WithMemberType(memberType) + .WithName(name) + .WithEmail("test" + i + "@test.com") + .WithLogin("test" + i, "test" + i); + + + builder = builder + .AddPropertyData() + .WithKeyValue("title", name + " member" + i) + .WithKeyValue("bodyText", "This is a subpage" + i) + .WithKeyValue("author", "John Doe" + i) + .Done(); + + list.Add(builder.Build()); + } + + return list; + } + public static Member CreateSimpleMember(IMemberType memberType, string name, string email, string password, string username, Guid? key = null) + { + var builder = new MemberBuilder() + .WithMemberType(memberType) + .WithName(name) + .WithEmail(email) + .WithIsApproved(true) + .WithLogin(username, password); + + if (key.HasValue) + { + builder = builder.WithKey(key.Value); + } + + builder = builder + .AddPropertyData() + .WithKeyValue("title", name + " member") + .WithKeyValue("bodyText", "Member profile") + .WithKeyValue("author", "John Doe") + .Done(); + + return builder.Build(); + } + + public static IEnumerable CreateMultipleSimpleMembers(IMemberType memberType, int amount, Action onCreating = null) + { + var list = new List(); + + for (var i = 0; i < amount; i++) + { + var name = "Member No-" + i; + var member = new MemberBuilder() + .WithMemberType(memberType) + .WithName(name) + .WithEmail("test" + i + "@test.com") + .WithLogin("test" + i, "test" + i) + .AddPropertyData() + .WithKeyValue("title", name + " member" + i) + .WithKeyValue("bodyText", "Member profile" + i) + .WithKeyValue("author", "John Doe" + i) + .Done() + .Build(); + + onCreating?.Invoke(i, member); + + list.Add(member); + } + + return list; + } + int? IWithIdBuilder.Id { get => _id; diff --git a/src/Umbraco.Tests.Common/Builders/MemberTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/MemberTypeBuilder.cs index 0bc5b2e602..e111ae8cb4 100644 --- a/src/Umbraco.Tests.Common/Builders/MemberTypeBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/MemberTypeBuilder.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; using Umbraco.Core; @@ -134,6 +133,40 @@ namespace Umbraco.Tests.Common.Builders return memberType; } + public static MemberType CreateSimpleMemberType(string alias = null, string name = null) + { + var builder = new MemberTypeBuilder(); + var memberType = builder + .WithAlias(alias) + .WithName(name) + .AddPropertyGroup() + .WithName("Content") + .WithSortOrder(1) + .AddPropertyType() + .WithAlias("title") + .WithName("Title") + .WithSortOrder(1) + .Done() + .AddPropertyType() + .WithAlias("bodyText") + .WithName("Body text") + .WithSortOrder(2) + .WithDataTypeId(-87) + .Done() + .AddPropertyType() + .WithAlias("author") + .WithName("Author") + .WithSortOrder(3) + .Done() + .Done() + .Build(); + + // Ensure that nothing is marked as dirty + memberType.ResetDirtyProperties(false); + + return (MemberType)memberType; + } + int? IWithPropertyTypeIdsIncrementingFrom.PropertyTypeIdsIncrementingFrom { get => _propertyTypeIdsIncrementingFrom; diff --git a/src/Umbraco.Tests.Common/Builders/PropertyGroupBuilder.cs b/src/Umbraco.Tests.Common/Builders/PropertyGroupBuilder.cs index 5df61dd072..f153283764 100644 --- a/src/Umbraco.Tests.Common/Builders/PropertyGroupBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/PropertyGroupBuilder.cs @@ -25,7 +25,8 @@ namespace Umbraco.Tests.Common.Builders IWithCreateDateBuilder, IWithUpdateDateBuilder, IWithNameBuilder, - IWithSortOrderBuilder where TParent: IBuildPropertyGroups + IWithSortOrderBuilder, + IWithSupportsPublishing where TParent: IBuildPropertyGroups { private readonly List>> _propertyTypeBuilders = new List>>(); @@ -35,6 +36,7 @@ namespace Umbraco.Tests.Common.Builders private DateTime? _updateDate; private string _name; private int? _sortOrder; + private bool? _supportsPublishing; public PropertyGroupBuilder(TParent parentBuilder) : base(parentBuilder) { @@ -55,8 +57,9 @@ namespace Umbraco.Tests.Common.Builders var updateDate = _updateDate ?? DateTime.Now; var name = _name ?? Guid.NewGuid().ToString(); var sortOrder = _sortOrder ?? 0; + var supportsPublishing = _supportsPublishing ?? false; - var properties = new PropertyTypeCollection(false); + var properties = new PropertyTypeCollection(supportsPublishing); foreach (var propertyType in _propertyTypeBuilders.Select(x => x.Build())) { properties.Add(propertyType); @@ -108,5 +111,11 @@ namespace Umbraco.Tests.Common.Builders get => _sortOrder; set => _sortOrder = value; } + + bool? IWithSupportsPublishing.SupportsPublishing + { + get => _supportsPublishing; + set => _supportsPublishing = value; + } } } diff --git a/src/Umbraco.Tests.Common/Builders/PropertyTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/PropertyTypeBuilder.cs index ed02cfa02f..e4e9b4d621 100644 --- a/src/Umbraco.Tests.Common/Builders/PropertyTypeBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/PropertyTypeBuilder.cs @@ -27,7 +27,8 @@ namespace Umbraco.Tests.Common.Builders IWithCreateDateBuilder, IWithUpdateDateBuilder, IWithSortOrderBuilder, - IWithDescriptionBuilder where TParent : IBuildPropertyTypes + IWithDescriptionBuilder, + IWithSupportsPublishing where TParent : IBuildPropertyTypes { private int? _id; private Guid? _key; @@ -45,6 +46,8 @@ namespace Umbraco.Tests.Common.Builders private string _mandatoryMessage; private string _validationRegExp; private string _validationRegExpMessage; + private bool? _supportsPublishing; + private ContentVariation? _variations; public PropertyTypeBuilder(TParent parentBuilder) : base(parentBuilder) { @@ -88,6 +91,12 @@ namespace Umbraco.Tests.Common.Builders return this; } + public PropertyTypeBuilder WithVariations(ContentVariation variation) + { + _variations = variation; + return this; + } + public override PropertyType Build() { var id = _id ?? 0; @@ -106,10 +115,12 @@ namespace Umbraco.Tests.Common.Builders var mandatoryMessage = _mandatoryMessage ?? string.Empty; var validationRegExp = _validationRegExp ?? string.Empty; var validationRegExpMessage = _validationRegExpMessage ?? string.Empty; + var supportsPublishing = _supportsPublishing ?? false; + var variations = _variations ?? ContentVariation.Nothing; var shortStringHelper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); - return new PropertyType(shortStringHelper, propertyEditorAlias, valueStorageType) + var propertyType = new PropertyType(shortStringHelper, propertyEditorAlias, valueStorageType) { Id = id, Key = key, @@ -125,7 +136,11 @@ namespace Umbraco.Tests.Common.Builders MandatoryMessage = mandatoryMessage, ValidationRegExp = validationRegExp, ValidationRegExpMessage = validationRegExpMessage, + SupportsPublishing = supportsPublishing, + Variations = variations, }; + + return propertyType; } int? IWithIdBuilder.Id @@ -175,5 +190,11 @@ namespace Umbraco.Tests.Common.Builders get => _description; set => _description = value; } + + bool? IWithSupportsPublishing.SupportsPublishing + { + get => _supportsPublishing; + set => _supportsPublishing = value; + } } } diff --git a/src/Umbraco.Tests.Common/Builders/RelationBuilder.cs b/src/Umbraco.Tests.Common/Builders/RelationBuilder.cs index 2cea234200..9c29897de4 100644 --- a/src/Umbraco.Tests.Common/Builders/RelationBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/RelationBuilder.cs @@ -20,6 +20,7 @@ namespace Umbraco.Tests.Common.Builders private DateTime? _createDate; private DateTime? _updateDate; private string _comment; + private IRelationType _relationType; public RelationBuilder WithComment(string comment) { @@ -34,8 +35,16 @@ namespace Umbraco.Tests.Common.Builders return this; } + public RelationBuilder WithRelationType(IRelationType relationType) + { + _relationType = relationType; + _relationTypeBuilder = null; + return this; + } + public RelationTypeBuilder AddRelationType() { + _relationType = null; var builder = new RelationTypeBuilder(this); _relationTypeBuilder = builder; return builder; @@ -51,12 +60,12 @@ namespace Umbraco.Tests.Common.Builders var updateDate = _updateDate ?? DateTime.Now; var comment = _comment ?? string.Empty; - if (_relationTypeBuilder == null) + if (_relationTypeBuilder == null && _relationType == null) { - throw new InvalidOperationException("Cannot construct a Relation without a RelationType. Use AddRelationType()."); + throw new InvalidOperationException("Cannot construct a Relation without a RelationType. Use AddRelationType() or WithRelationType()."); } - var relationType = _relationTypeBuilder.Build(); + var relationType = _relationType ?? _relationTypeBuilder.Build(); return new Relation(parentId, childId, relationType) { diff --git a/src/Umbraco.Tests.Common/Builders/RelationTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/RelationTypeBuilder.cs index 243f5e3c96..7c47c1dad1 100644 --- a/src/Umbraco.Tests.Common/Builders/RelationTypeBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/RelationTypeBuilder.cs @@ -57,7 +57,7 @@ namespace Umbraco.Tests.Common.Builders var name = _name ?? Guid.NewGuid().ToString(); var parentObjectType = _parentObjectType ?? null; var childObjectType = _childObjectType ?? null; - var id = _id ?? 1; + var id = _id ?? 0; var key = _key ?? Guid.NewGuid(); var isBidirectional = _isBidirectional ?? false; var createDate = _createDate ?? DateTime.Now; diff --git a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs b/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs deleted file mode 100644 index bd85807203..0000000000 --- a/src/Umbraco.Tests.Common/Builders/SmtpSettingsBuilder.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System.Net.Mail; -using Umbraco.Core.Configuration; -using Umbraco.Core.Models.Membership; - -namespace Umbraco.Tests.Common.Builders -{ - public class SmtpSettingsBuilder : SmtpSettingsBuilder - { - public SmtpSettingsBuilder() : base(null) - { - } - } - - public class SmtpSettingsBuilder - : ChildBuilderBase - { - private string _from; - private string _host; - private int? _port; - private string _pickupDirectoryLocation; - private SmtpDeliveryMethod? _deliveryMethod; - private string _username; - private string _password; - - public SmtpSettingsBuilder(TParent parentBuilder) : base(parentBuilder) - { - } - - public SmtpSettingsBuilder WithFrom(string from) - { - _from = from; - return this; - } - - public SmtpSettingsBuilder WithHost(string host) - { - _host = host; - return this; - } - - public SmtpSettingsBuilder WithUsername(string username) - { - _username = username; - return this; - } - - public SmtpSettingsBuilder WithPost(int port) - { - _port = port; - return this; - } - - public SmtpSettingsBuilder WithPassword(string password) - { - _password = password; - return this; - } - - public SmtpSettingsBuilder WithPickupDirectoryLocation(string pickupDirectoryLocation) - { - _pickupDirectoryLocation = pickupDirectoryLocation; - return this; - } - - public SmtpSettingsBuilder WithDeliveryMethod(SmtpDeliveryMethod deliveryMethod) - { - _deliveryMethod = deliveryMethod; - return this; - } - - public override ISmtpSettings Build() - { - var from = _from ?? null; - var host = _host ?? null; - var port = _port ?? 25; - var pickupDirectoryLocation = _pickupDirectoryLocation ?? null; - var deliveryMethod = _deliveryMethod ?? SmtpDeliveryMethod.Network; - var username = _username ?? null; - var password = _password ?? null; - - return new TestSmtpSettings() - { - From = from, - Host = host, - Port = port, - PickupDirectoryLocation = pickupDirectoryLocation, - DeliveryMethod = deliveryMethod, - Username = username, - 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/TemplateBuilder.cs b/src/Umbraco.Tests.Common/Builders/TemplateBuilder.cs index 7a2007967e..2fd86b60b7 100644 --- a/src/Umbraco.Tests.Common/Builders/TemplateBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/TemplateBuilder.cs @@ -62,11 +62,11 @@ namespace Umbraco.Tests.Common.Builders var content = _content; var isMasterTemplate = _isMasterTemplate ?? false; var masterTemplateAlias = _masterTemplateAlias ?? string.Empty; - var masterTemplateId = _masterTemplateId ?? null; + var masterTemplateId = _masterTemplateId ?? new Lazy(() => -1); var shortStringHelper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); - return new Template(shortStringHelper, name, alias) + var template = new Template(shortStringHelper, name, alias) { Id = id, Key = key, @@ -78,6 +78,16 @@ namespace Umbraco.Tests.Common.Builders MasterTemplateAlias = masterTemplateAlias, MasterTemplateId = masterTemplateId, }; + + return template; + } + + public static Template CreateTextPageTemplate(string alias = "textPage") + { + return (Template)new TemplateBuilder() + .WithAlias(alias) + .WithName("Text page") + .Build(); } int? IWithIdBuilder.Id diff --git a/src/Umbraco.Tests.Common/Builders/UserBuilder.cs b/src/Umbraco.Tests.Common/Builders/UserBuilder.cs index 83c036c101..46f45b0c8c 100644 --- a/src/Umbraco.Tests.Common/Builders/UserBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/UserBuilder.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; using Umbraco.Tests.Common.Builders.Interfaces; +using Umbraco.Tests.Common.Builders.Extensions; namespace Umbraco.Tests.Common.Builders { @@ -12,6 +14,7 @@ namespace Umbraco.Tests.Common.Builders { } } + public class UserBuilder : ChildBuilderBase, IWithIdBuilder, @@ -91,8 +94,6 @@ namespace Umbraco.Tests.Common.Builders return this; } - - public UserBuilder WithSessionTimeout(int sessionTimeout) { _sessionTimeout = sessionTimeout; @@ -122,11 +123,18 @@ namespace Umbraco.Tests.Common.Builders return this; } + public UserGroupBuilder> AddUserGroup() + { + var builder = new UserGroupBuilder>(this); + _userGroupBuilders.Add(builder); + return builder; + } + public override User Build() { var id = _id ?? 0; var defaultLang = _defaultLang ?? "en"; - var globalSettings = new GlobalSettingsBuilder().WithDefaultUiLanguage(defaultLang).Build(); + var globalSettings = new GlobalSettings { DefaultUILanguage = defaultLang }; var key = _key ?? Guid.NewGuid(); var createDate = _createDate ?? DateTime.Now; var updateDate = _updateDate ?? DateTime.Now; @@ -175,19 +183,41 @@ namespace Umbraco.Tests.Common.Builders result.AddGroup(readOnlyUserGroup.ToReadOnlyGroup()); } - return result; } - public UserGroupBuilder> AddUserGroup() + public static IEnumerable CreateMulipleUsers(int amount, Action onCreating = null) { - var builder = new UserGroupBuilder>(this); + var list = new List(); - _userGroupBuilders.Add(builder); + for (var i = 0; i < amount; i++) + { + var name = "User No-" + i; + var user = new UserBuilder() + .WithName(name) + .WithEmail("test" + i + "@test.com") + .WithLogin("test" + i, "test" + i) + .Build(); - return builder; + onCreating?.Invoke(i, user); + + user.ResetDirtyProperties(false); + + list.Add(user); + } + + return list; } + public static User CreateUser(string suffix = "") + { + return new UserBuilder() + .WithIsApproved(true) + .WithName("TestUser" + suffix) + .WithLogin("TestUser" + suffix, "testing") + .WithEmail("test" + suffix + "@test.com") + .Build(); + } int? IWithIdBuilder.Id { diff --git a/src/Umbraco.Tests.Common/Builders/UserGroupBuilder.cs b/src/Umbraco.Tests.Common/Builders/UserGroupBuilder.cs index 6bdc766ee2..9785c27218 100644 --- a/src/Umbraco.Tests.Common/Builders/UserGroupBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/UserGroupBuilder.cs @@ -4,6 +4,7 @@ using Moq; using Umbraco.Core.Models.Membership; using Umbraco.Core.Strings; using Umbraco.Tests.Common.Builders.Interfaces; +using Umbraco.Tests.Common.Builders.Extensions; namespace Umbraco.Tests.Common.Builders { @@ -26,7 +27,7 @@ namespace Umbraco.Tests.Common.Builders private string _icon; private string _name; private IEnumerable _permissions = Enumerable.Empty(); - private IEnumerable _sectionCollection = Enumerable.Empty(); + private IEnumerable _allowedSections = Enumerable.Empty(); private string _suffix; private int? _startContentId; private int? _startMediaId; @@ -55,7 +56,7 @@ namespace Umbraco.Tests.Common.Builders public UserGroupBuilder WithPermissions(string permissions) { - _permissions = permissions.Split(); + _permissions = permissions.ToCharArray().Select(x => x.ToString()); return this; } @@ -65,6 +66,12 @@ namespace Umbraco.Tests.Common.Builders return this; } + public UserGroupBuilder WithAllowedSections(IList allowedSections) + { + _allowedSections = allowedSections; + return this; + } + public UserGroupBuilder WithStartContentId(int startContentId) { _startContentId = startContentId; @@ -107,15 +114,25 @@ namespace Umbraco.Tests.Common.Builders userGroup.StartContentId = startContentId; userGroup.StartMediaId = startMediaId; - foreach (var item in _sectionCollection) + foreach (var section in _allowedSections) { - userGroup.AddAllowedSection(item); + userGroup.AddAllowedSection(section); } return userGroup; } - int? IWithIdBuilder.Id + public static UserGroup CreateUserGroup(string alias = "testGroup", string name = "Test Group", string suffix = "", string[] permissions = null, string[] allowedSections = null) + { + return (UserGroup)new UserGroupBuilder() + .WithAlias(alias + suffix) + .WithName(name + suffix) + .WithPermissions(permissions ?? new[] { "A", "B", "C" }) + .WithAllowedSections(allowedSections ?? new[] { "content", "media" }) + .Build(); + } + + int? IWithIdBuilder.Id { get => _id; set => _id = value; diff --git a/src/Umbraco.Tests.Common/Extensions/ContentBaseExtensions.cs b/src/Umbraco.Tests.Common/Extensions/ContentBaseExtensions.cs index d33818a31b..c442efe334 100644 --- a/src/Umbraco.Tests.Common/Extensions/ContentBaseExtensions.cs +++ b/src/Umbraco.Tests.Common/Extensions/ContentBaseExtensions.cs @@ -1,15 +1,10 @@ using System; -using System.Linq; -using Umbraco.Core; -using Umbraco.Core.Composing; using Umbraco.Core.Models; -using Umbraco.Core.Services; namespace Umbraco.Tests.Testing { public static class ContentBaseExtensions { - /// /// Set property values by alias with an anonymous object. /// 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..511b100137 100644 --- a/src/Umbraco.Tests.Common/TestHelperBase.cs +++ b/src/Umbraco.Tests.Common/TestHelperBase.cs @@ -1,11 +1,14 @@ using System; using System.IO; using System.Reflection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; 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 +21,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,30 +37,22 @@ namespace Umbraco.Tests.Common protected TestHelperBase(Assembly entryAssembly) { - SettingsForTests = new SettingsForTests(); MainDom = new SimpleMainDom(); - _typeFinder = new TypeFinder(Mock.Of(), new DefaultUmbracoAssemblyProvider(entryAssembly), new VaryingRuntimeHash()); + _typeFinder = new TypeFinder(NullLoggerFactory.Instance.CreateLogger(), new DefaultUmbracoAssemblyProvider(entryAssembly), new VaryingRuntimeHash()); } public ITypeFinder GetTypeFinder() => _typeFinder; public TypeLoader GetMockedTypeLoader() { - return new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of()); + return new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(IOHelper.MapPath("~/App_Data/TEMP")), Mock.Of>(), 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 +78,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 +100,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 +118,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 GlobalSettings()); } public abstract IHostingEnvironment GetHostingEnvironment(); @@ -154,9 +146,7 @@ namespace Umbraco.Tests.Common { hostingEnv = hostingEnv ?? GetHostingEnvironment(); return new LoggingConfiguration( - Path.Combine(hostingEnv.ApplicationPhysicalPath, "App_Data","Logs"), - Path.Combine(hostingEnv.ApplicationPhysicalPath, "config","serilog.config"), - Path.Combine(hostingEnv.ApplicationPhysicalPath, "config","serilog.user.config")); + Path.Combine(hostingEnv.ApplicationPhysicalPath, "umbraco","logs")); } } } diff --git a/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedUser.cs b/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedUser.cs deleted file mode 100644 index 7488fc1a88..0000000000 --- a/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedUser.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Moq; -using System; -using System.Collections.Generic; -using Umbraco.Core.Models.Membership; - -namespace Umbraco.Tests.Common.TestHelpers.Entities -{ - public static class MockedUser - { - /// - /// Returns a and ensures that the ToUserCache and FromUserCache methods are mapped correctly for - /// dealing with start node caches - /// - /// - public static Mock GetUserMock() - { - var userCache = new Dictionary(); - var userMock = new Mock(); - userMock.Setup(x => x.FromUserCache(It.IsAny())).Returns((string key) => userCache.TryGetValue(key, out var val) ? val is int[] iVal ? iVal : null : null); - userMock.Setup(x => x.ToUserCache(It.IsAny(), It.IsAny())).Callback((string key, int[] val) => userCache[key] = val); - return userMock; - } - - } -} 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..975f656b82 --- /dev/null +++ b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs @@ -0,0 +1,446 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Logging; +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..5faf5a1279 100644 --- a/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj +++ b/src/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj @@ -5,15 +5,16 @@ - - + + + + - diff --git a/src/Umbraco.Tests.Integration/ContainerTests.cs b/src/Umbraco.Tests.Integration/ContainerTests.cs index 2098b7241e..6b4026057b 100644 --- a/src/Umbraco.Tests.Integration/ContainerTests.cs +++ b/src/Umbraco.Tests.Integration/ContainerTests.cs @@ -3,6 +3,7 @@ using LightInject; using LightInject.Microsoft.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -21,55 +22,6 @@ namespace Umbraco.Tests.Integration [TestFixture] public class ContainerTests { - [Test] - public void CrossWire() - { - // MSDI - var services = new ServiceCollection(); - services.AddSingleton(); - var msdiServiceProvider = services.BuildServiceProvider(); - - // LightInject / Umbraco - var container = UmbracoServiceProviderFactory.CreateServiceContainer(); - var serviceProviderFactory = new UmbracoServiceProviderFactory(container, false); - var umbracoContainer = serviceProviderFactory.GetContainer(); - serviceProviderFactory.CreateBuilder(services); // called during Host Builder, needed to capture services - - // Dependencies needed for creating composition/register essentials - var testHelper = new TestHelper(); - var runtimeState = Mock.Of(); - var umbracoDatabaseFactory = Mock.Of(); - var dbProviderFactoryCreator = Mock.Of(); - var typeLoader = testHelper.GetMockedTypeLoader(); - - // Register in the container - var composition = new Composition(umbracoContainer, typeLoader, - testHelper.Logger, runtimeState, testHelper.GetConfigs(), testHelper.IOHelper, testHelper.AppCaches); - composition.RegisterEssentials(testHelper.Logger, testHelper.Profiler, testHelper.Logger, testHelper.MainDom, - testHelper.AppCaches, umbracoDatabaseFactory, typeLoader, runtimeState, testHelper.GetTypeFinder(), - testHelper.IOHelper, testHelper.GetUmbracoVersion(), dbProviderFactoryCreator, - testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo()); - - // Cross wire - this would be called by the Host Builder at the very end of ConfigureServices - var lightInjectServiceProvider = serviceProviderFactory.CreateServiceProvider(umbracoContainer.Container); - - // From MSDI - var foo1 = msdiServiceProvider.GetService(); - var foo2 = lightInjectServiceProvider.GetService(); - var foo3 = umbracoContainer.GetInstance(); - - Assert.IsNotNull(foo1); - Assert.IsNotNull(foo2); - Assert.IsNotNull(foo3); - - // These are not the same because cross wiring means copying the container, not falling back to a container - Assert.AreNotSame(foo1, foo2); - // These are the same because the umbraco container wraps the light inject container - Assert.AreSame(foo2, foo3); - - Assertions.AssertContainer(umbracoContainer.Container); - } - [Explicit("This test just shows that resolving services from the container before the host is done resolves 2 different instances")] [Test] public async Task BuildServiceProvider_Before_Host_Is_Configured() @@ -83,7 +35,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; @@ -110,6 +62,58 @@ namespace Umbraco.Tests.Integration } + [Test] + public void CrossWire() + { + // MSDI + var services = new ServiceCollection(); + services.AddSingleton(); + var msdiServiceProvider = services.BuildServiceProvider(); + + // LightInject / Umbraco + var container = UmbracoServiceProviderFactory.CreateServiceContainer(); + var serviceProviderFactory = new UmbracoServiceProviderFactory(container, false); + var umbracoContainer = serviceProviderFactory.GetContainer(); + + serviceProviderFactory.CreateBuilder(services); // called during Host Builder, needed to capture services + + // Dependencies needed for creating composition/register essentials + var testHelper = new TestHelper(); + var runtimeState = Mock.Of(); + var umbracoDatabaseFactory = Mock.Of(); + var dbProviderFactoryCreator = Mock.Of(); + var typeLoader = testHelper.GetMockedTypeLoader(); + var loggerFactory = testHelper.ConsoleLoggerFactory; + var logger = testHelper.ConsoleLoggerFactory.CreateLogger("RegisterEssentials"); + + // Register in the container + var composition = new Composition(umbracoContainer, typeLoader, + testHelper.ProfilingLogger, runtimeState, testHelper.IOHelper, testHelper.AppCaches); + composition.RegisterEssentials(logger, loggerFactory, testHelper.Profiler, testHelper.ProfilingLogger, testHelper.MainDom, + testHelper.AppCaches, umbracoDatabaseFactory, typeLoader, runtimeState, testHelper.GetTypeFinder(), + testHelper.IOHelper, testHelper.GetUmbracoVersion(), dbProviderFactoryCreator, + testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo()); + + // Cross wire - this would be called by the Host Builder at the very end of ConfigureServices + var lightInjectServiceProvider = serviceProviderFactory.CreateServiceProvider(umbracoContainer.Container); + + // From MSDI + var foo1 = msdiServiceProvider.GetService(); + var foo2 = lightInjectServiceProvider.GetService(); + var foo3 = umbracoContainer.GetInstance(); + + Assert.IsNotNull(foo1); + Assert.IsNotNull(foo2); + Assert.IsNotNull(foo3); + + // These are not the same because cross wiring means copying the container, not falling back to a container + Assert.AreNotSame(foo1, foo2); + // These are the same because the umbraco container wraps the light inject container + Assert.AreSame(foo2, foo3); + + Assertions.AssertContainer(umbracoContainer.Container); + } + private class Foo { public Foo() 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..22b3821b3c 100644 --- a/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs +++ b/src/Umbraco.Tests.Integration/Implementations/TestHelper.cs @@ -1,21 +1,31 @@ - -using System; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Hosting; -using Moq; +using System; +using System.Collections; +using System.ComponentModel; using System.Data.Common; using System.IO; +using System.Linq; using System.Net; using System.Reflection; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; 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.Models; +using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Runtime; +using Umbraco.Net; using Umbraco.Tests.Common; using Umbraco.Web.Common.AspNetCore; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; @@ -39,16 +49,22 @@ 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()); - - Logger = new ProfilingLogger(new ConsoleLogger(new MessageTemplates()), Profiler); + ConsoleLoggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); + ProfilingLogger = new ProfilingLogger(ConsoleLoggerFactory.CreateLogger("ProfilingLogger"), Profiler); } @@ -84,7 +100,8 @@ namespace Umbraco.Tests.Integration.Implementations public AppCaches AppCaches { get; } = new AppCaches(NoAppCache.Instance, NoAppCache.Instance, new IsolatedCaches(type => NoAppCache.Instance)); - public IProfilingLogger Logger { get; private set; } + public ILoggerFactory ConsoleLoggerFactory { get; private set; } + public IProfilingLogger ProfilingLogger { get; private set; } public IProfiler Profiler { get; } = new VoidProfiler(); @@ -102,16 +119,26 @@ namespace Umbraco.Tests.Integration.Implementations public override IBackOfficeInfo GetBackOfficeInfo() { if (_backOfficeInfo == null) - _backOfficeInfo = - new AspNetCoreBackOfficeInfo(SettingsForTests.GetDefaultGlobalSettings(GetUmbracoVersion())); + { + var globalSettings = new GlobalSettings(); + 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 HostingSettings(); + return Mock.Of>(x => x.CurrentValue == hostingSettings); + } + public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _hostingLifetime; public override IIpResolver GetIpResolver() => _ipResolver; @@ -133,5 +160,101 @@ namespace Umbraco.Tests.Integration.Implementations return relativePath.Replace("~/", bin + "/"); } + + public void AssertPropertyValuesAreEqual(object actual, object expected, string dateTimeFormat = null, Func sorter = null, string[] ignoreProperties = null) + { + const int dateDeltaMilliseconds = 500; // .5s + + var properties = expected.GetType().GetProperties(); + foreach (var property in properties) + { + // ignore properties that are attributed with EditorBrowsableState.Never + var att = property.GetCustomAttribute(false); + if (att != null && att.State == EditorBrowsableState.Never) + continue; + + // ignore explicitely ignored properties + if (ignoreProperties != null && ignoreProperties.Contains(property.Name)) + continue; + + var actualValue = property.GetValue(actual, null); + var expectedValue = property.GetValue(expected, null); + + AssertAreEqual(property, expectedValue, actualValue, sorter, dateDeltaMilliseconds); + } + } + + private static void AssertListsAreEqual(PropertyInfo property, IEnumerable expected, IEnumerable actual, Func sorter = null, int dateDeltaMilliseconds = 0) + { + + + if (sorter == null) + { + // this is pretty hackerific but saves us some code to write + sorter = enumerable => + { + // semi-generic way of ensuring any collection of IEntity are sorted by Ids for comparison + var entities = enumerable.OfType().ToList(); + return entities.Count > 0 ? (IEnumerable) entities.OrderBy(x => x.Id) : entities; + }; + } + + var expectedListEx = sorter(expected).Cast().ToList(); + var actualListEx = sorter(actual).Cast().ToList(); + + if (actualListEx.Count != expectedListEx.Count) + Assert.Fail("Collection {0}.{1} does not match. Expected IEnumerable containing {2} elements but was IEnumerable containing {3} elements", property.PropertyType.Name, property.Name, expectedListEx.Count, actualListEx.Count); + + for (var i = 0; i < actualListEx.Count; i++) + AssertAreEqual(property, expectedListEx[i], actualListEx[i], sorter, dateDeltaMilliseconds); + } + + private static void AssertAreEqual(PropertyInfo property, object expected, object actual, Func sorter = null, int dateDeltaMilliseconds = 0) + { + if (!(expected is string) && expected is IEnumerable) + { + // sort property collection by alias, not by property ids + // on members, built-in properties don't have ids (always zero) + if (expected is PropertyCollection) + sorter = e => ((PropertyCollection) e).OrderBy(x => x.Alias); + + // compare lists + AssertListsAreEqual(property, (IEnumerable) actual, (IEnumerable) expected, sorter, dateDeltaMilliseconds); + } + else if (expected is DateTime expectedDateTime) + { + // compare date & time with delta + var actualDateTime = (DateTime) actual; + var delta = (actualDateTime - expectedDateTime).TotalMilliseconds; + Assert.IsTrue(Math.Abs(delta) <= dateDeltaMilliseconds, "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expected, actual); + } + else if (expected is Property expectedProperty) + { + // compare values + var actualProperty = (Property) actual; + var expectedPropertyValues = expectedProperty.Values.OrderBy(x => x.Culture).ThenBy(x => x.Segment).ToArray(); + var actualPropertyValues = actualProperty.Values.OrderBy(x => x.Culture).ThenBy(x => x.Segment).ToArray(); + if (expectedPropertyValues.Length != actualPropertyValues.Length) + Assert.Fail($"{property.DeclaringType.Name}.{property.Name}: Expected {expectedPropertyValues.Length} but got {actualPropertyValues.Length}."); + for (var i = 0; i < expectedPropertyValues.Length; i++) + { + Assert.AreEqual(expectedPropertyValues[i].EditedValue, actualPropertyValues[i].EditedValue, $"{property.DeclaringType.Name}.{property.Name}: Expected draft value \"{expectedPropertyValues[i].EditedValue}\" but got \"{actualPropertyValues[i].EditedValue}\"."); + Assert.AreEqual(expectedPropertyValues[i].PublishedValue, actualPropertyValues[i].PublishedValue, $"{property.DeclaringType.Name}.{property.Name}: Expected published value \"{expectedPropertyValues[i].EditedValue}\" but got \"{actualPropertyValues[i].EditedValue}\"."); + } + } + else if (expected is IDataEditor expectedEditor) + { + Assert.IsInstanceOf(actual); + var actualEditor = (IDataEditor) actual; + Assert.AreEqual(expectedEditor.Alias, actualEditor.Alias); + // what else shall we test? + } + else + { + // directly compare values + Assert.AreEqual(expected, actual, "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, + expected?.ToString() ?? "", actual?.ToString() ?? ""); + } + } } } 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/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests.Integration/Mapping/ContentTypeModelMappingTests.cs index d982d4b291..96e49e79e9 100644 --- a/src/Umbraco.Tests.Integration/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests.Integration/Mapping/ContentTypeModelMappingTests.cs @@ -8,8 +8,8 @@ using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; -using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; using Umbraco.Web.Models.ContentEditing; @@ -22,16 +22,13 @@ namespace Umbraco.Tests.Models.Mapping private IDataTypeService _dataTypeService; private UmbracoMapper _sut; private IFileService _fileService; - private IEntityService _entityService; - [SetUp] - public void Setup() + public void SetupTest() { _sut = Services.GetRequiredService(); _dataTypeService = Services.GetRequiredService(); _fileService = Services.GetRequiredService(); - _entityService = Services.GetRequiredService(); } [Test] @@ -275,12 +272,12 @@ namespace Umbraco.Tests.Models.Mapping public void IMemberType_To_MemberTypeDisplay() { //Arrange - var memberType = MockedContentTypes.CreateSimpleMemberType(); + var memberType = MemberTypeBuilder.CreateSimpleMemberType(); var alias = memberType.PropertyTypes.Last().Alias; memberType.SetIsSensitiveProperty(alias, true); memberType.SetMemberCanEditProperty(alias, true); memberType.SetMemberCanViewProperty(alias, true); - MockedContentTypes.EnsureAllIds(memberType, 8888); + MemberTypeBuilder.EnsureAllIds(memberType, 8888); //Act @@ -334,8 +331,8 @@ namespace Umbraco.Tests.Models.Mapping { //Arrange - var mediaType = MockedContentTypes.CreateImageMediaType(); - MockedContentTypes.EnsureAllIds(mediaType, 8888); + var mediaType = MediaTypeBuilder.CreateImageMediaType(); + MediaTypeBuilder.EnsureAllIds(mediaType, 8888); //Act @@ -389,8 +386,8 @@ namespace Umbraco.Tests.Models.Mapping // // // setup the mocks to return the data we want to test against... - var contentType = MockedContentTypes.CreateTextPageContentType(); - MockedContentTypes.EnsureAllIds(contentType, 8888); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); + ContentTypeBuilder.EnsureAllIds(contentType, 8888); //Act @@ -667,7 +664,7 @@ namespace Umbraco.Tests.Models.Mapping public void IMediaTypeComposition_To_MediaTypeDisplay() { //Arrange - var ctMain = MockedContentTypes.CreateSimpleMediaType("parent", "Parent"); + var ctMain = MediaTypeBuilder.CreateSimpleMediaType("parent", "Parent"); //not assigned to tab ctMain.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { @@ -678,8 +675,8 @@ namespace Umbraco.Tests.Models.Mapping SortOrder = 1, DataTypeId = -88 }); - MockedContentTypes.EnsureAllIds(ctMain, 8888); - var ctChild1 = MockedContentTypes.CreateSimpleMediaType("child1", "Child 1", ctMain, true); + MediaTypeBuilder.EnsureAllIds(ctMain, 8888); + var ctChild1 = MediaTypeBuilder.CreateSimpleMediaType("child1", "Child 1", ctMain, true); ctChild1.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "someProperty", @@ -689,8 +686,8 @@ namespace Umbraco.Tests.Models.Mapping SortOrder = 1, DataTypeId = -88 }, "Another tab"); - MockedContentTypes.EnsureAllIds(ctChild1, 7777); - var contentType = MockedContentTypes.CreateSimpleMediaType("child2", "Child 2", ctChild1, true, "CustomGroup"); + MediaTypeBuilder.EnsureAllIds(ctChild1, 7777); + var contentType = MediaTypeBuilder.CreateSimpleMediaType("child2", "Child 2", ctChild1, true, "CustomGroup"); //not assigned to tab contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { @@ -701,7 +698,7 @@ namespace Umbraco.Tests.Models.Mapping SortOrder = 1, DataTypeId = -88 }); - MockedContentTypes.EnsureAllIds(contentType, 6666); + MediaTypeBuilder.EnsureAllIds(contentType, 6666); //Act @@ -745,23 +742,21 @@ namespace Umbraco.Tests.Models.Mapping { Assert.AreEqual(contentType.AllowedContentTypes.ElementAt(i).Id.Value, result.AllowedContentTypes.ElementAt(i)); } - } - [Test] public void IContentTypeComposition_To_ContentTypeDisplay() { //Arrange - var ctMain = MockedContentTypes.CreateSimpleContentType(); + var ctMain = ContentTypeBuilder.CreateSimpleContentType(); //not assigned to tab ctMain.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "umbracoUrlName", Name = "Slug", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - MockedContentTypes.EnsureAllIds(ctMain, 8888); - var ctChild1 = MockedContentTypes.CreateSimpleContentType("child1", "Child 1", ctMain, true); + ContentTypeBuilder.EnsureAllIds(ctMain, 8888); + var ctChild1 = ContentTypeBuilder.CreateSimpleContentType("child1", "Child 1", ctMain, true); ctChild1.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "someProperty", @@ -771,14 +766,14 @@ namespace Umbraco.Tests.Models.Mapping SortOrder = 1, DataTypeId = -88 }, "Another tab"); - MockedContentTypes.EnsureAllIds(ctChild1, 7777); - var contentType = MockedContentTypes.CreateSimpleContentType("child2", "Child 2", ctChild1, true, "CustomGroup"); + ContentTypeBuilder.EnsureAllIds(ctChild1, 7777); + var contentType = ContentTypeBuilder.CreateSimpleContentType("child2", "Child 2", ctChild1, true, "CustomGroup"); //not assigned to tab contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "umbracoUrlAlias", Name = "AltUrl", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - MockedContentTypes.EnsureAllIds(contentType, 6666); + ContentTypeBuilder.EnsureAllIds(contentType, 6666); //Act diff --git a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs b/src/Umbraco.Tests.Integration/Packaging/CreatedPackagesRepositoryTests.cs similarity index 80% rename from src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs rename to src/Umbraco.Tests.Integration/Packaging/CreatedPackagesRepositoryTests.cs index 6533dd6113..2500dd97a4 100644 --- a/src/Umbraco.Tests/Packaging/CreatedPackagesRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Packaging/CreatedPackagesRepositoryTests.cs @@ -6,45 +6,53 @@ 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.Configuration.Models; +using Umbraco.Core.Hosting; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Services; -using Umbraco.Tests.Services; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Packaging { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class CreatedPackagesRepositoryTests : TestWithDatabaseBase + public class CreatedPackagesRepositoryTests : UmbracoIntegrationTest { private Guid _testBaseFolder; - public override void SetUp() + [SetUp] + public void SetupTestData() { - base.SetUp(); _testBaseFolder = Guid.NewGuid(); } - public override void TearDown() + [TearDown] + public void DeleteTestFolder() { - base.TearDown(); - //clear out files/folders - Directory.Delete(IOHelper.MapPath("~/" + _testBaseFolder), true); + Directory.Delete(HostingEnvironment.MapPathContentRoot("~/" + _testBaseFolder), true); } + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IDataTypeService DataTypeService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + private IMacroService MacroService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IEntityXmlSerializer EntityXmlSerializer => GetRequiredService(); + private IHostingEnvironment HostingEnvironment => GetRequiredService(); + private IUmbracoVersion UmbracoVersion => GetRequiredService(); + public ICreatedPackagesRepository PackageBuilder => new PackagesRepository( - ServiceContext.ContentService, ServiceContext.ContentTypeService, ServiceContext.DataTypeService, - ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, + ContentService, ContentTypeService, DataTypeService, + FileService, MacroService, LocalizationService, HostingEnvironment, - Factory.GetInstance(), Logger, + EntityXmlSerializer, LoggerFactory, UmbracoVersion, - Factory.GetInstance(), + Microsoft.Extensions.Options.Options.Create(new GlobalSettings()), "createdPackages.config", //temp paths tempFolderPath: "~/" + _testBaseFolder + "/temp", diff --git a/src/Umbraco.Tests.Integration/Packaging/Packages/Document_Type_Picker_1.1.umb b/src/Umbraco.Tests.Integration/Packaging/Packages/Document_Type_Picker_1.1.umb new file mode 100644 index 0000000000..18449bd373 Binary files /dev/null and b/src/Umbraco.Tests.Integration/Packaging/Packages/Document_Type_Picker_1.1.umb differ diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs index e92653fb98..24316eb931 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; +using Microsoft.Extensions.Logging; namespace Umbraco.Tests.Integration.Persistence.Repositories { @@ -15,6 +16,13 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)] public class AuditRepositoryTest : UmbracoIntegrationTest { + private ILogger _logger; + + [SetUp] + public void Prepare() + { + _logger = LoggerFactory.CreateLogger(); + } [Test] public void Can_Add_Audit_Entry() @@ -22,7 +30,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var sp = ScopeProvider; using (var scope = ScopeProvider.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); repo.Save(new AuditItem(-1, AuditType.System, -1, UmbracoObjectTypes.Document.GetName(), "This is a System audit trail")); var dtos = scope.Database.Fetch("WHERE id > -1"); @@ -38,7 +46,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var sp = ScopeProvider; using (var scope = sp.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); for (var i = 0; i < 100; i++) { @@ -51,7 +59,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories using (var scope = sp.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); var page = repo.GetPagedResultsByQuery(sp.SqlContext.Query(), 0, 10, out var total, Direction.Descending, null, null); @@ -66,7 +74,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var sp = ScopeProvider; using (var scope = sp.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); for (var i = 0; i < 100; i++) { @@ -79,7 +87,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories using (var scope = sp.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); var query = sp.SqlContext.Query().Where(x => x.UserId == -1); @@ -109,7 +117,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var sp = ScopeProvider; using (var scope = sp.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); for (var i = 0; i < 100; i++) { @@ -122,7 +130,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories using (var scope = sp.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); var page = repo.GetPagedResultsByQuery(sp.SqlContext.Query(), 0, 9, out var total, Direction.Descending, new[] { AuditType.Publish }, null) @@ -140,7 +148,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var sp = ScopeProvider; using (var scope = sp.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); for (var i = 0; i < 100; i++) { @@ -153,7 +161,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories using (var scope = sp.CreateScope()) { - var repo = new AuditRepository((IScopeAccessor)sp, Logger); + var repo = new AuditRepository((IScopeAccessor)sp, _logger); var page = repo.GetPagedResultsByQuery(sp.SqlContext.Query(), 0, 8, out var total, Direction.Descending, null, sp.SqlContext.Query().Where(item => item.Comment == "Content created")) diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/ContentTypeRepositoryTest.cs similarity index 65% rename from src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Persistence/Repositories/ContentTypeRepositoryTest.cs index 53a632132d..f265519e28 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -1,15 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.IO; +using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.Persistence.Repositories; 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.Testing; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -19,53 +28,36 @@ namespace Umbraco.Tests.Persistence.Repositories { [TestFixture] [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class ContentTypeRepositoryTest : TestWithDatabaseBase + public class ContentTypeRepositoryTest : UmbracoIntegrationTest { - public override void SetUp() - { - base.SetUp(); + private ContentType _simpleContentType; + private ContentType _textpageContentType; + private IFileSystems FileSystems => GetRequiredService(); + private UmbracoMapper Mapper => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IDocumentTypeContainerRepository DocumentTypeContainerRepository => GetRequiredService(); + private IMediaTypeContainerRepository MediaTypeContainerRepository => GetRequiredService(); + private IMediaTypeRepository MediaTypeRepository => GetRequiredService(); + private IDocumentRepository DocumentRepository => GetRequiredService(); + private ContentTypeRepository ContentTypeRepository => (ContentTypeRepository) GetRequiredService(); + + [SetUp] + public void SetUpData() + { CreateTestData(); } - private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository) + public void CreateTestData() { - var langRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger,TestObjects.GetGlobalSettings()); - 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 relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); - var entityRepository = new EntityRepository(scopeAccessor); - var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository); - var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); - var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new DocumentRepository(scopeAccessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); - return repository; - } + //Create and Save ContentType "umbTextpage" -> (_simpleContentType.Id) + _simpleContentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: 0); - private ContentTypeRepository CreateRepository(IScopeAccessor scopeAccessor) - { - var langRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); - 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); - return contentTypeRepository; - } + ContentTypeService.Save(_simpleContentType); - private MediaTypeRepository CreateMediaTypeRepository(IScopeAccessor scopeAccessor) - { - 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 contentTypeRepository = new MediaTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository, langRepository, ShortStringHelper); - return contentTypeRepository; - } - - private EntityContainerRepository CreateContainerRepository(IScopeAccessor scopeAccessor, Guid containerEntityType) - { - return new EntityContainerRepository(scopeAccessor, AppCaches.Disabled, Logger, containerEntityType); + //Create and Save ContentType "textPage" -> (_textpageContentType.Id) + _textpageContentType = ContentTypeBuilder.CreateTextPageContentType( defaultTemplateId: 0); + ContentTypeService.Save(_textpageContentType); } // TODO: Add test to verify SetDefaultTemplates updates both AllowedTemplates and DefaultTemplate(id). @@ -74,11 +66,11 @@ namespace Umbraco.Tests.Persistence.Repositories public void Maps_Templates_Correctly() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var templateRepo = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); - var repository = CreateRepository((IScopeAccessor) provider); + var templateRepo = new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper); + var repository = ContentTypeRepository; var templates = new[] { new Template(ShortStringHelper, "test1", "test1"), @@ -91,7 +83,7 @@ namespace Umbraco.Tests.Persistence.Repositories } - var contentType = MockedContentTypes.CreateSimpleContentType(); + var contentType = ContentTypeBuilder.CreateSimpleContentType(); contentType.AllowedTemplates = new[] { templates[0], templates[1] }; contentType.SetDefaultTemplate(templates[0]); repository.Save(contentType); @@ -109,20 +101,20 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Move() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var containerRepository = CreateContainerRepository((IScopeAccessor) provider, Constants.ObjectTypes.DocumentTypeContainer); - var repository = CreateRepository((IScopeAccessor) provider); + + var repository = ContentTypeRepository; var container1 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah1" }; - containerRepository.Save(container1); + DocumentTypeContainerRepository.Save(container1); var container2 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah2", ParentId = container1.Id }; - containerRepository.Save(container2); + DocumentTypeContainerRepository.Save(container2); - var contentType = (IContentType)MockedContentTypes.CreateBasicContentType("asdfasdf"); + var contentType = (IContentType)ContentTypeBuilder.CreateBasicContentType("asdfasdf"); contentType.ParentId = container2.Id; repository.Save(contentType); @@ -155,16 +147,16 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Create_Container() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var containerRepository = CreateContainerRepository((IScopeAccessor) provider, Constants.ObjectTypes.DocumentTypeContainer); + var container = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah" }; - containerRepository.Save(container); + DocumentTypeContainerRepository.Save(container); Assert.That(container.Id, Is.GreaterThan(0)); - var found = containerRepository.Get(container.Id); + var found = DocumentTypeContainerRepository.Get(container.Id); Assert.IsNotNull(found); } } @@ -174,29 +166,28 @@ namespace Umbraco.Tests.Persistence.Repositories { EntityContainer container1, container2, container3; - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var containerRepository = CreateContainerRepository((IScopeAccessor) provider, Constants.ObjectTypes.DocumentTypeContainer); container1 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "container1" }; - containerRepository.Save(container1); + DocumentTypeContainerRepository.Save(container1); container2 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "container2" }; - containerRepository.Save(container2); + DocumentTypeContainerRepository.Save(container2); container3 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "container3" }; - containerRepository.Save(container3); + DocumentTypeContainerRepository.Save(container3); Assert.That(container1.Id, Is.GreaterThan(0)); Assert.That(container2.Id, Is.GreaterThan(0)); Assert.That(container3.Id, Is.GreaterThan(0)); - var found1 = containerRepository.Get(container1.Id); + var found1 = DocumentTypeContainerRepository.Get(container1.Id); Assert.IsNotNull(found1); - var found2 = containerRepository.Get(container2.Id); + var found2 = DocumentTypeContainerRepository.Get(container2.Id); Assert.IsNotNull(found2); - var found3 = containerRepository.Get(container3.Id); + var found3 = DocumentTypeContainerRepository.Get(container3.Id); Assert.IsNotNull(found3); - var allContainers = containerRepository.GetMany(); + var allContainers = DocumentTypeContainerRepository.GetMany(); Assert.AreEqual(3, allContainers.Count()); } } @@ -204,19 +195,18 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Delete_Container() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var containerRepository = CreateContainerRepository((IScopeAccessor) provider, Constants.ObjectTypes.DocumentTypeContainer); var container = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah" }; - containerRepository.Save(container); + DocumentTypeContainerRepository.Save(container); // Act - containerRepository.Delete(container); + DocumentTypeContainerRepository.Delete(container); - var found = containerRepository.Get(container.Id); + var found = DocumentTypeContainerRepository.Get(container.Id); Assert.IsNull(found); } } @@ -224,16 +214,15 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Create_Container_Containing_Media_Types() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var containerRepository = CreateContainerRepository((IScopeAccessor) provider, Constants.ObjectTypes.MediaTypeContainer); - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; var container = new EntityContainer(Constants.ObjectTypes.MediaType) { Name = "blah" }; - containerRepository.Save(container); + MediaTypeContainerRepository.Save(container); - var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test", propertyGroupName: "testGroup"); + var contentType = ContentTypeBuilder.CreateSimpleContentType("test", "Test", propertyGroupName: "testGroup", defaultTemplateId:0); contentType.ParentId = container.Id; repository.Save(contentType); @@ -245,28 +234,27 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Delete_Container_Containing_Media_Types() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var containerRepository = CreateContainerRepository((IScopeAccessor) provider, Constants.ObjectTypes.MediaTypeContainer); - var repository = CreateMediaTypeRepository((IScopeAccessor) provider); + var container = new EntityContainer(Constants.ObjectTypes.MediaType) { Name = "blah" }; - containerRepository.Save(container); + MediaTypeContainerRepository.Save(container); - IMediaType contentType = MockedContentTypes.CreateSimpleMediaType("test", "Test", propertyGroupName: "testGroup"); + IMediaType contentType = MediaTypeBuilder.CreateSimpleMediaType("test", "Test", propertyGroupName: "testGroup"); contentType.ParentId = container.Id; - repository.Save(contentType); + MediaTypeRepository.Save(contentType); // Act - containerRepository.Delete(container); + MediaTypeContainerRepository.Delete(container); - var found = containerRepository.Get(container.Id); + var found = MediaTypeContainerRepository.Get(container.Id); Assert.IsNull(found); - contentType = repository.Get(contentType.Id); + contentType = MediaTypeRepository.Get(contentType.Id); Assert.IsNotNull(contentType); Assert.AreEqual(-1, contentType.ParentId); } @@ -276,16 +264,16 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Add_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + // Act - var contentType = MockedContentTypes.CreateSimpleContentType("test", "Test", propertyGroupName: "testGroup"); - repository.Save(contentType); + var contentType = ContentTypeBuilder.CreateSimpleContentType("test", "Test", propertyGroupName: "testGroup"); + ContentTypeRepository.Save(contentType); - var fetched = repository.Get(contentType.Id); + var fetched = ContentTypeRepository.Get(contentType.Id); // Assert Assert.That(contentType.HasIdentity, Is.True); @@ -311,12 +299,12 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Add_On_ContentTypeRepository_After_Model_Mapping() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act - var contentType = (IContentType)MockedContentTypes.CreateSimpleContentType2("test", "Test", propertyGroupName: "testGroup"); + var contentType = (IContentType)ContentTypeBuilder.CreateSimpleContentType2("test", "Test", propertyGroupName: "testGroup"); Assert.AreEqual(4, contentType.PropertyTypes.Count()); @@ -363,12 +351,12 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Update_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var contentType = repository.Get(_textpageContentType.Id); contentType.Thumbnail = "Doc2.png"; contentType.PropertyGroups["Content"].PropertyTypes.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") @@ -439,12 +427,12 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Update_On_ContentTypeRepository_After_Model_Mapping() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var contentType = repository.Get(_textpageContentType.Id); // there is NO mapping from display to contentType, but only from save // to contentType, so if we want to test, let's to it properly! @@ -483,7 +471,7 @@ namespace Umbraco.Tests.Persistence.Repositories var dirty = mapped.IsDirty(); //re-get - contentType = repository.Get(NodeDto.NodeIdSeed + 1); + contentType = repository.Get(_textpageContentType.Id); // Assert Assert.That(contentType.HasIdentity, Is.True); @@ -502,12 +490,12 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Delete_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act - var contentType = MockedContentTypes.CreateSimpleContentType(); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId:0); repository.Save(contentType); @@ -526,13 +514,13 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Delete_With_Heirarchy_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); - var ctMain = MockedContentTypes.CreateSimpleContentType(); - var ctChild1 = MockedContentTypes.CreateSimpleContentType("child1", "Child 1", ctMain, true); - var ctChild2 = MockedContentTypes.CreateSimpleContentType("child2", "Child 2", ctChild1, true); + var repository = ContentTypeRepository; + var ctMain = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId:0); + var ctChild1 = ContentTypeBuilder.CreateSimpleContentType("child1", "Child 1", ctMain, true, defaultTemplateId:0); + var ctChild2 = ContentTypeBuilder.CreateSimpleContentType("child2", "Child 2", ctChild1, true, defaultTemplateId:0); repository.Save(ctMain); repository.Save(ctChild1); @@ -558,16 +546,16 @@ namespace Umbraco.Tests.Persistence.Repositories IContentType contentType; // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); - contentType = repository.Get(NodeDto.NodeIdSeed + 1); - var child1 = MockedContentTypes.CreateSimpleContentType("abc", "abc", contentType, randomizeAliases: true); + var repository = ContentTypeRepository; + contentType = repository.Get(_textpageContentType.Id); + var child1 = ContentTypeBuilder.CreateSimpleContentType("abc", "abc", contentType, randomizeAliases: true, defaultTemplateId:0); repository.Save(child1); - var child3 = MockedContentTypes.CreateSimpleContentType("zyx", "zyx", contentType, randomizeAliases: true); + var child3 = ContentTypeBuilder.CreateSimpleContentType("zyx", "zyx", contentType, randomizeAliases: true, defaultTemplateId:0); repository.Save(child3); - var child2 = MockedContentTypes.CreateSimpleContentType("a123", "a123", contentType, randomizeAliases: true); + var child2 = ContentTypeBuilder.CreateSimpleContentType("a123", "a123", contentType, randomizeAliases: true, defaultTemplateId:0); repository.Save(child2); scope.Complete(); @@ -575,7 +563,7 @@ namespace Umbraco.Tests.Persistence.Repositories using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor)provider); + var repository = ContentTypeRepository; // Act var contentTypes = repository.Get(scope.SqlContext.Query().Where(x => x.ParentId == contentType.Id)); @@ -593,17 +581,17 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Get_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var contentType = repository.Get(_textpageContentType.Id); // Assert Assert.That(contentType, Is.Not.Null); - Assert.That(contentType.Id, Is.EqualTo(NodeDto.NodeIdSeed + 1)); + Assert.That(contentType.Id, Is.EqualTo(_textpageContentType.Id)); } } @@ -611,12 +599,12 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Get_By_Guid_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); - var childContentType = MockedContentTypes.CreateSimpleContentType("blah", "Blah", contentType, randomizeAliases:true); + var repository = ContentTypeRepository; + var contentType = repository.Get(_textpageContentType.Id); + var childContentType = ContentTypeBuilder.CreateSimpleContentType("blah", "Blah", contentType, randomizeAliases:true, defaultTemplateId:0); repository.Save(childContentType); @@ -633,10 +621,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Get_By_Missing_Guid_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act var result = repository.Get(Guid.NewGuid()); @@ -649,10 +637,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetAll_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = (ContentTypeRepository)ContentTypeRepository; // Act var contentTypes = repository.GetMany(); @@ -671,10 +659,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetAll_By_Guid_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = (ContentTypeRepository)ContentTypeRepository; var allGuidIds = repository.GetMany().Select(x => x.Key).ToArray(); // Act @@ -694,13 +682,13 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Exists_On_ContentTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act - var exists = repository.Exists(NodeDto.NodeIdSeed); + var exists = repository.Exists(_simpleContentType.Id); // Assert Assert.That(exists, Is.True); @@ -711,18 +699,18 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Update_ContentType_With_PropertyType_Removed() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var repository = ContentTypeRepository; + var contentType = repository.Get(_textpageContentType.Id); // Act contentType.PropertyGroups["Meta"].PropertyTypes.Remove("description"); repository.Save(contentType); - var result = repository.Get(NodeDto.NodeIdSeed + 1); + var result = repository.Get(_textpageContentType.Id); // Assert Assert.That(result.PropertyTypes.Any(x => x.Alias == "description"), Is.False); @@ -735,13 +723,13 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_PropertyTypes_On_SimpleTextpage() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act - var contentType = repository.Get(NodeDto.NodeIdSeed); + var contentType = repository.Get(_simpleContentType.Id); // Assert Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(3)); @@ -753,13 +741,13 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_PropertyTypes_On_Textpage() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; // Act - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var contentType = repository.Get(_textpageContentType.Id); // Assert Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(4)); @@ -771,11 +759,11 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_PropertyType_With_No_Group() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var repository = ContentTypeRepository; + var contentType = repository.Get(_textpageContentType.Id); Assert.That(contentType.PropertyGroups.Count, Is.EqualTo(2)); Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(4)); @@ -799,7 +787,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Assert - var updated = repository.Get(NodeDto.NodeIdSeed + 1); + var updated = repository.Get(_textpageContentType.Id); Assert.That(addedPropertyType, Is.True); Assert.That(updated.PropertyGroups.Count, Is.EqualTo(2)); Assert.That(updated.PropertyTypes.Count(), Is.EqualTo(5)); @@ -812,19 +800,19 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_AllowedChildContentTypes_On_ContentType() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateRepository((IScopeAccessor) provider); + var repository = ContentTypeRepository; - var subpageContentType = MockedContentTypes.CreateSimpleContentType("umbSubpage", "Subpage"); - var simpleSubpageContentType = MockedContentTypes.CreateSimpleContentType("umbSimpleSubpage", "Simple Subpage"); + var subpageContentType = ContentTypeBuilder.CreateSimpleContentType("umbSubpage", "Subpage"); + var simpleSubpageContentType = ContentTypeBuilder.CreateSimpleContentType("umbSimpleSubpage", "Simple Subpage"); repository.Save(subpageContentType); repository.Save(simpleSubpageContentType); // Act - var contentType = repository.Get(NodeDto.NodeIdSeed); + var contentType = repository.Get(_simpleContentType.Id); contentType.AllowedContentTypes = new List { new ContentTypeSort(new Lazy(() => subpageContentType.Id), 0, subpageContentType.Alias), @@ -834,7 +822,7 @@ namespace Umbraco.Tests.Persistence.Repositories //Assert - var updated = repository.Get(NodeDto.NodeIdSeed); + var updated = repository.Get(_simpleContentType.Id); Assert.That(updated.AllowedContentTypes.Any(), Is.True); Assert.That(updated.AllowedContentTypes.Any(x => x.Alias == subpageContentType.Alias), Is.True); @@ -846,15 +834,14 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_Removal_Of_Used_PropertyType_From_ContentType() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - ContentTypeRepository repository; - var contentRepository = CreateRepository((IScopeAccessor) provider, out repository); - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var repository = ContentTypeRepository; + var contentType = repository.Get(_textpageContentType.Id); - var subpage = MockedContent.CreateTextpageContent(contentType, "Text Page 1", contentType.Id); - contentRepository.Save(subpage); + var subpage = ContentBuilder.CreateTextpageContent(contentType, "Text Page 1", contentType.Id); + DocumentRepository.Save(subpage); // Act @@ -873,15 +860,14 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_Addition_Of_PropertyType_After_ContentType_Is_Used() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - ContentTypeRepository repository; - var contentRepository = CreateRepository((IScopeAccessor) provider, out repository); - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var repository = ContentTypeRepository; + var contentType = repository.Get(_textpageContentType.Id); - var subpage = MockedContent.CreateTextpageContent(contentType, "Text Page 1", contentType.Id); - contentRepository.Save(subpage); + var subpage = ContentBuilder.CreateTextpageContent(contentType, "Text Page 1", contentType.Id); + DocumentRepository.Save(subpage); // Act @@ -901,15 +887,15 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_Usage_Of_New_PropertyType_On_Content() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - ContentTypeRepository repository; - var contentRepository = CreateRepository((IScopeAccessor) provider, out repository); - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var repository = ContentTypeRepository; - var subpage = MockedContent.CreateTextpageContent(contentType, "Text Page 1", contentType.Id); - contentRepository.Save(subpage); + var contentType = repository.Get(_textpageContentType.Id); + + var subpage = ContentBuilder.CreateTextpageContent(contentType, "Text Page 1", contentType.Id); + DocumentRepository.Save(subpage); var propertyGroup = contentType.PropertyGroups.First(x => x.Name == "Meta"); @@ -918,13 +904,13 @@ namespace Umbraco.Tests.Persistence.Repositories // Act - var content = contentRepository.Get(subpage.Id); + var content = DocumentRepository.Get(subpage.Id); content.SetValue("metaAuthor", "John Doe"); - contentRepository.Save(content); + DocumentRepository.Save(content); //Assert - var updated = contentRepository.Get(subpage.Id); + var updated = DocumentRepository.Get(subpage.Id); Assert.That(updated.GetValue("metaAuthor").ToString(), Is.EqualTo("John Doe")); Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(5)); Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "metaAuthor"), Is.True); @@ -935,15 +921,15 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_That_A_Combination_Of_Adding_And_Deleting_PropertyTypes_Doesnt_Cause_Issues_For_Content_And_ContentType() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - ContentTypeRepository repository; - var contentRepository = CreateRepository((IScopeAccessor) provider, out repository); - var contentType = repository.Get(NodeDto.NodeIdSeed + 1); + var repository = ContentTypeRepository; - var subpage = MockedContent.CreateTextpageContent(contentType, "Text Page 1", contentType.Id); - contentRepository.Save(subpage); + var contentType = repository.Get(_textpageContentType.Id); + + var subpage = ContentBuilder.CreateTextpageContent(contentType, "Text Page 1", contentType.Id); + DocumentRepository.Save(subpage); //Remove PropertyType @@ -955,13 +941,13 @@ namespace Umbraco.Tests.Persistence.Repositories // Act - var content = contentRepository.Get(subpage.Id); + var content = DocumentRepository.Get(subpage.Id); content.SetValue("metaAuthor", "John Doe"); - contentRepository.Save(content); + DocumentRepository.Save(content); //Assert - var updated = contentRepository.Get(subpage.Id); + var updated = DocumentRepository.Get(subpage.Id); Assert.That(updated.GetValue("metaAuthor").ToString(), Is.EqualTo("John Doe")); Assert.That(updated.Properties.First(x => x.Alias == "description").GetValue(), Is.EqualTo("This is the meta description for a textpage")); @@ -975,19 +961,19 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_Content_Type_Has_Content_Nodes() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - ContentTypeRepository repository; - var contentRepository = CreateRepository((IScopeAccessor)provider, out repository); - var contentTypeId = NodeDto.NodeIdSeed + 1; + var repository = ContentTypeRepository; + + var contentTypeId = _textpageContentType.Id; var contentType = repository.Get(contentTypeId); // Act var result = repository.HasContentNodes(contentTypeId); - var subpage = MockedContent.CreateTextpageContent(contentType, "Test Page 1", contentType.Id); - contentRepository.Save(subpage); + var subpage = ContentBuilder.CreateTextpageContent(contentType, "Test Page 1", contentType.Id); + DocumentRepository.Save(subpage); var result2 = repository.HasContentNodes(contentTypeId); @@ -997,15 +983,6 @@ namespace Umbraco.Tests.Persistence.Repositories } } - public void CreateTestData() - { - //Create and Save ContentType "umbTextpage" -> (NodeDto.NodeIdSeed) - ContentType simpleContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage"); - ServiceContext.ContentTypeService.Save(simpleContentType); - //Create and Save ContentType "textPage" -> (NodeDto.NodeIdSeed + 1) - ContentType textpageContentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.ContentTypeService.Save(textpageContentType); - } } } diff --git a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs similarity index 57% rename from src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index e1c79b9d26..6d991117a1 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -1,47 +1,37 @@ using System.Linq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; -using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Core.Composing; -using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Scoping; +using Umbraco.Core.Services; +using Umbraco.Tests.Integration.Testing; using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class DataTypeDefinitionRepositoryTest : TestWithDatabaseBase + public class DataTypeDefinitionRepositoryTest : UmbracoIntegrationTest { - private IDataTypeRepository CreateRepository() - { - return Factory.GetInstance(); - } - - private EntityContainerRepository CreateContainerRepository(IScopeAccessor scopeAccessor) - { - return new EntityContainerRepository(scopeAccessor, AppCaches.Disabled, Logger, Constants.ObjectTypes.DataTypeContainer); - } + private IDataTypeService DataTypeService => GetRequiredService(); + private ILocalizedTextService LocalizedTextService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IContentTypeRepository ContentTypeRepository => GetRequiredService(); + private IDataTypeContainerRepository DataTypeContainerRepository => GetRequiredService(); + private IDataTypeRepository DataTypeRepository => GetRequiredService(); [Test] public void Can_Find_Usages() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var dtRepo = CreateRepository(); - IDataType dataType1 = new DataType(new RadioButtonsPropertyEditor(Logger, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) { Name = "dt1" }; - dtRepo.Save(dataType1); - IDataType dataType2 = new DataType(new RadioButtonsPropertyEditor(Logger, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) { Name = "dt2" }; - dtRepo.Save(dataType2); + IDataType dataType1 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) { Name = "dt1" }; + DataTypeRepository.Save(dataType1); + IDataType dataType2 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) { Name = "dt2" }; + DataTypeRepository.Save(dataType2); - var ctRepo = Factory.GetInstance(); IContentType ct = new ContentType(ShortStringHelper, -1) { Alias = "ct1", @@ -71,9 +61,9 @@ namespace Umbraco.Tests.Persistence.Repositories } } }; - ctRepo.Save(ct); + ContentTypeRepository.Save(ct); - var usages = dtRepo.FindUsages(dataType1.Id); + var usages = DataTypeRepository.FindUsages(dataType1.Id); var key = usages.First().Key; Assert.AreEqual(ct.Key, ((GuidUdi)key).Guid); @@ -81,7 +71,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual("pt1", usages[key].ElementAt(0)); Assert.AreEqual("pt2", usages[key].ElementAt(1)); - usages = dtRepo.FindUsages(dataType2.Id); + usages = DataTypeRepository.FindUsages(dataType2.Id); key = usages.First().Key; Assert.AreEqual(ct.Key, ((GuidUdi)key).Guid); @@ -93,39 +83,35 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Move() { - var provider = TestObjects.GetScopeProvider(Logger); - var accessor = (IScopeAccessor) provider; - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var containerRepository = CreateContainerRepository(accessor); - var repository = CreateRepository(); + var container1 = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah1" }; - containerRepository.Save(container1); + DataTypeContainerRepository.Save(container1); var container2 = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah2", ParentId = container1.Id }; - containerRepository.Save(container2); + DataTypeContainerRepository.Save(container2); - var dataType = (IDataType) new DataType(new RadioButtonsPropertyEditor(Logger, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container2.Id) + var dataType = (IDataType) new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container2.Id) { Name = "dt1" }; - repository.Save(dataType); + DataTypeRepository.Save(dataType); //create a - var dataType2 = (IDataType)new DataType(new RadioButtonsPropertyEditor(Logger, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), dataType.Id) + var dataType2 = (IDataType)new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), dataType.Id) { Name = "dt2" }; - repository.Save(dataType2); + DataTypeRepository.Save(dataType2); - var result = repository.Move(dataType, container1).ToArray(); + var result = DataTypeRepository.Move(dataType, container1).ToArray(); Assert.AreEqual(2, result.Length); //re-get - dataType = repository.Get(dataType.Id); - dataType2 = repository.Get(dataType2.Id); + dataType = DataTypeRepository.Get(dataType.Id); + dataType2 = DataTypeRepository.Get(dataType2.Id); Assert.AreEqual(container1.Id, dataType.ParentId); Assert.AreNotEqual(result.Single(x => x.Entity.Id == dataType.Id).OriginalPath, dataType.Path); @@ -136,18 +122,14 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Create_Container() { - var provider = TestObjects.GetScopeProvider(Logger); - var accessor = (IScopeAccessor) provider; - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var containerRepository = CreateContainerRepository(accessor); var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" }; - containerRepository.Save(container); + DataTypeContainerRepository.Save(container); Assert.That(container.Id, Is.GreaterThan(0)); - var found = containerRepository.Get(container.Id); + var found = DataTypeContainerRepository.Get(container.Id); Assert.IsNotNull(found); } } @@ -155,19 +137,15 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Delete_Container() { - var provider = TestObjects.GetScopeProvider(Logger); - var accessor = (IScopeAccessor) provider; - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var containerRepository = CreateContainerRepository(accessor); var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" }; - containerRepository.Save(container); + DataTypeContainerRepository.Save(container); // Act - containerRepository.Delete(container); + DataTypeContainerRepository.Delete(container); - var found = containerRepository.Get(container.Id); + var found = DataTypeContainerRepository.Get(container.Id); Assert.IsNull(found); } } @@ -175,18 +153,13 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Create_Container_Containing_Data_Types() { - var provider = TestObjects.GetScopeProvider(Logger); - var accessor = (IScopeAccessor) provider; - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var containerRepository = CreateContainerRepository(accessor); - var repository = CreateRepository(); var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" }; - containerRepository.Save(container); + DataTypeContainerRepository.Save(container); - var dataTypeDefinition = new DataType(new RadioButtonsPropertyEditor(Logger, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container.Id) { Name = "test" }; - repository.Save(dataTypeDefinition); + var dataTypeDefinition = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container.Id) { Name = "test" }; + DataTypeRepository.Save(dataTypeDefinition); Assert.AreEqual(container.Id, dataTypeDefinition.ParentId); } @@ -195,26 +168,21 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Delete_Container_Containing_Data_Types() { - var provider = TestObjects.GetScopeProvider(Logger); - var accessor = (IScopeAccessor) provider; - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var containerRepository = CreateContainerRepository(accessor); - var repository = CreateRepository(); var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" }; - containerRepository.Save(container); + DataTypeContainerRepository.Save(container); - IDataType dataType = new DataType(new RadioButtonsPropertyEditor(Logger, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container.Id) { Name = "test" }; - repository.Save(dataType); + IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container.Id) { Name = "test" }; + DataTypeRepository.Save(dataType); // Act - containerRepository.Delete(container); + DataTypeContainerRepository.Delete(container); - var found = containerRepository.Get(container.Id); + var found = DataTypeContainerRepository.Get(container.Id); Assert.IsNull(found); - dataType = repository.Get(dataType.Id); + dataType = DataTypeRepository.Get(dataType.Id); Assert.IsNotNull(dataType); Assert.AreEqual(-1, dataType.ParentId); } @@ -223,20 +191,17 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Create() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var repository = CreateRepository(); - IDataType dataType = new DataType(new RadioButtonsPropertyEditor(Logger, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) {Name = "test"}; + IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) {Name = "test"}; - repository.Save(dataType); + DataTypeRepository.Save(dataType); var id = dataType.Id; Assert.That(id, Is.GreaterThan(0)); // Act - dataType = repository.Get(id); + dataType = DataTypeRepository.Get(id); // Assert Assert.That(dataType, Is.Not.Null); @@ -248,13 +213,10 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Get_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var repository = CreateRepository(); // Act - var dataTypeDefinition = repository.Get(Constants.DataTypes.DropDownSingle); + var dataTypeDefinition = DataTypeRepository.Get(Constants.DataTypes.DropDownSingle); // Assert Assert.That(dataTypeDefinition, Is.Not.Null); @@ -266,14 +228,10 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_GetAll_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var repository = CreateRepository(); - // Act - var dataTypeDefinitions = repository.GetMany().ToArray(); + var dataTypeDefinitions = DataTypeRepository.GetMany().ToArray(); // Assert Assert.That(dataTypeDefinitions, Is.Not.Null); @@ -286,14 +244,10 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_GetAll_With_Params_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var repository = CreateRepository(); - // Act - var dataTypeDefinitions = repository.GetMany(-40, -41, -42).ToArray(); + var dataTypeDefinitions = DataTypeRepository.GetMany(-40, -41, -42).ToArray(); // Assert Assert.That(dataTypeDefinitions, Is.Not.Null); @@ -306,15 +260,12 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_GetByQuery_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateRepository(); // Act var query = scope.SqlContext.Query().Where(x => x.EditorAlias == Constants.PropertyEditors.Aliases.RadioButtonList); - var result = repository.Get(query).ToArray(); + var result = DataTypeRepository.Get(query).ToArray(); // Assert Assert.That(result, Is.Not.Null); @@ -326,15 +277,11 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Count_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateRepository(); - // Act var query = scope.SqlContext.Query().Where(x => x.Name.StartsWith("D")); - int count = repository.Count(query); + int count = DataTypeRepository.Count(query); // Assert Assert.That(count, Is.EqualTo(4)); @@ -344,12 +291,9 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Add_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var repository = CreateRepository(); - var dataTypeDefinition = new DataType(new LabelPropertyEditor(Logger, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper)) + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper)) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", @@ -358,10 +302,10 @@ namespace Umbraco.Tests.Persistence.Repositories }; // Act - repository.Save(dataTypeDefinition); + DataTypeRepository.Save(dataTypeDefinition); - var exists = repository.Exists(dataTypeDefinition.Id); - var fetched = repository.Get(dataTypeDefinition.Id); + var exists = DataTypeRepository.Exists(dataTypeDefinition.Id); + var fetched = DataTypeRepository.Get(dataTypeDefinition.Id); // Assert Assert.That(dataTypeDefinition.HasIdentity, Is.True); @@ -382,26 +326,23 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Update_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var repository = CreateRepository(); - var dataTypeDefinition = new DataType(new IntegerPropertyEditor(Logger, DataTypeService, LocalizationService, ShortStringHelper, LocalizedTextService)) + var dataTypeDefinition = new DataType(new IntegerPropertyEditor(LoggerFactory, DataTypeService, LocalizationService, ShortStringHelper, LocalizedTextService)) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", CreatorId = 0 }; - repository.Save(dataTypeDefinition); + DataTypeRepository.Save(dataTypeDefinition); // Act - var definition = repository.Get(dataTypeDefinition.Id); + var definition = DataTypeRepository.Get(dataTypeDefinition.Id); definition.Name = "AgeDataType Updated"; - definition.Editor = new LabelPropertyEditor(Logger, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper); //change - repository.Save(definition); + definition.Editor = new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper); //change + DataTypeRepository.Save(definition); - var definitionUpdated = repository.Get(dataTypeDefinition.Id); + var definitionUpdated = DataTypeRepository.Get(dataTypeDefinition.Id); // Assert Assert.That(definitionUpdated, Is.Not.Null); @@ -413,12 +354,9 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Delete_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var repository = CreateRepository(); - var dataTypeDefinition = new DataType(new LabelPropertyEditor(Logger, IOHelper, DataTypeService,LocalizedTextService, LocalizationService, ShortStringHelper)) + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService,LocalizedTextService, LocalizationService, ShortStringHelper)) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", @@ -426,13 +364,13 @@ namespace Umbraco.Tests.Persistence.Repositories }; // Act - repository.Save(dataTypeDefinition); + DataTypeRepository.Save(dataTypeDefinition); - var existsBefore = repository.Exists(dataTypeDefinition.Id); + var existsBefore = DataTypeRepository.Exists(dataTypeDefinition.Id); - repository.Delete(dataTypeDefinition); + DataTypeRepository.Delete(dataTypeDefinition); - var existsAfter = repository.Exists(dataTypeDefinition.Id); + var existsAfter = DataTypeRepository.Exists(dataTypeDefinition.Id); // Assert Assert.That(existsBefore, Is.True); @@ -443,15 +381,11 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Exists_On_DataTypeDefinitionRepository() { - var provider = TestObjects.GetScopeProvider(Logger); - - using (provider.CreateScope()) + using (ScopeProvider.CreateScope()) { - var repository = CreateRepository(); - // Act - var exists = repository.Exists(1046); //Content picker - var doesntExist = repository.Exists(-80); + var exists = DataTypeRepository.Exists(1046); //Content picker + var doesntExist = DataTypeRepository.Exists(-80); // Assert Assert.That(exists, Is.True); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs index a85873a761..4d5bdac6b4 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Services; using Umbraco.Tests.Integration.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 GlobalSettings(); + 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 GlobalSettings(); + 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/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/DocumentRepositoryTest.cs similarity index 74% rename from src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Persistence/Repositories/DocumentRepositoryTest.cs index fe59e431ec..7dff775c8f 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/DocumentRepositoryTest.cs @@ -1,17 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using Moq; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Persistence; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Persistence.SqlSyntax; @@ -20,17 +15,34 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Tests.Testing; using Umbraco.Web.PropertyEditors; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.IO; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; namespace Umbraco.Tests.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class DocumentRepositoryTest : TestWithDatabaseBase + public class DocumentRepositoryTest : UmbracoIntegrationTest { - public override void SetUp() - { - base.SetUp(); + private ContentType _contentType; + private Content _textpage; + private Content _subpage; + private Content _subpage2; + private Content _trashed; + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + private IDataTypeService DataTypeService => GetRequiredService(); + private ILocalizedTextService LocalizedTextService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IFileSystems FileSystems => GetRequiredService(); + + [SetUp] + public void SetUpData() + { CreateTestData(); ContentRepositoryBase.ThrowOnWarning = true; @@ -43,6 +55,36 @@ namespace Umbraco.Tests.Persistence.Repositories base.TearDown(); } + public void CreateTestData() + { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + //Create and Save ContentType "umbTextpage" -> (_contentType.Id) + _contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId:template.Id); + _contentType.Key = new Guid("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"); + ContentTypeService.Save(_contentType); + + //Create and Save Content "Homepage" based on "umbTextpage" -> (_textpage.Id) + _textpage = ContentBuilder.CreateSimpleContent(_contentType); + _textpage.Key = new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0"); + ContentService.Save(_textpage, 0); + + //Create and Save Content "Text Page 1" based on "umbTextpage" -> (_subpage.Id) + _subpage = ContentBuilder.CreateSimpleContent(_contentType, "Text Page 1", _textpage.Id); + _subpage.Key = new Guid("FF11402B-7E53-4654-81A7-462AC2108059"); + ContentService.Save(_subpage, 0); + + //Create and Save Content "Text Page 1" based on "umbTextpage" -> (_subpage2.Id) + _subpage2 = ContentBuilder.CreateSimpleContent(_contentType, "Text Page 2", _textpage.Id); + ContentService.Save(_subpage2, 0); + + //Create and Save Content "Text Page Deleted" based on "umbTextpage" -> (_trashed.Id) + _trashed = ContentBuilder.CreateSimpleContent(_contentType, "Text Page Deleted", -20); + _trashed.Trashed = true; + ContentService.Save(_trashed, 0); + } + private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, out DataTypeRepository dtdRepository, AppCaches appCaches = null) { appCaches = appCaches ?? AppCaches; @@ -50,7 +92,7 @@ namespace Umbraco.Tests.Persistence.Repositories TemplateRepository tr; var ctRepository = CreateRepository(scopeAccessor, out contentTypeRepository, out tr); var editors = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, new Lazy(() => editors), Logger); + dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, new Lazy(() => editors), LoggerFactory.CreateLogger(), LoggerFactory); return ctRepository; } @@ -62,19 +104,21 @@ 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 GlobalSettings()); + appCaches = appCaches ?? AppCaches; - templateRepository = new TemplateRepository(scopeAccessor, appCaches, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); - var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger); + templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper); + var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger, TestObjects.GetGlobalSettings()); - contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); + var languageRepository = new LanguageRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), globalSettings); + contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(scopeAccessor); - var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new DocumentRepository(scopeAccessor, appCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, + var repository = new DocumentRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); return repository; } @@ -87,7 +131,7 @@ namespace Umbraco.Tests.Persistence.Repositories new DictionaryAppCache(), new IsolatedCaches(t => new ObjectCacheAppCache())); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, appCaches: realCache); @@ -96,10 +140,12 @@ namespace Umbraco.Tests.Persistence.Repositories udb.EnableSqlCount = false; - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); + contentTypeRepository.Save(contentType); - var content = MockedContent.CreateSimpleContent(contentType); + var content = ContentBuilder.CreateSimpleContent(contentType); repository.Save(content); udb.EnableSqlCount = true; @@ -128,18 +174,20 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void CreateVersions() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, out DataTypeRepository _); var versions = new List(); - var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); - ServiceContext.FileService.SaveTemplate(hasPropertiesContentType.DefaultTemplate); // else, FK violation on contentType! + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var hasPropertiesContentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); + contentTypeRepository.Save(hasPropertiesContentType); - IContent content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType); + IContent content1 = ContentBuilder.CreateSimpleContent(hasPropertiesContentType); // save = create the initial version repository.Save(content1); @@ -302,20 +350,23 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void PropertyDataAssignedCorrectly() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, out DataTypeRepository _); - var emptyContentType = MockedContentTypes.CreateBasicContentType(); - var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); + var emptyContentType = ContentTypeBuilder.CreateBasicContentType(); + var hasPropertiesContentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); contentTypeRepository.Save(emptyContentType); contentTypeRepository.Save(hasPropertiesContentType); - ServiceContext.FileService.SaveTemplate(hasPropertiesContentType.DefaultTemplate); // else, FK violation on contentType! - var content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType); - var content2 = MockedContent.CreateBasicContent(emptyContentType); - var content3 = MockedContent.CreateSimpleContent(hasPropertiesContentType); + + var content1 = ContentBuilder.CreateSimpleContent(hasPropertiesContentType); + var content2 = ContentBuilder.CreateBasicContent(emptyContentType); + var content3 = ContentBuilder.CreateSimpleContent(hasPropertiesContentType); repository.Save(content1); @@ -342,74 +393,75 @@ namespace Umbraco.Tests.Persistence.Repositories } } - /// - /// This test ensures that when property values using special database fields are saved, the actual data in the - /// object being stored is also transformed in the same way as the data being stored in the database is. - /// Before you would see that ex: a decimal value being saved as 100 or "100", would be that exact value in the - /// object, but the value saved to the database was actually 100.000000. - /// When querying the database for the value again - the value would then differ from what is in the object. - /// This caused inconsistencies between saving+publishing and simply saving and then publishing, due to the former - /// sending the non-transformed data directly on to publishing. - /// - [Test] - public void PropertyValuesWithSpecialTypes() - { - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) - { - var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, out DataTypeRepository dataTypeDefinitionRepository); - - var editor = new DecimalPropertyEditor(Logger, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper); - var dtd = new DataType(editor) { Name = "test", DatabaseType = ValueStorageType.Decimal }; - dataTypeDefinitionRepository.Save(dtd); - - const string decimalPropertyAlias = "decimalProperty"; - const string intPropertyAlias = "intProperty"; - const string dateTimePropertyAlias = "datetimeProperty"; - var dateValue = new DateTime(2016, 1, 6); - - var propertyTypeCollection = new PropertyTypeCollection(true, - new List - { - MockedPropertyTypes.CreateDecimalProperty(decimalPropertyAlias, "Decimal property", dtd.Id), - MockedPropertyTypes.CreateIntegerProperty(intPropertyAlias, "Integer property"), - MockedPropertyTypes.CreateDateTimeProperty(dateTimePropertyAlias, "DateTime property") - }); - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage", propertyTypeCollection); - contentTypeRepository.Save(contentType); - - // int and decimal values are passed in as strings as they would be from the backoffice UI - var textpage = MockedContent.CreateSimpleContentWithSpecialDatabaseTypes(contentType, "test@umbraco.org", -1, "100", "150", dateValue); - - repository.Save(textpage); - scope.Complete(); - - Assert.That(contentType.HasIdentity, Is.True); - Assert.That(textpage.HasIdentity, Is.True); - - var persistedTextpage = repository.Get(textpage.Id); - Assert.That(persistedTextpage.Name, Is.EqualTo(textpage.Name)); - Assert.AreEqual(100m, persistedTextpage.GetValue(decimalPropertyAlias)); - Assert.AreEqual(persistedTextpage.GetValue(decimalPropertyAlias), textpage.GetValue(decimalPropertyAlias)); - Assert.AreEqual(150, persistedTextpage.GetValue(intPropertyAlias)); - Assert.AreEqual(persistedTextpage.GetValue(intPropertyAlias), textpage.GetValue(intPropertyAlias)); - Assert.AreEqual(dateValue, persistedTextpage.GetValue(dateTimePropertyAlias)); - Assert.AreEqual(persistedTextpage.GetValue(dateTimePropertyAlias), textpage.GetValue(dateTimePropertyAlias)); - } - } + // /// + // /// This test ensures that when property values using special database fields are saved, the actual data in the + // /// object being stored is also transformed in the same way as the data being stored in the database is. + // /// Before you would see that ex: a decimal value being saved as 100 or "100", would be that exact value in the + // /// object, but the value saved to the database was actually 100.000000. + // /// When querying the database for the value again - the value would then differ from what is in the object. + // /// This caused inconsistencies between saving+publishing and simply saving and then publishing, due to the former + // /// sending the non-transformed data directly on to publishing. + // /// + // [Test] + // public void PropertyValuesWithSpecialTypes() + // { + // var provider = ScopeProvider; + // using (var scope = provider.CreateScope()) + // { + // var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, out DataTypeRepository dataTypeDefinitionRepository); + // + // var editor = new DecimalPropertyEditor(LoggerFactory, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper); + // var dtd = new DataType(editor) { Name = "test", DatabaseType = ValueStorageType.Decimal }; + // dataTypeDefinitionRepository.Save(dtd); + // + // const string decimalPropertyAlias = "decimalProperty"; + // const string intPropertyAlias = "intProperty"; + // const string dateTimePropertyAlias = "datetimeProperty"; + // var dateValue = new DateTime(2016, 1, 6); + // + // var propertyTypeCollection = new PropertyTypeCollection(true, + // new List + // { + // MockedPropertyTypes.CreateDecimalProperty(decimalPropertyAlias, "Decimal property", dtd.Id), + // MockedPropertyTypes.CreateIntegerProperty(intPropertyAlias, "Integer property"), + // MockedPropertyTypes.CreateDateTimeProperty(dateTimePropertyAlias, "DateTime property") + // }); + // var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", propertyTypeCollection); + // contentTypeRepository.Save(contentType); + // + // // int and decimal values are passed in as strings as they would be from the backoffice UI + // var textpage = ContentBuilder.CreateSimpleContentWithSpecialDatabaseTypes(contentType, "test@umbraco.org", -1, "100", "150", dateValue); + // + // repository.Save(textpage); + // scope.Complete(); + // + // Assert.That(contentType.HasIdentity, Is.True); + // Assert.That(textpage.HasIdentity, Is.True); + // + // var persistedTextpage = repository.Get(textpage.Id); + // Assert.That(persistedTextpage.Name, Is.EqualTo(textpage.Name)); + // Assert.AreEqual(100m, persistedTextpage.GetValue(decimalPropertyAlias)); + // Assert.AreEqual(persistedTextpage.GetValue(decimalPropertyAlias), textpage.GetValue(decimalPropertyAlias)); + // Assert.AreEqual(150, persistedTextpage.GetValue(intPropertyAlias)); + // Assert.AreEqual(persistedTextpage.GetValue(intPropertyAlias), textpage.GetValue(intPropertyAlias)); + // Assert.AreEqual(dateValue, persistedTextpage.GetValue(dateTimePropertyAlias)); + // Assert.AreEqual(persistedTextpage.GetValue(dateTimePropertyAlias), textpage.GetValue(dateTimePropertyAlias)); + // } + // } [Test] public void SaveContent() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository); - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage"); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage2", "Textpage", defaultTemplateId: template.Id); contentTypeRepository.Save(contentType); - IContent textpage = MockedContent.CreateSimpleContent(contentType); + IContent textpage = ContentBuilder.CreateSimpleContent(contentType); repository.Save(textpage); scope.Complete(); @@ -422,7 +474,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void SaveContentWithDefaultTemplate() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, out TemplateRepository templateRepository); @@ -431,12 +483,12 @@ namespace Umbraco.Tests.Persistence.Repositories templateRepository.Save(template); - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage"); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage2", "Textpage"); contentType.AllowedTemplates = Enumerable.Empty(); // because CreateSimpleContentType assigns one already contentType.SetDefaultTemplate(template); contentTypeRepository.Save(contentType); - var textpage = MockedContent.CreateSimpleContent(contentType); + var textpage = ContentBuilder.CreateSimpleContent(contentType); repository.Save(textpage); @@ -457,17 +509,18 @@ namespace Umbraco.Tests.Persistence.Repositories public void SaveContentWithAtSignInName() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository); - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); contentTypeRepository.Save(contentType); - var textpage = MockedContent.CreateSimpleContent(contentType, "test@umbraco.org"); - var anotherTextpage = MockedContent.CreateSimpleContent(contentType, "@lightgiants"); + var textpage = ContentBuilder.CreateSimpleContent(contentType, "test@umbraco.org"); + var anotherTextpage = ContentBuilder.CreateSimpleContent(contentType, "@lightgiants"); repository.Save(textpage); repository.Save(anotherTextpage); @@ -490,20 +543,21 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void SaveContentMultiple() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository); - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); contentTypeRepository.Save(contentType); - var textpage = MockedContent.CreateSimpleContent(contentType); + var textpage = ContentBuilder.CreateSimpleContent(contentType); repository.Save(textpage); - var subpage = MockedContent.CreateSimpleContent(contentType, "Text Page 1", textpage.Id); + var subpage = ContentBuilder.CreateSimpleContent(contentType, "Text Page 1", textpage.Id); repository.Save(subpage); @@ -519,12 +573,12 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetContentIsNotDirty() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); - var content = repository.Get(NodeDto.NodeIdSeed + 3); + var content = repository.Get(_subpage2.Id); var dirty = ((Content)content).IsDirty(); Assert.That(dirty, Is.False); @@ -534,16 +588,16 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void UpdateContent() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); - var content = repository.Get(NodeDto.NodeIdSeed + 2); + var content = repository.Get(_subpage.Id); content.Name = "About 2"; repository.Save(content); - var updatedContent = repository.Get(NodeDto.NodeIdSeed + 2); + var updatedContent = repository.Get(_subpage.Id); Assert.AreEqual(content.Id, updatedContent.Id); Assert.AreEqual(content.Name, updatedContent.Name); @@ -553,7 +607,7 @@ namespace Umbraco.Tests.Persistence.Repositories content.SetValue("title", "toot"); repository.Save(content); - updatedContent = repository.Get(NodeDto.NodeIdSeed + 2); + updatedContent = repository.Get(_subpage.Id); Assert.AreEqual("toot", updatedContent.GetValue("title")); Assert.AreEqual(content.VersionId, updatedContent.VersionId); @@ -563,16 +617,16 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void UpdateContentWithNullTemplate() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); - var content = repository.Get(NodeDto.NodeIdSeed + 2); + var content = repository.Get(_subpage.Id); content.TemplateId = null; repository.Save(content); - var updatedContent = repository.Get(NodeDto.NodeIdSeed + 2); + var updatedContent = repository.Get(_subpage.Id); Assert.False(updatedContent.TemplateId.HasValue); } @@ -582,12 +636,12 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void DeleteContent() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository); - var contentType = contentTypeRepository.Get(NodeDto.NodeIdSeed + 1); - var content = new Content("Textpage 2 Child Node", NodeDto.NodeIdSeed + 4, contentType); + var contentType = contentTypeRepository.Get(_contentType.Id); + var content = new Content("Textpage 2 Child Node", _trashed.Id, contentType); content.CreatorId = 0; content.WriterId = 0; @@ -606,19 +660,19 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetContent() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); - var content = repository.Get(NodeDto.NodeIdSeed + 4); + var content = repository.Get(_subpage2.Id); - Assert.AreEqual(NodeDto.NodeIdSeed + 4, content.Id); + Assert.AreEqual(_subpage2.Id, content.Id); Assert.That(content.CreateDate, Is.GreaterThan(DateTime.MinValue)); Assert.That(content.UpdateDate, Is.GreaterThan(DateTime.MinValue)); Assert.AreNotEqual(0, content.ParentId); Assert.AreEqual("Text Page 2", content.Name); Assert.AreNotEqual(0, content.VersionId); - Assert.AreEqual(NodeDto.NodeIdSeed + 1, content.ContentTypeId); + Assert.AreEqual(_contentType.Id, content.ContentTypeId); Assert.That(content.Path, Is.Not.Empty); Assert.That(content.Properties.Any(), Is.True); } @@ -627,7 +681,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void QueryContent() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -644,7 +698,7 @@ namespace Umbraco.Tests.Persistence.Repositories { IContent[] result; - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -698,16 +752,18 @@ namespace Umbraco.Tests.Persistence.Repositories { // one invariant content type named "umbInvariantTextPage" // - var invariantCt = MockedContentTypes.CreateSimpleContentType("umbInvariantTextpage", "Invariant Textpage"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var invariantCt = ContentTypeBuilder.CreateSimpleContentType("umbInvariantTextpage", "Invariant Textpage", defaultTemplateId: template.Id); invariantCt.Variations = ContentVariation.Nothing; foreach (var p in invariantCt.PropertyTypes) p.Variations = ContentVariation.Nothing; - ServiceContext.FileService.SaveTemplate(invariantCt.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(invariantCt); + ContentTypeService.Save(invariantCt); // one variant (by culture) content type named "umbVariantTextPage" // with properties, every 2nd one being variant (by culture), the other being invariant // - var variantCt = MockedContentTypes.CreateSimpleContentType("umbVariantTextpage", "Variant Textpage"); + + var variantCt = ContentTypeBuilder.CreateSimpleContentType("umbVariantTextpage", "Variant Textpage", defaultTemplateId: template.Id); variantCt.Variations = ContentVariation.Culture; var propTypes = variantCt.PropertyTypes.ToList(); for (var i = 0; i < propTypes.Count; i++) @@ -715,16 +771,16 @@ namespace Umbraco.Tests.Persistence.Repositories var p = propTypes[i]; p.Variations = i % 2 == 0 ? ContentVariation.Culture : ContentVariation.Nothing; } - ServiceContext.FileService.SaveTemplate(variantCt.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(variantCt); + + ContentTypeService.Save(variantCt); invariantCt.AllowedContentTypes = new[] { new ContentTypeSort(invariantCt.Id, 0), new ContentTypeSort(variantCt.Id, 1) }; - ServiceContext.ContentTypeService.Save(invariantCt); + ContentTypeService.Save(invariantCt); //create content - var root = MockedContent.CreateSimpleContent(invariantCt); - ServiceContext.ContentService.Save(root); + var root = ContentBuilder.CreateSimpleContent(invariantCt); + ContentService.Save(root); var children = new List(); @@ -734,7 +790,7 @@ namespace Umbraco.Tests.Persistence.Repositories var name = (isInvariant ? "INV" : "VAR") + "_" + Guid.NewGuid(); var culture = isInvariant ? null : "en-US"; - var child = MockedContent.CreateSimpleContent( + var child = ContentBuilder.CreateSimpleContent( isInvariant ? invariantCt : variantCt, name, root, culture, @@ -748,7 +804,7 @@ namespace Umbraco.Tests.Persistence.Repositories child.SetValue("author", "John Doe", culture: culture); } - ServiceContext.ContentService.Save(child); + ContentService.Save(child); children.Add(child); } @@ -757,7 +813,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.IsTrue(child1.Name.StartsWith("VAR")); Assert.IsTrue(child1.GetCultureName("en-US").StartsWith("VAR")); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -804,7 +860,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetPagedResultsByQuery_CustomPropertySort() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -836,7 +892,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetPagedResultsByQuery_FirstPage() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -865,7 +921,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetPagedResultsByQuery_SecondPage() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -882,7 +938,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetPagedResultsByQuery_SinglePage() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -899,7 +955,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetPagedResultsByQuery_DescendingOrder() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -916,7 +972,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetPagedResultsByQuery_FilterMatchingSome() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -935,7 +991,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetPagedResultsByQuery_FilterMatchingAll() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -954,12 +1010,12 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetAllContentByIds() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); - var contents = repository.GetMany(NodeDto.NodeIdSeed + 2, NodeDto.NodeIdSeed + 3); + var contents = repository.GetMany(_subpage.Id, _subpage2.Id); Assert.That(contents, Is.Not.Null); @@ -971,7 +1027,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetAllContent() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -997,12 +1053,12 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void ExistContent() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); - var exists = repository.Exists(NodeDto.NodeIdSeed + 2); + var exists = repository.Exists(_subpage.Id); Assert.That(exists, Is.True); } @@ -1011,7 +1067,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void CountContent() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -1026,7 +1082,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void QueryContentByUniqueId() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { var repository = CreateRepository((IScopeAccessor)provider, out _); @@ -1035,36 +1091,10 @@ namespace Umbraco.Tests.Persistence.Repositories var content = repository.Get(query).SingleOrDefault(); Assert.IsNotNull(content); - Assert.AreEqual(NodeDto.NodeIdSeed + 2, content.Id); + Assert.AreEqual(_textpage.Id, content.Id); } } - public void CreateTestData() - { - //Create and Save ContentType "umbTextpage" -> (NodeDto.NodeIdSeed) - ContentType contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage"); - contentType.Key = new Guid("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(contentType); - //Create and Save Content "Homepage" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 1) - Content textpage = MockedContent.CreateSimpleContent(contentType); - textpage.Key = new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0"); - ServiceContext.ContentService.Save(textpage, 0); - - //Create and Save Content "Text Page 1" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 2) - Content subpage = MockedContent.CreateSimpleContent(contentType, "Text Page 1", textpage.Id); - subpage.Key = new Guid("FF11402B-7E53-4654-81A7-462AC2108059"); - ServiceContext.ContentService.Save(subpage, 0); - - //Create and Save Content "Text Page 1" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 3) - Content subpage2 = MockedContent.CreateSimpleContent(contentType, "Text Page 2", textpage.Id); - ServiceContext.ContentService.Save(subpage2, 0); - - //Create and Save Content "Text Page Deleted" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 4) - Content trashed = MockedContent.CreateSimpleContent(contentType, "Text Page Deleted", -20); - trashed.Trashed = true; - ServiceContext.ContentService.Save(trashed, 0); - } } } diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/EntityRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/EntityRepositoryTest.cs index 678e33d34b..c0da3ec8cd 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/EntityRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/EntityRepositoryTest.cs @@ -7,8 +7,8 @@ using Umbraco.Core.Models.Entities; 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.TestHelpers.Entities; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Integration.Persistence.Repositories @@ -31,25 +31,25 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var contentService = GetRequiredService(); var contentTypeService = GetRequiredService(); var createdContent = new List(); - var contentType = MockedContentTypes.CreateBasicContentType("blah"); + var contentType = ContentTypeBuilder.CreateBasicContentType("blah"); contentTypeService.Save(contentType); for (var i = 0; i < 10; i++) { - var c1 = MockedContent.CreateBasicContent(contentType); + var c1 = ContentBuilder.CreateBasicContent(contentType); contentService.Save(c1); createdContent.Add(c1); } //Create media - + var mediaService = GetRequiredService(); var mediaTypeService = GetRequiredService(); var createdMedia = new List(); - var imageType = MockedContentTypes.CreateImageMediaType("myImage"); + var imageType = MediaTypeBuilder.CreateImageMediaType("myImage"); mediaTypeService.Save(imageType); for (var i = 0; i < 10; i++) { - var c1 = MockedMedia.CreateMediaImage(imageType, -1); + var c1 = MediaBuilder.CreateMediaImage(imageType, -1); mediaService.Save(c1); createdMedia.Add(c1); } @@ -58,12 +58,12 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var memberService = GetRequiredService(); var memberTypeService = GetRequiredService(); - var memberType = MockedContentTypes.CreateSimpleMemberType("simple"); + var memberType = MemberTypeBuilder.CreateSimpleMemberType("simple"); memberTypeService.Save(memberType); - var createdMembers = MockedMember.CreateSimpleMember(memberType, 10).ToList(); + var createdMembers = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10).ToList(); memberService.Save(createdMembers); - + var provider = ScopeProvider; using (provider.CreateScope()) { @@ -77,7 +77,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories .WhereIn(e => e.Id, ids); var entities = repo.GetPagedResultsByQuery(query, objectTypes, 0, 20, out var totalRecords, null, null).ToList(); - + Assert.AreEqual(20, entities.Count); Assert.AreEqual(30, totalRecords); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/KeyValueRepositoryTests.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/KeyValueRepositoryTests.cs index c756b6273b..1b5b40cf3c 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/KeyValueRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/KeyValueRepositoryTests.cs @@ -1,5 +1,6 @@ using System; using NUnit.Framework; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; @@ -66,7 +67,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories private IKeyValueRepository CreateRepository(IScopeProvider provider) { - return new KeyValueRepository((IScopeAccessor) provider, Logger); - } + return new KeyValueRepository((IScopeAccessor) provider, LoggerFactory.CreateLogger()); + } } } diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs index e127a58cee..0b699823cb 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs @@ -1,11 +1,12 @@ using System; using System.Globalization; using System.Linq; +using Microsoft.Extensions.Logging; 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; @@ -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 GlobalSettings(); } private LanguageRepository CreateRepository(IScopeProvider provider) { - return new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, GlobalSettings); + return new LanguageRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), 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/MacroRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/MacroRepositoryTest.cs index 624fd9c566..901d905686 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/MacroRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/MacroRepositoryTest.cs @@ -1,5 +1,6 @@ using System.Data.SqlClient; using System.Linq; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Core.Models; @@ -15,9 +16,12 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class MacroRepositoryTest : UmbracoIntegrationTest { + private ILogger _logger; + [SetUp] public void SetUp() { + _logger = LoggerFactory.CreateLogger(); CreateTestData(); } @@ -28,7 +32,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); var macro = new Macro(ShortStringHelper, "test1", "Test", "~/views/macropartials/test.cshtml"); @@ -43,7 +47,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); var macro = repository.Get(1); macro.Alias = "test2"; @@ -59,7 +63,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Assert Assert.That(repository, Is.Not.Null); @@ -73,7 +77,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Act var macro = repository.Get(1); @@ -99,7 +103,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Act var macros = repository.GetMany(); @@ -116,7 +120,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Act var query = scope.SqlContext.Query().Where(x => x.Alias.ToUpper() == "TEST1"); @@ -134,7 +138,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Act var query = scope.SqlContext.Query().Where(x => x.Name.StartsWith("Test")); @@ -152,7 +156,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Act var macro = new Macro(ShortStringHelper, "test", "Test", "~/views/macropartials/test.cshtml"); @@ -173,7 +177,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Act var macro = repository.Get(2); @@ -208,7 +212,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Act var macro = repository.Get(3); @@ -229,7 +233,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); // Act var exists = repository.Exists(3); @@ -248,7 +252,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); var macro = repository.Get(1); macro.Properties.Add(new MacroProperty("new1", "New1", 3, "test")); @@ -274,7 +278,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml"); macro.Properties.Add(new MacroProperty("blah1", "New1", 4, "test.editor")); @@ -299,7 +303,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml"); macro.Properties.Add(new MacroProperty("blah1", "New1", 4, "test.editor")); @@ -323,7 +327,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml"); var prop1 = new MacroProperty("blah1", "New1", 4, "test.editor"); @@ -354,7 +358,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); var macro = repository.Get(1); macro.Properties.Add(new MacroProperty("new1", "New1", 3, "test")); @@ -381,7 +385,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); var macro = repository.Get(1); macro.Properties.Add(new MacroProperty("new1", "New1", 3, "test")); @@ -403,7 +407,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, _logger, ShortStringHelper); repository.Save(new Macro(ShortStringHelper, "test1", "Test1", "~/views/macropartials/test1.cshtml")); repository.Save(new Macro(ShortStringHelper, "test2", "Test2", "~/views/macropartials/test2.cshtml")); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/RedirectUrlRepositoryTests.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/RedirectUrlRepositoryTests.cs index 18cbb01c0e..ea1a7ed8db 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/RedirectUrlRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/RedirectUrlRepositoryTests.cs @@ -1,13 +1,14 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; 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.TestHelpers.Entities; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Integration.Persistence.Repositories @@ -187,7 +188,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories private IRedirectUrlRepository CreateRepository(IScopeProvider provider) { - return new RedirectUrlRepository((IScopeAccessor) provider, AppCaches, Logger); + return new RedirectUrlRepository((IScopeAccessor) provider, AppCaches, LoggerFactory.CreateLogger()); } private IContent _textpage, _subpage, _otherpage, _trashed; @@ -195,31 +196,33 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories public void CreateTestData() { var fileService = GetRequiredService(); + var template = TemplateBuilder.CreateTextPageTemplate(); + fileService.SaveTemplate(template); // else, FK violation on contentType! + var contentService = GetRequiredService(); var contentTypeService = GetRequiredService(); //Create and Save ContentType "umbTextpage" -> (NodeDto.NodeIdSeed) - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage"); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id); contentType.Key = Guid.NewGuid(); - fileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! contentTypeService.Save(contentType); //Create and Save Content "Homepage" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 1) - _textpage = MockedContent.CreateSimpleContent(contentType); + _textpage = ContentBuilder.CreateSimpleContent(contentType); _textpage.Key = Guid.NewGuid(); contentService.Save(_textpage); //Create and Save Content "Text Page 1" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 2) - _subpage = MockedContent.CreateSimpleContent(contentType, "Text Page 1", _textpage.Id); + _subpage = ContentBuilder.CreateSimpleContent(contentType, "Text Page 1", _textpage.Id); _subpage.Key = Guid.NewGuid(); contentService.Save(_subpage); //Create and Save Content "Text Page 1" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 3) - _otherpage = MockedContent.CreateSimpleContent(contentType, "Text Page 2", _textpage.Id); + _otherpage = ContentBuilder.CreateSimpleContent(contentType, "Text Page 2", _textpage.Id); _otherpage.Key = Guid.NewGuid(); contentService.Save(_otherpage); //Create and Save Content "Text Page Deleted" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 4) - _trashed = MockedContent.CreateSimpleContent(contentType, "Text Page Deleted", -20); + _trashed = ContentBuilder.CreateSimpleContent(contentType, "Text Page Deleted", -20); _trashed.Key = Guid.NewGuid(); ((Content) _trashed).Trashed = true; contentService.Save(_trashed); diff --git a/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationRepositoryTest.cs similarity index 60% rename from src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Persistence/Repositories/RelationRepositoryTest.cs index 209d5de4b3..63e4ada345 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/RelationRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationRepositoryTest.cs @@ -1,17 +1,20 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories; 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.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -20,37 +23,51 @@ namespace Umbraco.Tests.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class RelationRepositoryTest : TestWithDatabaseBase + public class RelationRepositoryTest : UmbracoIntegrationTest { - public override void SetUp() - { - base.SetUp(); + private RelationType _relateContent; + private RelationType _relateContentType; + private ContentType _contentType; + private Content _textpage; + private Content _subpage; + private Content _subpage2; + private Relation _relation; + private Relation _relation2; + private IContentTypeService ContentTypeService => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); + private IMediaService MediaService => GetRequiredService(); + + private IMemberTypeService MemberTypeService => GetRequiredService(); + private IMemberService MemberService => GetRequiredService(); + private IRelationService RelationService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + + [SetUp] + public void SetUp() + { CreateTestData(); } private RelationRepository CreateRepository(IScopeProvider provider, out RelationTypeRepository relationTypeRepository) { - var accessor = (IScopeAccessor) provider; - relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Mock.Of()); - var entityRepository = new EntityRepository(accessor); - var repository = new RelationRepository(accessor, Mock.Of(), relationTypeRepository, entityRepository); - return repository; + relationTypeRepository = (RelationTypeRepository)GetRequiredService(); + return (RelationRepository)GetRequiredService(); } [Test] public void Can_Perform_Add_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act var relationType = repositoryType.Get(1); - var relation = new Relation(NodeDto.NodeIdSeed + 2, NodeDto.NodeIdSeed + 3, relationType); + var relation = new Relation(_textpage.Id, _subpage.Id, relationType); repository.Save(relation); @@ -64,11 +81,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Update_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act var relation = repository.Get(1); @@ -89,11 +105,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Delete_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act var relation = repository.Get(2); @@ -111,11 +126,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Get_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act var relation = repository.Get(1); @@ -123,8 +137,8 @@ namespace Umbraco.Tests.Persistence.Repositories // Assert Assert.That(relation, Is.Not.Null); Assert.That(relation.HasIdentity, Is.True); - Assert.That(relation.ChildId, Is.EqualTo(NodeDto.NodeIdSeed + 3)); - Assert.That(relation.ParentId, Is.EqualTo(NodeDto.NodeIdSeed + 2)); + Assert.That(relation.ChildId, Is.EqualTo(_subpage.Id)); + Assert.That(relation.ParentId, Is.EqualTo(_textpage.Id)); Assert.That(relation.RelationType.Alias, Is.EqualTo("relateContentOnCopy")); } } @@ -133,11 +147,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetAll_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act var relations = repository.GetMany(); @@ -154,11 +167,10 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetAll_With_Params_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act var relations = repository.GetMany(1, 2); @@ -176,35 +188,34 @@ namespace Umbraco.Tests.Persistence.Repositories { CreateTestDataForPagingTests(out var createdContent, out var createdMembers, out var createdMedia); - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateRepository(provider, out var relationTypeRepository); + var repository = CreateRepository(ScopeProvider, out var relationTypeRepository); // Get parent entities for child id var parents = repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 11, out var totalRecords).ToList(); - Assert.AreEqual(20, totalRecords); - Assert.AreEqual(11, parents.Count); + Assert.AreEqual(6, totalRecords); + Assert.AreEqual(6, parents.Count); //add the next page parents.AddRange(repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 1, 11, out totalRecords)); - Assert.AreEqual(20, totalRecords); - Assert.AreEqual(20, parents.Count); + Assert.AreEqual(6, totalRecords); + Assert.AreEqual(6, parents.Count); var contentEntities = parents.OfType().ToList(); var mediaEntities = parents.OfType().ToList(); var memberEntities = parents.OfType().ToList(); - Assert.AreEqual(10, contentEntities.Count); + Assert.AreEqual(3, contentEntities.Count); Assert.AreEqual(0, mediaEntities.Count); - Assert.AreEqual(10, memberEntities.Count); + Assert.AreEqual(3, memberEntities.Count); //only of a certain type parents.AddRange(repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Document.GetGuid())); - Assert.AreEqual(10, totalRecords); + Assert.AreEqual(3, totalRecords); parents.AddRange(repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Member.GetGuid())); - Assert.AreEqual(10, totalRecords); + Assert.AreEqual(3, totalRecords); parents.AddRange(repository.GetPagedParentEntitiesByChildId(createdMedia[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Media.GetGuid())); Assert.AreEqual(0, totalRecords); @@ -214,18 +225,17 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Get_Paged_Parent_Child_Entities_With_Same_Entity_Relation() { - //Create a media item and create a relationship between itself (parent -> child) - var imageType = MockedContentTypes.CreateImageMediaType("myImage"); - ServiceContext.MediaTypeService.Save(imageType); - var media = MockedMedia.CreateMediaImage(imageType, -1); - ServiceContext.MediaService.Save(media); - var relType = ServiceContext.RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); - ServiceContext.RelationService.Relate(media.Id, media.Id, relType); + //Create a media item and create a relationship between itself (parent -> child) + var imageType = MediaTypeBuilder.CreateImageMediaType("myImage"); + MediaTypeService.Save(imageType); + var media = MediaBuilder.CreateMediaImage(imageType, -1); + MediaService.Save(media); + var relType = RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); + RelationService.Relate(media.Id, media.Id, relType); - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateRepository(provider, out var relationTypeRepository); + var repository = CreateRepository(ScopeProvider, out var relationTypeRepository); // Get parent entities for child id var parents = repository.GetPagedParentEntitiesByChildId(media.Id, 0, 10, out var totalRecords).ToList(); @@ -244,35 +254,34 @@ namespace Umbraco.Tests.Persistence.Repositories { CreateTestDataForPagingTests(out var createdContent, out var createdMembers, out var createdMedia); - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateRepository(provider, out var relationTypeRepository); + var repository = CreateRepository(ScopeProvider, out var relationTypeRepository); // Get parent entities for child id var parents = repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 6, out var totalRecords).ToList(); - Assert.AreEqual(10, totalRecords); - Assert.AreEqual(6, parents.Count); + Assert.AreEqual(3, totalRecords); + Assert.AreEqual(3, parents.Count); //add the next page parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 1, 6, out totalRecords)); - Assert.AreEqual(10, totalRecords); - Assert.AreEqual(10, parents.Count); + Assert.AreEqual(3, totalRecords); + Assert.AreEqual(3, parents.Count); var contentEntities = parents.OfType().ToList(); var mediaEntities = parents.OfType().ToList(); var memberEntities = parents.OfType().ToList(); Assert.AreEqual(0, contentEntities.Count); - Assert.AreEqual(10, mediaEntities.Count); + Assert.AreEqual(3, mediaEntities.Count); Assert.AreEqual(0, memberEntities.Count); //only of a certain type parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Media.GetGuid())); - Assert.AreEqual(10, totalRecords); + Assert.AreEqual(3, totalRecords); parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdMembers[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Media.GetGuid())); - Assert.AreEqual(10, totalRecords); + Assert.AreEqual(3, totalRecords); parents.AddRange(repository.GetPagedChildEntitiesByParentId(createdContent[0].Id, 0, 100, out totalRecords, UmbracoObjectTypes.Member.GetGuid())); Assert.AreEqual(0, totalRecords); @@ -283,53 +292,52 @@ namespace Umbraco.Tests.Persistence.Repositories { //Create content createdContent = new List(); - var contentType = MockedContentTypes.CreateBasicContentType("blah"); - ServiceContext.ContentTypeService.Save(contentType); - for (int i = 0; i < 10; i++) + var contentType = ContentTypeBuilder.CreateBasicContentType("blah"); + ContentTypeService.Save(contentType); + for (int i = 0; i < 3; i++) { - var c1 = MockedContent.CreateBasicContent(contentType); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateBasicContent(contentType); + ContentService.Save(c1); createdContent.Add(c1); } //Create media createdMedia = new List(); - var imageType = MockedContentTypes.CreateImageMediaType("myImage"); - ServiceContext.MediaTypeService.Save(imageType); - for (int i = 0; i < 10; i++) + var imageType = MediaTypeBuilder.CreateImageMediaType("myImage"); + MediaTypeService.Save(imageType); + for (int i = 0; i < 3; i++) { - var c1 = MockedMedia.CreateMediaImage(imageType, -1); - ServiceContext.MediaService.Save(c1); + var c1 = MediaBuilder.CreateMediaImage(imageType, -1); + MediaService.Save(c1); createdMedia.Add(c1); } // Create members - var memberType = MockedContentTypes.CreateSimpleMemberType("simple"); - ServiceContext.MemberTypeService.Save(memberType); - createdMembers = MockedMember.CreateSimpleMember(memberType, 10).ToList(); - ServiceContext.MemberService.Save(createdMembers); + var memberType = MemberTypeBuilder.CreateSimpleMemberType("simple"); + MemberTypeService.Save(memberType); + createdMembers = MemberBuilder.CreateSimpleMembers(memberType, 3).ToList(); + MemberService.Save(createdMembers); - var relType = ServiceContext.RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); + var relType = RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); // Relate content to media foreach (var content in createdContent) foreach (var media in createdMedia) - ServiceContext.RelationService.Relate(content.Id, media.Id, relType); + RelationService.Relate(content.Id, media.Id, relType); // Relate members to media foreach (var member in createdMembers) foreach (var media in createdMedia) - ServiceContext.RelationService.Relate(member.Id, media.Id, relType); + RelationService.Relate(member.Id, media.Id, relType); } [Test] public void Can_Perform_Exists_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act var exists = repository.Exists(2); @@ -345,14 +353,13 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Count_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act - var query = scope.SqlContext.Query().Where(x => x.ParentId == NodeDto.NodeIdSeed + 2); + var query = scope.SqlContext.Query().Where(x => x.ParentId == _textpage.Id); int count = repository.Count(query); // Assert @@ -364,14 +371,13 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetByQuery_On_RelationRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); // Act - var query = scope.SqlContext.Query().Where(x => x.RelationTypeId == RelationTypeDto.NodeIdSeed); + var query = scope.SqlContext.Query().Where(x => x.RelationTypeId == _relateContent.Id); var relations = repository.Get(query); // Assert @@ -386,14 +392,13 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Delete_Content_And_Verify_Relation_Is_Removed() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { RelationTypeRepository repositoryType; - var repository = CreateRepository(provider, out repositoryType); + var repository = CreateRepository(ScopeProvider, out repositoryType); - var content = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 3); - ServiceContext.ContentService.Delete(content, 0); + var content = ContentService.GetById(_subpage.Id); + ContentService.Delete(content, 0); // Act var shouldntExist = repository.Exists(1); @@ -413,49 +418,50 @@ namespace Umbraco.Tests.Persistence.Repositories public void CreateTestData() { - var relateContent = new RelationType( - "Relate Content on Copy", "relateContentOnCopy", true, + _relateContent = new RelationType( + "Relate Content on Copy", "relateContentOnCopy", true, Constants.ObjectTypes.Document, new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972")); - var relateContentType = new RelationType("Relate ContentType on Copy", + _relateContentType = new RelationType("Relate ContentType on Copy", "relateContentTypeOnCopy", true, Constants.ObjectTypes.DocumentType, new Guid("A2CB7800-F571-4787-9638-BC48539A0EFB")); - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var accessor = (IScopeAccessor)provider; - var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Mock.Of()); + var accessor = (IScopeAccessor)ScopeProvider; + var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Mock.Of>()); var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Mock.Of(), relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(accessor, Mock.Of>(), relationTypeRepository, entityRepository); - relationTypeRepository.Save(relateContent); - relationTypeRepository.Save(relateContentType); + relationTypeRepository.Save(_relateContent); + relationTypeRepository.Save(_relateContentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); //Create and Save ContentType "umbTextpage" -> (NodeDto.NodeIdSeed) - ContentType contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage"); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(contentType); + _contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id); + + ContentTypeService.Save(_contentType); //Create and Save Content "Homepage" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 1) - Content textpage = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(textpage, 0); + _textpage = ContentBuilder.CreateSimpleContent(_contentType); + ContentService.Save(_textpage, 0); //Create and Save Content "Text Page 1" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 2) - Content subpage = MockedContent.CreateSimpleContent(contentType, "Text Page 1", textpage.Id); - ServiceContext.ContentService.Save(subpage, 0); + _subpage = ContentBuilder.CreateSimpleContent(_contentType, "Text Page 1", _textpage.Id); + ContentService.Save(_subpage, 0); //Create and Save Content "Text Page 1" based on "umbTextpage" -> (NodeDto.NodeIdSeed + 3) - Content subpage2 = MockedContent.CreateSimpleContent(contentType, "Text Page 2", textpage.Id); - ServiceContext.ContentService.Save(subpage2, 0); + _subpage2 = ContentBuilder.CreateSimpleContent(_contentType, "Text Page 2", _textpage.Id); + ContentService.Save(_subpage2, 0); - var relation = new Relation(textpage.Id, subpage.Id, relateContent) { Comment = string.Empty }; - var relation2 = new Relation(textpage.Id, subpage2.Id, relateContent) { Comment = string.Empty }; - relationRepository.Save(relation); - relationRepository.Save(relation2); + _relation = new Relation(_textpage.Id, _subpage.Id, _relateContent) { Comment = string.Empty }; + _relation2 = new Relation(_textpage.Id, _subpage2.Id, _relateContent) { Comment = string.Empty }; + relationRepository.Save(_relation); + relationRepository.Save(_relation2); scope.Complete(); } } diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationTypeRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationTypeRepositoryTest.cs index 9a08c3f9c8..6a93d73713 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationTypeRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationTypeRepositoryTest.cs @@ -1,4 +1,5 @@ using System.Linq; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; @@ -22,7 +23,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories private RelationTypeRepository CreateRepository(IScopeProvider provider) { - return new RelationTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + return new RelationTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger()); } [Test] @@ -221,7 +222,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = new RelationTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + var repository = new RelationTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger()); repository.Save(relateContent);//Id 2 repository.Save(relateContentType);//Id 3 diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/ServerRegistrationRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/ServerRegistrationRepositoryTest.cs index 0ac8b3a829..3107770672 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/ServerRegistrationRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/ServerRegistrationRepositoryTest.cs @@ -1,6 +1,7 @@ using System; using System.Data.SqlClient; using System.Linq; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Core.Models; @@ -26,7 +27,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories private ServerRegistrationRepository CreateRepository(IScopeProvider provider) { - return new ServerRegistrationRepository((IScopeAccessor) provider, Logger); + return new ServerRegistrationRepository((IScopeAccessor) provider, LoggerFactory.CreateLogger()); } [Test] @@ -55,7 +56,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var server = repository.Get(1); server.ServerIdentity = "COMPUTER2"; - + Assert.Throws(() => repository.Save(server)); } } diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs index ebab6e5d17..a7894b9dc6 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs @@ -3,10 +3,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; @@ -14,9 +16,9 @@ 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; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Integration.Persistence.Repositories @@ -25,20 +27,11 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class TemplateRepositoryTest : UmbracoIntegrationTest { - private IFileSystems _fileSystems; + private IFileSystems FileSystems => GetRequiredService(); private ITemplateRepository CreateRepository(IScopeProvider provider) { - return new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, _fileSystems, IOHelper, ShortStringHelper); - } - - [SetUp] - public void SetUp() - { - var testHelper = new TestHelper(); - _fileSystems = Mock.Of(); - var viewsFileSystem = new PhysicalFileSystem(IOHelper, testHelper.GetHostingEnvironment(), Logger, Constants.SystemDirectories.MvcViews); - Mock.Get(_fileSystems).Setup(x => x.MvcViewsFileSystem).Returns(viewsFileSystem); + return new TemplateRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper); } [Test] @@ -73,7 +66,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories //Assert Assert.That(repository.Get("test"), Is.Not.Null); - Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); + Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); } } @@ -96,9 +89,9 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories //Assert Assert.That(repository.Get("test"), Is.Not.Null); - Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); + 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()); } } @@ -124,9 +117,9 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories //Assert Assert.That(repository.Get("test2"), Is.Not.Null); - Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test2.cshtml"), Is.True); + 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()); } } @@ -187,8 +180,8 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories //Assert Assert.AreEqual("test11", template.Alias); - Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test11.cshtml"), Is.True); - Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.False); + Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test11.cshtml"), Is.True); + Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.False); } } @@ -215,7 +208,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var updated = repository.Get("test"); // Assert - Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); + Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); Assert.That(updated.Content, Is.EqualTo(ViewHelper.GetDefaultFileContent() + "")); } } @@ -238,12 +231,12 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories // Act var templates = repository.Get("test"); - Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); + Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.True); repository.Delete(templates); // Assert Assert.IsNull(repository.Get("test")); - Assert.That(_fileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.False); + Assert.That(FileSystems.MvcViewsFileSystem.FileExists("test.cshtml"), Is.False); } } @@ -259,39 +252,36 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories using (provider.CreateScope()) { var templateRepository = CreateRepository(provider); - - var tagRepository = new TagRepository(scopeAccessor, AppCaches.Disabled, Logger); + var globalSettings = new GlobalSettings(); + var tagRepository = new TagRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, Logger, GlobalSettings); - var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); + var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); + var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(scopeAccessor); - var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var contentRepo = new DocumentRepository(scopeAccessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, dataTypeService); + var contentRepo = new DocumentRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, dataTypeService); - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage"); - fileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! + var template = TemplateBuilder.CreateTextPageTemplate(); + fileService.SaveTemplate(template); // else, FK violation on contentType! + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage2", "Textpage", defaultTemplateId: template.Id); contentTypeRepository.Save(contentType); - var textpage = MockedContent.CreateSimpleContent(contentType); - contentRepo.Save(textpage); - var template = new Template(ShortStringHelper, "test", "test") - { - Content = @"<%@ Master Language=""C#"" %>" - }; - templateRepository.Save(template); + var textpage = ContentBuilder.CreateSimpleContent(contentType); + contentRepo.Save(textpage); textpage.TemplateId = template.Id; contentRepo.Save(textpage); // Act - var templates = templateRepository.Get("test"); + var templates = templateRepository.Get("textPage"); templateRepository.Delete(templates); // Assert - Assert.IsNull(templateRepository.Get("test")); + Assert.IsNull(templateRepository.Get("textPage")); } } @@ -566,10 +556,9 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories public void TearDown() { var testHelper = new TestHelper(); - _fileSystems = null; //Delete all files - var fsViews = new PhysicalFileSystem(IOHelper, testHelper.GetHostingEnvironment(), Logger, Constants.SystemDirectories.MvcViews); + var fsViews = new PhysicalFileSystem(IOHelper, testHelper.GetHostingEnvironment(), LoggerFactory.CreateLogger(), Constants.SystemDirectories.MvcViews); var views = fsViews.GetFiles("", "*.cshtml"); foreach (var file in views) fsViews.DeleteFile(file); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserGroupRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/UserGroupRepositoryTest.cs index b18d1a95c2..f6444fef00 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserGroupRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/UserGroupRepositoryTest.cs @@ -1,11 +1,12 @@ using System.Linq; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; -using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Integration.Persistence.Repositories @@ -16,7 +17,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { private UserGroupRepository CreateRepository(IScopeProvider provider) { - return new UserGroupRepository((IScopeAccessor) provider, Core.Cache.AppCaches.Disabled, Logger, ShortStringHelper); + return new UserGroupRepository((IScopeAccessor) provider, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, ShortStringHelper); } [Test] @@ -28,7 +29,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(provider); - var userGroup = MockedUserGroup.CreateUserGroup(); + var userGroup = UserGroupBuilder.CreateUserGroup(); // Act repository.Save(userGroup); @@ -48,8 +49,8 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(provider); - var userGroup1 = MockedUserGroup.CreateUserGroup("1"); - var userGroup2 = MockedUserGroup.CreateUserGroup("2"); + var userGroup1 = UserGroupBuilder.CreateUserGroup(suffix: "1"); + var userGroup2 = UserGroupBuilder.CreateUserGroup(suffix: "2"); // Act repository.Save(userGroup1); @@ -72,7 +73,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(provider); - var userGroup = MockedUserGroup.CreateUserGroup(); + var userGroup = UserGroupBuilder.CreateUserGroup(); repository.Save(userGroup); scope.Complete(); @@ -94,7 +95,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(provider); - var userGroup = MockedUserGroup.CreateUserGroup(); + var userGroup = UserGroupBuilder.CreateUserGroup(); repository.Save(userGroup); // Act @@ -120,14 +121,14 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(provider); - var userGroup = MockedUserGroup.CreateUserGroup(); + var userGroup = UserGroupBuilder.CreateUserGroup(); // Act repository.Save(userGroup); var id = userGroup.Id; - var repository2 = new UserGroupRepository((IScopeAccessor) provider, Core.Cache.AppCaches.Disabled, Logger, ShortStringHelper); + var repository2 = new UserGroupRepository((IScopeAccessor) provider, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, ShortStringHelper); repository2.Delete(userGroup); scope.Complete(); @@ -147,7 +148,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(provider); - var userGroup = MockedUserGroup.CreateUserGroup(); + var userGroup = UserGroupBuilder.CreateUserGroup(); repository.Save(userGroup); scope.Complete(); @@ -176,7 +177,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories CreateAndCommitMultipleUserGroups(repository); // Act - var query = scope.SqlContext.Query().Where(x => x.Alias == "testUserGroup1"); + var query = scope.SqlContext.Query().Where(x => x.Alias == "testGroup1"); var result = repository.Get(query); // Assert @@ -257,7 +258,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var userGroups = CreateAndCommitMultipleUserGroups(repository); // Act - var query = scope.SqlContext.Query().Where(x => x.Alias == "testUserGroup1" || x.Alias == "testUserGroup2"); + var query = scope.SqlContext.Query().Where(x => x.Alias == "testGroup1" || x.Alias == "testGroup2"); var result = repository.Count(query); // Assert @@ -378,7 +379,6 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories } } - [Test] public void Get_Groups_Assigned_To_Section() { @@ -388,9 +388,9 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { var repository = CreateRepository(provider); - var user1 = MockedUserGroup.CreateUserGroup("1", allowedSections: new[] { "test1" }); - var user2 = MockedUserGroup.CreateUserGroup("2", allowedSections: new[] { "test2" }); - var user3 = MockedUserGroup.CreateUserGroup("3", allowedSections: new[] { "test1" }); + var user1 = UserGroupBuilder.CreateUserGroup(suffix: "1", allowedSections: new[] { "test1" }); + var user2 = UserGroupBuilder.CreateUserGroup(suffix: "2", allowedSections: new[] { "test2" }); + var user3 = UserGroupBuilder.CreateUserGroup(suffix: "3", allowedSections: new[] { "test1" }); repository.Save(user1); repository.Save(user2); repository.Save(user3); @@ -402,17 +402,17 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories // Assert Assert.AreEqual(2, groups.Count()); var names = groups.Select(x => x.Name).ToArray(); - Assert.IsTrue(names.Contains("TestUserGroup1")); - Assert.IsFalse(names.Contains("TestUserGroup2")); - Assert.IsTrue(names.Contains("TestUserGroup3")); + Assert.IsTrue(names.Contains("Test Group1")); + Assert.IsFalse(names.Contains("Test Group2")); + Assert.IsTrue(names.Contains("Test Group3")); } } private IUserGroup[] CreateAndCommitMultipleUserGroups(IUserGroupRepository repository) { - var userGroup1 = MockedUserGroup.CreateUserGroup("1"); - var userGroup2 = MockedUserGroup.CreateUserGroup("2"); - var userGroup3 = MockedUserGroup.CreateUserGroup("3"); + var userGroup1 = UserGroupBuilder.CreateUserGroup(suffix: "1"); + var userGroup2 = UserGroupBuilder.CreateUserGroup(suffix: "2"); + var userGroup3 = UserGroupBuilder.CreateUserGroup(suffix: "3"); repository.Save(userGroup1); repository.Save(userGroup2); repository.Save(userGroup3); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs index dddcff4331..0df619544d 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs @@ -1,10 +1,12 @@ using System; using System.Linq; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; 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,14 +27,14 @@ 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, LoggerFactory.CreateLogger(), Mappers, Options.Create(GlobalSettings), Options.Create(new UserPasswordConfigurationSettings()), new JsonNetSerializer()); return repository; } private UserGroupRepository CreateUserGroupRepository(IScopeProvider provider) { var accessor = (IScopeAccessor) provider; - return new UserGroupRepository(accessor, AppCaches.Disabled, Logger, ShortStringHelper); + return new UserGroupRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, ShortStringHelper); } [Test] @@ -44,7 +46,7 @@ namespace Umbraco.Tests.Persistence.Repositories { var repository = CreateRepository(provider); - var user = UserBuilder.Build(); + var user = UserBuilderInstance.Build(); // Act repository.Save(user); @@ -64,8 +66,8 @@ namespace Umbraco.Tests.Persistence.Repositories { var repository = CreateRepository(provider); - var user1 = UserBuilder.WithSuffix("1").Build(); - var use2 = UserBuilder.WithSuffix("2").Build(); + var user1 = UserBuilderInstance.WithSuffix("1").Build(); + var use2 = UserBuilderInstance.WithSuffix("2").Build(); // Act repository.Save(user1); @@ -88,7 +90,7 @@ namespace Umbraco.Tests.Persistence.Repositories { var repository = CreateRepository(provider); - var user = UserBuilder.WithoutIdentity().Build(); + var user = UserBuilderInstance.WithoutIdentity().Build(); repository.Save(user); @@ -110,14 +112,14 @@ namespace Umbraco.Tests.Persistence.Repositories { var repository = CreateRepository(provider); - var user = UserBuilder.Build(); + var user = UserBuilderInstance.Build(); // Act repository.Save(user); 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, LoggerFactory.CreateLogger(), Mock.Of(), Options.Create(GlobalSettings), Options.Create(new UserPasswordConfigurationSettings()), new JsonNetSerializer()); repository2.Delete(user); @@ -366,22 +368,22 @@ namespace Umbraco.Tests.Persistence.Repositories private User CreateAndCommitUserWithGroup(IUserRepository repository, IUserGroupRepository userGroupRepository) { - var user = UserBuilder.WithoutIdentity().Build(); + var user = UserBuilderInstance.WithoutIdentity().Build(); repository.Save(user); - var group = UserGroupBuilder.Build(); + var group = UserGroupBuilderInstance.Build(); userGroupRepository.AddOrUpdateGroupWithUsers(@group, new[] { user.Id }); - user.AddGroup(UserGroupBuilder.BuildReadOnly(group)); + user.AddGroup(UserGroupBuilderInstance.BuildReadOnly(group)); return user; } private IUser[] CreateAndCommitMultipleUsers(IUserRepository repository) { - var user1 = UserBuilder.WithoutIdentity().WithSuffix("1").Build(); - var user2 = UserBuilder.WithoutIdentity().WithSuffix("2").Build(); - var user3 = UserBuilder.WithoutIdentity().WithSuffix("3").Build(); + var user1 = UserBuilderInstance.WithoutIdentity().WithSuffix("1").Build(); + var user2 = UserBuilderInstance.WithoutIdentity().WithSuffix("2").Build(); + var user3 = UserBuilderInstance.WithoutIdentity().WithSuffix("3").Build(); repository.Save(user1); repository.Save(user2); repository.Save(user3); diff --git a/src/Umbraco.Tests.Integration/RuntimeTests.cs b/src/Umbraco.Tests.Integration/RuntimeTests.cs index bd7684fcae..87b1bdd198 100644 --- a/src/Umbraco.Tests.Integration/RuntimeTests.cs +++ b/src/Umbraco.Tests.Integration/RuntimeTests.cs @@ -1,22 +1,21 @@ -using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Smidge; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Runtime; +using Umbraco.Extensions; using Umbraco.Tests.Common; using Umbraco.Tests.Integration.Extensions; using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.Integration.Testing; -using Umbraco.Web.Common.AspNetCore; -using Umbraco.Extensions; namespace Umbraco.Tests.Integration { @@ -54,13 +53,16 @@ namespace Umbraco.Tests.Integration var testHelper = new TestHelper(); - // Create the core runtime - var coreRuntime = new CoreRuntime(testHelper.GetConfigs(), testHelper.GetUmbracoVersion(), - testHelper.IOHelper, testHelper.Logger, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker, - testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator, - testHelper.MainDom, testHelper.GetTypeFinder(), NoAppCache.Instance); + var globalSettings = new GlobalSettings(); + var connectionStrings = new ConnectionStrings(); - // boot it! + // Create the core runtime + var coreRuntime = new CoreRuntime(globalSettings, connectionStrings, testHelper.GetUmbracoVersion(), + testHelper.IOHelper, testHelper.ConsoleLoggerFactory, testHelper.Profiler, testHelper.UmbracoBootPermissionChecker, + testHelper.GetHostingEnvironment(), testHelper.GetBackOfficeInfo(), testHelper.DbProviderFactoryCreator, + testHelper.MainDom, testHelper.GetTypeFinder(), AppCaches.NoCache); + + // boot it! var factory = coreRuntime.Configure(umbracoContainer); Assert.IsTrue(coreRuntime.MainDom.IsMainDom); @@ -70,6 +72,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 ContentSettings(); + var coreDebugSettings = new CoreDebugSettings(); + var nuCacheSettings = new NuCacheSettings(); + var requestHandlerSettings = new RequestHandlerSettings(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); + var webRoutingSettings = new WebRoutingSettings(); + + 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)); + umbracoContainer.Register(typeof(ILogger<>), typeof(Logger<>), Lifetime.Singleton); coreRuntime.Start(); Assert.IsTrue(MyComponent.IsInit); @@ -88,7 +107,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 +120,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(), hostContext.Configuration,out _); }); var host = await hostBuilder.StartAsync(); @@ -128,7 +147,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 +160,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(),hostContext.Configuration, out _); }); var host = await hostBuilder.StartAsync(); @@ -187,9 +206,9 @@ namespace Umbraco.Tests.Integration public static bool IsInit { get; private set; } public static bool IsTerminated { get; private set; } - private readonly ILogger _logger; + private readonly ILogger _logger; - public MyComponent(ILogger logger) + public MyComponent(ILogger logger) { _logger = logger; } diff --git a/src/Umbraco.Tests.Integration/Services/AuditServiceTests.cs b/src/Umbraco.Tests.Integration/Services/AuditServiceTests.cs index 9a0ba54082..474229372c 100644 --- a/src/Umbraco.Tests.Integration/Services/AuditServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/AuditServiceTests.cs @@ -9,7 +9,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Services/CachedDataTypeServiceTests.cs similarity index 52% rename from src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/CachedDataTypeServiceTests.cs index ee08c16bdd..a5b89dc2cf 100644 --- a/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/CachedDataTypeServiceTests.cs @@ -2,9 +2,11 @@ using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering the DataTypeService with cache enabled @@ -12,8 +14,12 @@ namespace Umbraco.Tests.Services [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class CachedDataTypeServiceTests : TestWithSomeContentBase + public class CachedDataTypeServiceTests : UmbracoIntegrationTest { + private IDataTypeService DataTypeService => GetRequiredService(); + private ILocalizedTextService LocalizedTextService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + /// /// This tests validates that with the new scope changes that the underlying cache policies work - in this case it tests that the cache policy /// with Count verification works. @@ -21,15 +27,13 @@ namespace Umbraco.Tests.Services [Test] public void DataTypeService_Can_Get_All() { - var dataTypeService = ServiceContext.DataTypeService; - - IDataType dataType = new DataType(new LabelPropertyEditor(Logger, IOHelper, DataTypeService,LocalizedTextService, LocalizationService, ShortStringHelper)) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; - dataTypeService.Save(dataType); + IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper)) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; + DataTypeService.Save(dataType); //Get all the first time (no cache) - var all = dataTypeService.GetAll(); + var all = DataTypeService.GetAll(); //Get all a second time (with cache) - all = dataTypeService.GetAll(); + all = DataTypeService.GetAll(); Assert.Pass(); } diff --git a/src/Umbraco.Tests/Services/ConsentServiceTests.cs b/src/Umbraco.Tests.Integration/Services/ConsentServiceTests.cs similarity index 74% rename from src/Umbraco.Tests/Services/ConsentServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/ConsentServiceTests.cs index a27d6a164e..3cc8666099 100644 --- a/src/Umbraco.Tests/Services/ConsentServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/ConsentServiceTests.cs @@ -2,23 +2,24 @@ using System.Linq; using NUnit.Framework; using Umbraco.Core.Models; -using Umbraco.Tests.TestHelpers; +using Umbraco.Core.Services; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; namespace Umbraco.Tests.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class ConsentServiceTests : TestWithDatabaseBase + public class ConsentServiceTests : UmbracoIntegrationTest { + private IConsentService ConsentService => GetRequiredService(); + [Test] public void CanCrudConsent() { - var consentService = ServiceContext.ConsentService; - // can register - var consent = consentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Granted, "no comment"); + var consent = ConsentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Granted, "no comment"); Assert.AreNotEqual(0, consent.Id); Assert.IsTrue(consent.Current); @@ -32,16 +33,16 @@ namespace Umbraco.Tests.Services // can register more - consentService.RegisterConsent("user/1234", "app1", "do-something-else", ConsentState.Granted, "no comment"); - consentService.RegisterConsent("user/1236", "app1", "do-something", ConsentState.Granted, "no comment"); - consentService.RegisterConsent("user/1237", "app2", "do-something", ConsentState.Granted, "no comment"); + ConsentService.RegisterConsent("user/1234", "app1", "do-something-else", ConsentState.Granted, "no comment"); + ConsentService.RegisterConsent("user/1236", "app1", "do-something", ConsentState.Granted, "no comment"); + ConsentService.RegisterConsent("user/1237", "app2", "do-something", ConsentState.Granted, "no comment"); // can get by source - var consents = consentService.LookupConsent(source: "user/1235").ToArray(); + var consents = ConsentService.LookupConsent(source: "user/1235").ToArray(); Assert.IsEmpty(consents); - consents = consentService.LookupConsent(source: "user/1234").ToArray(); + consents = ConsentService.LookupConsent(source: "user/1234").ToArray(); Assert.AreEqual(2, consents.Length); Assert.IsTrue(consents.All(x => x.Source == "user/1234")); Assert.IsTrue(consents.Any(x => x.Action == "do-something")); @@ -49,23 +50,23 @@ namespace Umbraco.Tests.Services // can get by context - consents = consentService.LookupConsent(context: "app3").ToArray(); + consents = ConsentService.LookupConsent(context: "app3").ToArray(); Assert.IsEmpty(consents); - consents = consentService.LookupConsent(context: "app2").ToArray(); + consents = ConsentService.LookupConsent(context: "app2").ToArray(); Assert.AreEqual(1, consents.Length); - consents = consentService.LookupConsent(context: "app1").ToArray(); + consents = ConsentService.LookupConsent(context: "app1").ToArray(); Assert.AreEqual(3, consents.Length); Assert.IsTrue(consents.Any(x => x.Action == "do-something")); Assert.IsTrue(consents.Any(x => x.Action == "do-something-else")); // can get by action - consents = consentService.LookupConsent(action: "do-whatever").ToArray(); + consents = ConsentService.LookupConsent(action: "do-whatever").ToArray(); Assert.IsEmpty(consents); - consents = consentService.LookupConsent(context: "app1", action: "do-something").ToArray(); + consents = ConsentService.LookupConsent(context: "app1", action: "do-something").ToArray(); Assert.AreEqual(2, consents.Length); Assert.IsTrue(consents.All(x => x.Action == "do-something")); Assert.IsTrue(consents.Any(x => x.Source == "user/1234")); @@ -73,23 +74,23 @@ namespace Umbraco.Tests.Services // can revoke - consent = consentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Revoked, "no comment"); + consent = ConsentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Revoked, "no comment"); - consents = consentService.LookupConsent(source: "user/1234", context: "app1", action: "do-something").ToArray(); + consents = ConsentService.LookupConsent(source: "user/1234", context: "app1", action: "do-something").ToArray(); Assert.AreEqual(1, consents.Length); Assert.IsTrue(consents[0].Current); Assert.AreEqual(ConsentState.Revoked, consents[0].State); // can filter - consents = consentService.LookupConsent(context: "app1", action: "do-", actionStartsWith: true).ToArray(); + consents = ConsentService.LookupConsent(context: "app1", action: "do-", actionStartsWith: true).ToArray(); Assert.AreEqual(3, consents.Length); Assert.IsTrue(consents.All(x => x.Context == "app1")); Assert.IsTrue(consents.All(x => x.Action.StartsWith("do-"))); // can get history - consents = consentService.LookupConsent(source: "user/1234", context: "app1", action: "do-something", includeHistory: true).ToArray(); + consents = ConsentService.LookupConsent(source: "user/1234", context: "app1", action: "do-something", includeHistory: true).ToArray(); Assert.AreEqual(1, consents.Length); Assert.IsTrue(consents[0].Current); Assert.AreEqual(ConsentState.Revoked, consents[0].State); @@ -103,19 +104,17 @@ namespace Umbraco.Tests.Services // cannot be stupid Assert.Throws(() => - consentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Granted | ConsentState.Revoked, "no comment")); + ConsentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Granted | ConsentState.Revoked, "no comment")); } [Test] public void CanRegisterConsentWithoutComment() { - var consentService = ServiceContext.ConsentService; - // Attept to add consent without a comment - consentService.RegisterConsent("user/1234", "app1", "consentWithoutComment", ConsentState.Granted); + ConsentService.RegisterConsent("user/1234", "app1", "consentWithoutComment", ConsentState.Granted); // Attempt to retrieve the consent we just added without a comment - var consents = consentService.LookupConsent(source: "user/1234", action: "consentWithoutComment").ToArray(); + var consents = ConsentService.LookupConsent(source: "user/1234", action: "consentWithoutComment").ToArray(); // Confirm we got our expected consent record Assert.AreEqual(1, consents.Length); diff --git a/src/Umbraco.Tests/Integration/ContentEventsTests.cs b/src/Umbraco.Tests.Integration/Services/ContentEventsTests.cs similarity index 84% rename from src/Umbraco.Tests/Integration/ContentEventsTests.cs rename to src/Umbraco.Tests.Integration/Services/ContentEventsTests.cs index 575215c41f..913ed6dd00 100644 --- a/src/Umbraco.Tests/Integration/ContentEventsTests.cs +++ b/src/Umbraco.Tests.Integration/Services/ContentEventsTests.cs @@ -1,39 +1,41 @@ 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.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Core.Services; using Umbraco.Core.Sync; -using Umbraco.Tests.Services; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.Cache; -using static Umbraco.Tests.Cache.DistributedCache.DistributedCacheTests; -namespace Umbraco.Tests.Integration +namespace Umbraco.Tests.Services { [TestFixture] - [Category("Slow")] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class ContentEventsTests : TestWithSomeContentBase + public class ContentEventsTests : UmbracoIntegrationTestWithContent { + private CacheRefresherCollection CacheRefresherCollection => GetRequiredService(); + private IUmbracoContextFactory UmbracoContextFactory => GetRequiredService(); + private ILogger Logger => GetRequiredService>(); + private IContentService ContentService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + #region Setup // trace ContentRepository unit-of-work events (refresh, remove), and ContentCacheRefresher CacheUpdated event // - public override void SetUp() + [SetUp] + public void SetUp() { - base.SetUp(); - - _h1 = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of()); + _h1 = new DistributedCacheBinder(new DistributedCache(new LocalServerMessenger(), CacheRefresherCollection), UmbracoContextFactory, GetRequiredService>()); _h1.BindEvents(true); _events = new List(); @@ -43,38 +45,33 @@ namespace Umbraco.Tests.Integration DocumentRepository.ScopeVersionRemove += ContentRepositoryRemovedVersion; ContentCacheRefresher.CacheUpdated += ContentCacheUpdated; - // ensure there's a current context - GetUmbracoContext("http://www.example.com/", 0, null, true); - } - - protected override void Compose() - { - base.Compose(); - - Composition.Register(_ => new TestServerRegistrar()); // localhost-only - Composition.RegisterUnique(); - - Composition.WithCollectionBuilder() - .Add() - .Add() - .Add(); - } - - protected override void Initialize() - { - base.Initialize(); - // prepare content type - _contentType = MockedContentTypes.CreateSimpleContentType("whatever", "Whatever"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + _contentType = ContentTypeBuilder.CreateSimpleContentType("whatever", "Whatever", defaultTemplateId: template.Id); _contentType.Key = Guid.NewGuid(); - ServiceContext.FileService.SaveTemplate(_contentType.DefaultTemplate); - ServiceContext.ContentTypeService.Save(_contentType); + FileService.SaveTemplate(_contentType.DefaultTemplate); + ContentTypeService.Save(_contentType); } - public override void TearDown() - { - base.TearDown(); + // protected override void Compose() + // { + // base.Compose(); + // + // Composition.Register(_ => new TestServerRegistrar()); // localhost-only + // Composition.RegisterUnique(); + // + // Composition.WithCollectionBuilder() + // .Add() + // .Add() + // .Add(); + // } + + [TearDown] + public void TearDownTest() + { _h1?.UnbindEvents(); // clear ALL events @@ -94,63 +91,63 @@ namespace Umbraco.Tests.Integration { _events = new List(); _msgCount = 0; - Current.Logger.Debug("RESET EVENTS"); + Logger.LogDebug("RESET EVENTS"); } private IContent CreateContent(int parentId = -1) { - var content1 = MockedContent.CreateSimpleContent(_contentType, "Content1", parentId); - ServiceContext.ContentService.Save(content1); + var content1 = ContentBuilder.CreateSimpleContent(_contentType, "Content1", parentId); + ContentService.Save(content1); return content1; } private IContent CreateBranch() { - var content1 = MockedContent.CreateSimpleContent(_contentType, "Content1"); - ServiceContext.ContentService.SaveAndPublish(content1); + var content1 = ContentBuilder.CreateSimpleContent(_contentType, "Content1"); + ContentService.SaveAndPublish(content1); // 2 (published) // .1 (published) // .2 (not published) - var content2 = MockedContent.CreateSimpleContent(_contentType, "Content2", content1); - ServiceContext.ContentService.SaveAndPublish(content2); - var content21 = MockedContent.CreateSimpleContent(_contentType, "Content21", content2); - ServiceContext.ContentService.SaveAndPublish(content21); - var content22 = MockedContent.CreateSimpleContent(_contentType, "Content22", content2); - ServiceContext.ContentService.Save(content22); + var content2 = ContentBuilder.CreateSimpleContent(_contentType, "Content2", content1); + ContentService.SaveAndPublish(content2); + var content21 = ContentBuilder.CreateSimpleContent(_contentType, "Content21", content2); + ContentService.SaveAndPublish(content21); + var content22 = ContentBuilder.CreateSimpleContent(_contentType, "Content22", content2); + ContentService.Save(content22); // 3 (not published) // .1 (not published) // .2 (not published) - var content3 = MockedContent.CreateSimpleContent(_contentType, "Content3", content1); - ServiceContext.ContentService.Save(content3); - var content31 = MockedContent.CreateSimpleContent(_contentType, "Content31", content3); - ServiceContext.ContentService.Save(content31); - var content32 = MockedContent.CreateSimpleContent(_contentType, "Content32", content3); - ServiceContext.ContentService.Save(content32); + var content3 = ContentBuilder.CreateSimpleContent(_contentType, "Content3", content1); + ContentService.Save(content3); + var content31 = ContentBuilder.CreateSimpleContent(_contentType, "Content31", content3); + ContentService.Save(content31); + var content32 = ContentBuilder.CreateSimpleContent(_contentType, "Content32", content3); + ContentService.Save(content32); // 4 (published + saved) // .1 (published) // .2 (not published) - var content4 = MockedContent.CreateSimpleContent(_contentType, "Content4", content1); - ServiceContext.ContentService.SaveAndPublish(content4); + var content4 = ContentBuilder.CreateSimpleContent(_contentType, "Content4", content1); + ContentService.SaveAndPublish(content4); content4.Name = "Content4X"; - ServiceContext.ContentService.Save(content4); - var content41 = MockedContent.CreateSimpleContent(_contentType, "Content41", content4); - ServiceContext.ContentService.SaveAndPublish(content41); - var content42 = MockedContent.CreateSimpleContent(_contentType, "Content42", content4); - ServiceContext.ContentService.Save(content42); + ContentService.Save(content4); + var content41 = ContentBuilder.CreateSimpleContent(_contentType, "Content41", content4); + ContentService.SaveAndPublish(content41); + var content42 = ContentBuilder.CreateSimpleContent(_contentType, "Content42", content4); + ContentService.Save(content42); // 5 (not published) // .1 (published) // .2 (not published) - var content5 = MockedContent.CreateSimpleContent(_contentType, "Content5", content1); - ServiceContext.ContentService.SaveAndPublish(content5); - var content51 = MockedContent.CreateSimpleContent(_contentType, "Content51", content5); - ServiceContext.ContentService.SaveAndPublish(content51); - var content52 = MockedContent.CreateSimpleContent(_contentType, "Content52", content5); - ServiceContext.ContentService.Save(content52); - ServiceContext.ContentService.Unpublish(content5); + var content5 = ContentBuilder.CreateSimpleContent(_contentType, "Content5", content1); + ContentService.SaveAndPublish(content5); + var content51 = ContentBuilder.CreateSimpleContent(_contentType, "Content51", content5); + ContentService.SaveAndPublish(content51); + var content52 = ContentBuilder.CreateSimpleContent(_contentType, "Content52", content5); + ContentService.Save(content52); + ContentService.Unpublish(content5); return content1; } @@ -458,7 +455,7 @@ namespace Umbraco.Tests.Integration #region Utils private IEnumerable Children(IContent content) - => ServiceContext.ContentService.GetPagedChildren(content.Id, 0, int.MaxValue, out var total); + => ContentService.GetPagedChildren(content.Id, 0, int.MaxValue, out var total); #endregion @@ -471,12 +468,12 @@ namespace Umbraco.Tests.Integration // - repository : refresh u=u // - content cache : refresh newest - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); ResetEvents(); content.Name = "changed"; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -494,13 +491,13 @@ namespace Umbraco.Tests.Integration // - repository : refresh (u) // - content cache :: refresh newest - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); content.Name = "changed"; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -512,7 +509,7 @@ namespace Umbraco.Tests.Integration ResetEvents(); content.Name = "again"; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -530,13 +527,13 @@ namespace Umbraco.Tests.Integration // - repository : refresh (u) // - content cache :: refresh newest - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); content.SortOrder = 666; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -548,7 +545,7 @@ namespace Umbraco.Tests.Integration ResetEvents(); content.SortOrder = 667; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -566,13 +563,13 @@ namespace Umbraco.Tests.Integration // - repository : refresh (u) // - content cache :: refresh newest - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); content.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -584,7 +581,7 @@ namespace Umbraco.Tests.Integration ResetEvents(); content.Properties.First().SetValue("again"); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -602,12 +599,12 @@ namespace Umbraco.Tests.Integration // - repository : refresh (p) // - content cache :: refresh published, newest - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); ResetEvents(); content.Name = "changed"; - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -625,13 +622,13 @@ namespace Umbraco.Tests.Integration // - repository : refresh (p) // - content cache :: refresh published, newest - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); content.Name = "changed"; - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -652,12 +649,12 @@ namespace Umbraco.Tests.Integration // assume that the unpublished cache is also refreshed, with the same // values, and deal with it. - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); ResetEvents(); content.Name = "changed"; - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -675,12 +672,12 @@ namespace Umbraco.Tests.Integration // - repository : refresh (u) // - content cache :: refresh newest, remove published - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); - ServiceContext.ContentService.Unpublish(content); + ContentService.Unpublish(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -698,14 +695,14 @@ namespace Umbraco.Tests.Integration // - repository : refresh (u) // - content cache :: refresh newest, remove published - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); content.Name = "changed"; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); ResetEvents(); - ServiceContext.ContentService.Unpublish(content); + ContentService.Unpublish(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -714,7 +711,7 @@ namespace Umbraco.Tests.Integration Assert.AreEqual($"{m:000}: ContentRepository/Refresh/{content.Id}.p-u", _events[i++].ToString()); m++; //Assert.AreEqual(string.Format("{0:000}: ContentCacheRefresher/Refresh/{1}", m, content.Id), _events[i++].ToString()); - //Assert.AreEqual("changed", ServiceContext.ContentService.GetById(((ContentCacheRefresher.JsonPayload)_events[i - 1].EventArgs).Id).Name); + //Assert.AreEqual("changed", ContentService.GetById(((ContentCacheRefresher.JsonPayload)_events[i - 1].EventArgs).Id).Name); Assert.AreEqual($"{m:000}: ContentCacheRefresher/RefreshBranch/{content.Id}", _events[i].ToString()); } @@ -737,7 +734,7 @@ namespace Umbraco.Tests.Integration var content1 = CreateBranch(); ResetEvents(); - ServiceContext.ContentService.Unpublish(content1); + ContentService.Unpublish(content1); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -757,10 +754,10 @@ namespace Umbraco.Tests.Integration // - published page cache :: refresh root & descendants, database (level, sortOrder) order var content1 = CreateBranch(); - ServiceContext.ContentService.Unpublish(content1); + ContentService.Unpublish(content1); ResetEvents(); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -773,7 +770,7 @@ namespace Umbraco.Tests.Integration var content1C = content1.Children().ToArray(); Assert.AreEqual(string.Format("{0:000}: ContentCacheRefresher/RefreshPublished/{1}", m, content1C[0].Id), _events[i++].ToString()); // repub content1.content2 Assert.AreEqual(string.Format("{0:000}: ContentCacheRefresher/RefreshPublished/{1}", m, content1C[2].Id), _events[i++].ToString()); // repub content1.content4 - var c = ServiceContext.ContentService.GetPublishedVersion(((ContentCacheRefresher.JsonPayload)_events[i - 1].EventArgs).Id); + var c = ContentService.GetPublishedVersion(((ContentCacheRefresher.JsonPayload)_events[i - 1].EventArgs).Id); Assert.IsTrue(c.Published); // get the published one Assert.AreEqual("Content4", c.Name); // published has old name var content2C = content1C[0].Children().ToArray(); @@ -789,12 +786,12 @@ namespace Umbraco.Tests.Integration // rule? var content1 = CreateBranch(); - ServiceContext.ContentService.Unpublish(content1); + ContentService.Unpublish(content1); // branch is: ResetEvents(); - ServiceContext.ContentService.SaveAndPublishBranch(content1, force: false); // force = false, don't publish unpublished items + ContentService.SaveAndPublishBranch(content1, force: false); // force = false, don't publish unpublished items foreach (var e in _events) Console.WriteLine(e); @@ -825,10 +822,10 @@ namespace Umbraco.Tests.Integration // rule? var content1 = CreateBranch(); - ServiceContext.ContentService.Unpublish(content1); + ContentService.Unpublish(content1); ResetEvents(); - ServiceContext.ContentService.SaveAndPublishBranch(content1, force: true); // force = true, also publish unpublished items + ContentService.SaveAndPublishBranch(content1, force: true); // force = true, also publish unpublished items foreach (var e in _events) Console.WriteLine(e); @@ -875,7 +872,7 @@ namespace Umbraco.Tests.Integration var content1Csorted = new[] { content1C[3], content1C[0], content1C[1], content1C[2] }; ResetEvents(); - ServiceContext.ContentService.Sort(content1Csorted); + ContentService.Sort(content1Csorted); var content1Cagain = Children(content1).ToArray(); Assert.AreEqual(4, content1Cagain.Length); @@ -910,7 +907,7 @@ namespace Umbraco.Tests.Integration var content1Csorted = new[] { content1C[0], content1C[1], content1C[3], content1C[2] }; ResetEvents(); - ServiceContext.ContentService.Sort(content1Csorted); + ContentService.Sort(content1Csorted); var content1Cagain = Children(content1).ToArray(); Assert.AreEqual(4, content1Cagain.Length); @@ -945,7 +942,7 @@ namespace Umbraco.Tests.Integration Assert.IsNotNull(content); ResetEvents(); - ServiceContext.ContentService.MoveToRecycleBin(content); + ContentService.MoveToRecycleBin(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -962,10 +959,10 @@ namespace Umbraco.Tests.Integration var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.MoveToRecycleBin(content); + ContentService.MoveToRecycleBin(content); ResetEvents(); - ServiceContext.ContentService.Move(content, -1); + ContentService.Move(content, -1); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -984,10 +981,10 @@ namespace Umbraco.Tests.Integration var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); - ServiceContext.ContentService.MoveToRecycleBin(content); + ContentService.MoveToRecycleBin(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1007,11 +1004,11 @@ namespace Umbraco.Tests.Integration var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); - ServiceContext.ContentService.MoveToRecycleBin(content); + ContentService.SaveAndPublish(content); + ContentService.MoveToRecycleBin(content); ResetEvents(); - ServiceContext.ContentService.Move(content, -1); + ContentService.Move(content, -1); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1031,12 +1028,12 @@ namespace Umbraco.Tests.Integration var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); content.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); ResetEvents(); - ServiceContext.ContentService.MoveToRecycleBin(content); + ContentService.MoveToRecycleBin(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1054,7 +1051,7 @@ namespace Umbraco.Tests.Integration var content1 = CreateBranch(); ResetEvents(); - ServiceContext.ContentService.MoveToRecycleBin(content1); + ContentService.MoveToRecycleBin(content1); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -1087,15 +1084,15 @@ namespace Umbraco.Tests.Integration [Test] public void EmptyRecycleBinContent() { - ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.MoveToRecycleBin(content); + ContentService.MoveToRecycleBin(content); ResetEvents(); - ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1109,18 +1106,18 @@ namespace Umbraco.Tests.Integration [Test] public void EmptyRecycleBinContents() { - ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.MoveToRecycleBin(content1); + ContentService.MoveToRecycleBin(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.MoveToRecycleBin(content2); + ContentService.MoveToRecycleBin(content2); ResetEvents(); - ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); Assert.AreEqual(3, _msgCount); Assert.AreEqual(4, _events.Count); @@ -1136,12 +1133,12 @@ namespace Umbraco.Tests.Integration [Test] public void EmptyRecycleBinBranch() { - ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); var content1 = CreateBranch(); Assert.IsNotNull(content1); - ServiceContext.ContentService.MoveToRecycleBin(content1); + ContentService.MoveToRecycleBin(content1); ResetEvents(); @@ -1151,7 +1148,7 @@ namespace Umbraco.Tests.Integration var content4C = Children(content1C[2]).ToArray(); var content5C = Children(content1C[3]).ToArray(); - ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -1186,7 +1183,7 @@ namespace Umbraco.Tests.Integration Assert.IsNotNull(content); ResetEvents(); - ServiceContext.ContentService.Delete(content); + ContentService.Delete(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1202,10 +1199,10 @@ namespace Umbraco.Tests.Integration { var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); - ServiceContext.ContentService.Delete(content); + ContentService.Delete(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1221,12 +1218,12 @@ namespace Umbraco.Tests.Integration { var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); content.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); ResetEvents(); - ServiceContext.ContentService.Delete(content); + ContentService.Delete(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1242,14 +1239,14 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(content1.Id); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); - ServiceContext.ContentService.Unpublish(content1); + ContentService.SaveAndPublish(content2); + ContentService.Unpublish(content1); ResetEvents(); - ServiceContext.ContentService.Delete(content2); + ContentService.Delete(content2); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1274,7 +1271,7 @@ namespace Umbraco.Tests.Integration var content5C = Children(content1C[3]).ToArray(); ResetEvents(); - ServiceContext.ContentService.Delete(content1); + ContentService.Delete(content1); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -1310,7 +1307,7 @@ namespace Umbraco.Tests.Integration Assert.IsNotNull(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1326,12 +1323,12 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1347,14 +1344,14 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); content1.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content1); + ContentService.Save(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1372,10 +1369,10 @@ namespace Umbraco.Tests.Integration Assert.IsNotNull(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1393,14 +1390,14 @@ namespace Umbraco.Tests.Integration Assert.IsNotNull(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); var content3 = CreateContent(); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); - ServiceContext.ContentService.Unpublish(content2); + ContentService.SaveAndPublish(content3); + ContentService.Unpublish(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content3.Id); + ContentService.Move(content1, content3.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1416,13 +1413,13 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1438,17 +1435,17 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); var content3 = CreateContent(content2.Id); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); - ServiceContext.ContentService.Unpublish(content2); + ContentService.SaveAndPublish(content3); + ContentService.Unpublish(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content3.Id); + ContentService.Move(content1, content3.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1464,15 +1461,15 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); content1.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content1); + ContentService.Save(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1488,19 +1485,19 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); content1.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content1); + ContentService.Save(content1); var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); var content3 = CreateContent(content2.Id); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); - ServiceContext.ContentService.Unpublish(content2); + ContentService.SaveAndPublish(content3); + ContentService.Unpublish(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content3.Id); + ContentService.Move(content1, content3.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1516,17 +1513,17 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(content1.Id); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); - ServiceContext.ContentService.Unpublish(content1); + ContentService.SaveAndPublish(content2); + ContentService.Unpublish(content1); var content3 = CreateContent(); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); + ContentService.SaveAndPublish(content3); ResetEvents(); - ServiceContext.ContentService.Move(content2, content3.Id); + ContentService.Move(content2, content3.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1542,21 +1539,21 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(content1.Id); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); - ServiceContext.ContentService.Unpublish(content1); + ContentService.SaveAndPublish(content2); + ContentService.Unpublish(content1); var content3 = CreateContent(); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); + ContentService.SaveAndPublish(content3); var content4 = CreateContent(content3.Id); Assert.IsNotNull(content4); - ServiceContext.ContentService.SaveAndPublish(content4); - ServiceContext.ContentService.Unpublish(content3); + ContentService.SaveAndPublish(content4); + ContentService.Unpublish(content3); ResetEvents(); - ServiceContext.ContentService.Move(content2, content4.Id); + ContentService.Move(content2, content4.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1572,19 +1569,19 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(content1.Id); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); content2.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content2); - ServiceContext.ContentService.Unpublish(content1); + ContentService.Save(content2); + ContentService.Unpublish(content1); var content3 = CreateContent(); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); + ContentService.SaveAndPublish(content3); ResetEvents(); - ServiceContext.ContentService.Move(content2, content3.Id); + ContentService.Move(content2, content3.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1600,23 +1597,23 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(content1.Id); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); content2.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content2); - ServiceContext.ContentService.Unpublish(content1); + ContentService.Save(content2); + ContentService.Unpublish(content1); var content3 = CreateContent(); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); + ContentService.SaveAndPublish(content3); var content4 = CreateContent(content3.Id); Assert.IsNotNull(content4); - ServiceContext.ContentService.SaveAndPublish(content4); - ServiceContext.ContentService.Unpublish(content3); + ContentService.SaveAndPublish(content4); + ContentService.Unpublish(content3); ResetEvents(); - ServiceContext.ContentService.Move(content2, content4.Id); + ContentService.Move(content2, content4.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1632,16 +1629,16 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(content1.Id); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); - ServiceContext.ContentService.Unpublish(content1); + ContentService.SaveAndPublish(content2); + ContentService.Unpublish(content1); var content3 = CreateContent(); Assert.IsNotNull(content3); ResetEvents(); - ServiceContext.ContentService.Move(content2, content3.Id); + ContentService.Move(content2, content3.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1657,18 +1654,18 @@ namespace Umbraco.Tests.Integration { var content1 = CreateContent(); Assert.IsNotNull(content1); - ServiceContext.ContentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); var content2 = CreateContent(content1.Id); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); content2.Properties.First().SetValue("changed"); - ServiceContext.ContentService.Save(content2); - ServiceContext.ContentService.Unpublish(content1); + ContentService.Save(content2); + ContentService.Unpublish(content1); var content3 = CreateContent(); Assert.IsNotNull(content3); ResetEvents(); - ServiceContext.ContentService.Move(content2, content3.Id); + ContentService.Move(content2, content3.Id); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -1689,7 +1686,7 @@ namespace Umbraco.Tests.Integration Assert.IsNotNull(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -1739,10 +1736,10 @@ namespace Umbraco.Tests.Integration var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -1792,14 +1789,14 @@ namespace Umbraco.Tests.Integration var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); var content3 = CreateContent(content2.Id); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); - ServiceContext.ContentService.Unpublish(content2); + ContentService.SaveAndPublish(content3); + ContentService.Unpublish(content2); ResetEvents(); - ServiceContext.ContentService.Move(content1, content3.Id); + ContentService.Move(content1, content3.Id); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -1849,12 +1846,12 @@ namespace Umbraco.Tests.Integration var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); ResetEvents(); - ServiceContext.ContentService.Move(content1, -1); + ContentService.Move(content1, -1); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -1905,10 +1902,10 @@ namespace Umbraco.Tests.Integration var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.Move(content1, content2.Id); + ContentService.Move(content1, content2.Id); ResetEvents(); - ServiceContext.ContentService.Move(content1, -1); + ContentService.Move(content1, -1); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -1958,16 +1955,16 @@ namespace Umbraco.Tests.Integration var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); var content3 = CreateContent(content2.Id); Assert.IsNotNull(content3); - ServiceContext.ContentService.SaveAndPublish(content3); - ServiceContext.ContentService.Unpublish(content2); + ContentService.SaveAndPublish(content3); + ContentService.Unpublish(content2); - ServiceContext.ContentService.Move(content1, content3.Id); + ContentService.Move(content1, content3.Id); ResetEvents(); - ServiceContext.ContentService.Move(content1, -1); + ContentService.Move(content1, -1); Assert.AreEqual(14, _msgCount); Assert.AreEqual(14, _events.Count); @@ -2020,7 +2017,7 @@ namespace Umbraco.Tests.Integration Assert.IsNotNull(content); ResetEvents(); - var copy = ServiceContext.ContentService.Copy(content, Constants.System.Root, false); + var copy = ContentService.Copy(content, Constants.System.Root, false); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -2036,10 +2033,10 @@ namespace Umbraco.Tests.Integration { var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); - var copy = ServiceContext.ContentService.Copy(content, Constants.System.Root, false); + var copy = ContentService.Copy(content, Constants.System.Root, false); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -2055,13 +2052,13 @@ namespace Umbraco.Tests.Integration { var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); var content2 = CreateContent(); Assert.IsNotNull(content2); - ServiceContext.ContentService.Move(content, content2.Id); + ContentService.Move(content, content2.Id); ResetEvents(); - var copy = ServiceContext.ContentService.Copy(content, Constants.System.Root, false); + var copy = ContentService.Copy(content, Constants.System.Root, false); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -2077,10 +2074,10 @@ namespace Umbraco.Tests.Integration { var content = CreateBranch(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); ResetEvents(); - var copy = ServiceContext.ContentService.Copy(content, Constants.System.Root, false); + var copy = ContentService.Copy(content, Constants.System.Root, false); var copyC = Children(copy).ToArray(); var copy2C = Children(copyC[0]).ToArray(); @@ -2118,15 +2115,15 @@ namespace Umbraco.Tests.Integration { var content = CreateContent(); Assert.IsNotNull(content); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); var v1 = content.VersionId; content.Properties.First().SetValue("changed"); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); var v2 = content.VersionId; content.Properties.First().SetValue("again"); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); var v3 = content.VersionId; Console.WriteLine(v1); @@ -2134,8 +2131,8 @@ namespace Umbraco.Tests.Integration Console.WriteLine(v3); ResetEvents(); - content.CopyFrom(ServiceContext.ContentService.GetVersion(v2)); - ServiceContext.ContentService.Save(content); + content.CopyFrom(ContentService.GetVersion(v2)); + ContentService.Save(content); Assert.AreEqual(2, _msgCount); Assert.AreEqual(2, _events.Count); @@ -2152,18 +2149,18 @@ namespace Umbraco.Tests.Integration [Test] public void ContentRemembers() { - var content = ServiceContext.ContentService.GetRootContent().FirstOrDefault(); + var content = ContentService.GetRootContent().FirstOrDefault(); Assert.IsNotNull(content); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); Assert.IsFalse(content.IsPropertyDirty("Published")); Assert.IsFalse(content.WasPropertyDirty("Published")); - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); Assert.IsFalse(content.IsPropertyDirty("Published")); Assert.IsTrue(content.WasPropertyDirty("Published")); // has just been published - ServiceContext.ContentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); Assert.IsFalse(content.IsPropertyDirty("Published")); Assert.IsFalse(content.WasPropertyDirty("Published")); // was published already } @@ -2171,7 +2168,7 @@ namespace Umbraco.Tests.Integration [Test] public void HasInitialContent() { - Assert.AreEqual(4, ServiceContext.ContentService.Count()); + Assert.AreEqual(4, ContentService.Count()); } #endregion diff --git a/src/Umbraco.Tests/Services/ContentServiceEventTests.cs b/src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs similarity index 64% rename from src/Umbraco.Tests/Services/ContentServiceEventTests.cs rename to src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs index 26f6d37456..74e71351af 100644 --- a/src/Umbraco.Tests/Services/ContentServiceEventTests.cs +++ b/src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs @@ -1,27 +1,50 @@ 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.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true, Logger = UmbracoTestOptions.Logger.Console)] - public class ContentServiceEventTests : TestWithSomeContentBase + public class ContentServiceEventTests : UmbracoIntegrationTest { - public override void SetUp() + private IContentTypeService ContentTypeService => GetRequiredService(); + private ContentService ContentService => (ContentService)GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + + private GlobalSettings _globalSettings; + private IContentType _contentType; + + [SetUp] + public void SetupTest() { - base.SetUp(); ContentRepositoryBase.ThrowOnWarning = true; + _globalSettings = new GlobalSettings(); + // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. + Umbraco.Core.Services.Implement.ContentTypeService.ClearScopeEvents(); + CreateTestData(); + } + + private void CreateTestData() + { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); // else, FK violation on contentType! + + _contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(_contentType); } public override void TearDown() @@ -33,28 +56,20 @@ namespace Umbraco.Tests.Services [Test] public void Saving_Culture() { - var languageService = ServiceContext.LocalizationService; + LocalizationService.Save(new Language(_globalSettings, "fr-FR")); - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); - - var contentTypeService = ServiceContext.ContentTypeService; - - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentType.Variations = ContentVariation.Culture; - foreach (var propertyType in contentType.PropertyTypes) + _contentType.Variations = ContentVariation.Culture; + foreach (var propertyType in _contentType.PropertyTypes) propertyType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + ContentTypeService.Save(_contentType); - var contentService = ServiceContext.ContentService; - - IContent document = new Content("content", -1, contentType); + IContent document = new Content("content", -1, _contentType); document.SetCultureName("hello", "en-US"); document.SetCultureName("bonjour", "fr-FR"); - contentService.Save(document); + ContentService.Save(document); //re-get - dirty properties need resetting - document = contentService.GetById(document.Id); + document = ContentService.GetById(document.Id); // properties: title, bodyText, keywords, description document.SetValue("title", "title-en", "en-US"); @@ -83,7 +98,7 @@ namespace Umbraco.Tests.Services ContentService.Saved += OnSaved; try { - contentService.Save(document); + ContentService.Save(document); } finally { @@ -95,15 +110,7 @@ namespace Umbraco.Tests.Services [Test] public void Saving_Set_Value() { - var contentTypeService = ServiceContext.ContentTypeService; - - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentTypeService.Save(contentType); - - var contentService = ServiceContext.ContentService; - - IContent document = new Content("content", -1, contentType); + IContent document = new Content("content", -1, _contentType); void OnSaving(IContentService sender, ContentSavingEventArgs e) { @@ -131,44 +138,35 @@ namespace Umbraco.Tests.Services ContentService.Saved += OnSaved; try { - contentService.Save(document); + ContentService.Save(document); } finally { ContentService.Saving -= OnSaving; ContentService.Saved -= OnSaved; } - } [Test] public void Publishing_Culture() { - var languageService = ServiceContext.LocalizationService; + LocalizationService.Save(new Language(_globalSettings, "fr-FR")); - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); - - var contentTypeService = ServiceContext.ContentTypeService; - - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentType.Variations = ContentVariation.Culture; - foreach (var propertyType in contentType.PropertyTypes) + _contentType.Variations = ContentVariation.Culture; + foreach (var propertyType in _contentType.PropertyTypes) propertyType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + ContentTypeService.Save(_contentType); - var contentService = ServiceContext.ContentService; - - IContent document = new Content("content", -1, contentType); + IContent document = new Content("content", -1, _contentType); document.SetCultureName("hello", "en-US"); document.SetCultureName("bonjour", "fr-FR"); - contentService.Save(document); + ContentService.Save(document); Assert.IsFalse(document.IsCulturePublished("fr-FR")); Assert.IsFalse(document.IsCulturePublished("en-US")); //re-get - dirty properties need resetting - document = contentService.GetById(document.Id); + document = ContentService.GetById(document.Id); void OnPublishing(IContentService sender, ContentPublishingEventArgs e) { @@ -194,7 +192,7 @@ namespace Umbraco.Tests.Services ContentService.Published += OnPublished; try { - contentService.SaveAndPublish(document, "fr-FR"); + ContentService.SaveAndPublish(document, "fr-FR"); } finally { @@ -202,7 +200,7 @@ namespace Umbraco.Tests.Services ContentService.Published -= OnPublished; } - document = contentService.GetById(document.Id); + document = ContentService.GetById(document.Id); // ensure it works and does not throw Assert.IsTrue(document.IsCulturePublished("fr-FR")); @@ -212,15 +210,7 @@ namespace Umbraco.Tests.Services [Test] public void Publishing_Set_Value() { - var contentTypeService = ServiceContext.ContentTypeService; - - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentTypeService.Save(contentType); - - var contentService = ServiceContext.ContentService; - - IContent document = new Content("content", -1, contentType); + IContent document = new Content("content", -1, _contentType); void OnSaving(IContentService sender, ContentSavingEventArgs e) { @@ -237,21 +227,21 @@ namespace Umbraco.Tests.Services Assert.AreSame("title", document.GetValue("title")); - //we're only dealing with invariant here + // We're only dealing with invariant here. var propValue = saved.Properties["title"].Values.First(x => x.Culture == null && x.Segment == null); Assert.AreEqual("title", propValue.EditedValue); Assert.AreEqual("title", propValue.PublishedValue); } - //We are binding to Saving (not Publishing), because the Publishing event is really just used for cancelling, it should not be - //used for setting values and it won't actually work! This is because the Publishing event is raised AFTER the values on the model - //are published, but Saving is raised BEFORE. + // We are binding to Saving (not Publishing), because the Publishing event is really just used for cancelling, it should not be + // used for setting values and it won't actually work! This is because the Publishing event is raised AFTER the values on the model + // are published, but Saving is raised BEFORE. ContentService.Saving += OnSaving; ContentService.Saved += OnSaved; try { - contentService.SaveAndPublish(document); + ContentService.SaveAndPublish(document); } finally { @@ -263,25 +253,19 @@ namespace Umbraco.Tests.Services [Test] public void Publishing_Set_Mandatory_Value() { - var contentTypeService = ServiceContext.ContentTypeService; - - var contentType = MockedContentTypes.CreateTextPageContentType(); - var titleProperty = contentType.PropertyTypes.First(x => x.Alias == "title"); + var titleProperty = _contentType.PropertyTypes.First(x => x.Alias == "title"); titleProperty.Mandatory = true; // make this required! - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentTypeService.Save(contentType); + ContentTypeService.Save(_contentType); - var contentService = ServiceContext.ContentService; + IContent document = new Content("content", -1, _contentType); - IContent document = new Content("content", -1, contentType); - - var result = contentService.SaveAndPublish(document); + var result = ContentService.SaveAndPublish(document); Assert.IsFalse(result.Success); Assert.AreEqual("title", result.InvalidProperties.First().Alias); // when a service operation fails, the object is dirty and should not be re-used, // re-create it - document = new Content("content", -1, contentType); + document = new Content("content", -1, _contentType); void OnSaving(IContentService sender, ContentSavingEventArgs e) { @@ -292,13 +276,13 @@ namespace Umbraco.Tests.Services saved.SetValue("title", "title"); } - //We are binding to Saving (not Publishing), because the Publishing event is really just used for cancelling, it should not be - //used for setting values and it won't actually work! This is because the Publishing event is raised AFTER the values on the model - //are published, but Saving is raised BEFORE. + // We are binding to Saving (not Publishing), because the Publishing event is really just used for cancelling, it should not be + // used for setting values and it won't actually work! This is because the Publishing event is raised AFTER the values on the model + // are published, but Saving is raised BEFORE. ContentService.Saving += OnSaving; try { - result = contentService.SaveAndPublish(document); + result = ContentService.SaveAndPublish(document); Assert.IsTrue(result.Success); //will succeed now because we were able to specify the required value in the Saving event } finally @@ -310,22 +294,16 @@ namespace Umbraco.Tests.Services [Test] public void Unpublishing_Culture() { - var languageService = ServiceContext.LocalizationService; + LocalizationService.Save(new Language(_globalSettings, "fr-FR")); - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); - - var contentTypeService = ServiceContext.ContentTypeService; - - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentType.Variations = ContentVariation.Culture; - foreach (var propertyType in contentType.PropertyTypes) + _contentType.Variations = ContentVariation.Culture; + foreach (var propertyType in _contentType.PropertyTypes) propertyType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + ContentTypeService.Save(_contentType); - var contentService = (ContentService)ServiceContext.ContentService; + var contentService = (ContentService)ContentService; - IContent document = new Content("content", -1, contentType); + IContent document = new Content("content", -1, _contentType); document.SetCultureName("hello", "en-US"); document.SetCultureName("bonjour", "fr-FR"); contentService.SaveAndPublish(document); diff --git a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs b/src/Umbraco.Tests.Integration/Services/ContentServicePerformanceTest.cs similarity index 50% rename from src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs rename to src/Umbraco.Tests.Integration/Services/ContentServicePerformanceTest.cs index d5afde6477..273a24337a 100644 --- a/src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs +++ b/src/Umbraco.Tests.Integration/Services/ContentServicePerformanceTest.cs @@ -2,72 +2,51 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Moq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; +using Umbraco.Composing; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Scoping; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; -using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Services { - [TestFixture, NUnit.Framework.Ignore("fixme - ignored test")] + [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class ContentServicePerformanceTest : TestWithDatabaseBase + public class ContentServicePerformanceTest : UmbracoIntegrationTest { - public override void SetUp() + protected DocumentRepository DocumentRepository => (DocumentRepository)GetRequiredService(); + protected IFileService FileService => GetRequiredService(); + protected IContentTypeService ContentTypeService => GetRequiredService(); + protected IContentService ContentService => GetRequiredService(); + + protected IContentType ContentType { get; set; } + + [SetUp] + public void SetUpData() { - base.SetUp(); CreateTestData(); } - protected override void Compose() - { - base.Compose(); - Composition.Register(); - } - - private DocumentRepository CreateDocumentRepository(IScopeProvider provider) - { - var accessor = (IScopeAccessor)provider; - 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 ctRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); - var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); - var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); - var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, ctRepository, tRepository, tagRepo, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); - return repository; - } - [Test] public void Profiler() { - Assert.IsInstanceOf(Current.Profiler); + Assert.IsInstanceOf(GetRequiredService()); } private static IProfilingLogger GetTestProfilingLogger() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); + var profiler = new TestProfiler(); - return new ProfilingLogger(logger, profiler); + return new ProfilingLogger(new NullLogger(), profiler); } [Test] @@ -85,10 +64,13 @@ namespace Umbraco.Tests.Services // ... NOPE, made even more nice changes, it is now... // 4452ms !!!!!!! - var contentType1 = MockedContentTypes.CreateTextPageContentType("test1", "test1"); - var contentType2 = MockedContentTypes.CreateTextPageContentType("test2", "test2"); - var contentType3 = MockedContentTypes.CreateTextPageContentType("test3", "test3"); - ServiceContext.ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 }); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType1 = ContentTypeBuilder.CreateTextPageContentType("test1", "test1", defaultTemplateId: template.Id); + var contentType2 = ContentTypeBuilder.CreateTextPageContentType("test2", "test2", defaultTemplateId: template.Id); + var contentType3 = ContentTypeBuilder.CreateTextPageContentType("test3", "test3", defaultTemplateId: template.Id); + ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 }); contentType1.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy(() => contentType2.Id), 0, contentType2.Alias), @@ -104,17 +86,17 @@ namespace Umbraco.Tests.Services new ContentTypeSort(new Lazy(() => contentType1.Id), 0, contentType1.Alias), new ContentTypeSort(new Lazy(() => contentType2.Id), 1, contentType2.Alias) }; - ServiceContext.ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 }); + ContentTypeService.Save(new[] { contentType1, contentType2, contentType3 }); - var roots = MockedContent.CreateTextpageContent(contentType1, -1, 10); - ServiceContext.ContentService.Save(roots); + var roots = ContentBuilder.CreateTextpageContent(contentType1, -1, 10); + ContentService.Save(roots); foreach (var root in roots) { - var item1 = MockedContent.CreateTextpageContent(contentType1, root.Id, 10); - var item2 = MockedContent.CreateTextpageContent(contentType2, root.Id, 10); - var item3 = MockedContent.CreateTextpageContent(contentType3, root.Id, 10); + var item1 = ContentBuilder.CreateTextpageContent(contentType1, root.Id, 10); + var item2 = ContentBuilder.CreateTextpageContent(contentType2, root.Id, 10); + var item3 = ContentBuilder.CreateTextpageContent(contentType3, root.Id, 10); - ServiceContext.ContentService.Save(item1.Concat(item2).Concat(item3)); + ContentService.Save(item1.Concat(item2).Concat(item3)); } var total = new List(); @@ -122,13 +104,13 @@ namespace Umbraco.Tests.Services using (GetTestProfilingLogger().TraceDuration("Getting all content in site")) { TestProfiler.Enable(); - total.AddRange(ServiceContext.ContentService.GetRootContent()); + total.AddRange(ContentService.GetRootContent()); foreach (var content in total.ToArray()) { - total.AddRange(ServiceContext.ContentService.GetPagedDescendants(content.Id, 0, int.MaxValue, out var _)); + total.AddRange(ContentService.GetPagedDescendants(content.Id, 0, int.MaxValue, out var _)); } TestProfiler.Disable(); - Current.Logger.Info("Returned {Total} items", total.Count); + Current.Logger.LogInformation("Returned {Total} items", total.Count); } } @@ -136,12 +118,12 @@ namespace Umbraco.Tests.Services public void Creating_100_Items() { // Arrange - var contentType = ServiceContext.ContentTypeService.Get(NodeDto.NodeIdSeed); - var pages = MockedContent.CreateTextpageContent(contentType, -1, 100); + var contentType = ContentTypeService.Get(ContentType.Id); + var pages = ContentBuilder.CreateTextpageContent(contentType, -1, 100); // Act Stopwatch watch = Stopwatch.StartNew(); - ServiceContext.ContentService.Save(pages, 0); + ContentService.Save(pages, 0); watch.Stop(); var elapsed = watch.ElapsedMilliseconds; @@ -155,12 +137,12 @@ namespace Umbraco.Tests.Services public void Creating_1000_Items() { // Arrange - var contentType = ServiceContext.ContentTypeService.Get(NodeDto.NodeIdSeed); - var pages = MockedContent.CreateTextpageContent(contentType, -1, 1000); + var contentType = ContentTypeService.Get(ContentType.Id); + var pages = ContentBuilder.CreateTextpageContent(contentType, -1, 1000); // Act Stopwatch watch = Stopwatch.StartNew(); - ServiceContext.ContentService.Save(pages, 0); + ContentService.Save(pages, 0); watch.Stop(); var elapsed = watch.ElapsedMilliseconds; @@ -174,14 +156,14 @@ namespace Umbraco.Tests.Services public void Getting_100_Uncached_Items() { // Arrange - var contentType = ServiceContext.ContentTypeService.Get(NodeDto.NodeIdSeed); - var pages = MockedContent.CreateTextpageContent(contentType, -1, 100); - ServiceContext.ContentService.Save(pages, 0); + var contentType = ContentTypeService.Get(ContentType.Id); + var pages = ContentBuilder.CreateTextpageContent(contentType, -1, 100); + ContentService.Save(pages, 0); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = ScopeProvider; using (var scope = provider.CreateScope()) { - var repository = CreateDocumentRepository(provider); + var repository = DocumentRepository; // Act Stopwatch watch = Stopwatch.StartNew(); @@ -199,18 +181,17 @@ namespace Umbraco.Tests.Services } - [Test, NUnit.Framework.Ignore("fixme - ignored test")] + [Test] public void Getting_1000_Uncached_Items() { // Arrange - var contentType = ServiceContext.ContentTypeService.Get(NodeDto.NodeIdSeed); - var pages = MockedContent.CreateTextpageContent(contentType, -1, 1000); - ServiceContext.ContentService.Save(pages, 0); + var contentType = ContentTypeService.Get(ContentType.Id); + var pages = ContentBuilder.CreateTextpageContent(contentType, -1, 1000); + ContentService.Save(pages, 0); - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateDocumentRepository(provider); + var repository = DocumentRepository; // Act Stopwatch watch = Stopwatch.StartNew(); @@ -230,14 +211,13 @@ namespace Umbraco.Tests.Services public void Getting_100_Cached_Items() { // Arrange - var contentType = ServiceContext.ContentTypeService.Get(NodeDto.NodeIdSeed); - var pages = MockedContent.CreateTextpageContent(contentType, -1, 100); - ServiceContext.ContentService.Save(pages, 0); + var contentType = ContentTypeService.Get(ContentType.Id); + var pages = ContentBuilder.CreateTextpageContent(contentType, -1, 100); + ContentService.Save(pages, 0); - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateDocumentRepository(provider); + var repository = DocumentRepository; // Act var contents = repository.GetMany(); @@ -256,18 +236,17 @@ namespace Umbraco.Tests.Services } } - [Test, NUnit.Framework.Ignore("fixme - ignored test")] + [Test] public void Getting_1000_Cached_Items() { // Arrange - var contentType = ServiceContext.ContentTypeService.Get(NodeDto.NodeIdSeed); - var pages = MockedContent.CreateTextpageContent(contentType, -1, 1000); - ServiceContext.ContentService.Save(pages, 0); + var contentType = ContentTypeService.Get(ContentType.Id); + var pages = ContentBuilder.CreateTextpageContent(contentType, -1, 1000); + ContentService.Save(pages, 0); - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateDocumentRepository(provider); + var repository = DocumentRepository; // Act var contents = repository.GetMany(); @@ -294,9 +273,13 @@ namespace Umbraco.Tests.Services public void CreateTestData() { - //Create and Save ContentType "textpage" -> NodeDto.NodeIdSeed - ContentType contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.ContentTypeService.Save(contentType); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + //Create and Save ContentType "textpage" -> ContentType.Id + ContentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(ContentType); } } } diff --git a/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs b/src/Umbraco.Tests.Integration/Services/ContentServicePublishBranchTests.cs similarity index 82% rename from src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs rename to src/Umbraco.Tests.Integration/Services/ContentServicePublishBranchTests.cs index d856f3bd82..54103af6f1 100644 --- a/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs +++ b/src/Umbraco.Tests.Integration/Services/ContentServicePublishBranchTests.cs @@ -3,19 +3,24 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; // ReSharper disable CommentTypo // ReSharper disable StringLiteralTypo -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] - public class ContentServicePublishBranchTests : TestWithDatabaseBase + public class ContentServicePublishBranchTests : UmbracoIntegrationTest { + private IContentService ContentService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + [TestCase(1)] // use overload w/ culture: "*" [TestCase(2)] // use overload w/ cultures: new [] { "*" } public void Can_Publish_Invariant_Branch(int method) @@ -24,13 +29,13 @@ namespace Umbraco.Tests.Services IContent iRoot = new Content("iroot", -1, iContentType); iRoot.SetValue("ip", "iroot"); - ServiceContext.ContentService.Save(iRoot); + ContentService.Save(iRoot); IContent ii1 = new Content("ii1", iRoot, iContentType); ii1.SetValue("ip", "vii1"); - ServiceContext.ContentService.Save(ii1); + ContentService.Save(ii1); IContent ii2 = new Content("ii2", iRoot, iContentType); ii2.SetValue("ip", "vii2"); - ServiceContext.ContentService.Save(ii2); + ContentService.Save(ii2); // iroot !published !edited // ii1 !published !edited @@ -49,24 +54,24 @@ namespace Umbraco.Tests.Services // prepare - ServiceContext.ContentService.SaveAndPublish(iRoot); - ServiceContext.ContentService.SaveAndPublish(ii1); + ContentService.SaveAndPublish(iRoot); + ContentService.SaveAndPublish(ii1); IContent ii11 = new Content("ii11", ii1, iContentType); ii11.SetValue("ip", "vii11"); - ServiceContext.ContentService.SaveAndPublish(ii11); + ContentService.SaveAndPublish(ii11); IContent ii12 = new Content("ii12", ii1, iContentType); ii11.SetValue("ip", "vii12"); - ServiceContext.ContentService.Save(ii12); + ContentService.Save(ii12); - ServiceContext.ContentService.SaveAndPublish(ii2); + ContentService.SaveAndPublish(ii2); IContent ii21 = new Content("ii21", ii2, iContentType); ii21.SetValue("ip", "vii21"); - ServiceContext.ContentService.SaveAndPublish(ii21); + ContentService.SaveAndPublish(ii21); IContent ii22 = new Content("ii22", ii2, iContentType); ii22.SetValue("ip", "vii22"); - ServiceContext.ContentService.Save(ii22); - ServiceContext.ContentService.Unpublish(ii2); + ContentService.Save(ii22); + ContentService.Unpublish(ii2); // iroot published !edited // ii1 published !edited @@ -92,9 +97,9 @@ namespace Umbraco.Tests.Services // prepare iRoot.SetValue("ip", "changed"); - ServiceContext.ContentService.Save(iRoot); + ContentService.Save(iRoot); ii11.SetValue("ip", "changed"); - ServiceContext.ContentService.Save(ii11); + ContentService.Save(ii11); // iroot published edited *** // ii1 published !edited @@ -131,7 +136,7 @@ namespace Umbraco.Tests.Services PublishResultType.SuccessPublishAlready, // was masked PublishResultType.SuccessPublish); - ii21 = ServiceContext.ContentService.GetById(ii21.Id); + ii21 = ContentService.GetById(ii21.Id); Assert.IsTrue(ii21.Published); } @@ -149,7 +154,7 @@ namespace Umbraco.Tests.Services vRoot.SetValue("vp", "vroot.de", "de"); vRoot.SetValue("vp", "vroot.ru", "ru"); vRoot.SetValue("vp", "vroot.es", "es"); - ServiceContext.ContentService.SaveAndPublish(vRoot); + ContentService.SaveAndPublish(vRoot); //create/publish child IContent iv1 = new Content("iv1", vRoot, vContentType, "de"); @@ -160,13 +165,13 @@ namespace Umbraco.Tests.Services iv1.SetValue("vp", "iv1.de", "de"); iv1.SetValue("vp", "iv1.ru", "ru"); iv1.SetValue("vp", "iv1.es", "es"); - ServiceContext.ContentService.SaveAndPublish(iv1); + ContentService.SaveAndPublish(iv1); //update the child iv1.SetValue("vp", "UPDATED-iv1.de", "de"); - ServiceContext.ContentService.Save(iv1); + ContentService.Save(iv1); - var r = ServiceContext.ContentService.SaveAndPublishBranch(vRoot, false).ToArray(); //no culture specified so "*" is used, so all cultures + var r = ContentService.SaveAndPublishBranch(vRoot, false).ToArray(); //no culture specified so "*" is used, so all cultures Assert.AreEqual(PublishResultType.SuccessPublishAlready, r[0].Result); Assert.AreEqual(PublishResultType.SuccessPublishCulture, r[1].Result); } @@ -185,7 +190,7 @@ namespace Umbraco.Tests.Services vRoot.SetValue("vp", "vroot.de", "de"); vRoot.SetValue("vp", "vroot.ru", "ru"); vRoot.SetValue("vp", "vroot.es", "es"); - ServiceContext.ContentService.SaveAndPublish(vRoot); + ContentService.SaveAndPublish(vRoot); //create/publish child IContent iv1 = new Content("iv1", vRoot, vContentType, "de"); @@ -196,13 +201,13 @@ namespace Umbraco.Tests.Services iv1.SetValue("vp", "iv1.de", "de"); iv1.SetValue("vp", "iv1.ru", "ru"); iv1.SetValue("vp", "iv1.es", "es"); - ServiceContext.ContentService.SaveAndPublish(iv1); + ContentService.SaveAndPublish(iv1); //update the child iv1.SetValue("vp", "UPDATED-iv1.de", "de"); - var saveResult = ServiceContext.ContentService.Save(iv1); + var saveResult = ContentService.Save(iv1); - var r = ServiceContext.ContentService.SaveAndPublishBranch(vRoot, false, "de").ToArray(); + var r = ContentService.SaveAndPublishBranch(vRoot, false, "de").ToArray(); Assert.AreEqual(PublishResultType.SuccessPublishAlready, r[0].Result); Assert.AreEqual(PublishResultType.SuccessPublishCulture, r[1].Result); } @@ -220,7 +225,7 @@ namespace Umbraco.Tests.Services vRoot.SetValue("vp", "vroot.de", "de"); vRoot.SetValue("vp", "vroot.ru", "ru"); vRoot.SetValue("vp", "vroot.es", "es"); - ServiceContext.ContentService.Save(vRoot); + ContentService.Save(vRoot); IContent iv1 = new Content("iv1", vRoot, vContentType, "de"); iv1.SetCultureName("iv1.de", "de"); @@ -230,7 +235,7 @@ namespace Umbraco.Tests.Services iv1.SetValue("vp", "iv1.de", "de"); iv1.SetValue("vp", "iv1.ru", "ru"); iv1.SetValue("vp", "iv1.es", "es"); - ServiceContext.ContentService.Save(iv1); + ContentService.Save(iv1); IContent iv2 = new Content("iv2", vRoot, vContentType, "de"); iv2.SetCultureName("iv2.de", "de"); @@ -240,7 +245,7 @@ namespace Umbraco.Tests.Services iv2.SetValue("vp", "iv2.de", "de"); iv2.SetValue("vp", "iv2.ru", "ru"); iv2.SetValue("vp", "iv2.es", "es"); - ServiceContext.ContentService.Save(iv2); + ContentService.Save(iv2); // vroot !published !edited // iv1 !published !edited @@ -249,7 +254,7 @@ namespace Umbraco.Tests.Services // !force = publishes those that are actually published, and have changes // here: nothing - var r = ServiceContext.ContentService.SaveAndPublishBranch(vRoot, false).ToArray(); // no culture specified = all cultures + var r = ContentService.SaveAndPublishBranch(vRoot, false).ToArray(); // no culture specified = all cultures // not forcing, iv1 and iv2 not published yet: only root got published AssertPublishResults(r, x => x.Content.Name, @@ -262,15 +267,15 @@ namespace Umbraco.Tests.Services vRoot.SetValue("vp", "changed.de", "de"); vRoot.SetValue("vp", "changed.ru", "ru"); vRoot.SetValue("vp", "changed.es", "es"); - ServiceContext.ContentService.Save(vRoot); // now root has drafts in all cultures + ContentService.Save(vRoot); // now root has drafts in all cultures - ServiceContext.ContentService.SaveAndPublish(iv1, new []{"de", "ru"}); // now iv1 de and ru are published + ContentService.SaveAndPublish(iv1, new []{"de", "ru"}); // now iv1 de and ru are published iv1.SetValue("ip", "changed"); iv1.SetValue("vp", "changed.de", "de"); iv1.SetValue("vp", "changed.ru", "ru"); iv1.SetValue("vp", "changed.es", "es"); - ServiceContext.ContentService.Save(iv1); // now iv1 has drafts in all cultures + ContentService.Save(iv1); // now iv1 has drafts in all cultures // validate - everything published for root, because no culture was specified = all Assert.IsTrue(vRoot.Published); @@ -284,7 +289,7 @@ namespace Umbraco.Tests.Services Assert.IsTrue(iv1.IsCulturePublished("ru")); Assert.IsFalse(iv1.IsCulturePublished("es")); - r = ServiceContext.ContentService.SaveAndPublishBranch(vRoot, false, "de").ToArray(); + r = ContentService.SaveAndPublishBranch(vRoot, false, "de").ToArray(); // not forcing, iv2 not published yet: only root and iv1 got published AssertPublishResults(r, x => x.Content.Name, @@ -330,21 +335,21 @@ namespace Umbraco.Tests.Services // invariant root -> invariant -> variant iRoot = new Content("iroot", -1, iContentType); iRoot.SetValue("ip", "iroot"); - ServiceContext.ContentService.SaveAndPublish(iRoot); + ContentService.SaveAndPublish(iRoot); ii1 = new Content("ii1", iRoot, iContentType); ii1.SetValue("ip", "vii1"); - ServiceContext.ContentService.SaveAndPublish(ii1); + ContentService.SaveAndPublish(ii1); ii1.SetValue("ip", "changed"); - ServiceContext.ContentService.Save(ii1); + ContentService.Save(ii1); iv11 = new Content("iv11.de", ii1, vContentType, "de"); iv11.SetValue("ip", "iv11"); iv11.SetValue("vp", "iv11.de", "de"); iv11.SetValue("vp", "iv11.ru", "ru"); iv11.SetValue("vp", "iv11.es", "es"); - ServiceContext.ContentService.Save(iv11); + ContentService.Save(iv11); iv11.SetCultureName("iv11.ru", "ru"); - var xxx = ServiceContext.ContentService.SaveAndPublish(iv11, new []{"de", "ru"}); + var xxx = ContentService.SaveAndPublish(iv11, new []{"de", "ru"}); Assert.AreEqual("iv11.de", iv11.GetValue("vp", "de", published: true)); Assert.AreEqual("iv11.ru", iv11.GetValue("vp", "ru", published: true)); @@ -352,7 +357,7 @@ namespace Umbraco.Tests.Services iv11.SetValue("ip", "changed"); iv11.SetValue("vp", "changed.de", "de"); iv11.SetValue("vp", "changed.ru", "ru"); - ServiceContext.ContentService.Save(iv11); + ContentService.Save(iv11); } [Test] @@ -360,7 +365,7 @@ namespace Umbraco.Tests.Services { Can_Publish_Mixed_Branch(out var iRoot, out var ii1, out var iv11); - var r = ServiceContext.ContentService.SaveAndPublishBranch(iRoot, false, "de").ToArray(); + var r = ContentService.SaveAndPublishBranch(iRoot, false, "de").ToArray(); AssertPublishResults(r, x => x.Content.Name, "iroot", "ii1", "iv11.de"); AssertPublishResults(r, x => x.Result, @@ -386,7 +391,7 @@ namespace Umbraco.Tests.Services { Can_Publish_Mixed_Branch(out var iRoot, out var ii1, out var iv11); - var r = ServiceContext.ContentService.SaveAndPublishBranch(iRoot, false, new[] { "de", "ru" }).ToArray(); + var r = ContentService.SaveAndPublishBranch(iRoot, false, new[] { "de", "ru" }).ToArray(); AssertPublishResults(r, x => x.Content.Name, "iroot", "ii1", "iv11.de"); AssertPublishResults(r, x => x.Result, @@ -421,16 +426,18 @@ namespace Umbraco.Tests.Services } private void Reload(ref IContent document) - => document = ServiceContext.ContentService.GetById(document.Id); + => document = ContentService.GetById(document.Id); private void CreateTypes(out IContentType iContentType, out IContentType vContentType) { - var langDe = new Language(TestObjects.GetGlobalSettings(), "de") { IsDefault = true }; - ServiceContext.LocalizationService.Save(langDe); - var langRu = new Language(TestObjects.GetGlobalSettings(), "ru"); - ServiceContext.LocalizationService.Save(langRu); - var langEs = new Language(TestObjects.GetGlobalSettings(), "es"); - ServiceContext.LocalizationService.Save(langEs); + var globalSettings = new GlobalSettings(); + + var langDe = new Language(globalSettings, "de") { IsDefault = true }; + LocalizationService.Save(langDe); + var langRu = new Language(globalSettings, "ru"); + LocalizationService.Save(langRu); + var langEs = new Language(globalSettings, "es"); + LocalizationService.Save(langEs); iContentType = new ContentType(ShortStringHelper, -1) { @@ -439,7 +446,7 @@ namespace Umbraco.Tests.Services Variations = ContentVariation.Nothing }; iContentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Nvarchar, "ip") { Variations = ContentVariation.Nothing }); - ServiceContext.ContentTypeService.Save(iContentType); + ContentTypeService.Save(iContentType); vContentType = new ContentType(ShortStringHelper, -1) { @@ -449,7 +456,7 @@ namespace Umbraco.Tests.Services }; vContentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Nvarchar, "ip") { Variations = ContentVariation.Nothing }); vContentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Nvarchar, "vp") { Variations = ContentVariation.Culture }); - ServiceContext.ContentTypeService.Save(vContentType); + ContentTypeService.Save(vContentType); } private IEnumerable SaveAndPublishInvariantBranch(IContent content, bool force, int method) @@ -459,9 +466,9 @@ namespace Umbraco.Tests.Services switch (method) { case 1: - return ServiceContext.ContentService.SaveAndPublishBranch(content, force, culture: "*"); + return ContentService.SaveAndPublishBranch(content, force, culture: "*"); case 2: - return ServiceContext.ContentService.SaveAndPublishBranch(content, force, cultures: new [] { "*" }); + return ContentService.SaveAndPublishBranch(content, force, cultures: new [] { "*" }); default: throw new ArgumentOutOfRangeException(nameof(method)); } diff --git a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests.Integration/Services/ContentServiceTagsTests.cs similarity index 52% rename from src/Umbraco.Tests/Services/ContentServiceTagsTests.cs rename to src/Umbraco.Tests.Integration/Services/ContentServiceTagsTests.cs index 5e2c3823af..3cf02f6b10 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests.Integration/Services/ContentServiceTagsTests.cs @@ -1,29 +1,36 @@ using System; using System.Linq; -using Umbraco.Core.Composing; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true, Logger = UmbracoTestOptions.Logger.Console)] - public class ContentServiceTagsTests : TestWithSomeContentBase + public class ContentServiceTagsTests : UmbracoIntegrationTest { - public PropertyEditorCollection PropertyEditorCollection => Factory.GetInstance(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private ITagService TagService => GetRequiredService(); + private IDataTypeService DataTypeService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + public PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); - public override void SetUp() + public override void Setup() { - base.SetUp(); + base.Setup(); ContentRepositoryBase.ThrowOnWarning = true; } @@ -33,41 +40,29 @@ namespace Umbraco.Tests.Services base.TearDown(); } - protected override void Compose() - { - base.Compose(); - - // FIXME: do it differently - Composition.Register(factory => factory.GetInstance().TextService); - } - [Test] public void TagsCanBeInvariant() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + + IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - content1 = contentService.GetById(content1.Id); + content1 = ContentService.GetById(content1.Id); var enTags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService).ToArray(); Assert.AreEqual(4, enTags.Length); Assert.Contains("one", enTags); Assert.AreEqual(-1, enTags.IndexOf("plus")); - var tagGroups = tagService.GetAllTags().GroupBy(x => x.LanguageId); - foreach (var tag in tagService.GetAllTags()) + var tagGroups = TagService.GetAllTags().GroupBy(x => x.LanguageId); + foreach (var tag in TagService.GetAllTags()) Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); Assert.AreEqual(1, tagGroups.Count()); var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == null); @@ -80,30 +75,27 @@ namespace Umbraco.Tests.Services [Test] public void TagsCanBeVariant() { - var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + var languageService = LocalizationService; + var language = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); + LocalizationService.Save(language); // en-US is already there - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041, - Variations = ContentVariation.Culture - }); - contentType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); + ContentTypeService.Save(contentType); + + IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - content1 = contentService.GetById(content1.Id); + content1 = ContentService.GetById(content1.Id); var frTags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "fr-FR").ToArray(); Assert.AreEqual(5, frTags.Length); @@ -115,8 +107,8 @@ namespace Umbraco.Tests.Services Assert.Contains("one", enTags); Assert.AreEqual(-1, enTags.IndexOf("plus")); - var tagGroups = tagService.GetAllTags(culture:"*").GroupBy(x => x.LanguageId); - foreach (var tag in tagService.GetAllTags()) + var tagGroups = TagService.GetAllTags(culture:"*").GroupBy(x => x.LanguageId); + foreach (var tag in TagService.GetAllTags()) Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); Assert.AreEqual(2, tagGroups.Count()); var frTagGroup = tagGroups.FirstOrDefault(x => x.Key == 2); @@ -134,37 +126,32 @@ namespace Umbraco.Tests.Services [Test] public void TagsCanBecomeVariant() { - var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + var enId = LocalizationService.GetLanguageIdByIsoCode("en-US").Value; - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - PropertyType propertyType; - contentType.PropertyGroups.First().PropertyTypes.Add( - propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var propertyType = CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + + IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); contentType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); // no changes - content1 = contentService.GetById(content1.Id); + content1 = ContentService.GetById(content1.Id); var tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService).ToArray(); Assert.AreEqual(4, tags.Length); Assert.Contains("one", tags); Assert.AreEqual(-1, tags.IndexOf("plus")); - var tagGroups = tagService.GetAllTags().GroupBy(x => x.LanguageId); - foreach (var tag in tagService.GetAllTags()) + var tagGroups = TagService.GetAllTags().GroupBy(x => x.LanguageId); + foreach (var tag in TagService.GetAllTags()) Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); Assert.AreEqual(1, tagGroups.Count()); var enTagGroup = tagGroups.FirstOrDefault(x => x.Key == null); @@ -174,10 +161,10 @@ namespace Umbraco.Tests.Services Assert.IsFalse(enTagGroup.Any(x => x.Text == "plus")); propertyType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); // changes - content1 = contentService.GetById(content1.Id); + content1 = ContentService.GetById(content1.Id); // property value has been moved from invariant to en-US tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService).ToArray(); @@ -189,8 +176,8 @@ namespace Umbraco.Tests.Services Assert.AreEqual(-1, tags.IndexOf("plus")); // tags have been copied from invariant to en-US - tagGroups = tagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); - foreach (var tag in tagService.GetAllTags("*")) + tagGroups = TagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); + foreach (var tag in TagService.GetAllTags("*")) Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); Assert.AreEqual(1, tagGroups.Count()); @@ -204,37 +191,32 @@ namespace Umbraco.Tests.Services [Test] public void TagsCanBecomeInvariant() { - var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + var language = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); + LocalizationService.Save(language); // en-US is already there - var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + var enId = LocalizationService.GetLanguageIdByIsoCode("en-US").Value; - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - PropertyType propertyType; - contentType.PropertyGroups.First().PropertyTypes.Add( - propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041, - Variations = ContentVariation.Culture - }); - contentType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); + ContentTypeService.Save(contentType); + + IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); contentType.Variations = ContentVariation.Nothing; - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); // changes - content1 = contentService.GetById(content1.Id); + content1 = ContentService.GetById(content1.Id); // property value has been moved from en-US to invariant, fr-FR tags are gone Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "fr-FR")); @@ -246,8 +228,8 @@ namespace Umbraco.Tests.Services Assert.AreEqual(-1, tags.IndexOf("plus")); // tags have been copied from en-US to invariant, fr-FR tags are gone - var tagGroups = tagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); - foreach (var tag in tagService.GetAllTags("*")) + var tagGroups = TagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); + foreach (var tag in TagService.GetAllTags("*")) Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); Assert.AreEqual(1, tagGroups.Count()); @@ -261,38 +243,33 @@ namespace Umbraco.Tests.Services [Test] public void TagsCanBecomeInvariant2() { - var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + var language = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); + LocalizationService.Save(language); // en-US is already there - var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + var enId = LocalizationService.GetLanguageIdByIsoCode("en-US").Value; - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - PropertyType propertyType; - contentType.PropertyGroups.First().PropertyTypes.Add( - propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041, - Variations = ContentVariation.Culture - }); - contentType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var propertyType = CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); + ContentTypeService.Save(contentType); + + IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - IContent content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + IContent content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", -1); content2.SetCultureName("name-fr", "fr-FR"); content2.SetCultureName("name-en", "en-US"); content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); - contentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); //// pretend we already have invariant values //using (var scope = ScopeProvider.CreateScope()) @@ -302,43 +279,38 @@ namespace Umbraco.Tests.Services // this should work propertyType.Variations = ContentVariation.Nothing; - Assert.DoesNotThrow(() => contentTypeService.Save(contentType)); + Assert.DoesNotThrow(() => ContentTypeService.Save(contentType)); } [Test] public void TagsCanBecomeInvariantByPropertyType() { - var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + var language = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); + LocalizationService.Save(language); // en-US is already there - var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + var enId = LocalizationService.GetLanguageIdByIsoCode("en-US").Value; - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - PropertyType propertyType; - contentType.PropertyGroups.First().PropertyTypes.Add( - propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041, - Variations = ContentVariation.Culture - }); - contentType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var propertyType = CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); + ContentTypeService.Save(contentType); + + IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); propertyType.Variations = ContentVariation.Nothing; - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); // changes - content1 = contentService.GetById(content1.Id); + content1 = ContentService.GetById(content1.Id); // property value has been moved from en-US to invariant, fr-FR tags are gone Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "fr-FR")); @@ -350,8 +322,8 @@ namespace Umbraco.Tests.Services Assert.AreEqual(-1, tags.IndexOf("plus")); // tags have been copied from en-US to invariant, fr-FR tags are gone - var tagGroups = tagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); - foreach (var tag in tagService.GetAllTags("*")) + var tagGroups = TagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); + foreach (var tag in TagService.GetAllTags("*")) Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); Assert.AreEqual(1, tagGroups.Count()); @@ -365,38 +337,31 @@ namespace Umbraco.Tests.Services [Test] public void TagsCanBecomeInvariantByPropertyTypeAndBackToVariant() { - var languageService = ServiceContext.LocalizationService; - languageService.Save(new Language(TestObjects.GetGlobalSettings(), "fr-FR")); // en-US is already there + var language = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); + LocalizationService.Save(language); // en-US is already there - var enId = ServiceContext.LocalizationService.GetLanguageIdByIsoCode("en-US").Value; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - PropertyType propertyType; - contentType.PropertyGroups.First().PropertyTypes.Add( - propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041, - Variations = ContentVariation.Culture - }); - contentType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var propertyType = CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); + ContentTypeService.Save(contentType); - IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); propertyType.Variations = ContentVariation.Nothing; - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); // FIXME: This throws due to index violations propertyType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); // TODO: Assert results } @@ -404,128 +369,116 @@ namespace Umbraco.Tests.Services [Test] public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_One() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + + var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", -1); content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); // verify - var tags = tagService.GetTagsForEntity(content1.Id); + var tags = TagService.GetTagsForEntity(content1.Id); Assert.AreEqual(5, tags.Count()); - var allTags = tagService.GetAllContentTags(); + var allTags = TagService.GetAllContentTags(); Assert.AreEqual(5, allTags.Count()); - contentService.MoveToRecycleBin(content1); + ContentService.MoveToRecycleBin(content1); } [Test] public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_All() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + + var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "bam" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", -1); content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); // verify - var tags = tagService.GetTagsForEntity(content1.Id); + var tags = TagService.GetTagsForEntity(content1.Id); Assert.AreEqual(5, tags.Count()); - var allTags = tagService.GetAllContentTags(); + var allTags = TagService.GetAllContentTags(); Assert.AreEqual(5, allTags.Count()); - contentService.Unpublish(content1); - contentService.Unpublish(content2); + ContentService.Unpublish(content1); + ContentService.Unpublish(content2); } [Test] [Ignore("https://github.com/umbraco/Umbraco-CMS/issues/3821 (U4-8442), will need to be fixed.")] public void TagsAreUpdatedWhenContentIsTrashedAndUnTrashed_Tree() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + + var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1.Id); + var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", content1.Id); content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); // verify - var tags = tagService.GetTagsForEntity(content1.Id); + var tags = TagService.GetTagsForEntity(content1.Id); Assert.AreEqual(5, tags.Count()); - var allTags = tagService.GetAllContentTags(); + var allTags = TagService.GetAllContentTags(); Assert.AreEqual(5, allTags.Count()); - contentService.MoveToRecycleBin(content1); + ContentService.MoveToRecycleBin(content1); // no more tags - tags = tagService.GetTagsForEntity(content1.Id); + tags = TagService.GetTagsForEntity(content1.Id); Assert.AreEqual(0, tags.Count()); - tags = tagService.GetTagsForEntity(content2.Id); + tags = TagService.GetTagsForEntity(content2.Id); Assert.AreEqual(0, tags.Count()); // no more tags - allTags = tagService.GetAllContentTags(); + allTags = TagService.GetAllContentTags(); Assert.AreEqual(0, allTags.Count()); - contentService.Move(content1, -1); + ContentService.Move(content1, -1); Assert.IsFalse(content1.Published); // no more tags - tags = tagService.GetTagsForEntity(content1.Id); + tags = TagService.GetTagsForEntity(content1.Id); Assert.AreEqual(0, tags.Count()); - tags = tagService.GetTagsForEntity(content2.Id); + tags = TagService.GetTagsForEntity(content2.Id); Assert.AreEqual(0, tags.Count()); // no more tags - allTags = tagService.GetAllContentTags(); + allTags = TagService.GetAllContentTags(); Assert.AreEqual(0, allTags.Count()); content1.PublishCulture(CultureImpact.Invariant); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); Assert.IsTrue(content1.Published); // tags are back - tags = tagService.GetTagsForEntity(content1.Id); + tags = TagService.GetTagsForEntity(content1.Id); Assert.AreEqual(5, tags.Count()); // FIXME: tag & tree issue @@ -533,82 +486,74 @@ namespace Umbraco.Tests.Services // what we should do is... NOT clear tags when unpublishing or trashing or... // and just update the tag service to NOT return anything related to trashed or // unpublished entities (since trashed is set on ALL entities in the trashed branch) - tags = tagService.GetTagsForEntity(content2.Id); // including that one! + tags = TagService.GetTagsForEntity(content2.Id); // including that one! Assert.AreEqual(4, tags.Count()); // tags are back - allTags = tagService.GetAllContentTags(); + allTags = TagService.GetAllContentTags(); Assert.AreEqual(5, allTags.Count()); } [Test] public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + + var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "bam" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", -1); content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); - contentService.Unpublish(content1); - contentService.Unpublish(content2); + ContentService.Unpublish(content1); + ContentService.Unpublish(content2); } [Test] [Ignore("https://github.com/umbraco/Umbraco-CMS/issues/3821 (U4-8442), will need to be fixed.")] public void TagsAreUpdatedWhenContentIsUnpublishedAndRePublished_Tree() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + + var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "bam" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", content1); + var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", content1); content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); - contentService.Unpublish(content1); + ContentService.Unpublish(content1); - var tags = tagService.GetTagsForEntity(content1.Id); + var tags = TagService.GetTagsForEntity(content1.Id); Assert.AreEqual(0, tags.Count()); // FIXME: tag & tree issue // when we (un)publish, we 'just' publish the top one and not the ones below = fails // see similar note above - tags = tagService.GetTagsForEntity(content2.Id); + tags = TagService.GetTagsForEntity(content2.Id); Assert.AreEqual(0, tags.Count()); - var allTags = tagService.GetAllContentTags(); + var allTags = TagService.GetAllContentTags(); Assert.AreEqual(0, allTags.Count()); content1.PublishCulture(CultureImpact.Invariant); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - tags = tagService.GetTagsForEntity(content2.Id); + tags = TagService.GetTagsForEntity(content2.Id); Assert.AreEqual(4, tags.Count()); - allTags = tagService.GetAllContentTags(); + allTags = TagService.GetAllContentTags(); Assert.AreEqual(5, allTags.Count()); } @@ -616,41 +561,36 @@ namespace Umbraco.Tests.Services public void Create_Tag_Data_Bulk_Publish_Operation() { //Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var dataTypeService = ServiceContext.DataTypeService; - //set configuration - var dataType = dataTypeService.GetDataType(1041); + var dataType = DataTypeService.GetDataType(1041); dataType.Configuration = new TagConfiguration { Group = "test", StorageType = TagsStorageType.Csv }; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias) }; - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.Save(content); + ContentService.Save(content); - var child1 = MockedContent.CreateSimpleContent(contentType, "child 1 content", content.Id); + var child1 = ContentBuilder.CreateSimpleContent(contentType, "child 1 content", content.Id); child1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello1", "world1", "some1" }); - contentService.Save(child1); + ContentService.Save(child1); - var child2 = MockedContent.CreateSimpleContent(contentType, "child 2 content", content.Id); + var child2 = ContentBuilder.CreateSimpleContent(contentType, "child 2 content", content.Id); child2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello2", "world2" }); - contentService.Save(child2); + ContentService.Save(child2); // Act - contentService.SaveAndPublishBranch(content, true); + ContentService.SaveAndPublishBranch(content, true); // Assert var propertyTypeId = contentType.PropertyTypes.Single(x => x.Alias == "tags").Id; @@ -676,22 +616,22 @@ namespace Umbraco.Tests.Services [Test] public void Does_Not_Create_Tag_Data_For_Non_Published_Version() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); // create content type with a tag property - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") { DataTypeId = 1041 }); - contentTypeService.Save(contentType); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); // create a content with tags and publish - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // edit tags and save content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "another", "world" }, merge: true); - contentService.Save(content); + ContentService.Save(content); // the (edit) property does contain all tags Assert.AreEqual(5, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); @@ -710,23 +650,20 @@ namespace Umbraco.Tests.Services [Test] public void Can_Replace_Tag_Data_To_Published_Content() { - //Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + //Arrange + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + + var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); // Act content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // Assert Assert.AreEqual(4, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); @@ -744,23 +681,20 @@ namespace Umbraco.Tests.Services [Test] public void Can_Append_Tag_Data_To_Published_Content() { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + //Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // Act content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "another", "world" }, merge: true); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // Assert Assert.AreEqual(5, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); @@ -778,23 +712,20 @@ namespace Umbraco.Tests.Services [Test] public void Can_Remove_Tag_Data_To_Published_Content() { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + //Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - var content = MockedContent.CreateSimpleContent(contentType, "Tagged content", -1); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + CreateAndAddTagsPropertyType(contentType); + ContentTypeService.Save(contentType); + var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // Act content.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "some", "world" }); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // Assert Assert.AreEqual(2, content.Properties["tags"].GetValue().ToString().Split(',').Distinct().Count()); @@ -809,5 +740,17 @@ namespace Umbraco.Tests.Services } } + private PropertyType CreateAndAddTagsPropertyType(ContentType contentType, ContentVariation variations = ContentVariation.Nothing) + { + var propertyType = new PropertyTypeBuilder() + .WithPropertyEditorAlias("test") + .WithAlias("tags") + .WithDataTypeId(1041) + .WithVariations(variations) + .Build(); + contentType.PropertyGroups.First().PropertyTypes.Add(propertyType); + contentType.Variations = variations; + return propertyType; + } } } diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests.Integration/Services/ContentServiceTests.cs similarity index 63% rename from src/Umbraco.Tests/Services/ContentServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/ContentServiceTests.cs index 81f8a5bcad..c4ae836bec 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/ContentServiceTests.cs @@ -3,46 +3,60 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; -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.Configuration.Models; +using Umbraco.Core.Events; +using Umbraco.Core.IO; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; -using Umbraco.Tests.Common.TestHelpers.Entities; -using Umbraco.Tests.LegacyXmlPublishedCache; +using Umbraco.Core.Scoping; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; namespace Umbraco.Tests.Services { /// /// Tests covering all methods in the ContentService class. - /// This is more of an integration test as it involves multiple layers - /// as well as configuration. /// [TestFixture] - [Category("Slow")] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, - WithApplication = true, - Logger = UmbracoTestOptions.Logger.Console)] - public class ContentServiceTests : TestWithSomeContentBase + WithApplication = true)] + public class ContentServiceTests : UmbracoIntegrationTestWithContent { // 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. - public override void SetUp() + private IMediaTypeService MediaTypeService => GetRequiredService(); + private MediaService MediaService => (MediaService)GetRequiredService(); + private IDataTypeService DataTypeService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IAuditService AuditService => GetRequiredService(); + private IUserService UserService => GetRequiredService(); + private IRelationService RelationService => GetRequiredService(); + private ILocalizedTextService TextService => GetRequiredService(); + private ITagService TagService => GetRequiredService(); + private IPublicAccessService PublicAccessService => GetRequiredService(); + private IDomainService DomainService => GetRequiredService(); + private INotificationService NotificationService => GetRequiredService(); + private PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); + private IDocumentRepository DocumentRepository => GetRequiredService(); + + public override void Setup() { - base.SetUp(); + base.Setup(); ContentRepositoryBase.ThrowOnWarning = true; } @@ -52,60 +66,51 @@ namespace Umbraco.Tests.Services base.TearDown(); } - protected override void Compose() - { - base.Compose(); - - Composition.RegisterUnique(factory => Mock.Of()); - } - [Test] public void Create_Blueprint() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentTypeService.Save(contentType); + var contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); - var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", Constants.System.Root); + var blueprint = ContentBuilder.CreateTextpageContent(contentType, "hello", Constants.System.Root); blueprint.SetValue("title", "blueprint 1"); blueprint.SetValue("bodyText", "blueprint 2"); blueprint.SetValue("keywords", "blueprint 3"); blueprint.SetValue("description", "blueprint 4"); - contentService.SaveBlueprint(blueprint); + ContentService.SaveBlueprint(blueprint); - var found = contentService.GetBlueprintsForContentTypes().ToArray(); + var found = ContentService.GetBlueprintsForContentTypes().ToArray(); Assert.AreEqual(1, found.Length); //ensures it's not found by normal content - var contentFound = contentService.GetById(found[0].Id); + var contentFound = ContentService.GetById(found[0].Id); Assert.IsNull(contentFound); } [Test] public void Delete_Blueprint() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentTypeService.Save(contentType); + var contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); - var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", Constants.System.Root); + var blueprint = ContentBuilder.CreateTextpageContent(contentType, "hello", Constants.System.Root); blueprint.SetValue("title", "blueprint 1"); blueprint.SetValue("bodyText", "blueprint 2"); blueprint.SetValue("keywords", "blueprint 3"); blueprint.SetValue("description", "blueprint 4"); - contentService.SaveBlueprint(blueprint); + ContentService.SaveBlueprint(blueprint); - contentService.DeleteBlueprint(blueprint); + ContentService.DeleteBlueprint(blueprint); - var found = contentService.GetBlueprintsForContentTypes().ToArray(); + var found = ContentService.GetBlueprintsForContentTypes().ToArray(); Assert.AreEqual(0, found.Length); } @@ -114,23 +119,22 @@ namespace Umbraco.Tests.Services { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var contentType = MockedContentTypes.CreateTextPageContentType(); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - contentTypeService.Save(contentType); + var contentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); - var blueprint = MockedContent.CreateTextpageContent(contentType, "hello", Constants.System.Root); + var blueprint = ContentBuilder.CreateTextpageContent(contentType, "hello", Constants.System.Root); blueprint.SetValue("title", "blueprint 1"); blueprint.SetValue("bodyText", "blueprint 2"); blueprint.SetValue("keywords", "blueprint 3"); blueprint.SetValue("description", "blueprint 4"); - contentService.SaveBlueprint(blueprint); + ContentService.SaveBlueprint(blueprint); - var fromBlueprint = contentService.CreateContentFromBlueprint(blueprint, "hello world"); - contentService.Save(fromBlueprint); + var fromBlueprint = ContentService.CreateContentFromBlueprint(blueprint, "hello world"); + ContentService.Save(fromBlueprint); Assert.IsTrue(fromBlueprint.HasIdentity); Assert.AreEqual("blueprint 1", fromBlueprint.Properties["title"].GetValue()); @@ -144,47 +148,52 @@ namespace Umbraco.Tests.Services [Test] public void Get_All_Blueprints() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var ct1 = MockedContentTypes.CreateTextPageContentType("ct1"); - ServiceContext.FileService.SaveTemplate(ct1.DefaultTemplate); - contentTypeService.Save(ct1); - var ct2 = MockedContentTypes.CreateTextPageContentType("ct2"); - ServiceContext.FileService.SaveTemplate(ct2.DefaultTemplate); - contentTypeService.Save(ct2); + var ct1 = ContentTypeBuilder.CreateTextPageContentType("ct1", defaultTemplateId: template.Id); + FileService.SaveTemplate(ct1.DefaultTemplate); + ContentTypeService.Save(ct1); + var ct2 = ContentTypeBuilder.CreateTextPageContentType("ct2", defaultTemplateId: template.Id); + FileService.SaveTemplate(ct2.DefaultTemplate); + ContentTypeService.Save(ct2); for (int i = 0; i < 10; i++) { - var blueprint = MockedContent.CreateTextpageContent(i % 2 == 0 ? ct1 : ct2, "hello" + i, Constants.System.Root); - contentService.SaveBlueprint(blueprint); + var blueprint = ContentBuilder.CreateTextpageContent(i % 2 == 0 ? ct1 : ct2, "hello" + i, Constants.System.Root); + ContentService.SaveBlueprint(blueprint); } - var found = contentService.GetBlueprintsForContentTypes().ToArray(); + var found = ContentService.GetBlueprintsForContentTypes().ToArray(); Assert.AreEqual(10, found.Length); - found = contentService.GetBlueprintsForContentTypes(ct1.Id).ToArray(); + found = ContentService.GetBlueprintsForContentTypes(ct1.Id).ToArray(); Assert.AreEqual(5, found.Length); - found = contentService.GetBlueprintsForContentTypes(ct2.Id).ToArray(); + found = ContentService.GetBlueprintsForContentTypes(ct2.Id).ToArray(); Assert.AreEqual(5, found.Length); } [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 LanguageBuilder() + .WithCultureInfo("en-GB") + .WithIsDefault(true) + .Build(); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); - ServiceContext.LocalizationService.Save(langFr); - ServiceContext.LocalizationService.Save(langUk); + LocalizationService.Save(langFr); + LocalizationService.Save(langUk); - var ctInvariant = MockedContentTypes.CreateBasicContentType("invariantPage"); - ServiceContext.ContentTypeService.Save(ctInvariant); + var ctInvariant = ContentTypeBuilder.CreateBasicContentType("invariantPage"); + ContentTypeService.Save(ctInvariant); - var ctVariant = MockedContentTypes.CreateBasicContentType("variantPage"); + var ctVariant = ContentTypeBuilder.CreateBasicContentType("variantPage"); ctVariant.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(ctVariant); + ContentTypeService.Save(ctVariant); var now = DateTime.Now; @@ -192,18 +201,18 @@ namespace Umbraco.Tests.Services var invariant = new List(); for (var i = 0; i < 10; i++) { - var c = MockedContent.CreateBasicContent(ctInvariant); + var c = ContentBuilder.CreateBasicContent(ctInvariant); c.Name = "name" + i; if (i % 2 == 0) { c.ContentSchedule.Add(now.AddSeconds(5), null); //release in 5 seconds - var r = ServiceContext.ContentService.Save(c); + var r = ContentService.Save(c); Assert.IsTrue(r.Success, r.Result.ToString()); } else { c.ContentSchedule.Add(null, now.AddSeconds(5)); //expire in 5 seconds - var r = ServiceContext.ContentService.SaveAndPublish(c); + var r = ContentService.SaveAndPublish(c); Assert.IsTrue(r.Success, r.Result.ToString()); } invariant.Add(c); @@ -214,14 +223,14 @@ namespace Umbraco.Tests.Services var alternatingCulture = langFr.IsoCode; for (var i = 0; i < 10; i++) { - var c = MockedContent.CreateBasicContent(ctVariant); + var c = ContentBuilder.CreateBasicContent(ctVariant); c.SetCultureName("name-uk" + i, langUk.IsoCode); c.SetCultureName("name-fr" + i, langFr.IsoCode); if (i % 2 == 0) { c.ContentSchedule.Add(alternatingCulture, now.AddSeconds(5), null); //release in 5 seconds - var r = ServiceContext.ContentService.Save(c); + var r = ContentService.Save(c); Assert.IsTrue(r.Success, r.Result.ToString()); alternatingCulture = alternatingCulture == langFr.IsoCode ? langUk.IsoCode : langFr.IsoCode; @@ -229,14 +238,14 @@ namespace Umbraco.Tests.Services else { c.ContentSchedule.Add(alternatingCulture, null, now.AddSeconds(5)); //expire in 5 seconds - var r = ServiceContext.ContentService.SaveAndPublish(c); + var r = ContentService.SaveAndPublish(c); Assert.IsTrue(r.Success, r.Result.ToString()); } variant.Add(c); } - var runSched = ServiceContext.ContentService.PerformScheduledPublish( + var runSched = ContentService.PerformScheduledPublish( now.AddMinutes(1)).ToList(); //process anything scheduled before a minute from now //this is 21 because the test data installed before this test runs has a scheduled item! @@ -254,7 +263,7 @@ namespace Umbraco.Tests.Services string.Join(Environment.NewLine, runSched.Select(x => $"{x.Entity.Name} - {x.Result}"))); //re-run the scheduled publishing, there should be no results - runSched = ServiceContext.ContentService.PerformScheduledPublish( + runSched = ContentService.PerformScheduledPublish( now.AddMinutes(1)).ToList(); Assert.AreEqual(0, runSched.Count); @@ -264,49 +273,46 @@ namespace Umbraco.Tests.Services public void Remove_Scheduled_Publishing_Date() { // Arrange - var contentService = ServiceContext.ContentService; // Act - var content = contentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + var content = ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); content.ContentSchedule.Add(null, DateTime.Now.AddHours(2)); - contentService.Save(content, Constants.Security.SuperUserId); + ContentService.Save(content, Constants.Security.SuperUserId); Assert.AreEqual(1, content.ContentSchedule.FullSchedule.Count); - content = contentService.GetById(content.Id); + content = ContentService.GetById(content.Id); var sched = content.ContentSchedule.FullSchedule; Assert.AreEqual(1, sched.Count); Assert.AreEqual(1, sched.Count(x => x.Culture == string.Empty)); content.ContentSchedule.Clear(ContentScheduleAction.Expire); - contentService.Save(content, Constants.Security.SuperUserId); + ContentService.Save(content, Constants.Security.SuperUserId); // Assert - content = contentService.GetById(content.Id); + content = ContentService.GetById(content.Id); sched = content.ContentSchedule.FullSchedule; Assert.AreEqual(0, sched.Count); - Assert.IsTrue(contentService.SaveAndPublish(content).Success); + Assert.IsTrue(ContentService.SaveAndPublish(content).Success); } [Test] public void Get_Top_Version_Ids() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var content = contentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + var content = ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); for (var i = 0; i < 20; i++) { content.SetValue("bodyText", "hello world " + Guid.NewGuid()); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); } // Assert - var allVersions = contentService.GetVersionIds(content.Id, int.MaxValue); + var allVersions = ContentService.GetVersionIds(content.Id, int.MaxValue); Assert.AreEqual(21, allVersions.Count()); - var topVersions = contentService.GetVersionIds(content.Id, 4); + var topVersions = ContentService.GetVersionIds(content.Id, 4); Assert.AreEqual(4, topVersions.Count()); } @@ -314,16 +320,14 @@ namespace Umbraco.Tests.Services public void Get_By_Ids_Sorted() { // Arrange - var contentService = ServiceContext.ContentService; - // Act var results = new List(); for (var i = 0; i < 20; i++) { - results.Add(contentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", 0)); + results.Add(ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", 0)); } - var sortedGet = contentService.GetByIds(new[] {results[10].Id, results[5].Id, results[12].Id}).ToArray(); + var sortedGet = ContentService.GetByIds(new[] {results[10].Id, results[5].Id, results[12].Id}).ToArray(); // Assert Assert.AreEqual(sortedGet[0].Id, results[10].Id); @@ -335,87 +339,86 @@ namespace Umbraco.Tests.Services public void Count_All() { // Arrange - var contentService = ServiceContext.ContentService; - // Act for (int i = 0; i < 20; i++) { - contentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); } // Assert - Assert.AreEqual(24, contentService.Count()); + Assert.AreEqual(24, ContentService.Count()); } [Test] public void Count_By_Content_Type() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type"); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); // Act - for (int i = 0; i < 20; i++) + for (var i = 0; i < 20; i++) { - contentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); + ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); } // Assert - Assert.AreEqual(20, contentService.Count(documentTypeAlias: "umbBlah")); + Assert.AreEqual(20, ContentService.Count(contentTypeAlias: "umbBlah")); } [Test] public void Count_Children() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type"); - contentTypeService.Save(contentType); - var parent = contentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var parent = ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); // Act for (int i = 0; i < 20; i++) { - contentService.CreateAndSave("Test", parent, "umbBlah"); + ContentService.CreateAndSave("Test", parent, "umbBlah"); } // Assert - Assert.AreEqual(20, contentService.CountChildren(parent.Id)); + Assert.AreEqual(20, ContentService.CountChildren(parent.Id)); } [Test] public void Count_Descendants() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbBlah", "test Doc Type"); - contentTypeService.Save(contentType); - var parent = contentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbBlah", "test Doc Type", defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var parent = ContentService.CreateAndSave("Test", Constants.System.Root, "umbBlah", Constants.Security.SuperUserId); // Act IContent current = parent; for (int i = 0; i < 20; i++) { - current = contentService.CreateAndSave("Test", current, "umbBlah"); + current = ContentService.CreateAndSave("Test", current, "umbBlah"); } // Assert - Assert.AreEqual(20, contentService.CountDescendants(parent.Id)); + Assert.AreEqual(20, ContentService.CountDescendants(parent.Id)); } [Test] public void GetAncestors_Returns_Empty_List_When_Path_Is_Null() { // Arrange - var contentService = ServiceContext.ContentService; - // Act var current = new Mock(); - var res = contentService.GetAncestors(current.Object); + var res = ContentService.GetAncestors(current.Object); // Assert Assert.IsEmpty(res); @@ -425,10 +428,8 @@ namespace Umbraco.Tests.Services public void Can_Remove_Property_Type() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var content = contentService.Create("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + var content = ContentService.Create("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); // Assert Assert.That(content, Is.Not.Null); @@ -439,10 +440,8 @@ namespace Umbraco.Tests.Services public void Can_Create_Content() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var content = contentService.Create("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + var content = ContentService.Create("Test", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); // Assert Assert.That(content, Is.Not.Null); @@ -452,22 +451,25 @@ namespace Umbraco.Tests.Services [Test] public void Automatically_Track_Relations() { - var mt = MockedContentTypes.CreateSimpleMediaType("testMediaType", "Test Media Type"); - ServiceContext.MediaTypeService.Save(mt); - var m1 = MockedMedia.CreateSimpleMedia(mt, "hello 1", -1); - var m2 = MockedMedia.CreateSimpleMedia(mt, "hello 1", -1); - ServiceContext.MediaService.Save(m1); - ServiceContext.MediaService.Save(m2); + var mt = MediaTypeBuilder.CreateSimpleMediaType("testMediaType", "Test Media Type"); + MediaTypeService.Save(mt); + var m1 = MediaBuilder.CreateSimpleMedia(mt, "hello 1", -1); + var m2 = MediaBuilder.CreateSimpleMedia(mt, "hello 1", -1); + MediaService.Save(m1); + MediaService.Save(m2); - var ct = MockedContentTypes.CreateTextPageContentType("richTextTest"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var ct = ContentTypeBuilder.CreateTextPageContentType("richTextTest", defaultTemplateId: template.Id); ct.AllowedTemplates = Enumerable.Empty(); - ServiceContext.ContentTypeService.Save(ct); + ContentTypeService.Save(ct); - var c1 = MockedContent.CreateTextpageContent(ct, "my content 1", -1); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateTextpageContent(ct, "my content 1", -1); + ContentService.Save(c1); - var c2 = MockedContent.CreateTextpageContent(ct, "my content 2", -1); + var c2 = ContentBuilder.CreateTextpageContent(ct, "my content 2", -1); //'bodyText' is a property with a RTE property editor which we knows tracks relations c2.Properties["bodyText"].SetValue(@"

@@ -478,9 +480,9 @@ namespace Umbraco.Tests.Services hello

"); - ServiceContext.ContentService.Save(c2); + ContentService.Save(c2); - var relations = ServiceContext.RelationService.GetByParentId(c2.Id).ToList(); + var relations = RelationService.GetByParentId(c2.Id).ToList(); Assert.AreEqual(3, relations.Count); Assert.AreEqual(Constants.Conventions.RelationTypes.RelatedMediaAlias, relations[0].RelationType.Alias); Assert.AreEqual(m1.Id, relations[0].ChildId); @@ -494,10 +496,8 @@ namespace Umbraco.Tests.Services public void Can_Create_Content_Without_Explicitly_Set_User() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var content = contentService.Create("Test", Constants.System.Root, "umbTextpage"); + var content = ContentService.Create("Test", Constants.System.Root, "umbTextpage"); // Assert Assert.That(content, Is.Not.Null); @@ -508,18 +508,12 @@ namespace Umbraco.Tests.Services [Test] public void Can_Save_New_Content_With_Explicit_User() { - var user = new User(TestObjects.GetGlobalSettings()) - { - Name = "Test", - Email = "test@test.com", - Username = "test", - RawPasswordValue = "test" - }; - ServiceContext.UserService.Save(user); - var content = new Content("Test", Constants.System.Root, ServiceContext.ContentTypeService.Get("umbTextpage")); + var user = new UserBuilder().Build(); + UserService.Save(user); + var content = new Content("Test", Constants.System.Root, ContentTypeService.Get("umbTextpage")); // Act - ServiceContext.ContentService.Save(content, (int)user.Id); + ContentService.Save(content, user.Id); // Assert Assert.That(content.CreatorId, Is.EqualTo(user.Id)); @@ -530,59 +524,50 @@ namespace Umbraco.Tests.Services public void Cannot_Create_Content_With_Non_Existing_ContentType_Alias() { // Arrange - var contentService = ServiceContext.ContentService; - // Act & Assert - Assert.Throws(() => contentService.Create("Test", Constants.System.Root, "umbAliasDoesntExist")); + Assert.Throws(() => ContentService.Create("Test", Constants.System.Root, "umbAliasDoesntExist")); } [Test] public void Cannot_Save_Content_With_Empty_Name() { // Arrange - var contentService = ServiceContext.ContentService; - var content = new Content(string.Empty, Constants.System.Root, ServiceContext.ContentTypeService.Get("umbTextpage")); + var content = new Content(string.Empty, Constants.System.Root, ContentTypeService.Get("umbTextpage")); // Act & Assert - Assert.Throws(() => contentService.Save(content)); + Assert.Throws(() => ContentService.Save(content)); } [Test] public void Can_Get_Content_By_Id() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var content = contentService.GetById(NodeDto.NodeIdSeed + 2 ); + var content = ContentService.GetById(Textpage.Id); // Assert Assert.That(content, Is.Not.Null); - Assert.That(content.Id, Is.EqualTo(NodeDto.NodeIdSeed + 2)); + Assert.That(content.Id, Is.EqualTo(Textpage.Id)); } [Test] public void Can_Get_Content_By_Guid_Key() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var content = contentService.GetById(new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0")); + var content = ContentService.GetById(new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0")); // Assert Assert.That(content, Is.Not.Null); - Assert.That(content.Id, Is.EqualTo(NodeDto.NodeIdSeed + 2)); + Assert.That(content.Id, Is.EqualTo(Textpage.Id)); } [Test] public void Can_Get_Content_By_Level() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var contents = contentService.GetByLevel(2).ToList(); + var contents = ContentService.GetByLevel(2).ToList(); // Assert Assert.That(contents, Is.Not.Null); @@ -593,15 +578,13 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_All_Versions_Of_Content() { - var contentService = ServiceContext.ContentService; - - var parent = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 2); + var parent = ContentService.GetById(Textpage.Id); Assert.IsFalse(parent.Published); - ServiceContext.ContentService.SaveAndPublish(parent); // publishing parent, so Text Page 2 can be updated. + ContentService.SaveAndPublish(parent); // publishing parent, so Text Page 2 can be updated. - var content = contentService.GetById(NodeDto.NodeIdSeed + 4); + var content = ContentService.GetById(Subpage.Id); Assert.IsFalse(content.Published); - var versions = contentService.GetVersions(NodeDto.NodeIdSeed + 4).ToList(); + var versions = ContentService.GetVersions(Subpage.Id).ToList(); Assert.AreEqual(1, versions.Count); var version1 = content.VersionId; @@ -609,31 +592,31 @@ namespace Umbraco.Tests.Services content.Name = "Text Page 2 Updated"; content.SetValue("author", "Jane Doe"); - contentService.SaveAndPublish(content); // publishes the current version, creates a version + ContentService.SaveAndPublish(content); // publishes the current version, creates a version var version2 = content.VersionId; Console.WriteLine($"2 e={content.VersionId} p={content.PublishedVersionId}"); content.Name = "Text Page 2 ReUpdated"; content.SetValue("author", "Bob Hope"); - contentService.SaveAndPublish(content); // publishes again, creates a version + ContentService.SaveAndPublish(content); // publishes again, creates a version var version3 = content.VersionId; Console.WriteLine($"3 e={content.VersionId} p={content.PublishedVersionId}"); - var content1 = contentService.GetById(content.Id); + var content1 = ContentService.GetById(content.Id); Assert.AreEqual("Bob Hope", content1.GetValue("author")); Assert.AreEqual("Bob Hope", content1.GetValue("author", published: true)); content.Name = "Text Page 2 ReReUpdated"; content.SetValue("author", "John Farr"); - contentService.Save(content); // no new version + ContentService.Save(content); // no new version - content1 = contentService.GetById(content.Id); + content1 = ContentService.GetById(content.Id); Assert.AreEqual("John Farr", content1.GetValue("author")); Assert.AreEqual("Bob Hope", content1.GetValue("author", published: true)); - versions = contentService.GetVersions(NodeDto.NodeIdSeed + 4).ToList(); + versions = ContentService.GetVersions(Subpage.Id).ToList(); Assert.AreEqual(3, versions.Count); // versions come with most recent first @@ -665,10 +648,8 @@ namespace Umbraco.Tests.Services public void Can_Get_Root_Content() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var contents = contentService.GetRootContent().ToList(); + var contents = ContentService.GetRootContent().ToList(); // Assert Assert.That(contents, Is.Not.Null); @@ -680,16 +661,15 @@ namespace Umbraco.Tests.Services public void Can_Get_Content_For_Expiration() { // Arrange - var contentService = ServiceContext.ContentService; - var root = contentService.GetById(NodeDto.NodeIdSeed + 2); - contentService.SaveAndPublish(root); - var content = contentService.GetById(NodeDto.NodeIdSeed + 4); + var root = ContentService.GetById(Textpage.Id); + ContentService.SaveAndPublish(root); + var content = ContentService.GetById(Subpage.Id); content.ContentSchedule.Add(null, DateTime.Now.AddSeconds(1)); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // Act Thread.Sleep(new TimeSpan(0, 0, 0, 2)); - var contents = contentService.GetContentForExpiration(DateTime.Now).ToList(); + var contents = ContentService.GetContentForExpiration(DateTime.Now).ToList(); // Assert Assert.That(contents, Is.Not.Null); @@ -701,10 +681,8 @@ namespace Umbraco.Tests.Services public void Can_Get_Content_For_Release() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var contents = contentService.GetContentForRelease(DateTime.Now).ToList(); + var contents = ContentService.GetContentForRelease(DateTime.Now).ToList(); // Assert Assert.That(DateTime.Now.AddMinutes(-5) <= DateTime.Now); @@ -717,10 +695,8 @@ namespace Umbraco.Tests.Services public void Can_Get_Content_In_RecycleBin() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - var contents = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); + var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents, Is.Not.Null); @@ -732,28 +708,17 @@ namespace Umbraco.Tests.Services public void Can_Unpublish_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 2); - var published = contentService.SaveAndPublish(content, userId: 0); - - using (var scope = ScopeProvider.CreateScope()) - { - Assert.IsTrue(scope.Database.Exists(content.Id)); - } + var content = ContentService.GetById(Textpage.Id); + var published = ContentService.SaveAndPublish(content, userId: 0); // Act - var unpublished = contentService.Unpublish(content, userId: 0); + var unpublished = ContentService.Unpublish(content, userId: 0); // Assert Assert.That(published.Success, Is.True); Assert.That(unpublished.Success, Is.True); Assert.That(content.Published, Is.False); Assert.AreEqual(PublishResultType.SuccessUnpublish, unpublished.Result); - - using (var scope = ScopeProvider.CreateScope()) - { - Assert.IsFalse(scope.Database.Exists(content.Id)); - } } [Test] @@ -766,24 +731,24 @@ namespace Umbraco.Tests.Services Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); - var published = ServiceContext.ContentService.SaveAndPublish(content, new[]{ langFr.IsoCode , langUk.IsoCode }); + var published = ContentService.SaveAndPublish(content, new[]{ langFr.IsoCode , langUk.IsoCode }); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsTrue(published.Success); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); - var unpublished = ServiceContext.ContentService.Unpublish(content, langFr.IsoCode); + var unpublished = ContentService.Unpublish(content, langFr.IsoCode); Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishCulture, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); @@ -795,34 +760,34 @@ namespace Umbraco.Tests.Services { var content = CreateEnglishAndFrenchDocument(out var langUk, out var langFr, out var contentType); - var published = ServiceContext.ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); + var published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.AreEqual(PublishedState.Published, content.PublishedState); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); - var unpublished = ServiceContext.ContentService.Unpublish(content, langUk.IsoCode); //first culture + var unpublished = ContentService.Unpublish(content, langUk.IsoCode); //first culture Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishCulture, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langUk.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); - unpublished = ServiceContext.ContentService.Unpublish(content, langFr.IsoCode); //last culture + unpublished = ContentService.Unpublish(content, langFr.IsoCode); //last culture Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishLastCulture, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); Assert.IsFalse(content.IsCulturePublished(langUk.IsoCode)); - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); - published = ServiceContext.ContentService.SaveAndPublish(content, langUk.IsoCode); + published = ContentService.SaveAndPublish(content, langUk.IsoCode); Assert.AreEqual(PublishedState.Published, content.PublishedState); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); - content = ServiceContext.ContentService.GetById(content.Id); //reget + content = ContentService.GetById(content.Id); //reget Assert.AreEqual(PublishedState.Published, content.PublishedState); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); @@ -836,19 +801,19 @@ namespace Umbraco.Tests.Services { var content = CreateEnglishAndFrenchDocument(out var langUk, out var langFr, out var contentType); - var published = ServiceContext.ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); + var published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); Assert.IsTrue(published.Success); Assert.AreEqual(PublishedState.Published, content.PublishedState); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); Assert.AreEqual(PublishedState.Published, content.PublishedState); - var unpublished = ServiceContext.ContentService.Unpublish(content, langFr.IsoCode); //first culture + var unpublished = ContentService.Unpublish(content, langFr.IsoCode); //first culture Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishCulture, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); @@ -856,11 +821,11 @@ namespace Umbraco.Tests.Services Assert.AreEqual(PublishedState.Published, content.PublishedState); //still published //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); - unpublished = ServiceContext.ContentService.Unpublish(content, langUk.IsoCode); //last culture + unpublished = ContentService.Unpublish(content, langUk.IsoCode); //last culture Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishLastCulture, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); @@ -868,7 +833,7 @@ namespace Umbraco.Tests.Services Assert.AreEqual(PublishedState.Unpublished, content.PublishedState); //the last culture was unpublished so the document should also reflect this //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.AreEqual(PublishedState.Unpublished, content.PublishedState); //just double checking Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); Assert.IsFalse(content.IsCulturePublished(langUk.IsoCode)); @@ -877,30 +842,36 @@ 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 LanguageBuilder() + .WithCultureInfo("en-GB") + .WithIsDefault(true) + .WithIsMandatory(true) + .Build(); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); - ServiceContext.LocalizationService.Save(langFr); - ServiceContext.LocalizationService.Save(langUk); + LocalizationService.Save(langFr); + LocalizationService.Save(langUk); - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); IContent content = new Content("content", Constants.System.Root, contentType); content.SetCultureName("content-fr", langFr.IsoCode); content.SetCultureName("content-en", langUk.IsoCode); - var published = ServiceContext.ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); + var published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); Assert.IsTrue(published.Success); Assert.AreEqual(PublishedState.Published, content.PublishedState); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); - var unpublished = ServiceContext.ContentService.Unpublish(content, langUk.IsoCode); //unpublish mandatory lang + var unpublished = ContentService.Unpublish(content, langUk.IsoCode); //unpublish mandatory lang Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishMandatoryCulture, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langUk.IsoCode)); @@ -913,31 +884,31 @@ namespace Umbraco.Tests.Services { var content = CreateEnglishAndFrenchDocument(out var langUk, out var langFr, out var contentType); - var published = ServiceContext.ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); + var published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); Assert.IsTrue(published.Success); Assert.AreEqual(PublishedState.Published, content.PublishedState); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); - var unpublished = ServiceContext.ContentService.Unpublish(content, langUk.IsoCode); + var unpublished = ContentService.Unpublish(content, langUk.IsoCode); Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishCulture, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langUk.IsoCode)); - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); //Change some data since Unpublish should always Save content.SetCultureName("content-en-updated", langUk.IsoCode); - unpublished = ServiceContext.ContentService.Unpublish(content, langUk.IsoCode); //unpublish again + unpublished = ContentService.Unpublish(content, langUk.IsoCode); //unpublish again Assert.IsTrue(unpublished.Success); Assert.AreEqual(PublishResultType.SuccessUnpublishAlready, unpublished.Result); Assert.IsFalse(content.IsCulturePublished(langUk.IsoCode)); - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); //ensure that even though the culture was already unpublished that the data was still persisted Assert.AreEqual("content-en-updated", content.GetCultureName(langUk.IsoCode)); } @@ -947,23 +918,23 @@ namespace Umbraco.Tests.Services { var content = CreateEnglishAndFrenchDocument(out var langUk, out var langFr, out var contentType); - var published = ServiceContext.ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); + var published = ContentService.SaveAndPublish(content, new[] { langFr.IsoCode, langUk.IsoCode }); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); Assert.IsTrue(published.Success); Assert.AreEqual(PublishedState.Published, content.PublishedState); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); //Change some data since SaveAndPublish should always Save content.SetCultureName("content-en-updated", langUk.IsoCode); - var saved = ServiceContext.ContentService.SaveAndPublish(content, new string [] { }); //save without cultures + var saved = ContentService.SaveAndPublish(content, new string [] { }); //save without cultures Assert.AreEqual(PublishResultType.FailedPublishNothingToPublish, saved.Result); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); //ensure that even though nothing was published that the data was still persisted Assert.AreEqual("content-en-updated", content.GetCultureName(langUk.IsoCode)); } @@ -973,46 +944,50 @@ namespace Umbraco.Tests.Services public void Pending_Invariant_Property_Changes_Affect_Default_Language_Edited_State() { // Arrange + var langGb = new LanguageBuilder() + .WithCultureInfo("en-GB") + .WithIsDefault(true) + .Build(); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); - var langGB = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + LocalizationService.Save(langFr); + LocalizationService.Save(langGb); - ServiceContext.LocalizationService.Save(langFr); - ServiceContext.LocalizationService.Save(langGB); - - var contentType = MockedContentTypes.CreateMetaContentType(); + var contentType = ContentTypeBuilder.CreateMetaContentType(); contentType.Variations = ContentVariation.Culture; foreach(var prop in contentType.PropertyTypes) prop.Variations = ContentVariation.Culture; var keywordsProp = contentType.PropertyTypes.Single(x => x.Alias == "metakeywords"); keywordsProp.Variations = ContentVariation.Nothing; // this one is invariant - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); IContent content = new Content("content", Constants.System.Root, contentType); - content.SetCultureName("content-en", langGB.IsoCode); + content.SetCultureName("content-en", langGb.IsoCode); content.SetCultureName("content-fr", langFr.IsoCode); - Assert.IsTrue(ServiceContext.ContentService.SaveAndPublish(content, new []{ langGB.IsoCode , langFr.IsoCode }).Success); + Assert.IsTrue(ContentService.SaveAndPublish(content, new []{ langGb.IsoCode , langFr.IsoCode }).Success); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.AreEqual(PublishedState.Published, content.PublishedState); - Assert.IsTrue(content.IsCulturePublished(langGB.IsoCode)); + Assert.IsTrue(content.IsCulturePublished(langGb.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); - Assert.IsFalse(content.IsCultureEdited(langGB.IsoCode)); + Assert.IsFalse(content.IsCultureEdited(langGb.IsoCode)); Assert.IsFalse(content.IsCultureEdited(langFr.IsoCode)); //update the invariant property and save a pending version content.SetValue("metakeywords", "hello"); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.AreEqual(PublishedState.Published, content.PublishedState); - Assert.IsTrue(content.IsCulturePublished(langGB.IsoCode)); + Assert.IsTrue(content.IsCulturePublished(langGb.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); - Assert.IsTrue(content.IsCultureEdited(langGB.IsoCode)); + Assert.IsTrue(content.IsCultureEdited(langGb.IsoCode)); Assert.IsFalse(content.IsCultureEdited(langFr.IsoCode)); } @@ -1023,17 +998,17 @@ namespace Umbraco.Tests.Services IContent content = new Content("content", Constants.System.Root, contentType); content.SetCultureName("content-fr", langFr.IsoCode); - var published = ServiceContext.ContentService.SaveAndPublish(content, langFr.IsoCode); + var published = ContentService.SaveAndPublish(content, langFr.IsoCode); //audit log will only show that french was published - var lastLog = ServiceContext.AuditService.GetLogs(content.Id).Last(); + var lastLog = AuditService.GetLogs(content.Id).Last(); Assert.AreEqual($"Published languages: French (France)", lastLog.Comment); //re-get - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); content.SetCultureName("content-en", langUk.IsoCode); - published = ServiceContext.ContentService.SaveAndPublish(content, langUk.IsoCode); + published = ContentService.SaveAndPublish(content, langUk.IsoCode); //audit log will only show that english was published - lastLog = ServiceContext.AuditService.GetLogs(content.Id).Last(); + lastLog = AuditService.GetLogs(content.Id).Last(); Assert.AreEqual($"Published languages: English (United Kingdom)", lastLog.Comment); } @@ -1041,36 +1016,41 @@ namespace Umbraco.Tests.Services public void Can_Unpublish_Content_Variation_And_Detect_Changed_Cultures() { // Arrange + var langGb = new LanguageBuilder() + .WithCultureInfo("en-GB") + .WithIsDefault(true) + .WithIsMandatory(true) + .Build(); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); - var langGB = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true, IsMandatory = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + LocalizationService.Save(langFr); + LocalizationService.Save(langGb); - ServiceContext.LocalizationService.Save(langFr); - ServiceContext.LocalizationService.Save(langGB); - - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); IContent content = new Content("content", Constants.System.Root, contentType); content.SetCultureName("content-fr", langFr.IsoCode); - content.SetCultureName("content-gb", langGB.IsoCode); - var published = ServiceContext.ContentService.SaveAndPublish(content, new[] {langGB.IsoCode, langFr.IsoCode}); + content.SetCultureName("content-gb", langGb.IsoCode); + var published = ContentService.SaveAndPublish(content, new[] {langGb.IsoCode, langFr.IsoCode}); Assert.IsTrue(published.Success); //re-get - content = ServiceContext.ContentService.GetById(content.Id); - var unpublished = ServiceContext.ContentService.Unpublish(content, langFr.IsoCode); + content = ContentService.GetById(content.Id); + var unpublished = ContentService.Unpublish(content, langFr.IsoCode); //audit log will only show that french was unpublished - var lastLog = ServiceContext.AuditService.GetLogs(content.Id).Last(); + var lastLog = AuditService.GetLogs(content.Id).Last(); Assert.AreEqual($"Unpublished languages: French (France)", lastLog.Comment); //re-get - content = ServiceContext.ContentService.GetById(content.Id); - content.SetCultureName("content-en", langGB.IsoCode); - unpublished = ServiceContext.ContentService.Unpublish(content, langGB.IsoCode); + content = ContentService.GetById(content.Id); + content.SetCultureName("content-en", langGb.IsoCode); + unpublished = ContentService.Unpublish(content, langGb.IsoCode); //audit log will only show that english was published - var logs = ServiceContext.AuditService.GetLogs(content.Id).ToList(); + var logs = AuditService.GetLogs(content.Id).ToList(); Assert.AreEqual($"Unpublished languages: English (United Kingdom)", logs[logs.Count - 2].Comment); Assert.AreEqual($"Unpublished (mandatory language unpublished)", logs[logs.Count - 1].Comment); } @@ -1079,11 +1059,10 @@ namespace Umbraco.Tests.Services public void Can_Publish_Content_1() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 2); + var content = ContentService.GetById(Textpage.Id); // Act - var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(published.Success, Is.True); @@ -1094,11 +1073,10 @@ namespace Umbraco.Tests.Services public void Can_Publish_Content_2() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 2); + var content = ContentService.GetById(Textpage.Id); // Act - var published = contentService.SaveAndPublish(content, userId: 0); + var published = ContentService.SaveAndPublish(content, userId: 0); // Assert Assert.That(published.Success, Is.True); @@ -1109,16 +1087,15 @@ namespace Umbraco.Tests.Services public void IsPublishable() { // Arrange - var contentService = ServiceContext.ContentService; - var parent = contentService.Create("parent", Constants.System.Root, "umbTextpage"); + var parent = ContentService.Create("parent", Constants.System.Root, "umbTextpage"); - contentService.SaveAndPublish(parent); - var content = contentService.Create("child", parent, "umbTextpage"); - contentService.Save(content); + ContentService.SaveAndPublish(parent); + var content = ContentService.Create("child", parent, "umbTextpage"); + ContentService.Save(content); - Assert.IsTrue(contentService.IsPathPublishable(content)); - contentService.Unpublish(parent); - Assert.IsFalse(contentService.IsPathPublishable(content)); + Assert.IsTrue(ContentService.IsPathPublishable(content)); + ContentService.Unpublish(parent); + Assert.IsFalse(ContentService.IsPathPublishable(content)); } [Test] @@ -1132,17 +1109,16 @@ namespace Umbraco.Tests.Services try { - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 2); + var content = ContentService.GetById(Textpage.Id); Assert.AreEqual("Home", content.Name); content.Name = "foo"; - var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); Assert.That(published.Success, Is.True); Assert.That(content.Published, Is.True); - var e = ServiceContext.ContentService.GetById(content.Id); + var e = ContentService.GetById(content.Id); Assert.AreEqual("foo", e.Name); } finally @@ -1157,55 +1133,58 @@ namespace Umbraco.Tests.Services var entity = args.PublishedEntities.First(); Assert.AreEqual("foo", entity.Name); - var e = ServiceContext.ContentService.GetById(entity.Id); + var e = ContentService.GetById(entity.Id); Assert.AreEqual("Home", e.Name); } [Test] public void Can_Not_Publish_Invalid_Cultures() { - var contentService = ServiceContext.ContentService; - var content = Mock.Of(c => c.ContentType == Mock.Of(s => s.Variations == ContentVariation.Culture)); + var content = new ContentBuilder() + .AddContentType() + .WithContentVariation(ContentVariation.Culture) + .Done() + .Build(); - Assert.Throws(() => contentService.SaveAndPublish(content, new[] {"*"})); - Assert.Throws(() => contentService.SaveAndPublish(content, new string[] { null })); - Assert.Throws(() => contentService.SaveAndPublish(content, new[] { "*", null })); - Assert.Throws(() => contentService.SaveAndPublish(content, new[] { "en-US", "*", "es-ES" })); + Assert.Throws(() => ContentService.SaveAndPublish(content, new[] {"*"})); + Assert.Throws(() => ContentService.SaveAndPublish(content, new string[] { null })); + Assert.Throws(() => ContentService.SaveAndPublish(content, new[] { "*", null })); + Assert.Throws(() => ContentService.SaveAndPublish(content, new[] { "en-US", "*", "es-ES" })); } [Test] public void Can_Publish_Only_Valid_Content() { - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - const int parentId = NodeDto.NodeIdSeed + 2; + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); - var contentService = ServiceContext.ContentService; + var parentId = Textpage.Id; - var parent = contentService.GetById(parentId); + var parent = ContentService.GetById(parentId); - var parentPublished = contentService.SaveAndPublish(parent); + var parentPublished = ContentService.SaveAndPublish(parent); // parent can publish values // and therefore can be published Assert.IsTrue(parentPublished.Success); Assert.IsTrue(parent.Published); - var content = MockedContent.CreateSimpleContent(contentType, "Invalid Content", parentId); + var content = ContentBuilder.CreateSimpleContent(contentType, "Invalid Content", parentId); content.SetValue("author", string.Empty); Assert.IsFalse(content.HasIdentity); // content cannot publish values because they are invalid - var propertyValidationService = new PropertyValidationService(Factory.GetInstance(), ServiceContext.DataTypeService, ServiceContext.TextService); + var propertyValidationService = new PropertyValidationService(PropertyEditorCollection, DataTypeService, TextService); var isValid = propertyValidationService.IsPropertyDataValid(content, out var invalidProperties, CultureImpact.Invariant); Assert.IsFalse(isValid); Assert.IsNotEmpty(invalidProperties); // and therefore cannot be published, // because it did not have a published version at all - var contentPublished = contentService.SaveAndPublish(content); + var contentPublished = ContentService.SaveAndPublish(content); Assert.IsFalse(contentPublished.Success); Assert.AreEqual(PublishResultType.FailedPublishContentInvalid, contentPublished.Result); Assert.IsFalse(content.Published); @@ -1220,35 +1199,38 @@ namespace Umbraco.Tests.Services public void Can_Publish_And_Unpublish_Cultures_In_Single_Operation() { //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 LanguageBuilder() + .WithCultureInfo("fr") + .Build(); + var langDa = new LanguageBuilder() + .WithCultureInfo("da") + .Build(); + LocalizationService.Save(langFr); + LocalizationService.Save(langDa); - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr"); - var langDa = new Language(TestObjects.GetGlobalSettings(), "da"); - ServiceContext.LocalizationService.Save(langFr); - ServiceContext.LocalizationService.Save(langDa); - - var ct = MockedContentTypes.CreateBasicContentType(); + var ct = ContentTypeBuilder.CreateBasicContentType(); ct.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(ct); + ContentTypeService.Save(ct); - IContent content = MockedContent.CreateBasicContent(ct); + IContent content = ContentBuilder.CreateBasicContent(ct); content.SetCultureName("name-fr", langFr.IsoCode); content.SetCultureName("name-da", langDa.IsoCode); content.PublishCulture(CultureImpact.Explicit(langFr.IsoCode, langFr.IsDefault)); - var result = ((ContentService)ServiceContext.ContentService).CommitDocumentChanges(content); + var result = ((ContentService)ContentService).CommitDocumentChanges(content); Assert.IsTrue(result.Success); - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); Assert.IsFalse(content.IsCulturePublished(langDa.IsoCode)); content.UnpublishCulture(langFr.IsoCode); content.PublishCulture(CultureImpact.Explicit(langDa.IsoCode, langDa.IsDefault)); - result = ((ContentService)ServiceContext.ContentService).CommitDocumentChanges(content); + result = ((ContentService)ContentService).CommitDocumentChanges(content); Assert.IsTrue(result.Success); Assert.AreEqual(PublishResultType.SuccessMixedCulture, result.Result); - content = ServiceContext.ContentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsFalse(content.IsCulturePublished(langFr.IsoCode)); Assert.IsTrue(content.IsCulturePublished(langDa.IsoCode)); } @@ -1277,10 +1259,9 @@ namespace Umbraco.Tests.Services [Test] public void Can_Publish_Content_Children() { - const int parentId = NodeDto.NodeIdSeed + 2; + var parentId = Textpage.Id; - var contentService = ServiceContext.ContentService; - var parent = contentService.GetById(parentId); + var parent = ContentService.GetById(parentId); Console.WriteLine(" " + parent.Id); const int pageSize = 500; @@ -1288,7 +1269,7 @@ namespace Umbraco.Tests.Services var total = long.MaxValue; while(page * pageSize < total) { - var descendants = contentService.GetPagedDescendants(parent.Id, page++, pageSize, out total); + var descendants = ContentService.GetPagedDescendants(parent.Id, page++, pageSize, out total); foreach (var x in descendants) Console.WriteLine(" ".Substring(0, x.Level) + x.Id); } @@ -1298,7 +1279,7 @@ namespace Umbraco.Tests.Services // publish parent & its branch // only those that are not already published // only invariant/neutral values - var parentPublished = contentService.SaveAndPublishBranch(parent, true); + var parentPublished = ContentService.SaveAndPublishBranch(parent, true); foreach (var result in parentPublished) Console.WriteLine(" ".Substring(0, result.Content.Level) + $"{result.Content.Id}: {result.Result}"); @@ -1307,26 +1288,25 @@ namespace Umbraco.Tests.Services Assert.IsTrue(parentPublished.All(x => x.Success)); Assert.IsTrue(parent.Published); - var children = contentService.GetPagedChildren(parentId, 0, 500, out var totalChildren); //we only want the first so page size, etc.. is abitrary + var children = ContentService.GetPagedChildren(parentId, 0, 500, out var totalChildren); //we only want the first so page size, etc.. is abitrary // children are published including ... that was released 5 mins ago - Assert.IsTrue(children.First(x => x.Id == NodeDto.NodeIdSeed + 4).Published); + Assert.IsTrue(children.First(x => x.Id == Subpage.Id).Published); } [Test] public void Cannot_Publish_Expired_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 4); //This Content expired 5min ago + var content = ContentService.GetById(Subpage.Id); //This Content expired 5min ago content.ContentSchedule.Add(null, DateTime.Now.AddMinutes(-5)); - contentService.Save(content); + ContentService.Save(content); - var parent = contentService.GetById(NodeDto.NodeIdSeed + 2); - var parentPublished = contentService.SaveAndPublish(parent, userId: Constants.Security.SuperUserId);//Publish root Home node to enable publishing of 'NodeDto.NodeIdSeed + 3' + var parent = ContentService.GetById(Textpage.Id); + var parentPublished = ContentService.SaveAndPublish(parent, userId: Constants.Security.SuperUserId);//Publish root Home node to enable publishing of 'Subpage.Id' // Act - var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(parentPublished.Success, Is.True); @@ -1338,16 +1318,16 @@ namespace Umbraco.Tests.Services [Test] public void Cannot_Publish_Expired_Culture() { - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var content = MockedContent.CreateBasicContent(contentType); + var content = ContentBuilder.CreateBasicContent(contentType); content.SetCultureName("Hello", "en-US"); content.ContentSchedule.Add("en-US", null, DateTime.Now.AddMinutes(-5)); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); - var published = ServiceContext.ContentService.SaveAndPublish(content, "en-US", Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, "en-US", Constants.Security.SuperUserId); Assert.IsFalse(published.Success); Assert.AreEqual(PublishResultType.FailedPublishCultureHasExpired, published.Result); @@ -1358,16 +1338,15 @@ namespace Umbraco.Tests.Services public void Cannot_Publish_Content_Awaiting_Release() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 3); + var content = ContentService.GetById(Subpage.Id); content.ContentSchedule.Add(DateTime.Now.AddHours(2), null); - contentService.Save(content, Constants.Security.SuperUserId); + ContentService.Save(content, Constants.Security.SuperUserId); - var parent = contentService.GetById(NodeDto.NodeIdSeed + 2); - var parentPublished = contentService.SaveAndPublish(parent, userId: Constants.Security.SuperUserId);//Publish root Home node to enable publishing of 'NodeDto.NodeIdSeed + 3' + var parent = ContentService.GetById(Textpage.Id); + var parentPublished = ContentService.SaveAndPublish(parent, userId: Constants.Security.SuperUserId);//Publish root Home node to enable publishing of 'Subpage.Id' // Act - var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(parentPublished.Success, Is.True); @@ -1379,16 +1358,16 @@ namespace Umbraco.Tests.Services [Test] public void Cannot_Publish_Culture_Awaiting_Release() { - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var content = MockedContent.CreateBasicContent(contentType); + var content = ContentBuilder.CreateBasicContent(contentType); content.SetCultureName("Hello", "en-US"); content.ContentSchedule.Add("en-US", DateTime.Now.AddHours(2), null); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); - var published = ServiceContext.ContentService.SaveAndPublish(content, "en-US", Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, "en-US", Constants.Security.SuperUserId); Assert.IsFalse(published.Success); Assert.AreEqual(PublishResultType.FailedPublishCultureAwaitingRelease, published.Result); @@ -1399,12 +1378,11 @@ namespace Umbraco.Tests.Services public void Cannot_Publish_Content_Where_Parent_Is_Unpublished() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.Create("Subpage with Unpublished Parent", NodeDto.NodeIdSeed + 2, "umbTextpage", Constants.Security.SuperUserId); - contentService.Save(content, Constants.Security.SuperUserId); + var content = ContentService.Create("Subpage with Unpublished Parent", Textpage.Id, "umbTextpage", Constants.Security.SuperUserId); + ContentService.Save(content, Constants.Security.SuperUserId); // Act - var published = contentService.SaveAndPublishBranch(content, true); + var published = ContentService.SaveAndPublishBranch(content, true); // Assert Assert.That(published.All(x => x.Success), Is.False); @@ -1415,11 +1393,10 @@ namespace Umbraco.Tests.Services public void Cannot_Publish_Trashed_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 5); + var content = ContentService.GetById(Trashed.Id); // Act - var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(published.Success, Is.False); @@ -1431,12 +1408,11 @@ namespace Umbraco.Tests.Services public void Can_Save_And_Publish_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", - 1, "umbTextpage", Constants.Security.SuperUserId); + var content = ContentService.Create("Home US", - 1, "umbTextpage", Constants.Security.SuperUserId); content.SetValue("author", "Barack Obama"); // Act - var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(content.HasIdentity, Is.True); @@ -1455,18 +1431,17 @@ namespace Umbraco.Tests.Services public void Can_Save_And_Publish_Content_And_Child_Without_Identity() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); + var content = ContentService.Create("Home US", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); content.SetValue("author", "Barack Obama"); // Act - var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); - var childContent = contentService.Create("Child", content.Id, "umbTextpage", Constants.Security.SuperUserId); + var published = ContentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); + var childContent = ContentService.Create("Child", content.Id, "umbTextpage", Constants.Security.SuperUserId); // Reset all identity properties childContent.Id = 0; childContent.Path = null; ((Content)childContent).ResetIdentity(); - var childPublished = contentService.SaveAndPublish(childContent, userId: Constants.Security.SuperUserId); + var childPublished = ContentService.SaveAndPublish(childContent, userId: Constants.Security.SuperUserId); // Assert Assert.That(content.HasIdentity, Is.True); @@ -1481,22 +1456,20 @@ namespace Umbraco.Tests.Services public void Can_Get_Published_Descendant_Versions() { // Arrange - var contentService = ServiceContext.ContentService; + var root = ContentService.GetById(Textpage.Id); + var rootPublished = ContentService.SaveAndPublish(root); - var root = contentService.GetById(NodeDto.NodeIdSeed + 2); - var rootPublished = contentService.SaveAndPublish(root); - - var content = contentService.GetById(NodeDto.NodeIdSeed + 4); + var content = ContentService.GetById(Subpage.Id); content.Properties["title"].SetValue(content.Properties["title"].GetValue() + " Published"); - var contentPublished = contentService.SaveAndPublish(content); + var contentPublished = ContentService.SaveAndPublish(content); var publishedVersion = content.VersionId; content.Properties["title"].SetValue(content.Properties["title"].GetValue() + " Saved"); - contentService.Save(content); + ContentService.Save(content); Assert.AreEqual(publishedVersion, content.VersionId); // Act - var publishedDescendants = ((ContentService) contentService).GetPublishedDescendants(root).ToList(); + var publishedDescendants = ContentService.GetPublishedDescendants(root).ToList(); Assert.AreNotEqual(0, publishedDescendants.Count); // Assert @@ -1516,7 +1489,7 @@ namespace Umbraco.Tests.Services Assert.That(publishedContentVersion.Properties["title"].GetValue(), Contains.Substring("Saved")); //Ensure that the latest version of the content is ok - var currentContent = contentService.GetById(NodeDto.NodeIdSeed + 4); + var currentContent = ContentService.GetById(Subpage.Id); Assert.That(currentContent.Published, Is.True); Assert.That(currentContent.Properties["title"].GetValue(published: true), Contains.Substring("Published")); Assert.That(currentContent.Properties["title"].GetValue(), Contains.Substring("Saved")); @@ -1527,12 +1500,11 @@ namespace Umbraco.Tests.Services public void Can_Save_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", - 1, "umbTextpage", Constants.Security.SuperUserId); + var content = ContentService.Create("Home US", - 1, "umbTextpage", Constants.Security.SuperUserId); content.SetValue("author", "Barack Obama"); // Act - contentService.Save(content, Constants.Security.SuperUserId); + ContentService.Save(content, Constants.Security.SuperUserId); // Assert Assert.That(content.HasIdentity, Is.True); @@ -1542,16 +1514,13 @@ namespace Umbraco.Tests.Services public void Can_Bulk_Save_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - - var contentType = contentTypeService.Get("umbTextpage"); - Content subpage = MockedContent.CreateSimpleContent(contentType, "Text Subpage 1", NodeDto.NodeIdSeed + 2); - Content subpage2 = MockedContent.CreateSimpleContent(contentType, "Text Subpage 2", NodeDto.NodeIdSeed + 2); + var contentType = ContentTypeService.Get("umbTextpage"); + var subpage = ContentBuilder.CreateSimpleContent(contentType, "Text Subpage 1", Textpage.Id); + var subpage2 = ContentBuilder.CreateSimpleContent(contentType, "Text Subpage 2", Textpage.Id); var list = new List {subpage, subpage2}; // Act - contentService.Save(list, Constants.Security.SuperUserId); + ContentService.Save(list, Constants.Security.SuperUserId); // Assert Assert.That(list.Any(x => !x.HasIdentity), Is.False); @@ -1561,11 +1530,10 @@ namespace Umbraco.Tests.Services public void Can_Bulk_Save_New_Hierarchy_Content() { // Arrange - var contentService = ServiceContext.ContentService; var hierarchy = CreateContentHierarchy().ToList(); // Act - contentService.Save(hierarchy, Constants.Security.SuperUserId); + ContentService.Save(hierarchy, Constants.Security.SuperUserId); Assert.That(hierarchy.Any(), Is.True); Assert.That(hierarchy.Any(x => x.HasIdentity == false), Is.False); @@ -1578,14 +1546,12 @@ namespace Umbraco.Tests.Services public void Can_Delete_Content_Of_Specific_ContentType() { // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = contentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); // Act - contentService.DeleteOfType(contentType.Id); - var rootContent = contentService.GetRootContent(); - var contents = contentService.GetPagedOfType(contentType.Id, 0, int.MaxValue, out var _, null); + ContentService.DeleteOfType(contentType.Id); + var rootContent = ContentService.GetRootContent(); + var contents = ContentService.GetPagedOfType(contentType.Id, 0, int.MaxValue, out var _, null); // Assert Assert.That(rootContent.Any(), Is.False); @@ -1596,12 +1562,11 @@ namespace Umbraco.Tests.Services public void Can_Delete_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 4); + var content = ContentService.GetById(Textpage.Id); // Act - contentService.Delete(content, Constants.Security.SuperUserId); - var deleted = contentService.GetById(NodeDto.NodeIdSeed + 4); + ContentService.Delete(content, Constants.Security.SuperUserId); + var deleted = ContentService.GetById(Textpage.Id); // Assert Assert.That(deleted, Is.Null); @@ -1611,11 +1576,10 @@ namespace Umbraco.Tests.Services public void Can_Move_Content_To_RecycleBin() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 3); + var content = ContentService.GetById(Textpage.Id); // Act - contentService.MoveToRecycleBin(content, Constants.Security.SuperUserId); + ContentService.MoveToRecycleBin(content, Constants.Security.SuperUserId); // Assert Assert.That(content.ParentId, Is.EqualTo(-20)); @@ -1625,19 +1589,18 @@ namespace Umbraco.Tests.Services [Test] public void Can_Move_Content_Structure_To_RecycleBin_And_Empty_RecycleBin() { - var contentService = ServiceContext.ContentService; - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); - var subsubpage = MockedContent.CreateSimpleContent(contentType, "Text Page 3", NodeDto.NodeIdSeed + 3); - contentService.Save(subsubpage, Constants.Security.SuperUserId); + var subsubpage = ContentBuilder.CreateSimpleContent(contentType, "Text Page 3", Subpage.Id); + ContentService.Save(subsubpage, Constants.Security.SuperUserId); - var content = contentService.GetById(NodeDto.NodeIdSeed + 2); + var content = ContentService.GetById(Textpage.Id); const int pageSize = 500; var page = 0; var total = long.MaxValue; var descendants = new List(); while(page * pageSize < total) - descendants.AddRange(contentService.GetPagedDescendants(content.Id, page++, pageSize, out total)); + descendants.AddRange(ContentService.GetPagedDescendants(content.Id, page++, pageSize, out total)); Assert.AreNotEqual(-20, content.ParentId); Assert.IsFalse(content.Trashed); @@ -1645,12 +1608,12 @@ namespace Umbraco.Tests.Services Assert.IsFalse(descendants.Any(x => x.Path.StartsWith("-1,-20,"))); Assert.IsFalse(descendants.Any(x => x.Trashed)); - contentService.MoveToRecycleBin(content, Constants.Security.SuperUserId); + ContentService.MoveToRecycleBin(content, Constants.Security.SuperUserId); descendants.Clear(); page = 0; while (page * pageSize < total) - descendants.AddRange(contentService.GetPagedDescendants(content.Id, page++, pageSize, out total)); + descendants.AddRange(ContentService.GetPagedDescendants(content.Id, page++, pageSize, out total)); Assert.AreEqual(-20, content.ParentId); Assert.IsTrue(content.Trashed); @@ -1658,8 +1621,8 @@ namespace Umbraco.Tests.Services Assert.IsTrue(descendants.All(x => x.Path.StartsWith("-1,-20,"))); Assert.True(descendants.All(x => x.Trashed)); - contentService.EmptyRecycleBin(Constants.Security.SuperUserId); - var trashed = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + var trashed = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); Assert.IsEmpty(trashed); } @@ -1667,11 +1630,9 @@ namespace Umbraco.Tests.Services public void Can_Empty_RecycleBin() { // Arrange - var contentService = ServiceContext.ContentService; - // Act - contentService.EmptyRecycleBin(Constants.Security.SuperUserId); - var contents = contentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents.Any(), Is.False); @@ -1681,33 +1642,35 @@ namespace Umbraco.Tests.Services public void Ensures_Permissions_Are_Retained_For_Copied_Descendants_With_Explicit_Permissions() { // Arrange - var userGroup = MockedUserGroup.CreateUserGroup("1"); - ServiceContext.UserService.Save(userGroup); + var userGroup = UserGroupBuilder.CreateUserGroup("1"); + UserService.Save(userGroup); - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); contentType.AllowedContentTypes = new List { new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias) }; - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var parentPage = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(parentPage); + var parentPage = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(parentPage); - var childPage = MockedContent.CreateSimpleContent(contentType, "child", parentPage); - ServiceContext.ContentService.Save(childPage); + var childPage = ContentBuilder.CreateSimpleContent(contentType, "child", parentPage); + ContentService.Save(childPage); //assign explicit permissions to the child - ServiceContext.ContentService.SetPermission(childPage, 'A', new[] { userGroup.Id }); + ContentService.SetPermission(childPage, 'A', new[] { userGroup.Id }); //Ok, now copy, what should happen is the childPage will retain it's own permissions - var parentPage2 = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(parentPage2); + var parentPage2 = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(parentPage2); - var copy = ServiceContext.ContentService.Copy(childPage, parentPage2.Id, false, true); + var copy = ContentService.Copy(childPage, parentPage2.Id, false, true); //get the permissions and verify - var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, copy.Path, fallbackToDefaultPermissions: true); + var permissions = UserService.GetPermissionsForPath(userGroup, copy.Path, fallbackToDefaultPermissions: true); var allPermissions = permissions.GetAllPermissions().ToArray(); Assert.AreEqual(1, allPermissions.Length); Assert.AreEqual("A", allPermissions[0]); @@ -1717,27 +1680,29 @@ namespace Umbraco.Tests.Services public void Ensures_Permissions_Are_Inherited_For_Copied_Descendants() { // Arrange - var userGroup = MockedUserGroup.CreateUserGroup("1"); - ServiceContext.UserService.Save(userGroup); + var userGroup = UserGroupBuilder.CreateUserGroup("1"); + UserService.Save(userGroup); - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id); contentType.AllowedContentTypes = new List { new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias) }; - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var parentPage = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(parentPage); - ServiceContext.ContentService.SetPermission(parentPage, 'A', new[] { userGroup.Id }); + var parentPage = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(parentPage); + ContentService.SetPermission(parentPage, 'A', new[] { userGroup.Id }); - var childPage1 = MockedContent.CreateSimpleContent(contentType, "child1", parentPage); - ServiceContext.ContentService.Save(childPage1); - var childPage2 = MockedContent.CreateSimpleContent(contentType, "child2", childPage1); - ServiceContext.ContentService.Save(childPage2); - var childPage3 = MockedContent.CreateSimpleContent(contentType, "child3", childPage2); - ServiceContext.ContentService.Save(childPage3); + var childPage1 = ContentBuilder.CreateSimpleContent(contentType, "child1", parentPage); + ContentService.Save(childPage1); + var childPage2 = ContentBuilder.CreateSimpleContent(contentType, "child2", childPage1); + ContentService.Save(childPage2); + var childPage3 = ContentBuilder.CreateSimpleContent(contentType, "child3", childPage2); + ContentService.Save(childPage3); //Verify that the children have the inherited permissions var descendants = new List(); @@ -1745,34 +1710,34 @@ namespace Umbraco.Tests.Services var page = 0; var total = long.MaxValue; while(page * pageSize < total) - descendants.AddRange(ServiceContext.ContentService.GetPagedDescendants(parentPage.Id, page++, pageSize, out total)); + descendants.AddRange(ContentService.GetPagedDescendants(parentPage.Id, page++, pageSize, out total)); Assert.AreEqual(3, descendants.Count); foreach (var descendant in descendants) { - var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true); + var permissions = UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true); var allPermissions = permissions.GetAllPermissions().ToArray(); Assert.AreEqual(1, allPermissions.Length); Assert.AreEqual("A", allPermissions[0]); } //create a new parent with a new permission structure - var parentPage2 = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(parentPage2); - ServiceContext.ContentService.SetPermission(parentPage2, 'B', new[] { userGroup.Id }); + var parentPage2 = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(parentPage2); + ContentService.SetPermission(parentPage2, 'B', new[] { userGroup.Id }); //Now copy, what should happen is the child pages will now have permissions inherited from the new parent - var copy = ServiceContext.ContentService.Copy(childPage1, parentPage2.Id, false, true); + var copy = ContentService.Copy(childPage1, parentPage2.Id, false, true); descendants.Clear(); page = 0; while (page * pageSize < total) - descendants.AddRange(ServiceContext.ContentService.GetPagedDescendants(parentPage2.Id, page++, pageSize, out total)); + descendants.AddRange(ContentService.GetPagedDescendants(parentPage2.Id, page++, pageSize, out total)); Assert.AreEqual(3, descendants.Count); foreach (var descendant in descendants) { - var permissions = ServiceContext.UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true); + var permissions = UserService.GetPermissionsForPath(userGroup, descendant.Path, fallbackToDefaultPermissions: true); var allPermissions = permissions.GetAllPermissions().ToArray(); Assert.AreEqual(1, allPermissions.Length); Assert.AreEqual("B", allPermissions[0]); @@ -1793,37 +1758,37 @@ namespace Umbraco.Tests.Services // * published & preview data // * multiple versions - var contentType = MockedContentTypes.CreateAllTypesContentType("test", "test"); - ServiceContext.ContentTypeService.Save(contentType, Constants.Security.SuperUserId); + var contentType = ContentTypeBuilder.CreateAllTypesContentType("test", "test"); + ContentTypeService.Save(contentType, Constants.Security.SuperUserId); object obj = new { tags = "[\"Hello\",\"World\"]" }; - var content1 = MockedContent.CreateBasicContent(contentType); + var content1 = ContentBuilder.CreateBasicContent(contentType); content1.PropertyValues(obj); content1.ResetDirtyProperties(false); - ServiceContext.ContentService.Save(content1, Constants.Security.SuperUserId); - Assert.IsTrue(ServiceContext.ContentService.SaveAndPublish(content1, userId: 0).Success); - var content2 = MockedContent.CreateBasicContent(contentType); + ContentService.Save(content1, Constants.Security.SuperUserId); + Assert.IsTrue(ContentService.SaveAndPublish(content1, userId: 0).Success); + var content2 = ContentBuilder.CreateBasicContent(contentType); content2.PropertyValues(obj); content2.ResetDirtyProperties(false); - ServiceContext.ContentService.Save(content2, Constants.Security.SuperUserId); - Assert.IsTrue(ServiceContext.ContentService.SaveAndPublish(content2, userId: 0).Success); + ContentService.Save(content2, Constants.Security.SuperUserId); + Assert.IsTrue(ContentService.SaveAndPublish(content2, userId: 0).Success); - var editorGroup = ServiceContext.UserService.GetUserGroupByAlias(Constants.Security.EditorGroupAlias); + var editorGroup = UserService.GetUserGroupByAlias(Constants.Security.EditorGroupAlias); editorGroup.StartContentId = content1.Id; - ServiceContext.UserService.Save(editorGroup); + UserService.Save(editorGroup); - var admin = ServiceContext.UserService.GetUserById(Constants.Security.SuperUserId); + var admin = UserService.GetUserById(Constants.Security.SuperUserId); admin.StartContentIds = new[] {content1.Id}; - ServiceContext.UserService.Save(admin); + UserService.Save(admin); - ServiceContext.RelationService.Save(new RelationType("test", "test", false, Constants.ObjectTypes.Document, Constants.ObjectTypes.Document)); - Assert.IsNotNull(ServiceContext.RelationService.Relate(content1, content2, "test")); + RelationService.Save(new RelationType("test", "test", false, Constants.ObjectTypes.Document, Constants.ObjectTypes.Document)); + Assert.IsNotNull(RelationService.Relate(content1, content2, "test")); - ServiceContext.PublicAccessService.Save(new PublicAccessEntry(content1, content2, content2, new List + PublicAccessService.Save(new PublicAccessEntry(content1, content2, content2, new List { new PublicAccessRule { @@ -1831,23 +1796,23 @@ namespace Umbraco.Tests.Services RuleValue = "test" } })); - Assert.IsTrue(ServiceContext.PublicAccessService.AddRule(content1, "test2", "test2").Success); + Assert.IsTrue(PublicAccessService.AddRule(content1, "test2", "test2").Success); - var user = ServiceContext.UserService.GetUserById(Constants.Security.SuperUserId); - var userGroup = ServiceContext.UserService.GetUserGroupByAlias(user.Groups.First().Alias); - Assert.IsNotNull(ServiceContext.NotificationService.CreateNotification(user, content1, "X")); + var user = UserService.GetUserById(Constants.Security.SuperUserId); + var userGroup = UserService.GetUserGroupByAlias(user.Groups.First().Alias); + Assert.IsNotNull(NotificationService.CreateNotification(user, content1, "X")); - ServiceContext.ContentService.SetPermission(content1, 'A', new[] { userGroup.Id }); + ContentService.SetPermission(content1, 'A', new[] { userGroup.Id }); - Assert.IsTrue(ServiceContext.DomainService.Save(new UmbracoDomain("www.test.com", "en-AU") + Assert.IsTrue(DomainService.Save(new UmbracoDomain("www.test.com", "en-AU") { RootContentId = content1.Id }).Success); // Act - ServiceContext.ContentService.MoveToRecycleBin(content1); - ServiceContext.ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); - var contents = ServiceContext.ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); + ContentService.MoveToRecycleBin(content1, Constants.Security.SuperUserId); + ContentService.EmptyRecycleBin(Constants.Security.SuperUserId); + var contents = ContentService.GetPagedContentInRecycleBin(0, int.MaxValue, out var _).ToList(); // Assert Assert.That(contents.Any(), Is.False); @@ -1857,14 +1822,13 @@ namespace Umbraco.Tests.Services public void Can_Move_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 5); + var content = ContentService.GetById(Trashed.Id); // Act - moving out of recycle bin - contentService.Move(content, NodeDto.NodeIdSeed + 2); + ContentService.Move(content, Textpage.Id); // Assert - Assert.That(content.ParentId, Is.EqualTo(NodeDto.NodeIdSeed + 2)); + Assert.That(content.ParentId, Is.EqualTo(Textpage.Id)); Assert.That(content.Trashed, Is.False); Assert.That(content.Published, Is.False); } @@ -1873,12 +1837,11 @@ namespace Umbraco.Tests.Services public void Can_Copy_Content() { // Arrange - var contentService = ServiceContext.ContentService; - var temp = contentService.GetById(NodeDto.NodeIdSeed + 4); + var temp = ContentService.GetById(Subpage.Id); // Act - var copy = contentService.Copy(temp, temp.ParentId, false, Constants.Security.SuperUserId); - var content = contentService.GetById(NodeDto.NodeIdSeed + 4); + var copy = ContentService.Copy(temp, temp.ParentId, false, Constants.Security.SuperUserId); + var content = ContentService.GetById(Subpage.Id); // Assert Assert.That(copy, Is.Not.Null); @@ -1913,18 +1876,19 @@ namespace Umbraco.Tests.Services try { - var contentService = ServiceContext.ContentService; - ContentService.Copying += copying; ContentService.Copied += copied; - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); - var content = MockedContent.CreateSimpleContent(contentType); - content.SetValue("title", "New Value"); - contentService.Save(content); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var copy = contentService.Copy(content, content.ParentId, false, Constants.Security.SuperUserId); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var content = ContentBuilder.CreateSimpleContent(contentType); + content.SetValue("title", "New Value"); + ContentService.Save(content); + + var copy = ContentService.Copy(content, content.ParentId, false, Constants.Security.SuperUserId); Assert.AreEqual("1", copy.GetValue("title")); } finally @@ -1938,23 +1902,22 @@ namespace Umbraco.Tests.Services public void Can_Copy_Recursive() { // Arrange - var contentService = ServiceContext.ContentService; - var temp = contentService.GetById(NodeDto.NodeIdSeed + 2); + var temp = ContentService.GetById(Textpage.Id); Assert.AreEqual("Home", temp.Name); - Assert.AreEqual(2, contentService.CountChildren(temp.Id)); + Assert.AreEqual(2, ContentService.CountChildren(temp.Id)); // Act - var copy = contentService.Copy(temp, temp.ParentId, false, true, Constants.Security.SuperUserId); - var content = contentService.GetById(NodeDto.NodeIdSeed + 2); + var copy = ContentService.Copy(temp, temp.ParentId, false, true, Constants.Security.SuperUserId); + var content = ContentService.GetById(Textpage.Id); // Assert Assert.That(copy, Is.Not.Null); Assert.That(copy.Id, Is.Not.EqualTo(content.Id)); Assert.AreNotSame(content, copy); - Assert.AreEqual(2, contentService.CountChildren(copy.Id)); + Assert.AreEqual(2, ContentService.CountChildren(copy.Id)); - var child = contentService.GetById(NodeDto.NodeIdSeed + 3); - var childCopy = contentService.GetPagedChildren(copy.Id, 0, 500, out var total).First(); + var child = ContentService.GetById(Subpage.Id); + var childCopy = ContentService.GetPagedChildren(copy.Id, 0, 500, out var total).First(); Assert.AreEqual(childCopy.Name, child.Name); Assert.AreNotEqual(childCopy.Id, child.Id); Assert.AreNotEqual(childCopy.Key, child.Key); @@ -1964,20 +1927,19 @@ namespace Umbraco.Tests.Services public void Can_Copy_NonRecursive() { // Arrange - var contentService = ServiceContext.ContentService; - var temp = contentService.GetById(NodeDto.NodeIdSeed + 2); + var temp = ContentService.GetById(Textpage.Id); Assert.AreEqual("Home", temp.Name); - Assert.AreEqual(2, contentService.CountChildren(temp.Id)); + Assert.AreEqual(2, ContentService.CountChildren(temp.Id)); // Act - var copy = contentService.Copy(temp, temp.ParentId, false, false, Constants.Security.SuperUserId); - var content = contentService.GetById(NodeDto.NodeIdSeed + 2); + var copy = ContentService.Copy(temp, temp.ParentId, false, false, Constants.Security.SuperUserId); + var content = ContentService.GetById(Textpage.Id); // Assert Assert.That(copy, Is.Not.Null); Assert.That(copy.Id, Is.Not.EqualTo(content.Id)); Assert.AreNotSame(content, copy); - Assert.AreEqual(0, contentService.CountChildren(copy.Id)); + Assert.AreEqual(0, ContentService.CountChildren(copy.Id)); } [Test] @@ -1985,51 +1947,50 @@ namespace Umbraco.Tests.Services { const string propAlias = "tags"; - var contentService = ServiceContext.ContentService; - // create a content type that has a 'tags' property // the property needs to support tags, else nothing works of course! - var contentType = MockedContentTypes.CreateSimpleContentType3("umbTagsPage", "TagsPage"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleTagsContentType("umbTagsPage", "TagsPage", defaultTemplateId: template.Id); contentType.Key = new Guid("78D96D30-1354-4A1E-8450-377764200C58"); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var content = MockedContent.CreateSimpleContent(contentType, "Simple Tags Page", Constants.System.Root); - content.AssignTags(PropertyEditorCollection.Value, DataTypeService, propAlias, new[] {"hello", "world"}); - contentService.Save(content); + var content = ContentBuilder.CreateSimpleContent(contentType, "Simple Tags Page", Constants.System.Root); + content.AssignTags(PropertyEditorCollection, DataTypeService, propAlias, new[] {"hello", "world"}); + ContentService.Save(content); // value has been set but no tags have been created (not published) Assert.AreEqual("[\"hello\",\"world\"]", content.GetValue(propAlias)); - var contentTags = ServiceContext.TagService.GetTagsForEntity(content.Id).ToArray(); + var contentTags = TagService.GetTagsForEntity(content.Id).ToArray(); Assert.AreEqual(0, contentTags.Length); // reloading the content yields the same result - content = (Content) contentService.GetById(content.Id); + content = (Content) ContentService.GetById(content.Id); Assert.AreEqual("[\"hello\",\"world\"]", content.GetValue(propAlias)); - contentTags = ServiceContext.TagService.GetTagsForEntity(content.Id).ToArray(); + contentTags = TagService.GetTagsForEntity(content.Id).ToArray(); Assert.AreEqual(0, contentTags.Length); // publish - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // now tags have been set (published) Assert.AreEqual("[\"hello\",\"world\"]", content.GetValue(propAlias)); - contentTags = ServiceContext.TagService.GetTagsForEntity(content.Id).ToArray(); + contentTags = TagService.GetTagsForEntity(content.Id).ToArray(); Assert.AreEqual(2, contentTags.Length); // copy - var copy = contentService.Copy(content, content.ParentId, false); + var copy = ContentService.Copy(content, content.ParentId, false); // copy is not published, so property has value, but no tags have been created Assert.AreEqual("[\"hello\",\"world\"]", copy.GetValue(propAlias)); - var copiedTags = ServiceContext.TagService.GetTagsForEntity(copy.Id).ToArray(); + var copiedTags = TagService.GetTagsForEntity(copy.Id).ToArray(); Assert.AreEqual(0, copiedTags.Length); // publish - contentService.SaveAndPublish(copy); + ContentService.SaveAndPublish(copy); // now tags have been set (published) - copiedTags = ServiceContext.TagService.GetTagsForEntity(copy.Id).ToArray(); + copiedTags = TagService.GetTagsForEntity(copy.Id).ToArray(); Assert.AreEqual(2, copiedTags.Length); Assert.AreEqual("hello", copiedTags[0].Text); @@ -2040,16 +2001,14 @@ namespace Umbraco.Tests.Services public void Can_Rollback_Version_On_Content() { // Arrange - var contentService = ServiceContext.ContentService; - - var parent = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 2); + var parent = ContentService.GetById(Textpage.Id); Assert.IsFalse(parent.Published); - ServiceContext.ContentService.SaveAndPublish(parent); // publishing parent, so Text Page 2 can be updated. + ContentService.SaveAndPublish(parent); // publishing parent, so Text Page 2 can be updated. - var content = contentService.GetById(NodeDto.NodeIdSeed + 4); + var content = ContentService.GetById(Subpage.Id); Assert.IsFalse(content.Published); - var versions = contentService.GetVersions(NodeDto.NodeIdSeed + 4).ToList(); + var versions = ContentService.GetVersions(Subpage.Id).ToList(); Assert.AreEqual(1, versions.Count); var version1 = content.VersionId; @@ -2060,13 +2019,13 @@ namespace Umbraco.Tests.Services // non published = edited Assert.IsTrue(content.Edited); - contentService.SaveAndPublish(content); // new version + ContentService.SaveAndPublish(content); // new version var version2 = content.VersionId; Assert.AreNotEqual(version1, version2); Assert.IsTrue(content.Published); Assert.IsFalse(content.Edited); - Assert.AreEqual("Francis Doe", contentService.GetById(content.Id).GetValue("author")); // version2 author is Francis + Assert.AreEqual("Francis Doe", ContentService.GetById(content.Id).GetValue("author")); // version2 author is Francis Assert.AreEqual("Text Page 2 Updated", content.Name); Assert.AreEqual("Text Page 2 Updated", content.PublishName); @@ -2076,7 +2035,7 @@ namespace Umbraco.Tests.Services // is not actually 'edited' until changes have been saved Assert.IsFalse(content.Edited); - contentService.Save(content); // just save changes + ContentService.Save(content); // just save changes Assert.IsTrue(content.Edited); Assert.AreEqual("Text Page 2 ReUpdated", content.Name); @@ -2084,13 +2043,13 @@ namespace Umbraco.Tests.Services content.Name = "Text Page 2 ReReUpdated"; - contentService.SaveAndPublish(content); // new version + ContentService.SaveAndPublish(content); // new version var version3 = content.VersionId; Assert.AreNotEqual(version2, version3); Assert.IsTrue(content.Published); Assert.IsFalse(content.Edited); - Assert.AreEqual("Jane Doe", contentService.GetById(content.Id).GetValue("author")); // version3 author is Jane + Assert.AreEqual("Jane Doe", ContentService.GetById(content.Id).GetValue("author")); // version3 author is Jane Assert.AreEqual("Text Page 2 ReReUpdated", content.Name); Assert.AreEqual("Text Page 2 ReReUpdated", content.PublishName); @@ -2101,16 +2060,16 @@ namespace Umbraco.Tests.Services // version3, third and current published version // rollback all values to version1 - var rollback = contentService.GetById(NodeDto.NodeIdSeed + 4); - var rollto = contentService.GetVersion(version1); + var rollback = ContentService.GetById(Subpage.Id); + var rollto = ContentService.GetVersion(version1); rollback.CopyFrom(rollto); rollback.Name = rollto.Name; // must do it explicitly - contentService.Save(rollback); + ContentService.Save(rollback); Assert.IsNotNull(rollback); Assert.IsTrue(rollback.Published); Assert.IsTrue(rollback.Edited); - Assert.AreEqual("Francis Doe", contentService.GetById(content.Id).GetValue("author")); // author is now Francis again + Assert.AreEqual("Francis Doe", ContentService.GetById(content.Id).GetValue("author")); // author is now Francis again Assert.AreEqual(version3, rollback.VersionId); // same version but with edits // props and name have rolled back @@ -2123,11 +2082,11 @@ namespace Umbraco.Tests.Services // rollback all values to current version // special because... current has edits... this really is equivalent to rolling back to version2 - var rollback2 = contentService.GetById(NodeDto.NodeIdSeed + 4); - var rollto2 = contentService.GetVersion(version3); + var rollback2 = ContentService.GetById(Subpage.Id); + var rollto2 = ContentService.GetVersion(version3); rollback2.CopyFrom(rollto2); rollback2.Name = rollto2.PublishName; // must do it explicitely AND must pick the publish one! - contentService.Save(rollback2); + ContentService.Save(rollback2); Assert.IsTrue(rollback2.Published); Assert.IsFalse(rollback2.Edited); // all changes cleared! @@ -2136,19 +2095,19 @@ namespace Umbraco.Tests.Services Assert.AreEqual("Text Page 2 ReReUpdated", rollback2.Name); // test rollback to self, again - content = contentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.AreEqual("Text Page 2 ReReUpdated", content.Name); Assert.AreEqual("Jane Doe", content.GetValue("author")); - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); Assert.IsFalse(content.Edited); content.Name = "Xxx"; content.SetValue("author", "Bob Doe"); - contentService.Save(content); + ContentService.Save(content); Assert.IsTrue(content.Edited); - rollto = contentService.GetVersion(content.VersionId); + rollto = ContentService.GetVersion(content.VersionId); content.CopyFrom(rollto); content.Name = rollto.PublishName; // must do it explicitely AND must pick the publish one! - contentService.Save(content); + ContentService.Save(content); Assert.IsFalse(content.Edited); Assert.AreEqual("Text Page 2 ReReUpdated", content.Name); Assert.AreEqual("Jane Doe", content.GetValue("author")); @@ -2157,18 +2116,24 @@ 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"); - ServiceContext.LocalizationService.Save(langFr); - ServiceContext.LocalizationService.Save(langDa); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr") + .Build(); + var langDa = new LanguageBuilder() + .WithCultureInfo("da") + .Build(); + LocalizationService.Save(langFr); + LocalizationService.Save(langDa); - var contentType = MockedContentTypes.CreateSimpleContentType("multi", "Multi"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("multi", "Multi", defaultTemplateId: template.Id); contentType.Key = new Guid("45FF9A70-9C5F-448D-A476-DCD23566BBF8"); contentType.Variations = ContentVariation.Culture; var p1 = contentType.PropertyTypes.First(); p1.Variations = ContentVariation.Culture; - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var page = new Content("Page", Constants.System.Root, contentType) { @@ -2179,42 +2144,47 @@ namespace Umbraco.Tests.Services Key = new Guid("D7B84CC9-14AE-4D92-A042-023767AD3304") }; - page.SetCultureName("fr1", "fr"); - page.SetCultureName("da1", "da"); - ServiceContext.ContentService.Save(page); + page.SetCultureName("fr1", langFr.IsoCode); + page.SetCultureName("da1", langDa.IsoCode); + Thread.Sleep(1); + ContentService.Save(page); var versionId0 = page.VersionId; - page.SetValue(p1.Alias, "v1fr", "fr"); - page.SetValue(p1.Alias, "v1da", "da"); - ServiceContext.ContentService.SaveAndPublish(page); + page.SetValue(p1.Alias, "v1fr", langFr.IsoCode); + page.SetValue(p1.Alias, "v1da", langDa.IsoCode); + Thread.Sleep(1); + ContentService.SaveAndPublish(page); var versionId1 = page.VersionId; - Thread.Sleep(250); + Thread.Sleep(10); - page.SetCultureName("fr2", "fr"); - page.SetValue(p1.Alias, "v2fr", "fr"); - ServiceContext.ContentService.SaveAndPublish(page, "fr"); + page.SetCultureName("fr2", langFr.IsoCode); + page.SetValue(p1.Alias, "v2fr", langFr.IsoCode); + Thread.Sleep(1); + ContentService.SaveAndPublish(page, langFr.IsoCode); var versionId2 = page.VersionId; - Thread.Sleep(250); + Thread.Sleep(10); - page.SetCultureName("da2", "da"); - page.SetValue(p1.Alias, "v2da", "da"); - ServiceContext.ContentService.SaveAndPublish(page, "da"); + page.SetCultureName("da2", langDa.IsoCode); + page.SetValue(p1.Alias, "v2da", langDa.IsoCode); + Thread.Sleep(1); + ContentService.SaveAndPublish(page, langDa.IsoCode); var versionId3 = page.VersionId; - Thread.Sleep(250); + Thread.Sleep(10); - page.SetCultureName("fr3", "fr"); - page.SetCultureName("da3", "da"); - page.SetValue(p1.Alias, "v3fr", "fr"); - page.SetValue(p1.Alias, "v3da", "da"); - ServiceContext.ContentService.SaveAndPublish(page); + page.SetCultureName("fr3", langFr.IsoCode); + page.SetCultureName("da3", langDa.IsoCode); + page.SetValue(p1.Alias, "v3fr", langFr.IsoCode); + page.SetValue(p1.Alias, "v3da", langDa.IsoCode); + Thread.Sleep(1); + ContentService.SaveAndPublish(page); var versionId4 = page.VersionId; // now get all versions - var versions = ServiceContext.ContentService.GetVersions(page.Id).ToArray(); + var versions = ContentService.GetVersions(page.Id).ToArray(); Assert.AreEqual(5, versions.Length); @@ -2234,80 +2204,83 @@ namespace Umbraco.Tests.Services Assert.AreEqual(versionId0, versions[4].VersionId); Assert.AreEqual(versionId3, versions[4].PublishedVersionId); - Assert.AreEqual("fr3", versions[4].GetPublishName("fr")); - Assert.AreEqual("fr3", versions[3].GetPublishName("fr")); - Assert.AreEqual("fr3", versions[2].GetPublishName("fr")); - Assert.AreEqual("fr3", versions[1].GetPublishName("fr")); - Assert.AreEqual("fr3", versions[0].GetPublishName("fr")); + Assert.AreEqual("fr3", versions[4].GetPublishName(langFr.IsoCode)); + Assert.AreEqual("fr3", versions[3].GetPublishName(langFr.IsoCode)); + Assert.AreEqual("fr3", versions[2].GetPublishName(langFr.IsoCode)); + Assert.AreEqual("fr3", versions[1].GetPublishName(langFr.IsoCode)); + Assert.AreEqual("fr3", versions[0].GetPublishName(langFr.IsoCode)); - Assert.AreEqual("fr1", versions[4].GetCultureName("fr")); - Assert.AreEqual("fr2", versions[3].GetCultureName("fr")); - Assert.AreEqual("fr2", versions[2].GetCultureName("fr")); - Assert.AreEqual("fr3", versions[1].GetCultureName("fr")); - Assert.AreEqual("fr3", versions[0].GetCultureName("fr")); + Assert.AreEqual("fr1", versions[4].GetCultureName(langFr.IsoCode)); + Assert.AreEqual("fr2", versions[3].GetCultureName(langFr.IsoCode)); + Assert.AreEqual("fr2", versions[2].GetCultureName(langFr.IsoCode)); + Assert.AreEqual("fr3", versions[1].GetCultureName(langFr.IsoCode)); + Assert.AreEqual("fr3", versions[0].GetCultureName(langFr.IsoCode)); - Assert.AreEqual("da3", versions[4].GetPublishName("da")); - Assert.AreEqual("da3", versions[3].GetPublishName("da")); - Assert.AreEqual("da3", versions[2].GetPublishName("da")); - Assert.AreEqual("da3", versions[1].GetPublishName("da")); - Assert.AreEqual("da3", versions[0].GetPublishName("da")); + Assert.AreEqual("da3", versions[4].GetPublishName(langDa.IsoCode)); + Assert.AreEqual("da3", versions[3].GetPublishName(langDa.IsoCode)); + Assert.AreEqual("da3", versions[2].GetPublishName(langDa.IsoCode)); + Assert.AreEqual("da3", versions[1].GetPublishName(langDa.IsoCode)); + Assert.AreEqual("da3", versions[0].GetPublishName(langDa.IsoCode)); - Assert.AreEqual("da1", versions[4].GetCultureName("da")); - Assert.AreEqual("da1", versions[3].GetCultureName("da")); - Assert.AreEqual("da2", versions[2].GetCultureName("da")); - Assert.AreEqual("da3", versions[1].GetCultureName("da")); - Assert.AreEqual("da3", versions[0].GetCultureName("da")); + Assert.AreEqual("da1", versions[4].GetCultureName(langDa.IsoCode)); + Assert.AreEqual("da1", versions[3].GetCultureName(langDa.IsoCode)); + Assert.AreEqual("da2", versions[2].GetCultureName(langDa.IsoCode)); + Assert.AreEqual("da3", versions[1].GetCultureName(langDa.IsoCode)); + Assert.AreEqual("da3", versions[0].GetCultureName(langDa.IsoCode)); // all versions have the same publish infos for (var i = 0; i < 5; i++) { Assert.AreEqual(versions[0].PublishDate, versions[i].PublishDate); - Assert.AreEqual(versions[0].GetPublishDate("fr"), versions[i].GetPublishDate("fr")); - Assert.AreEqual(versions[0].GetPublishDate("da"), versions[i].GetPublishDate("da")); + Assert.AreEqual(versions[0].GetPublishDate(langFr.IsoCode), versions[i].GetPublishDate(langFr.IsoCode)); + Assert.AreEqual(versions[0].GetPublishDate(langDa.IsoCode), versions[i].GetPublishDate(langDa.IsoCode)); } for (var i = 0; i < 5; i++) { Console.Write("[{0}] ", i); Console.WriteLine(versions[i].UpdateDate.ToString("O").Substring(11)); - Console.WriteLine(" fr: {0}", versions[i].GetUpdateDate("fr")?.ToString("O").Substring(11)); - Console.WriteLine(" da: {0}", versions[i].GetUpdateDate("da")?.ToString("O").Substring(11)); + Console.WriteLine(" fr: {0}", versions[i].GetUpdateDate(langFr.IsoCode)?.ToString("O").Substring(11)); + Console.WriteLine(" da: {0}", versions[i].GetUpdateDate(langDa.IsoCode)?.ToString("O").Substring(11)); } Console.WriteLine("-"); // for all previous versions, UpdateDate is the published date - Assert.AreEqual(versions[4].UpdateDate, versions[4].GetUpdateDate("fr")); - Assert.AreEqual(versions[4].UpdateDate, versions[4].GetUpdateDate("da")); + Assert.AreEqual(versions[4].UpdateDate, versions[4].GetUpdateDate(langFr.IsoCode)); + Assert.AreEqual(versions[4].UpdateDate, versions[4].GetUpdateDate(langDa.IsoCode)); - Assert.AreEqual(versions[3].UpdateDate, versions[3].GetUpdateDate("fr")); - Assert.AreEqual(versions[4].UpdateDate, versions[3].GetUpdateDate("da")); + Assert.AreEqual(versions[3].UpdateDate, versions[3].GetUpdateDate(langFr.IsoCode)); + Assert.AreEqual(versions[4].UpdateDate, versions[3].GetUpdateDate(langDa.IsoCode)); - Assert.AreEqual(versions[3].UpdateDate, versions[2].GetUpdateDate("fr")); - Assert.AreEqual(versions[2].UpdateDate, versions[2].GetUpdateDate("da")); + Assert.AreEqual(versions[3].UpdateDate, versions[2].GetUpdateDate(langFr.IsoCode)); + Assert.AreEqual(versions[2].UpdateDate, versions[2].GetUpdateDate(langDa.IsoCode)); // for the published version, UpdateDate is the published date - Assert.AreEqual(versions[1].UpdateDate, versions[1].GetUpdateDate("fr")); - Assert.AreEqual(versions[1].UpdateDate, versions[1].GetUpdateDate("da")); + Assert.AreEqual(versions[1].UpdateDate, versions[1].GetUpdateDate(langFr.IsoCode)); + Assert.AreEqual(versions[1].UpdateDate, versions[1].GetUpdateDate(langDa.IsoCode)); Assert.AreEqual(versions[1].PublishDate, versions[1].UpdateDate); // for the current version, things are different // UpdateDate is the date it was last saved - Assert.AreEqual(versions[0].UpdateDate, versions[0].GetUpdateDate("fr")); - Assert.AreEqual(versions[0].UpdateDate, versions[0].GetUpdateDate("da")); + Assert.AreEqual(versions[0].UpdateDate, versions[0].GetUpdateDate(langFr.IsoCode)); + Assert.AreEqual(versions[0].UpdateDate, versions[0].GetUpdateDate(langDa.IsoCode)); // so if we save again... - - page.SetCultureName("fr4", "fr"); - //page.SetCultureName("da4", "da"); - page.SetValue(p1.Alias, "v4fr", "fr"); - page.SetValue(p1.Alias, "v4da", "da"); - ServiceContext.ContentService.Save(page); + page.SetCultureName("fr4", langFr.IsoCode); + //page.SetCultureName("da4", langDa.IsoCode); + page.SetValue(p1.Alias, "v4fr", langFr.IsoCode); + page.SetValue(p1.Alias, "v4da", langDa.IsoCode); + // This sleep ensures the save is called on later ticks then the SetValue and SetCultureName. Therefore + // we showcase the currect lack of handling dirty on variants on save. When this is implemented the sleep + // helps showcase the functionality is actually working + Thread.Sleep(1); + ContentService.Save(page); var versionId5 = page.VersionId; - versions = ServiceContext.ContentService.GetVersions(page.Id).ToArray(); + versions = ContentService.GetVersions(page.Id).ToArray(); // we just update the current version Assert.AreEqual(5, versions.Length); @@ -2317,42 +2290,46 @@ namespace Umbraco.Tests.Services { Console.Write("[{0}] ", i); Console.WriteLine(versions[i].UpdateDate.ToString("O").Substring(11)); - Console.WriteLine(" fr: {0}", versions[i].GetUpdateDate("fr")?.ToString("O").Substring(11)); - Console.WriteLine(" da: {0}", versions[i].GetUpdateDate("da")?.ToString("O").Substring(11)); + Console.WriteLine(" fr: {0}", versions[i].GetUpdateDate(langFr.IsoCode)?.ToString("O").Substring(11)); + Console.WriteLine(" da: {0}", versions[i].GetUpdateDate(langDa.IsoCode)?.ToString("O").Substring(11)); } Console.WriteLine("-"); - var versionsSlim = ServiceContext.ContentService.GetVersionsSlim(page.Id, 0, 50).ToArray(); + var versionsSlim = ContentService.GetVersionsSlim(page.Id, 0, 50).ToArray(); Assert.AreEqual(5, versionsSlim.Length); for (var i = 0; i < 5; i++) { - Console.Write("[{0}] ", i); - Console.WriteLine(versionsSlim[i].UpdateDate.ToString("O").Substring(11)); - Console.WriteLine(" fr: {0}", versionsSlim[i].GetUpdateDate("fr")?.ToString("O").Substring(11)); - Console.WriteLine(" da: {0}", versionsSlim[i].GetUpdateDate("da")?.ToString("O").Substring(11)); + Console.Write("[{0}] ", i); + Console.WriteLine(versionsSlim[i].UpdateDate.Ticks); + Console.WriteLine(" fr: {0}", versionsSlim[i].GetUpdateDate(langFr.IsoCode)?.Ticks); + Console.WriteLine(" da: {0}", versionsSlim[i].GetUpdateDate(langDa.IsoCode)?.Ticks); } Console.WriteLine("-"); // what we do in the controller to get rollback versions - var versionsSlimFr = versionsSlim.Where(x => x.UpdateDate == x.GetUpdateDate("fr")).ToArray(); + var versionsSlimFr = versionsSlim.Where(x => x.UpdateDate == x.GetUpdateDate(langFr.IsoCode)).ToArray(); + + // TODO this should expect 4, but as the comment below tells we are "*not* properly track 'dirty' for culture" + // This should be changed to 4 as soon a this functionality works. Currently it is always 3 due to the sleep + // before we save versionId5 Assert.AreEqual(3, versionsSlimFr.Length); // alas, at the moment we do *not* properly track 'dirty' for cultures, meaning // that we cannot synchronize dates the way we do with publish dates - and so this // would fail - the version UpdateDate is greater than the cultures'. - //Assert.AreEqual(versions[0].UpdateDate, versions[0].GetUpdateDate("fr")); - //Assert.AreEqual(versions[0].UpdateDate, versions[0].GetUpdateDate("da")); + //Assert.AreEqual(versions[0].UpdateDate, versions[0].GetUpdateDate(langFr.IsoCode)); + //Assert.AreEqual(versions[0].UpdateDate, versions[0].GetUpdateDate(langDa.IsoCode)); // now roll french back to its very first version - page.CopyFrom(versions[4], "fr"); // only the pure FR values + page.CopyFrom(versions[4], langFr.IsoCode); // only the pure FR values page.CopyFrom(versions[4], null); // so, must explicitly do the INVARIANT values too - page.SetCultureName(versions[4].GetPublishName("fr"), "fr"); - ServiceContext.ContentService.Save(page); + page.SetCultureName(versions[4].GetPublishName(langFr.IsoCode), langFr.IsoCode); + ContentService.Save(page); // and voila, rolled back! - Assert.AreEqual(versions[4].GetPublishName("fr"), page.GetCultureName("fr")); - Assert.AreEqual(versions[4].GetValue(p1.Alias, "fr"), page.GetValue(p1.Alias, "fr")); + Assert.AreEqual(versions[4].GetPublishName(langFr.IsoCode), page.GetCultureName(langFr.IsoCode)); + Assert.AreEqual(versions[4].GetValue(p1.Alias, langFr.IsoCode), page.GetValue(p1.Alias, langFr.IsoCode)); // note that rolling back invariant values means we also rolled back... DA... at least partially // bah? @@ -2361,16 +2338,16 @@ namespace Umbraco.Tests.Services [Test] public void Can_Save_Lazy_Content() { - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); - var root = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 2); + var contentType = ContentTypeService.Get("umbTextpage"); + var root = ContentService.GetById(Textpage.Id); - var c = new Lazy(() => MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Page", root.Id)); - var c2 = new Lazy(() => MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage", c.Value.Id)); + var c = new Lazy(() => ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Page", root.Id)); + var c2 = new Lazy(() => ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage", c.Value.Id)); var list = new List> {c, c2}; using (var scope = ScopeProvider.CreateScope()) { - var repository = CreateRepository(ScopeProvider, out _); + var repository = DocumentRepository; foreach (var content in list) { @@ -2393,16 +2370,15 @@ namespace Umbraco.Tests.Services public void Can_Verify_Property_Types_On_Content() { // Arrange - var contentTypeService = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateAllTypesContentType("allDataTypes", "All DataTypes"); - contentTypeService.Save(contentType); - var contentService = ServiceContext.ContentService; - var content = MockedContent.CreateAllTypesContent(contentType, "Random Content", Constants.System.Root); - contentService.Save(content); + var contentTypeService = ContentTypeService; + var contentType = ContentTypeBuilder.CreateAllTypesContentType("allDataTypes", "All DataTypes"); + ContentTypeService.Save(contentType); + var content = ContentBuilder.CreateAllTypesContent(contentType, "Random Content", Constants.System.Root); + ContentService.Save(content); var id = content.Id; // Act - var sut = contentService.GetById(id); + var sut = ContentService.GetById(id); // Arrange Assert.That(sut.GetValue("isTrue"), Is.True); @@ -2432,76 +2408,39 @@ namespace Umbraco.Tests.Services public void Can_Delete_Previous_Versions_Not_Latest() { // Arrange - var contentService = ServiceContext.ContentService; - var content = contentService.GetById(NodeDto.NodeIdSeed + 5); + var content = ContentService.GetById(Trashed.Id); var version = content.VersionId; // Act - contentService.DeleteVersion(NodeDto.NodeIdSeed + 5, version, true, Constants.Security.SuperUserId); - var sut = contentService.GetById(NodeDto.NodeIdSeed + 5); + ContentService.DeleteVersion(Trashed.Id, version, true, Constants.Security.SuperUserId); + var sut = ContentService.GetById(Trashed.Id); // Assert Assert.That(sut.VersionId, Is.EqualTo(version)); } - [Test] - public void Ensure_Content_Xml_Created() - { - var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); - content.SetValue("author", "Barack Obama"); - - contentService.Save(content); - - using (var scope = ScopeProvider.CreateScope()) - { - Assert.IsFalse(scope.Database.Exists(content.Id)); - } - - contentService.SaveAndPublish(content); - - using (var scope = ScopeProvider.CreateScope()) - { - Assert.IsTrue(scope.Database.Exists(content.Id)); - } - } - - [Test] - public void Ensure_Preview_Xml_Created() - { - var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", Constants.System.Root, "umbTextpage", Constants.Security.SuperUserId); - content.SetValue("author", "Barack Obama"); - - contentService.Save(content); - - using (var scope = ScopeProvider.CreateScope()) - { - Assert.IsTrue(scope.Database.SingleOrDefault("WHERE nodeId=@nodeId", new{nodeId = content.Id}) != null); - } - } - [Test] public void Can_Get_Paged_Children() { - var service = ServiceContext.ContentService; // Start by cleaning the "db" - var umbTextPage = service.GetById(new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0")); - service.Delete(umbTextPage); + var umbTextPage = ContentService.GetById(new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0")); + ContentService.Delete(umbTextPage, Constants.Security.SuperUserId); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); - for (int i = 0; i < 10; i++) + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + for (var i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(c1); } - long total; - var entities = service.GetPagedChildren(Constants.System.Root, 0, 6, out total).ToArray(); + var entities = ContentService.GetPagedChildren(Constants.System.Root, 0, 6, out var total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); - entities = service.GetPagedChildren(Constants.System.Root, 1, 6, out total).ToArray(); + entities = ContentService.GetPagedChildren(Constants.System.Root, 1, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); } @@ -2509,42 +2448,43 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_Paged_Children_Dont_Get_Descendants() { - var service = ServiceContext.ContentService; // Start by cleaning the "db" - var umbTextPage = service.GetById(new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0")); - service.Delete(umbTextPage); + var umbTextPage = ContentService.GetById(new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0")); + ContentService.Delete(umbTextPage, Constants.Security.SuperUserId); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); // only add 9 as we also add a content with children - for (int i = 0; i < 9; i++) + for (var i = 0; i < 9; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(c1); } - var willHaveChildren = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(willHaveChildren); - for (int i = 0; i < 10; i++) + var willHaveChildren = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(willHaveChildren); + for (var i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType, "Content" + i, willHaveChildren.Id); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType, "Content" + i, willHaveChildren.Id); + ContentService.Save(c1); } - long total; // children in root including the folder - not the descendants in the folder - var entities = service.GetPagedChildren(Constants.System.Root, 0, 6, out total).ToArray(); + var entities = ContentService.GetPagedChildren(Constants.System.Root, 0, 6, out var total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); - entities = service.GetPagedChildren(Constants.System.Root, 1, 6, out total).ToArray(); + entities = ContentService.GetPagedChildren(Constants.System.Root, 1, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); // children in folder - entities = service.GetPagedChildren(willHaveChildren.Id, 0, 6, out total).ToArray(); + entities = ContentService.GetPagedChildren(willHaveChildren.Id, 0, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); - entities = service.GetPagedChildren(willHaveChildren.Id, 1, 6, out total).ToArray(); + entities = ContentService.GetPagedChildren(willHaveChildren.Id, 1, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); } @@ -2566,49 +2506,48 @@ namespace Umbraco.Tests.Services contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "content" }); contentType.SetDefaultTemplate(new Template(ShortStringHelper, "Textpage", "textpage")); - ServiceContext.FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! - ServiceContext.ContentTypeService.Save(contentType); + FileService.SaveTemplate(contentType.DefaultTemplate); // else, FK violation on contentType! + ContentTypeService.Save(contentType); - var contentService = ServiceContext.ContentService; - var content = contentService.Create("foo", Constants.System.Root, "foo"); - contentService.Save(content); + var content = ContentService.Create("foo", Constants.System.Root, "foo"); + ContentService.Save(content); Assert.IsFalse(content.Published); Assert.IsTrue(content.Edited); - content = contentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsFalse(content.Published); Assert.IsTrue(content.Edited); content.SetValue("title", "foo"); Assert.IsTrue(content.Edited); - contentService.Save(content); + ContentService.Save(content); Assert.IsFalse(content.Published); Assert.IsTrue(content.Edited); - content = contentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsFalse(content.Published); Assert.IsTrue(content.Edited); - var versions = contentService.GetVersions(content.Id); + var versions = ContentService.GetVersions(content.Id); Assert.AreEqual(1, versions.Count()); // publish content // becomes Published, !Edited // creates a new version // can get published property values - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); Assert.IsTrue(content.Published); Assert.IsFalse(content.Edited); - content = contentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsTrue(content.Published); Assert.IsFalse(content.Edited); - versions = contentService.GetVersions(content.Id); + versions = ContentService.GetVersions(content.Id); Assert.AreEqual(2, versions.Count()); Assert.AreEqual("foo", content.GetValue("title", published: true)); @@ -2616,7 +2555,7 @@ namespace Umbraco.Tests.Services // unpublish content // becomes !Published, Edited - contentService.Unpublish(content); + ContentService.Unpublish(content); Assert.IsFalse(content.Published); Assert.IsTrue(content.Edited); @@ -2627,7 +2566,7 @@ namespace Umbraco.Tests.Services var vpk = ((Content) content).VersionId; var ppk = ((Content) content).PublishedVersionId; - content = contentService.GetById(content.Id); + content = ContentService.GetById(content.Id); Assert.IsFalse(content.Published); Assert.IsTrue(content.Edited); @@ -2644,14 +2583,14 @@ namespace Umbraco.Tests.Services Assert.AreEqual("foo", content.GetValue("title", published: true)); // still there Assert.AreEqual("foo", content.GetValue("title")); - versions = contentService.GetVersions(content.Id); + versions = ContentService.GetVersions(content.Id); Assert.AreEqual(2, versions.Count()); // ah - we have a problem here - since we're not published we don't have published values // and therefore we cannot "just" republish the content - we need to publish some values // so... that's not really an option // - //contentService.SaveAndPublish(content); + //ContentService.SaveAndPublish(content); // FIXME: what shall we do of all this? /* @@ -2659,50 +2598,54 @@ namespace Umbraco.Tests.Services // what if it never was published? // what if it has changes? // do we want to "publish" only some variants, or the entire content? - contentService.Publish(content); + ContentService.Publish(content); Assert.IsTrue(content.Published); Assert.IsFalse(content.Edited); // FIXME: should it be 2 or 3 - versions = contentService.GetVersions(content.Id); + versions = ContentService.GetVersions(content.Id); Assert.AreEqual(2, versions.Count()); // FIXME: now test rollbacks - var version = contentService.GetByVersion(content.Id); // test that it gets a version - should be GetVersion - var previousVersion = contentService.GetVersions(content.Id).Skip(1).FirstOrDefault(); // need an optimized way to do this + var version = ContentService.GetByVersion(content.Id); // test that it gets a version - should be GetVersion + var previousVersion = ContentService.GetVersions(content.Id).Skip(1).FirstOrDefault(); // need an optimized way to do this content.CopyValues(version); // copies the edited value - always content.Template = version.Template; content.Name = version.Name; - contentService.Save(content); // this is effectively a rollback? - contentService.Rollback(content); // just kill the method and offer options on values + template + name... + ContentService.Save(content); // this is effectively a rollback? + ContentService.Rollback(content); // just kill the method and offer options on values + template + name... */ } [Test] public void Ensure_Invariant_Name() { - var languageService = ServiceContext.LocalizationService; + var languageService = LocalizationService; - var langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var langUk = new LanguageBuilder() + .WithCultureInfo("en-GB") + .WithIsDefault(true) + .Build(); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); languageService.Save(langFr); languageService.Save(langUk); - var contentTypeService = ServiceContext.ContentTypeService; + var contentTypeService = ContentTypeService; - var contentType = contentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); contentType.Variations = ContentVariation.Culture; contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Nvarchar, "prop") { Variations = ContentVariation.Culture }); - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var contentService = ServiceContext.ContentService; var content = new Content(null, Constants.System.Root, contentType); content.SetCultureName("name-us", langUk.IsoCode); content.SetCultureName("name-fr", langFr.IsoCode); - contentService.Save(content); + ContentService.Save(content); //the name will be set to the default culture variant name Assert.AreEqual("name-us", content.Name); @@ -2710,43 +2653,46 @@ namespace Umbraco.Tests.Services // FIXME: should we always sync the invariant name even on update? see EnsureInvariantNameValues ////updating the default culture variant name should also update the invariant name so they stay in sync //content.SetName("name-us-2", langUk.IsoCode); - //contentService.Save(content); + //ContentService.Save(content); //Assert.AreEqual("name-us-2", content.Name); } [Test] public void Ensure_Unique_Culture_Names() { - var languageService = ServiceContext.LocalizationService; + var languageService = LocalizationService; - var langUk = new Language(TestObjects.GetGlobalSettings(), "en-GB") { IsDefault = true }; - var langFr = new Language(TestObjects.GetGlobalSettings(), "fr-FR"); + var langUk = new LanguageBuilder() + .WithCultureInfo("en-GB") + .WithIsDefault(true) + .Build(); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); languageService.Save(langFr); languageService.Save(langUk); - var contentTypeService = ServiceContext.ContentTypeService; + var contentTypeService = ContentTypeService; - var contentType = contentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); contentType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); - - var contentService = ServiceContext.ContentService; + ContentTypeService.Save(contentType); var content = new Content(null, Constants.System.Root, contentType); content.SetCultureName("root", langUk.IsoCode); - contentService.Save(content); + ContentService.Save(content); for (var i = 0; i < 5; i++) { var child = new Content(null, content, contentType); child.SetCultureName("child", langUk.IsoCode); - contentService.Save(child); + ContentService.Save(child); Assert.AreEqual("child" + (i == 0 ? "" : " (" + i + ")"), child.GetCultureName(langUk.IsoCode)); //Save it again to ensure that the unique check is not performed again against it's own name - contentService.Save(child); + ContentService.Save(child); Assert.AreEqual("child" + (i == 0 ? "" : " (" + i + ")"), child.GetCultureName(langUk.IsoCode)); } } @@ -2754,23 +2700,29 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_Paged_Children_WithFilterAndOrder() { - var languageService = ServiceContext.LocalizationService; + var languageService = 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 LanguageBuilder() + .WithCultureInfo("en-GB") + .WithIsDefault(true) + .WithIsMandatory(true) + .Build(); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); + var langDa = new LanguageBuilder() + .WithCultureInfo("da-DK") + .Build(); languageService.Save(langFr); languageService.Save(langUk); languageService.Save(langDa); - var contentTypeService = ServiceContext.ContentTypeService; + var contentTypeService = ContentTypeService; - var contentType = contentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); contentType.Variations = ContentVariation.Culture; - contentTypeService.Save(contentType); - - var contentService = ServiceContext.ContentService; + ContentTypeService.Save(contentType); var o = new[] { 2, 1, 3, 0, 4 }; // randomly different for (var i = 0; i < 5; i++) @@ -2779,17 +2731,17 @@ namespace Umbraco.Tests.Services contentA.SetCultureName("contentA" + i + "uk", langUk.IsoCode); contentA.SetCultureName("contentA" + o[i] + "fr", langFr.IsoCode); contentA.SetCultureName("contentX" + i + "da", langDa.IsoCode); - contentService.Save(contentA); + ContentService.Save(contentA); var contentB = new Content(null, Constants.System.Root, contentType); contentB.SetCultureName("contentB" + i + "uk", langUk.IsoCode); contentB.SetCultureName("contentB" + o[i] + "fr", langFr.IsoCode); contentB.SetCultureName("contentX" + i + "da", langDa.IsoCode); - contentService.Save(contentB); + ContentService.Save(contentB); } // get all - var list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out var total).ToList(); + var list = ContentService.GetPagedChildren(Constants.System.Root, 0, 100, out var total).ToList(); Console.WriteLine("ALL"); WriteList(list); @@ -2798,17 +2750,19 @@ namespace Umbraco.Tests.Services Assert.AreEqual(11, total); Assert.AreEqual(11, list.Count); + var sqlContext = GetRequiredService(); + // filter - list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, - SqlContext.Query().Where(x => x.Name.Contains("contentX")), + list = ContentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, + sqlContext.Query().Where(x => x.Name.Contains("contentX")), Ordering.By("name", culture: langFr.IsoCode)).ToList(); Assert.AreEqual(0, total); Assert.AreEqual(0, list.Count); // filter - list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, - SqlContext.Query().Where(x => x.Name.Contains("contentX")), + list = ContentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, + sqlContext.Query().Where(x => x.Name.Contains("contentX")), Ordering.By("name", culture: langDa.IsoCode)).ToList(); Console.WriteLine("FILTER BY NAME da:'contentX'"); @@ -2818,8 +2772,8 @@ namespace Umbraco.Tests.Services Assert.AreEqual(10, list.Count); // filter - list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, - SqlContext.Query().Where(x => x.Name.Contains("contentA")), + list = ContentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, + sqlContext.Query().Where(x => x.Name.Contains("contentA")), Ordering.By("name", culture: langFr.IsoCode)).ToList(); Console.WriteLine("FILTER BY NAME fr:'contentA', ORDER ASC"); @@ -2831,8 +2785,8 @@ namespace Umbraco.Tests.Services for (var i = 0; i < 5; i++) Assert.AreEqual("contentA" + i + "fr", list[i].GetCultureName(langFr.IsoCode)); - list = contentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, - SqlContext.Query().Where(x => x.Name.Contains("contentA")), + list = ContentService.GetPagedChildren(Constants.System.Root, 0, 100, out total, + sqlContext.Query().Where(x => x.Name.Contains("contentA")), Ordering.By("name", direction: Direction.Descending, culture: langFr.IsoCode)).ToList(); Console.WriteLine("FILTER BY NAME fr:'contentA', ORDER DESC"); @@ -2855,35 +2809,41 @@ namespace Umbraco.Tests.Services [Test] public void Can_SaveRead_Variations() { - 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 languageService = LocalizationService; + var langPt = new LanguageBuilder() + .WithCultureInfo("pt-PT") + .WithIsDefault(true) + .Build(); + var langFr = new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); + var langUk = new LanguageBuilder() + .WithCultureInfo("en-GB") + .Build(); + var langDe = new LanguageBuilder() + .WithCultureInfo("de-DE") + .Build(); languageService.Save(langFr); languageService.Save(langUk); languageService.Save(langDe); - var contentTypeService = ServiceContext.ContentTypeService; + var contentTypeService = ContentTypeService; - var contentType = contentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); contentType.Variations = ContentVariation.Culture; contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Nvarchar, "prop") { Variations = ContentVariation.Culture }); // FIXME: add test w/ an invariant prop - contentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var contentService = ServiceContext.ContentService; - var content = contentService.Create("Home US", Constants.System.Root, "umbTextpage"); + var content = ContentService.Create("Home US", Constants.System.Root, "umbTextpage"); // creating content with a name but no culture - will set the invariant name // but, because that content is variant, as soon as we save, we'll need to // replace the invariant name with whatever we have in cultures - always // // in fact, that would throw, because there is no name - //contentService.Save(content); + //ContentService.Save(content); // act @@ -2892,12 +2852,12 @@ namespace Umbraco.Tests.Services content.SetValue("prop", "value-uk1", langUk.IsoCode); content.SetCultureName("name-fr", langFr.IsoCode); // and then we can save content.SetCultureName("name-uk", langUk.IsoCode); - contentService.Save(content); + ContentService.Save(content); // content has been saved, // it has names, but no publishNames, and no published cultures - var content2 = contentService.GetById(content.Id); + var content2 = ContentService.GetById(content.Id); Assert.AreEqual("name-fr", content2.Name); // got the default culture name when saved Assert.AreEqual("name-fr", content2.GetCultureName(langFr.IsoCode)); @@ -2926,13 +2886,13 @@ namespace Umbraco.Tests.Services // act - contentService.SaveAndPublish(content, new[]{ langFr.IsoCode, langUk.IsoCode }); + ContentService.SaveAndPublish(content, new[]{ langFr.IsoCode, langUk.IsoCode }); // both FR and UK have been published, // and content has been published, // it has names, publishNames, and published cultures - content2 = contentService.GetById(content.Id); + content2 = ContentService.GetById(content.Id); Assert.AreEqual("name-fr", content2.Name); // got the default culture name when saved Assert.AreEqual("name-fr", content2.GetCultureName(langFr.IsoCode)); @@ -2971,11 +2931,11 @@ namespace Umbraco.Tests.Services // act - contentService.SaveAndPublish(content); + ContentService.SaveAndPublish(content); // now it has publish name for invariant neutral - content2 = contentService.GetById(content.Id); + content2 = ContentService.GetById(content.Id); Assert.AreEqual("name-fr", content2.PublishName); @@ -2988,12 +2948,12 @@ namespace Umbraco.Tests.Services content.SetValue("author", "Barack Obama2"); content.SetValue("prop", "value-fr2", langFr.IsoCode); content.SetValue("prop", "value-uk2", langUk.IsoCode); - contentService.Save(content); + ContentService.Save(content); // content has been saved, // it has updated names, unchanged publishNames, and published cultures - content2 = contentService.GetById(content.Id); + content2 = ContentService.GetById(content.Id); Assert.AreEqual("name-fr2", content2.Name); // got the default culture name when saved Assert.AreEqual("name-fr2", content2.GetCultureName(langFr.IsoCode)); @@ -3030,13 +2990,13 @@ namespace Umbraco.Tests.Services // act // cannot just 'save' since we are changing what's published! - contentService.Unpublish(content, langFr.IsoCode); + ContentService.Unpublish(content, langFr.IsoCode); // content has been published, // the french culture is gone // (only if french is not mandatory, else everything would be gone!) - content2 = contentService.GetById(content.Id); + content2 = ContentService.GetById(content.Id); Assert.AreEqual("name-fr2", content2.Name); // got the default culture name when saved Assert.AreEqual("name-fr2", content2.GetCultureName(langFr.IsoCode)); @@ -3072,7 +3032,7 @@ namespace Umbraco.Tests.Services // act - contentService.Unpublish(content); + ContentService.Unpublish(content); // content has been unpublished, // but properties, names, etc. retain their 'published' values so the content @@ -3084,7 +3044,7 @@ namespace Umbraco.Tests.Services // values even though the content is not published - hence many things being // non-null or true below - always check against content.Published to be sure - content2 = contentService.GetById(content.Id); + content2 = ContentService.GetById(content.Id); Assert.IsFalse(content2.Published); @@ -3123,12 +3083,12 @@ namespace Umbraco.Tests.Services //TODO: This is using an internal API - the test can't pass without this but we want to keep the test here // will need stephane to have a look at this test at some stage since there is a lot of logic here that we // want to keep on testing but don't need the public API to do these more complicated things. - ((ContentService)contentService).CommitDocumentChanges(content); + ContentService.CommitDocumentChanges(content); // content has been re-published, // everything is back to what it was before being unpublished - content2 = contentService.GetById(content.Id); + content2 = ContentService.GetById(content.Id); Assert.IsTrue(content2.Published); @@ -3163,9 +3123,9 @@ namespace Umbraco.Tests.Services // act - contentService.SaveAndPublish(content, langUk.IsoCode); + ContentService.SaveAndPublish(content, langUk.IsoCode); - content2 = contentService.GetById(content.Id); + content2 = ContentService.GetById(content.Id); // no change AssertPerCulture(content, (x, c) => x.IsCultureAvailable(c), (langFr, true), (langUk, true), (langDe, false)); @@ -3186,9 +3146,9 @@ namespace Umbraco.Tests.Services // act content.SetCultureName("name-uk3", langUk.IsoCode); - contentService.Save(content); + ContentService.Save(content); - content2 = contentService.GetById(content.Id); + content2 = ContentService.GetById(content.Id); // note that the 'edited' flags only change once saved - not immediately // but they change, on what's being saved, and when getting it back @@ -3210,14 +3170,14 @@ namespace Umbraco.Tests.Services private IEnumerable CreateContentHierarchy() { - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); - var root = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 2); + var contentType = ContentTypeService.Get("umbTextpage"); + var root = ContentService.GetById(Textpage.Id); var list = new List(); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { - var content = MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Page " + i, root); + var content = ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Page " + i, root); list.Add(content); list.AddRange(CreateChildrenOf(contentType, content, 4)); @@ -3231,9 +3191,9 @@ namespace Umbraco.Tests.Services private IEnumerable CreateChildrenOf(IContentType contentType, IContent content, int depth) { var list = new List(); - for (int i = 0; i < depth; i++) + for (var i = 0; i < depth; i++) { - var c = MockedContent.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage " + i, content); + var c = ContentBuilder.CreateSimpleContent(contentType, "Hierarchy Simple Text Subpage " + i, content); list.Add(c); Debug.Print("Created: 'Hierarchy Simple Text Subpage {0}' - Depth: {1}", i, depth); @@ -3241,33 +3201,21 @@ namespace Umbraco.Tests.Services return list; } - private DocumentRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) - { - var accessor = (IScopeAccessor) provider; - 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()); - contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); - var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); - var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); - var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); - return repository; - } - 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"); - ServiceContext.LocalizationService.Save(langFr); - ServiceContext.LocalizationService.Save(langUk); + langUk = (Language)new LanguageBuilder() + .WithCultureInfo("en-GB") + .WithIsDefault(true) + .Build(); + langFr = (Language)new LanguageBuilder() + .WithCultureInfo("fr-FR") + .Build(); + LocalizationService.Save(langFr); + LocalizationService.Save(langUk); - contentType = MockedContentTypes.CreateBasicContentType(); + contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); } private IContent CreateEnglishAndFrenchDocument(out Language langUk, out Language langFr, out ContentType contentType) diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Services/ContentTypeServiceTests.cs similarity index 64% rename from src/Umbraco.Tests/Services/ContentTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/ContentTypeServiceTests.cs index 1b48db7328..e7a3f9d066 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/ContentTypeServiceTests.cs @@ -1,33 +1,34 @@ -using NUnit.Framework; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -using Umbraco.Tests.Scoping; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] - [Category("Slow")] - [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] - public class ContentTypeServiceTests : TestWithSomeContentBase + public class ContentTypeServiceTests : UmbracoIntegrationTest { + private IFileService FileService => GetRequiredService(); + private ContentService ContentService => (ContentService)GetRequiredService(); + private IDataTypeService DataTypeService => GetRequiredService(); + private ContentTypeService ContentTypeService => (ContentTypeService)GetRequiredService(); + [Test] public void CanSaveAndGetIsElement() { //create content type with a property type that varies by culture - IContentType contentType = MockedContentTypes.CreateBasicContentType(); + IContentType contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = ContentVariation.Nothing; var contentCollection = new PropertyTypeCollection(true); contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext) @@ -41,46 +42,47 @@ namespace Umbraco.Tests.Services Variations = ContentVariation.Nothing }); contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - contentType = ServiceContext.ContentTypeService.Get(contentType.Id); + contentType = ContentTypeService.Get(contentType.Id); Assert.IsFalse(contentType.IsElement); contentType.IsElement = true; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - contentType = ServiceContext.ContentTypeService.Get(contentType.Id); + contentType = ContentTypeService.Get(contentType.Id); Assert.IsTrue(contentType.IsElement); } - - [Test] public void Deleting_Content_Type_With_Hierarchy_Of_Content_Items_Moves_Orphaned_Content_To_Recycle_Bin() { - IContentType contentType1 = MockedContentTypes.CreateSimpleContentType("test1", "Test1"); - ServiceContext.FileService.SaveTemplate(contentType1.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType1); - IContentType contentType2 = MockedContentTypes.CreateSimpleContentType("test2", "Test2"); - ServiceContext.FileService.SaveTemplate(contentType2.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType2); - IContentType contentType3 = MockedContentTypes.CreateSimpleContentType("test3", "Test3"); - ServiceContext.FileService.SaveTemplate(contentType3.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType3); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + IContentType contentType1 = ContentTypeBuilder.CreateSimpleContentType("test1", "Test1", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType1.DefaultTemplate); + ContentTypeService.Save(contentType1); + IContentType contentType2 = ContentTypeBuilder.CreateSimpleContentType("test2", "Test2", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType2.DefaultTemplate); + ContentTypeService.Save(contentType2); + IContentType contentType3 = ContentTypeBuilder.CreateSimpleContentType("test3", "Test3", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType3.DefaultTemplate); + ContentTypeService.Save(contentType3); var contentTypes = new[] { contentType1, contentType2, contentType3 }; var parentId = -1; var ids = new List(); - for (int i = 0; i < 2; i++) + for (var i = 0; i < 2; i++) { for (var index = 0; index < contentTypes.Length; index++) { var contentType = contentTypes[index]; - var contentItem = MockedContent.CreateSimpleContent(contentType, "MyName_" + index + "_" + i, parentId); - ServiceContext.ContentService.Save(contentItem); - ServiceContext.ContentService.SaveAndPublish(contentItem); + var contentItem = ContentBuilder.CreateSimpleContent(contentType, "MyName_" + index + "_" + i, parentId); + ContentService.Save(contentItem); + ContentService.SaveAndPublish(contentItem); parentId = contentItem.Id; ids.Add(contentItem.Id); @@ -88,9 +90,9 @@ namespace Umbraco.Tests.Services } //delete the first content type, all other content of different content types should be in the recycle bin - ServiceContext.ContentTypeService.Delete(contentTypes[0]); + ContentTypeService.Delete(contentTypes[0]); - var found = ServiceContext.ContentService.GetByIds(ids); + var found = ContentService.GetByIds(ids); Assert.AreEqual(4, found.Count()); foreach (var content in found) @@ -106,34 +108,37 @@ namespace Umbraco.Tests.Services try { - IContentType contentType1 = MockedContentTypes.CreateSimpleContentType("test1", "Test1"); - ServiceContext.FileService.SaveTemplate(contentType1.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType1); - IContentType contentType2 = MockedContentTypes.CreateSimpleContentType("test2", "Test2"); - ServiceContext.FileService.SaveTemplate(contentType2.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType2); - IContentType contentType3 = MockedContentTypes.CreateSimpleContentType("test3", "Test3"); - ServiceContext.FileService.SaveTemplate(contentType3.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType3); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + IContentType contentType1 = ContentTypeBuilder.CreateSimpleContentType("test1", "Test1", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType1.DefaultTemplate); + ContentTypeService.Save(contentType1); + IContentType contentType2 = ContentTypeBuilder.CreateSimpleContentType("test2", "Test2", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType2.DefaultTemplate); + ContentTypeService.Save(contentType2); + IContentType contentType3 = ContentTypeBuilder.CreateSimpleContentType("test3", "Test3", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType3.DefaultTemplate); + ContentTypeService.Save(contentType3); var contentTypes = new[] { contentType1, contentType2, contentType3 }; var parentId = -1; - for (int i = 0; i < 2; i++) + for (var i = 0; i < 2; i++) { for (var index = 0; index < contentTypes.Length; index++) { var contentType = contentTypes[index]; - var contentItem = MockedContent.CreateSimpleContent(contentType, "MyName_" + index + "_" + i, parentId); - ServiceContext.ContentService.Save(contentItem); - ServiceContext.ContentService.SaveAndPublish(contentItem); + var contentItem = ContentBuilder.CreateSimpleContent(contentType, "MyName_" + index + "_" + i, parentId); + ContentService.Save(contentItem); + ContentService.SaveAndPublish(contentItem); parentId = contentItem.Id; } } foreach (var contentType in contentTypes.Reverse()) { - ServiceContext.ContentTypeService.Delete(contentType); + ContentTypeService.Delete(contentType); } } finally @@ -149,32 +154,35 @@ namespace Umbraco.Tests.Services try { - IContentType contentType1 = MockedContentTypes.CreateSimpleContentType("test1", "Test1"); - ServiceContext.FileService.SaveTemplate(contentType1.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType1); - IContentType contentType2 = MockedContentTypes.CreateSimpleContentType("test2", "Test2"); - ServiceContext.FileService.SaveTemplate(contentType2.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType2); - IContentType contentType3 = MockedContentTypes.CreateSimpleContentType("test3", "Test3"); - ServiceContext.FileService.SaveTemplate(contentType3.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType3); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var root = MockedContent.CreateSimpleContent(contentType1, "Root", -1); - ServiceContext.ContentService.Save(root); - ServiceContext.ContentService.SaveAndPublish(root); + IContentType contentType1 = ContentTypeBuilder.CreateSimpleContentType("test1", "Test1", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType1.DefaultTemplate); + ContentTypeService.Save(contentType1); + IContentType contentType2 = ContentTypeBuilder.CreateSimpleContentType("test2", "Test2", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType2.DefaultTemplate); + ContentTypeService.Save(contentType2); + IContentType contentType3 = ContentTypeBuilder.CreateSimpleContentType("test3", "Test3", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType3.DefaultTemplate); + ContentTypeService.Save(contentType3); - var level1 = MockedContent.CreateSimpleContent(contentType2, "L1", root.Id); - ServiceContext.ContentService.Save(level1); - ServiceContext.ContentService.SaveAndPublish(level1); + var root = ContentBuilder.CreateSimpleContent(contentType1, "Root", -1); + ContentService.Save(root); + ContentService.SaveAndPublish(root); - for (int i = 0; i < 2; i++) + var level1 = ContentBuilder.CreateSimpleContent(contentType2, "L1", root.Id); + ContentService.Save(level1); + ContentService.SaveAndPublish(level1); + + for (var i = 0; i < 2; i++) { - var level3 = MockedContent.CreateSimpleContent(contentType3, "L2" + i, level1.Id); - ServiceContext.ContentService.Save(level3); - ServiceContext.ContentService.SaveAndPublish(level3); + var level3 = ContentBuilder.CreateSimpleContent(contentType3, "L2" + i, level1.Id); + ContentService.Save(level3); + ContentService.SaveAndPublish(level3); } - ServiceContext.ContentTypeService.Delete(contentType1); + ContentTypeService.Delete(contentType1); } finally { @@ -187,7 +195,7 @@ namespace Umbraco.Tests.Services foreach (var item in e.MoveInfoCollection) { //if this item doesn't exist then Fail! - var exists = ServiceContext.ContentService.GetById(item.Entity.Id); + var exists = ContentService.GetById(item.Entity.Id); if (exists == null) Assert.Fail("The item doesn't exist"); } @@ -196,142 +204,31 @@ namespace Umbraco.Tests.Services [Test] public void Deleting_PropertyType_Removes_The_Property_From_Content() { - IContentType contentType1 = MockedContentTypes.CreateTextPageContentType("test1", "Test1"); - ServiceContext.FileService.SaveTemplate(contentType1.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType1); - IContent contentItem = MockedContent.CreateTextpageContent(contentType1, "Testing", -1); - ServiceContext.ContentService.SaveAndPublish(contentItem); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + IContentType contentType1 = ContentTypeBuilder.CreateTextPageContentType("test1", "Test1", defaultTemplateId: template.Id); + FileService.SaveTemplate(contentType1.DefaultTemplate); + ContentTypeService.Save(contentType1); + IContent contentItem = ContentBuilder.CreateTextpageContent(contentType1, "Testing", -1); + ContentService.SaveAndPublish(contentItem); var initProps = contentItem.Properties.Count; //remove a property contentType1.RemovePropertyType(contentType1.PropertyTypes.First().Alias); - ServiceContext.ContentTypeService.Save(contentType1); + ContentTypeService.Save(contentType1); //re-load it from the db - contentItem = ServiceContext.ContentService.GetById(contentItem.Id); + contentItem = ContentService.GetById(contentItem.Id); Assert.AreEqual(initProps - 1, contentItem.Properties.Count); } - [Test] - public void Rebuild_Content_Xml_On_Alias_Change() - { - var contentType1 = MockedContentTypes.CreateTextPageContentType("test1", "Test1"); - ServiceContext.FileService.SaveTemplate(contentType1.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType1); - - var contentType2 = MockedContentTypes.CreateTextPageContentType("test2", "Test2"); - ServiceContext.FileService.SaveTemplate(contentType2.DefaultTemplate); - ServiceContext.ContentTypeService.Save(contentType2); - - var contentItems1 = MockedContent.CreateTextpageContent(contentType1, -1, 10).ToArray(); - foreach (var x in contentItems1) - { - ServiceContext.ContentService.SaveAndPublish(x); - } - - var contentItems2 = MockedContent.CreateTextpageContent(contentType2, -1, 5).ToArray(); - foreach (var x in contentItems2) - { - ServiceContext.ContentService.SaveAndPublish(x); - } - - // make sure we have everything - using (var scope = ScopeProvider.CreateScope()) - { - foreach (var c in contentItems1) - { - var xml = scope.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsTrue(xml.Xml.StartsWith("("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsTrue(xml.Xml.StartsWith("("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsTrue(xml.Xml.StartsWith("("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsTrue(xml.Xml.StartsWith(""; - - using (var scope = ScopeProvider.CreateScope()) - { - foreach (var c in contentItems1) - { - var xml = scope.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsTrue(xml.Xml.Contains(elementToMatch)); //verify that it is there before we remove the property - } - - scope.Complete(); - } - - //remove a property - contentType1.RemovePropertyType(contentType1.PropertyTypes.First().Alias); - ServiceContext.ContentTypeService.Save(contentType1); - - var reQueried = ServiceContext.ContentTypeService.Get(contentType1.Id); - var reContent = ServiceContext.ContentService.GetById(contentItems1.First().Id); - - using (var scope = ScopeProvider.CreateScope()) - { - foreach (var c in contentItems1) - { - var xml = scope.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsFalse(xml.Xml.Contains(elementToMatch)); //verify that it is no longer there - } - - scope.Complete(); - } - } - [Test] public void Get_Descendants() { // Arrange - var contentTypeService = ServiceContext.ContentTypeService; + var contentTypeService = ContentTypeService; var hierarchy = CreateContentTypeHierarchy(); contentTypeService.Save(hierarchy, 0); //ensure they are saved! var master = hierarchy.First(); @@ -347,7 +244,7 @@ namespace Umbraco.Tests.Services public void Get_Descendants_And_Self() { // Arrange - var contentTypeService = ServiceContext.ContentTypeService; + var contentTypeService = ContentTypeService; var hierarchy = CreateContentTypeHierarchy(); contentTypeService.Save(hierarchy, 0); //ensure they are saved! var master = hierarchy.First(); @@ -359,24 +256,11 @@ namespace Umbraco.Tests.Services Assert.AreEqual(11, descendants.Count()); } - [Test] - public void Get_With_Missing_Guid() - { - // Arrange - var mediaTypeService = ServiceContext.MediaTypeService; - - //Act - var result = mediaTypeService.Get(Guid.NewGuid()); - - //Assert - Assert.IsNull(result); - } - [Test] public void Can_Bulk_Save_New_Hierarchy_Content_Types() { // Arrange - var contentTypeService = ServiceContext.ContentTypeService; + var contentTypeService = ContentTypeService; var hierarchy = CreateContentTypeHierarchy(); // Act @@ -397,9 +281,9 @@ namespace Umbraco.Tests.Services public void Can_Save_ContentType_Structure_And_Create_Content_Based_On_It() { // Arrange - var cs = ServiceContext.ContentService; - var cts = ServiceContext.ContentTypeService; - var dtdYesNo = ServiceContext.DataTypeService.GetDataType(-49); + var cs = ContentService; + var cts = ContentTypeService; + var dtdYesNo = DataTypeService.GetDataType(-49); var ctBase = new ContentType(ShortStringHelper, -1) { Name = "Base", Alias = "Base", Icon = "folder.gif", Thumbnail = "folder.png" }; ctBase.AddPropertyType(new PropertyType(ShortStringHelper, dtdYesNo, Constants.Conventions.Content.NaviHide) { @@ -435,8 +319,6 @@ namespace Umbraco.Tests.Services [Test] public void Create_Content_Type_Ensures_Sort_Orders() { - var service = ServiceContext.ContentTypeService; - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "test", @@ -453,7 +335,7 @@ namespace Umbraco.Tests.Services contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TinyMce, ValueStorageType.Ntext, "bodyText") { Name = "Body Text", Description = "", Mandatory = false, DataTypeId = -87 }); contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "author") { Name = "Author", Description = "Name of the author", Mandatory = false, DataTypeId = -88 }); - service.Save(contentType); + ContentTypeService.Save(contentType); var sortOrders = contentType.PropertyTypes.Select(x => x.SortOrder).ToArray(); @@ -470,18 +352,20 @@ namespace Umbraco.Tests.Services * - Components * - Category */ - var service = ServiceContext.ContentTypeService; - var global = MockedContentTypes.CreateSimpleContentType("global", "Global"); - service.Save(global); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global, true); - service.Save(components); + var global = ContentTypeBuilder.CreateSimpleContentType("global", "Global", defaultTemplateId: template.Id); + ContentTypeService.Save(global); - var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components, true); - service.Save(component); + var components = ContentTypeBuilder.CreateSimpleContentType("components", "Components", global, true, defaultTemplateId: template.Id); + ContentTypeService.Save(components); - var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global, true); - service.Save(category); + var component = ContentTypeBuilder.CreateSimpleContentType("component", "Component", components, true, defaultTemplateId: template.Id); + ContentTypeService.Save(component); + + var category = ContentTypeBuilder.CreateSimpleContentType("category", "Category", global, true, defaultTemplateId: template.Id); + ContentTypeService.Save(category); var success = category.AddContentType(component); @@ -491,16 +375,18 @@ namespace Umbraco.Tests.Services [Test] public void Can_Delete_Parent_ContentType_When_Child_Has_Content() { - var cts = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true); - cts.Save(contentType); - var childContentType = MockedContentTypes.CreateSimpleContentType("childPage", "Child Page", contentType, true, "Child Content"); - cts.Save(childContentType); - var cs = ServiceContext.ContentService; - var content = cs.Create("Page 1", -1, childContentType.Alias); - cs.Save(content); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - cts.Delete(contentType); + var contentType = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, true, defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + + var childContentType = ContentTypeBuilder.CreateSimpleContentType("childPage", "Child Page", contentType, true, "Child Content", defaultTemplateId: template.Id); + ContentTypeService.Save(childContentType); + var content = ContentService.Create("Page 1", -1, childContentType.Alias); + ContentService.Save(content); + + ContentTypeService.Delete(contentType); Assert.IsNotNull(content.Id); Assert.AreNotEqual(0, content.Id); @@ -508,9 +394,9 @@ namespace Umbraco.Tests.Services Assert.AreNotEqual(0, childContentType.Id); Assert.IsNotNull(contentType.Id); Assert.AreNotEqual(0, contentType.Id); - var deletedContent = cs.GetById(content.Id); - var deletedChildContentType = cts.Get(childContentType.Id); - var deletedContentType = cts.Get(contentType.Id); + var deletedContent = ContentService.GetById(content.Id); + var deletedChildContentType = ContentTypeService.Get(childContentType.Id); + var deletedContentType = ContentTypeService.Get(contentType.Id); Assert.IsNull(deletedChildContentType); Assert.IsNull(deletedContent); @@ -521,7 +407,7 @@ namespace Umbraco.Tests.Services public void Can_Create_Container() { // Arrange - var cts = ServiceContext.ContentTypeService; + var cts = ContentTypeService; // Act var container = new EntityContainer(Constants.ObjectTypes.DocumentType); @@ -537,7 +423,7 @@ namespace Umbraco.Tests.Services public void Can_Get_All_Containers() { // Arrange - var cts = ServiceContext.ContentTypeService; + var cts = ContentTypeService; // Act var container1 = new EntityContainer(Constants.ObjectTypes.DocumentType); @@ -556,17 +442,20 @@ namespace Umbraco.Tests.Services [Test] public void Deleting_ContentType_Sends_Correct_Number_Of_DeletedEntities_In_Events() { - var cts = ServiceContext.ContentTypeService; var deletedEntities = 0; - var contentType = MockedContentTypes.CreateSimpleContentType("page", "Page"); - cts.Save(contentType); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("page", "Page", defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); ContentTypeService.Deleted += (sender, args) => { deletedEntities += args.DeletedEntities.Count(); }; - cts.Delete(contentType); + ContentTypeService.Delete(contentType); Assert.AreEqual(deletedEntities, 1); } @@ -574,20 +463,23 @@ namespace Umbraco.Tests.Services [Test] public void Deleting_Multiple_ContentTypes_Sends_Correct_Number_Of_DeletedEntities_In_Events() { - var cts = ServiceContext.ContentTypeService; var deletedEntities = 0; - var contentType = MockedContentTypes.CreateSimpleContentType("page", "Page"); - cts.Save(contentType); - var contentType2 = MockedContentTypes.CreateSimpleContentType("otherPage", "Other page"); - cts.Save(contentType2); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("page", "Page", defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var contentType2 = ContentTypeBuilder.CreateSimpleContentType("otherPage", "Other page", defaultTemplateId: template.Id); + ContentTypeService.Save(contentType2); ContentTypeService.Deleted += (sender, args) => { deletedEntities += args.DeletedEntities.Count(); }; - cts.Delete(contentType); - cts.Delete(contentType2); + ContentTypeService.Delete(contentType); + ContentTypeService.Delete(contentType2); Assert.AreEqual(2, deletedEntities); } @@ -595,20 +487,23 @@ namespace Umbraco.Tests.Services [Test] public void Deleting_ContentType_With_Child_Sends_Correct_Number_Of_DeletedEntities_In_Events() { - var cts = ServiceContext.ContentTypeService; var deletedEntities = 0; - var contentType = MockedContentTypes.CreateSimpleContentType("page", "Page"); - cts.Save(contentType); - var contentType2 = MockedContentTypes.CreateSimpleContentType("subPage", "Sub page"); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var contentType = ContentTypeBuilder.CreateSimpleContentType("page", "Page", defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var contentType2 = ContentTypeBuilder.CreateSimpleContentType("subPage", "Sub page", defaultTemplateId: template.Id); contentType2.ParentId = contentType.Id; - cts.Save(contentType2); + ContentTypeService.Save(contentType2); ContentTypeService.Deleted += (sender, args) => { deletedEntities += args.DeletedEntities.Count(); }; - cts.Delete(contentType); + ContentTypeService.Delete(contentType); Assert.AreEqual(2, deletedEntities); } @@ -617,7 +512,7 @@ namespace Umbraco.Tests.Services public void Can_Remove_ContentType_Composition_From_ContentType() { //Test for U4-2234 - var cts = ServiceContext.ContentTypeService; + var cts = ContentTypeService; //Arrange var component = CreateComponent(); cts.Save(component); @@ -657,24 +552,25 @@ namespace Umbraco.Tests.Services public void Can_Copy_ContentType_By_Performing_Clone() { // Arrange - var service = ServiceContext.ContentTypeService; - var metaContentType = MockedContentTypes.CreateMetaContentType(); - service.Save(metaContentType); + var metaContentType = ContentTypeBuilder.CreateMetaContentType(); + ContentTypeService.Save(metaContentType); - var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType) as IContentType; - service.Save(simpleContentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType("category", "Category", metaContentType, defaultTemplateId: template.Id) as IContentType; + ContentTypeService.Save(simpleContentType); var categoryId = simpleContentType.Id; // Act var sut = simpleContentType.DeepCloneWithResetIdentities("newcategory"); Assert.IsNotNull(sut); - service.Save(sut); + ContentTypeService.Save(sut); // Assert Assert.That(sut.HasIdentity, Is.True); - var contentType = service.Get(sut.Id); - var category = service.Get(categoryId); + var contentType = ContentTypeService.Get(sut.Id); + var category = ContentTypeService.Get(categoryId); Assert.That(contentType.CompositionAliases().Any(x => x.Equals("meta")), Is.True); Assert.AreEqual(contentType.ParentId, category.ParentId); @@ -692,15 +588,16 @@ namespace Umbraco.Tests.Services public void Can_Copy_ContentType_To_New_Parent_By_Performing_Clone() { // Arrange - var service = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var parentContentType1 = MockedContentTypes.CreateSimpleContentType("parent1", "Parent1"); - service.Save(parentContentType1); - var parentContentType2 = MockedContentTypes.CreateSimpleContentType("parent2", "Parent2", null, true); - service.Save(parentContentType2); + var parentContentType1 = ContentTypeBuilder.CreateSimpleContentType("parent1", "Parent1", defaultTemplateId: template.Id); + ContentTypeService.Save(parentContentType1); + var parentContentType2 = ContentTypeBuilder.CreateSimpleContentType("parent2", "Parent2", null, true, defaultTemplateId: template.Id); + ContentTypeService.Save(parentContentType2); - var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", parentContentType1, true) as IContentType; - service.Save(simpleContentType); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType("category", "Category", parentContentType1, true, defaultTemplateId: template.Id) as IContentType; + ContentTypeService.Save(simpleContentType); // Act var clone = simpleContentType.DeepCloneWithResetIdentities("newcategory"); @@ -708,13 +605,13 @@ namespace Umbraco.Tests.Services clone.RemoveContentType("parent1"); clone.AddContentType(parentContentType2); clone.ParentId = parentContentType2.Id; - service.Save(clone); + ContentTypeService.Save(clone); // Assert Assert.That(clone.HasIdentity, Is.True); - var clonedContentType = service.Get(clone.Id); - var originalContentType = service.Get(simpleContentType.Id); + var clonedContentType = ContentTypeService.Get(clone.Id); + var originalContentType = ContentTypeService.Get(simpleContentType.Id); Assert.That(clonedContentType.CompositionAliases().Any(x => x.Equals("parent2")), Is.True); Assert.That(clonedContentType.CompositionAliases().Any(x => x.Equals("parent1")), Is.False); @@ -737,22 +634,24 @@ namespace Umbraco.Tests.Services public void Can_Copy_ContentType_With_Service_To_Root() { // Arrange - var service = ServiceContext.ContentTypeService; - var metaContentType = MockedContentTypes.CreateMetaContentType(); - service.Save(metaContentType); + var metaContentType = ContentTypeBuilder.CreateMetaContentType(); + ContentTypeService.Save(metaContentType); - var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType); - service.Save(simpleContentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType("category", "Category", metaContentType, defaultTemplateId: template.Id); + ContentTypeService.Save(simpleContentType); var categoryId = simpleContentType.Id; // Act - var clone = service.Copy(simpleContentType, "newcategory", "new category"); + var clone = ContentTypeService.Copy(simpleContentType, "newcategory", "new category"); // Assert Assert.That(clone.HasIdentity, Is.True); - var cloned = service.Get(clone.Id); - var original = service.Get(categoryId); + var cloned = ContentTypeService.Get(clone.Id); + var original = ContentTypeService.Get(categoryId); Assert.That(cloned.CompositionAliases().Any(x => x.Equals("meta")), Is.False); //it's been copied to root Assert.AreEqual(cloned.ParentId, -1); @@ -786,24 +685,25 @@ namespace Umbraco.Tests.Services public void Can_Copy_ContentType_To_New_Parent_With_Service() { // Arrange - var service = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var parentContentType1 = MockedContentTypes.CreateSimpleContentType("parent1", "Parent1"); - service.Save(parentContentType1); - var parentContentType2 = MockedContentTypes.CreateSimpleContentType("parent2", "Parent2", null, true); - service.Save(parentContentType2); + var parentContentType1 = ContentTypeBuilder.CreateSimpleContentType("parent1", "Parent1", defaultTemplateId: template.Id); + ContentTypeService.Save(parentContentType1); + var parentContentType2 = ContentTypeBuilder.CreateSimpleContentType("parent2", "Parent2", null, true, defaultTemplateId: template.Id); + ContentTypeService.Save(parentContentType2); - var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", parentContentType1, true); - service.Save(simpleContentType); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType("category", "Category", parentContentType1, true, defaultTemplateId: template.Id); + ContentTypeService.Save(simpleContentType); // Act - var clone = service.Copy(simpleContentType, "newAlias", "new alias", parentContentType2); + var clone = ContentTypeService.Copy(simpleContentType, "newAlias", "new alias", parentContentType2); // Assert Assert.That(clone.HasIdentity, Is.True); - var clonedContentType = service.Get(clone.Id); - var originalContentType = service.Get(simpleContentType.Id); + var clonedContentType = ContentTypeService.Get(clone.Id); + var originalContentType = ContentTypeService.Get(simpleContentType.Id); Assert.That(clonedContentType.CompositionAliases().Any(x => x.Equals("parent2")), Is.True); Assert.That(clonedContentType.CompositionAliases().Any(x => x.Equals("parent1")), Is.False); @@ -828,18 +728,19 @@ namespace Umbraco.Tests.Services //Related the second issue in screencast from this post http://issues.umbraco.org/issue/U4-5986 // Arrange - var service = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var parent = MockedContentTypes.CreateSimpleContentType(); - service.Save(parent); - var child = MockedContentTypes.CreateSimpleContentType("simpleChildPage", "Simple Child Page", parent, true); - service.Save(child); - var composition = MockedContentTypes.CreateMetaContentType(); - service.Save(composition); + var parent = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(parent); + var child = ContentTypeBuilder.CreateSimpleContentType("simpleChildPage", "Simple Child Page", parent, true, defaultTemplateId: template.Id); + ContentTypeService.Save(child); + var composition = ContentTypeBuilder.CreateMetaContentType(); + ContentTypeService.Save(composition); //Adding Meta-composition to child doc type child.AddContentType(composition); - service.Save(child); + ContentTypeService.Save(child); // Act var duplicatePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "title") @@ -850,32 +751,33 @@ namespace Umbraco.Tests.Services // Assert Assert.That(added, Is.True); - Assert.Throws(() => service.Save(composition)); - Assert.DoesNotThrow(() => service.Get("simpleChildPage")); + Assert.Throws(() => ContentTypeService.Save(composition)); + Assert.DoesNotThrow(() => ContentTypeService.Get("simpleChildPage")); } [Test] public void Cannot_Add_Duplicate_PropertyType_Alias_In_Composition_Graph() { // Arrange - var service = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var basePage = MockedContentTypes.CreateSimpleContentType("basePage", "Base Page", null, true); - service.Save(basePage); - var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", basePage); - service.Save(contentPage); - var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true); - service.Save(advancedPage); + var basePage = ContentTypeBuilder.CreateSimpleContentType("basePage", "Base Page", null, true, defaultTemplateId: template.Id); + ContentTypeService.Save(basePage); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", basePage, defaultTemplateId: template.Id); + ContentTypeService.Save(contentPage); + var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, defaultTemplateId: template.Id); + ContentTypeService.Save(advancedPage); - var metaComposition = MockedContentTypes.CreateMetaContentType(); - service.Save(metaComposition); - var seoComposition = MockedContentTypes.CreateSeoContentType(); - service.Save(seoComposition); + var metaComposition = ContentTypeBuilder.CreateMetaContentType(); + ContentTypeService.Save(metaComposition); + var seoComposition = ContentTypeBuilder.CreateMetaContentType("seo", "SEO"); + ContentTypeService.Save(seoComposition); var metaAdded = contentPage.AddContentType(metaComposition); - service.Save(contentPage); + ContentTypeService.Save(contentPage); var seoAdded = advancedPage.AddContentType(seoComposition); - service.Save(advancedPage); + ContentTypeService.Save(advancedPage); // Act var duplicatePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "title") @@ -896,14 +798,14 @@ namespace Umbraco.Tests.Services Assert.That(addedToMeta, Is.True); Assert.That(addedToSeo, Is.True); - Assert.Throws(() => service.Save(basePage)); - Assert.Throws(() => service.Save(metaComposition)); - Assert.Throws(() => service.Save(seoComposition)); + Assert.Throws(() => ContentTypeService.Save(basePage)); + Assert.Throws(() => ContentTypeService.Save(metaComposition)); + Assert.Throws(() => ContentTypeService.Save(seoComposition)); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); - Assert.DoesNotThrow(() => service.Get("meta")); - Assert.DoesNotThrow(() => service.Get("seo")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("meta")); + Assert.DoesNotThrow(() => ContentTypeService.Get("seo")); } [Test] @@ -920,16 +822,15 @@ namespace Umbraco.Tests.Services */ // Arrange - var service = ServiceContext.ContentTypeService; - var basePage = MockedContentTypes.CreateBasicContentType(); - service.Save(basePage); - var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage); - service.Save(contentPage); - var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); - service.Save(advancedPage); + var basePage = ContentTypeBuilder.CreateBasicContentType(); + ContentTypeService.Save(basePage); + var contentPage = ContentTypeBuilder.CreateBasicContentType("contentPage", "Content Page", basePage); + ContentTypeService.Save(contentPage); + var advancedPage = ContentTypeBuilder.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); + ContentTypeService.Save(advancedPage); - var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType(); - service.Save(contentMetaComposition); + var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); + ContentTypeService.Save(contentMetaComposition); // Act var bodyTextPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "bodyText") @@ -937,17 +838,17 @@ namespace Umbraco.Tests.Services Name = "Body Text", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content"); - service.Save(basePage); + ContentTypeService.Save(basePage); var authorPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "author") { Name = "Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content"); - service.Save(contentPage); + ContentTypeService.Save(contentPage); var compositionAdded = advancedPage.AddContentType(contentMetaComposition); - service.Save(advancedPage); + ContentTypeService.Save(advancedPage); //NOTE: It should not be possible to Save 'BasePage' with the Title PropertyType added var titlePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "title") @@ -962,20 +863,20 @@ namespace Umbraco.Tests.Services Assert.That(titleAdded, Is.True); Assert.That(compositionAdded, Is.True); - Assert.Throws(() => service.Save(basePage)); + Assert.Throws(() => ContentTypeService.Save(basePage)); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); } [Test] public void Cannot_Save_ContentType_With_Empty_Name() { // Arrange - var contentType = MockedContentTypes.CreateSimpleContentType("contentType", string.Empty); + var contentType = ContentTypeBuilder.CreateSimpleContentType("contentType", string.Empty); // Act & Assert - Assert.Throws(() => ServiceContext.ContentTypeService.Save(contentType)); + Assert.Throws(() => ContentTypeService.Save(contentType)); } [Test] @@ -991,20 +892,19 @@ namespace Umbraco.Tests.Services */ // Arrange - var service = ServiceContext.ContentTypeService; - var basePage = MockedContentTypes.CreateBasicContentType(); - service.Save(basePage); - var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage); - service.Save(contentPage); - var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); - service.Save(advancedPage); - var moreAdvancedPage = MockedContentTypes.CreateBasicContentType("moreAdvancedPage", "More Advanced Page", advancedPage); - service.Save(moreAdvancedPage); + var basePage = ContentTypeBuilder.CreateBasicContentType(); + ContentTypeService.Save(basePage); + var contentPage = ContentTypeBuilder.CreateBasicContentType("contentPage", "Content Page", basePage); + ContentTypeService.Save(contentPage); + var advancedPage = ContentTypeBuilder.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); + ContentTypeService.Save(advancedPage); + var moreAdvancedPage = ContentTypeBuilder.CreateBasicContentType("moreAdvancedPage", "More Advanced Page", advancedPage); + ContentTypeService.Save(moreAdvancedPage); - var seoComposition = MockedContentTypes.CreateSeoContentType(); - service.Save(seoComposition); - var metaComposition = MockedContentTypes.CreateMetaContentType(); - service.Save(metaComposition); + var seoComposition = ContentTypeBuilder.CreateMetaContentType("seo", "SEO"); + ContentTypeService.Save(seoComposition); + var metaComposition = ContentTypeBuilder.CreateMetaContentType(); + ContentTypeService.Save(metaComposition); // Act var bodyTextPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "bodyText") @@ -1012,33 +912,33 @@ namespace Umbraco.Tests.Services Name = "Body Text", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content"); - service.Save(basePage); + ContentTypeService.Save(basePage); var authorPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "author") { Name = "Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content"); - service.Save(contentPage); + ContentTypeService.Save(contentPage); var subtitlePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "subtitle") { Name = "Subtitle", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var subtitleAdded = advancedPage.AddPropertyType(subtitlePropertyType, "Content"); - service.Save(advancedPage); + ContentTypeService.Save(advancedPage); var titlePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "title") { Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var titleAdded = seoComposition.AddPropertyType(titlePropertyType, "Content"); - service.Save(seoComposition); + ContentTypeService.Save(seoComposition); var seoCompositionAdded = advancedPage.AddContentType(seoComposition); var metaCompositionAdded = moreAdvancedPage.AddContentType(metaComposition); - service.Save(advancedPage); - service.Save(moreAdvancedPage); + ContentTypeService.Save(advancedPage); + ContentTypeService.Save(moreAdvancedPage); var keywordsPropertyType = metaComposition.PropertyTypes.First(x => x.Alias.Equals("metakeywords")); keywordsPropertyType.Alias = "title"; @@ -1051,11 +951,11 @@ namespace Umbraco.Tests.Services Assert.That(seoCompositionAdded, Is.True); Assert.That(metaCompositionAdded, Is.True); - Assert.Throws(() => service.Save(metaComposition)); + Assert.Throws(() => ContentTypeService.Save(metaComposition)); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); - Assert.DoesNotThrow(() => service.Get("moreAdvancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("moreAdvancedPage")); } [Test] @@ -1071,20 +971,19 @@ namespace Umbraco.Tests.Services */ // Arrange - var service = ServiceContext.ContentTypeService; - var basePage = MockedContentTypes.CreateBasicContentType(); - service.Save(basePage); - var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage); - service.Save(contentPage); - var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); - service.Save(advancedPage); - var moreAdvancedPage = MockedContentTypes.CreateBasicContentType("moreAdvancedPage", "More Advanced Page", advancedPage); - service.Save(moreAdvancedPage); + var basePage = ContentTypeBuilder.CreateBasicContentType(); + ContentTypeService.Save(basePage); + var contentPage = ContentTypeBuilder.CreateBasicContentType("contentPage", "Content Page", basePage); + ContentTypeService.Save(contentPage); + var advancedPage = ContentTypeBuilder.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); + ContentTypeService.Save(advancedPage); + var moreAdvancedPage = ContentTypeBuilder.CreateBasicContentType("moreAdvancedPage", "More Advanced Page", advancedPage); + ContentTypeService.Save(moreAdvancedPage); - var seoComposition = MockedContentTypes.CreateSeoContentType(); - service.Save(seoComposition); - var metaComposition = MockedContentTypes.CreateMetaContentType(); - service.Save(metaComposition); + var seoComposition = ContentTypeBuilder.CreateMetaContentType("seo", "SEO"); + ContentTypeService.Save(seoComposition); + var metaComposition = ContentTypeBuilder.CreateMetaContentType(); + ContentTypeService.Save(metaComposition); // Act var bodyTextPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "bodyText") @@ -1092,33 +991,33 @@ namespace Umbraco.Tests.Services Name = "Body Text", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content"); - service.Save(basePage); + ContentTypeService.Save(basePage); var authorPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "author") { Name = "Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content"); - service.Save(contentPage); + ContentTypeService.Save(contentPage); var subtitlePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "subtitle") { Name = "Subtitle", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var subtitleAdded = advancedPage.AddPropertyType(subtitlePropertyType, "Content"); - service.Save(advancedPage); + ContentTypeService.Save(advancedPage); var titlePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "title") { Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var titleAdded = seoComposition.AddPropertyType(titlePropertyType, "Content"); - service.Save(seoComposition); + ContentTypeService.Save(seoComposition); var seoCompositionAdded = advancedPage.AddContentType(seoComposition); var metaCompositionAdded = moreAdvancedPage.AddContentType(metaComposition); - service.Save(advancedPage); - service.Save(moreAdvancedPage); + ContentTypeService.Save(advancedPage); + ContentTypeService.Save(moreAdvancedPage); // Assert Assert.That(bodyTextAdded, Is.True); @@ -1133,29 +1032,31 @@ namespace Umbraco.Tests.Services Name = "Test", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var testAdded = seoComposition.AddPropertyType(testPropertyType, "Content"); - service.Save(seoComposition); + ContentTypeService.Save(seoComposition); Assert.That(testAdded, Is.True); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); - Assert.DoesNotThrow(() => service.Get("moreAdvancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("moreAdvancedPage")); } [Test] public void Cannot_Rename_PropertyGroup_On_Child_Avoiding_Conflict_With_Parent_PropertyGroup() { // Arrange - var service = ServiceContext.ContentTypeService; - var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content"); - service.Save(page); - var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content_"); - service.Save(contentPage); - var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Details"); - service.Save(advancedPage); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); - var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType(); - service.Save(contentMetaComposition); + var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, true, "Content", defaultTemplateId: template.Id); + ContentTypeService.Save(page); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content_", defaultTemplateId: template.Id); + ContentTypeService.Save(contentPage); + var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Details", defaultTemplateId: template.Id); + ContentTypeService.Save(advancedPage); + + var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); + ContentTypeService.Save(contentMetaComposition); // Act var subtitlePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "subtitle") @@ -1168,10 +1069,10 @@ namespace Umbraco.Tests.Services }; var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content"); var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content"); - service.Save(contentPage); + ContentTypeService.Save(contentPage); var compositionAdded = contentPage.AddContentType(contentMetaComposition); - service.Save(contentPage); + ContentTypeService.Save(contentPage); //Change the name of the tab on the "root" content type 'page'. var propertyGroup = contentPage.PropertyGroups["Content_"]; @@ -1187,21 +1088,20 @@ namespace Umbraco.Tests.Services Assert.That(subtitleAdded, Is.True); Assert.That(authorAdded, Is.True); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); } [Test] public void Cannot_Rename_PropertyType_Alias_Causing_Conflicts_With_Parents() { // Arrange - var service = ServiceContext.ContentTypeService; - var basePage = MockedContentTypes.CreateBasicContentType(); - service.Save(basePage); - var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage); - service.Save(contentPage); - var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); - service.Save(advancedPage); + var basePage = ContentTypeBuilder.CreateBasicContentType(); + ContentTypeService.Save(basePage); + var contentPage = ContentTypeBuilder.CreateBasicContentType("contentPage", "Content Page", basePage); + ContentTypeService.Save(contentPage); + var advancedPage = ContentTypeBuilder.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); + ContentTypeService.Save(advancedPage); // Act var titlePropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "title") @@ -1224,9 +1124,9 @@ namespace Umbraco.Tests.Services Name = "Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var authorAdded = advancedPage.AddPropertyType(authorPropertyType, "Content"); - service.Save(basePage); - service.Save(contentPage); - service.Save(advancedPage); + ContentTypeService.Save(basePage); + ContentTypeService.Save(contentPage); + ContentTypeService.Save(advancedPage); //Rename the PropertyType to something that already exists in the Composition - NOTE this should not be allowed and Saving should throw an exception var authorPropertyTypeToRename = advancedPage.PropertyTypes.First(x => x.Alias.Equals("author")); @@ -1238,10 +1138,10 @@ namespace Umbraco.Tests.Services Assert.That(titleAdded, Is.True); Assert.That(subtitleAdded, Is.True); - Assert.Throws(() => service.Save(advancedPage)); + Assert.Throws(() => ContentTypeService.Save(advancedPage)); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); } [Test] @@ -1255,26 +1155,26 @@ namespace Umbraco.Tests.Services * ---- Advanced Page */ // Arrange - var service = ServiceContext.ContentTypeService; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var basePage = ContentTypeBuilder.CreateSimpleContentType("basePage", "Base Page", null, true, defaultTemplateId: template.Id); + ContentTypeService.Save(basePage); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", basePage, true, defaultTemplateId: template.Id); + ContentTypeService.Save(contentPage); + var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, defaultTemplateId: template.Id); + ContentTypeService.Save(advancedPage); - var basePage = MockedContentTypes.CreateSimpleContentType("basePage", "Base Page", null, true); - service.Save(basePage); - var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", basePage, true); - service.Save(contentPage); - var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true); - service.Save(advancedPage); + var metaComposition = ContentTypeBuilder.CreateMetaContentType(); + ContentTypeService.Save(metaComposition); - var metaComposition = MockedContentTypes.CreateMetaContentType(); - service.Save(metaComposition); - - var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType(); - service.Save(contentMetaComposition); + var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); + ContentTypeService.Save(contentMetaComposition); var metaAdded = contentPage.AddContentType(metaComposition); - service.Save(contentPage); + ContentTypeService.Save(contentPage); var metaAddedToComposition = contentMetaComposition.AddContentType(metaComposition); - service.Save(contentMetaComposition); + ContentTypeService.Save(contentMetaComposition); // Act var propertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "title") @@ -1288,7 +1188,7 @@ namespace Umbraco.Tests.Services Assert.That(metaAddedToComposition, Is.True); Assert.That(addedToContentPage, Is.True); - Assert.DoesNotThrow(() => service.Save(contentPage)); + Assert.DoesNotThrow(() => ContentTypeService.Save(contentPage)); } [Test] @@ -1297,30 +1197,30 @@ namespace Umbraco.Tests.Services //Related the first issue in screencast from this post http://issues.umbraco.org/issue/U4-5986 // Arrange - var service = ServiceContext.ContentTypeService; - // create 'page' content type with a 'Content_' group - var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, false, "Content_"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, false, "Content_", defaultTemplateId: template.Id); Assert.AreEqual(1, page.PropertyGroups.Count); Assert.AreEqual("Content_", page.PropertyGroups.First().Name); Assert.AreEqual(3, page.PropertyTypes.Count()); Assert.AreEqual("Title", page.PropertyTypes.First().Name); - Assert.AreEqual("Body Text", page.PropertyTypes.Skip(1).First().Name); + Assert.AreEqual("Body text", page.PropertyTypes.Skip(1).First().Name); Assert.AreEqual("Author", page.PropertyTypes.Skip(2).First().Name); - service.Save(page); + ContentTypeService.Save(page); // create 'contentPage' content type as a child of 'page' - var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, true, defaultTemplateId: template.Id); Assert.AreEqual(1, page.PropertyGroups.Count); Assert.AreEqual("Content_", page.PropertyGroups.First().Name); Assert.AreEqual(3, contentPage.PropertyTypes.Count()); Assert.AreEqual("Title", contentPage.PropertyTypes.First().Name); - Assert.AreEqual("Body Text", contentPage.PropertyTypes.Skip(1).First().Name); + Assert.AreEqual("Body text", contentPage.PropertyTypes.Skip(1).First().Name); Assert.AreEqual("Author", contentPage.PropertyTypes.Skip(2).First().Name); - service.Save(contentPage); + ContentTypeService.Save(contentPage); // add 'Content' group to 'meta' content type - var meta = MockedContentTypes.CreateMetaContentType(); + var meta = ContentTypeBuilder.CreateMetaContentType(); Assert.AreEqual(1, meta.PropertyGroups.Count); Assert.AreEqual("Meta", meta.PropertyGroups.First().Name); Assert.AreEqual(2, meta.PropertyTypes.Count()); @@ -1328,11 +1228,11 @@ namespace Umbraco.Tests.Services Assert.AreEqual("Meta Description", meta.PropertyTypes.Skip(1).First().Name); meta.AddPropertyGroup("Content"); Assert.AreEqual(2, meta.PropertyTypes.Count()); - service.Save(meta); + ContentTypeService.Save(meta); // add 'meta' content type to 'contentPage' composition contentPage.AddContentType(meta); - service.Save(contentPage); + ContentTypeService.Save(contentPage); // add property 'prop1' to 'contentPage' group 'Content_' var prop1 = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "testTextbox") @@ -1351,15 +1251,15 @@ namespace Umbraco.Tests.Services Assert.IsTrue(prop2Added); // save 'contentPage' content type - service.Save(contentPage); + ContentTypeService.Save(contentPage); var group = page.PropertyGroups["Content_"]; group.Name = "ContentTab"; // rename the group - service.Save(page); + ContentTypeService.Save(page); Assert.AreEqual(3, page.PropertyTypes.Count()); // get 'contentPage' content type again - var contentPageAgain = service.Get("contentPage"); + var contentPageAgain = ContentTypeService.Get("contentPage"); Assert.IsNotNull(contentPageAgain); // assert that 'Content_' group is still there because we don't propagate renames @@ -1379,18 +1279,19 @@ namespace Umbraco.Tests.Services public void Can_Rename_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups() { // Arrange - var service = ServiceContext.ContentTypeService; - var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content_"); - service.Save(page); - var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Contentx"); - service.Save(contentPage); - var advancedPage = MockedContentTypes.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Contenty"); - service.Save(advancedPage); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, true, "Content_", defaultTemplateId: template.Id); + ContentTypeService.Save(page); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, true, "Contentx", defaultTemplateId: template.Id); + ContentTypeService.Save(contentPage); + var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Contenty", defaultTemplateId: template.Id); + ContentTypeService.Save(advancedPage); - var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType(); - service.Save(contentMetaComposition); + var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); + ContentTypeService.Save(contentMetaComposition); var compositionAdded = contentPage.AddContentType(contentMetaComposition); - service.Save(contentPage); + ContentTypeService.Save(contentPage); // Act var bodyTextPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "bodyText") @@ -1403,7 +1304,7 @@ namespace Umbraco.Tests.Services }; var bodyTextAdded = contentPage.AddPropertyType(bodyTextPropertyType, "Content_");//Will be added to the parent tab var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content");//Will be added to the "Content Meta" composition - service.Save(contentPage); + ContentTypeService.Save(contentPage); var authorPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "author") { @@ -1420,12 +1321,12 @@ namespace Umbraco.Tests.Services var authorAdded = advancedPage.AddPropertyType(authorPropertyType, "Content_");//Will be added to an ancestor tab var descriptionAdded = advancedPage.AddPropertyType(descriptionPropertyType, "Contentx");//Will be added to a parent tab var keywordsAdded = advancedPage.AddPropertyType(keywordsPropertyType, "Content");//Will be added to the "Content Meta" composition - service.Save(advancedPage); + ContentTypeService.Save(advancedPage); //Change the name of the tab on the "root" content type 'page'. var propertyGroup = page.PropertyGroups["Content_"]; page.PropertyGroups.Add(new PropertyGroup(true) { Id = propertyGroup.Id, Name = "Content", SortOrder = 0 }); - service.Save(page); + ContentTypeService.Save(page); // Assert Assert.That(compositionAdded, Is.True); @@ -1435,10 +1336,10 @@ namespace Umbraco.Tests.Services Assert.That(descriptionAdded, Is.True); Assert.That(keywordsAdded, Is.True); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); - var advancedPageReloaded = service.Get("advancedPage"); + var advancedPageReloaded = ContentTypeService.Get("advancedPage"); var contentUnderscoreTabExists = advancedPageReloaded.CompositionPropertyGroups.Any(x => x.Name.Equals("Content_")); // now is true, because we don't propagate renames anymore @@ -1452,14 +1353,15 @@ namespace Umbraco.Tests.Services public void Can_Rename_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups_v2() { // Arrange - var service = ServiceContext.ContentTypeService; - var page = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true, "Content_"); - service.Save(page); - var contentPage = MockedContentTypes.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content"); - service.Save(contentPage); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, true, "Content_", defaultTemplateId: template.Id); + ContentTypeService.Save(page); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content", defaultTemplateId: template.Id); + ContentTypeService.Save(contentPage); - var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType(); - service.Save(contentMetaComposition); + var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); + ContentTypeService.Save(contentMetaComposition); // Act var bodyTextPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "bodyText") @@ -1477,16 +1379,16 @@ namespace Umbraco.Tests.Services var bodyTextAdded = page.AddPropertyType(bodyTextPropertyType, "Content_"); var subtitleAdded = contentPage.AddPropertyType(subtitlePropertyType, "Content"); var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content_"); - service.Save(page); - service.Save(contentPage); + ContentTypeService.Save(page); + ContentTypeService.Save(contentPage); var compositionAdded = contentPage.AddContentType(contentMetaComposition); - service.Save(contentPage); + ContentTypeService.Save(contentPage); //Change the name of the tab on the "root" content type 'page'. var propertyGroup = page.PropertyGroups["Content_"]; page.PropertyGroups.Add(new PropertyGroup(true) { Id = propertyGroup.Id, Name = "Content", SortOrder = 0 }); - service.Save(page); + ContentTypeService.Save(page); // Assert Assert.That(compositionAdded, Is.True); @@ -1494,25 +1396,24 @@ namespace Umbraco.Tests.Services Assert.That(subtitleAdded, Is.True); Assert.That(authorAdded, Is.True); - Assert.DoesNotThrow(() => service.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); } [Test] public void Can_Remove_PropertyGroup_On_Parent_Without_Causing_Duplicate_PropertyGroups() { // Arrange - var service = ServiceContext.ContentTypeService; - var basePage = MockedContentTypes.CreateBasicContentType(); - service.Save(basePage); + var basePage = ContentTypeBuilder.CreateBasicContentType(); + ContentTypeService.Save(basePage); - var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage); - service.Save(contentPage); + var contentPage = ContentTypeBuilder.CreateBasicContentType("contentPage", "Content Page", basePage); + ContentTypeService.Save(contentPage); - var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); - service.Save(advancedPage); + var advancedPage = ContentTypeBuilder.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); + ContentTypeService.Save(advancedPage); - var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType(); - service.Save(contentMetaComposition); + var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); + ContentTypeService.Save(contentMetaComposition); // Act var bodyTextPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "bodyText") @@ -1520,42 +1421,40 @@ namespace Umbraco.Tests.Services Name = "Body Text", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content"); - service.Save(basePage); + ContentTypeService.Save(basePage); var authorPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "author") { Name = "Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content"); - service.Save(contentPage); + ContentTypeService.Save(contentPage); var compositionAdded = contentPage.AddContentType(contentMetaComposition); - service.Save(contentPage); + ContentTypeService.Save(contentPage); basePage.RemovePropertyGroup("Content"); - service.Save(basePage); + ContentTypeService.Save(basePage); // Assert Assert.That(bodyTextAdded, Is.True); Assert.That(authorAdded, Is.True); Assert.That(compositionAdded, Is.True); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); - var contentType = service.Get("contentPage"); + var contentType = ContentTypeService.Get("contentPage"); var propertyGroup = contentType.PropertyGroups["Content"]; } [Test] public void Can_Remove_PropertyGroup_Without_Removing_Property_Types() { - var service = ServiceContext.ContentTypeService; - - var basePage = (IContentType) MockedContentTypes.CreateBasicContentType(); + var basePage = (IContentType) ContentTypeBuilder.CreateBasicContentType(); basePage.AddPropertyGroup("Content"); basePage.AddPropertyGroup("Meta"); - service.Save(basePage); + ContentTypeService.Save(basePage); var authorPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "author") { @@ -1577,16 +1476,16 @@ namespace Umbraco.Tests.Services }; Assert.IsTrue(basePage.AddPropertyType(titlePropertyType, "Meta")); - service.Save(basePage); - basePage = service.Get(basePage.Id); + ContentTypeService.Save(basePage); + basePage = ContentTypeService.Get(basePage.Id); var count = basePage.PropertyTypes.Count(); Assert.AreEqual(2, count); basePage.RemovePropertyGroup("Content"); - service.Save(basePage); - basePage = service.Get(basePage.Id); + ContentTypeService.Save(basePage); + basePage = ContentTypeService.Get(basePage.Id); Assert.AreEqual(count, basePage.PropertyTypes.Count()); } @@ -1602,18 +1501,17 @@ namespace Umbraco.Tests.Services */ // Arrange - var service = ServiceContext.ContentTypeService; - var basePage = MockedContentTypes.CreateBasicContentType(); - service.Save(basePage); + var basePage = ContentTypeBuilder.CreateBasicContentType(); + ContentTypeService.Save(basePage); - var contentPage = MockedContentTypes.CreateBasicContentType("contentPage", "Content Page", basePage); - service.Save(contentPage); + var contentPage = ContentTypeBuilder.CreateBasicContentType("contentPage", "Content Page", basePage); + ContentTypeService.Save(contentPage); - var advancedPage = MockedContentTypes.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); - service.Save(advancedPage); + var advancedPage = ContentTypeBuilder.CreateBasicContentType("advancedPage", "Advanced Page", contentPage); + ContentTypeService.Save(advancedPage); - var contentMetaComposition = MockedContentTypes.CreateContentMetaContentType(); - service.Save(contentMetaComposition); + var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); + ContentTypeService.Save(contentMetaComposition); // Act var authorPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "author") @@ -1621,27 +1519,27 @@ namespace Umbraco.Tests.Services Name = "Author", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var authorAdded = contentPage.AddPropertyType(authorPropertyType, "Content"); - service.Save(contentPage); + ContentTypeService.Save(contentPage); var bodyTextPropertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext, "bodyText") { Name = "Body Text", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }; var bodyTextAdded = basePage.AddPropertyType(bodyTextPropertyType, "Content"); - service.Save(basePage); + ContentTypeService.Save(basePage); var compositionAdded = contentPage.AddContentType(contentMetaComposition); - service.Save(contentPage); + ContentTypeService.Save(contentPage); // Assert Assert.That(bodyTextAdded, Is.True); Assert.That(authorAdded, Is.True); Assert.That(compositionAdded, Is.True); - Assert.DoesNotThrow(() => service.Get("contentPage")); - Assert.DoesNotThrow(() => service.Get("advancedPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("contentPage")); + Assert.DoesNotThrow(() => ContentTypeService.Get("advancedPage")); - var contentType = service.Get("contentPage"); + var contentType = ContentTypeService.Get("contentPage"); var propertyGroup = contentType.PropertyGroups["Content"]; var numberOfContentTabs = contentType.CompositionPropertyGroups.Count(x => x.Name.Equals("Content")); @@ -1654,10 +1552,10 @@ namespace Umbraco.Tests.Services Alias = "description", Name = "Description", Description = "", Mandatory = false, SortOrder = 1,DataTypeId = -88 }; var descriptionAdded = contentType.AddPropertyType(descriptionPropertyType, "Content"); - service.Save(contentType); + ContentTypeService.Save(contentType); Assert.That(descriptionAdded, Is.True); - var contentPageReloaded = service.Get("contentPage"); + var contentPageReloaded = ContentTypeService.Get("contentPage"); var propertyGroupReloaded = contentPageReloaded.PropertyGroups["Content"]; var hasDescriptionPropertyType = propertyGroupReloaded.PropertyTypes.Contains("description"); Assert.That(hasDescriptionPropertyType, Is.True); @@ -1669,14 +1567,13 @@ namespace Umbraco.Tests.Services [Test] public void Empty_Description_Is_Always_Null_After_Saving_Content_Type() { - var service = ServiceContext.ContentTypeService; - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Description = null; - service.Save(contentType); + ContentTypeService.Save(contentType); - var contentType2 = MockedContentTypes.CreateBasicContentType("basePage2", "Base Page 2"); + var contentType2 = ContentTypeBuilder.CreateBasicContentType("basePage2", "Base Page 2"); contentType2.Description = string.Empty; - service.Save(contentType2); + ContentTypeService.Save(contentType2); Assert.IsNull(contentType.Description); Assert.IsNull(contentType2.Description); @@ -1685,32 +1582,33 @@ namespace Umbraco.Tests.Services [Test] public void Variations_In_Compositions() { - var service = ServiceContext.ContentTypeService; - var typeA = MockedContentTypes.CreateSimpleContentType("a", "A"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var typeA = ContentTypeBuilder.CreateSimpleContentType("a", "A", defaultTemplateId: template.Id); typeA.Variations = ContentVariation.Culture; // make it variant typeA.PropertyTypes.First(x => x.Alias.InvariantEquals("title")).Variations = ContentVariation.Culture; // with a variant property - service.Save(typeA); + ContentTypeService.Save(typeA); - var typeB = MockedContentTypes.CreateSimpleContentType("b", "B", typeA, true); + var typeB = ContentTypeBuilder.CreateSimpleContentType("b", "B", typeA, true, defaultTemplateId: template.Id); typeB.Variations = ContentVariation.Nothing; // make it invariant - service.Save(typeB); + ContentTypeService.Save(typeB); - var typeC = MockedContentTypes.CreateSimpleContentType("c", "C", typeA, true); + var typeC = ContentTypeBuilder.CreateSimpleContentType("c", "C", typeA, true, defaultTemplateId: template.Id); typeC.Variations = ContentVariation.Culture; // make it variant - service.Save(typeC); + ContentTypeService.Save(typeC); // property is variant on A - var test = service.Get(typeA.Id); + var test = ContentTypeService.Get(typeA.Id); Assert.AreEqual(ContentVariation.Culture, test.CompositionPropertyTypes.First(x => x.Alias.InvariantEquals("title")).Variations); Assert.AreEqual(ContentVariation.Culture, test.CompositionPropertyGroups.First().PropertyTypes.First(x => x.Alias.InvariantEquals("title")).Variations); // but not on B - test = service.Get(typeB.Id); + test = ContentTypeService.Get(typeB.Id); Assert.AreEqual(ContentVariation.Nothing, test.CompositionPropertyTypes.First(x => x.Alias.InvariantEquals("title")).Variations); Assert.AreEqual(ContentVariation.Nothing, test.CompositionPropertyGroups.First().PropertyTypes.First(x => x.Alias.InvariantEquals("title")).Variations); // but on C - test = service.Get(typeC.Id); + test = ContentTypeService.Get(typeC.Id); Assert.AreEqual(ContentVariation.Culture, test.CompositionPropertyTypes.First(x => x.Alias.InvariantEquals("title")).Variations); Assert.AreEqual(ContentVariation.Culture, test.CompositionPropertyGroups.First().PropertyTypes.First(x => x.Alias.InvariantEquals("title")).Variations); } @@ -1786,44 +1684,28 @@ namespace Umbraco.Tests.Services private ContentType CreateHomepage(ContentType parent) { - const string contentTypeAlias = "homepage"; - var contentType = new ContentType(ShortStringHelper, parent, contentTypeAlias) - { - Alias = contentTypeAlias, - Name = "Homepage", - Description = "ContentType used for the Homepage", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(true); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "title") { Name = "Title", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "bodyText") { Name = "Body Text", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 }); - contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "author") { Name = "Author", Description = "Name of the author", Mandatory = false, SortOrder = 3, DataTypeId = -88 }); - - contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - - return contentType; + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + return ContentTypeBuilder.CreateSimpleContentType("homepage", "Homepage", parent, defaultTemplateId: template.Id); } private IContentType[] CreateContentTypeHierarchy() { //create the master type - var masterContentType = MockedContentTypes.CreateSimpleContentType("masterContentType", "MasterContentType"); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var masterContentType = ContentTypeBuilder.CreateSimpleContentType("masterContentType", "MasterContentType", defaultTemplateId: template.Id); masterContentType.Key = new Guid("C00CA18E-5A9D-483B-A371-EECE0D89B4AE"); - ServiceContext.ContentTypeService.Save(masterContentType); + ContentTypeService.Save(masterContentType); //add the one we just created var list = new List { masterContentType }; for (var i = 0; i < 10; i++) { - var contentType = MockedContentTypes.CreateSimpleContentType("childType" + i, "ChildType" + i, + var contentType = ContentTypeBuilder.CreateSimpleContentType("childType" + i, "ChildType" + i, //make the last entry in the list, this one's parent - list.Last(), true); + list.Last(), true, defaultTemplateId: template.Id); list.Add(contentType); } diff --git a/src/Umbraco.Tests.Integration/Services/DataTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Services/DataTypeServiceTests.cs new file mode 100644 index 0000000000..160769439d --- /dev/null +++ b/src/Umbraco.Tests.Integration/Services/DataTypeServiceTests.cs @@ -0,0 +1,81 @@ +using System; +using System.Linq; +using System.Threading; +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Integration.Services +{ + /// + /// Tests covering the DataTypeService + /// + [TestFixture] + [Apartment(ApartmentState.STA)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class DataTypeServiceTests : UmbracoIntegrationTest + { + private IDataTypeService DataTypeService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + private ILocalizedTextService LocalizedTextService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); + + [Test] + public void DataTypeService_Can_Persist_New_DataTypeDefinition() + { + // Act + IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper)) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; + DataTypeService.Save(dataType); + + // Assert + Assert.That(dataType, Is.Not.Null); + Assert.That(dataType.HasIdentity, Is.True); + + dataType = DataTypeService.GetDataType(dataType.Id); + Assert.That(dataType, Is.Not.Null); + } + + [Test] + public void DataTypeService_Can_Delete_Textfield_DataType_And_Clear_Usages() + { + // Arrange + var textfieldId = "Umbraco.Textbox"; + var dataTypeDefinitions = DataTypeService.GetByEditorAlias(textfieldId); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var doctype = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id); + ContentTypeService.Save(doctype); + + + // Act + var definition = dataTypeDefinitions.First(); + var definitionId = definition.Id; + DataTypeService.Delete(definition); + + var deletedDefinition = DataTypeService.GetDataType(definitionId); + + // Assert + Assert.That(deletedDefinition, Is.Null); + + //Further assertions against the ContentType that contains PropertyTypes based on the TextField + var contentType = ContentTypeService.Get(doctype.Id); + Assert.That(contentType.Alias, Is.EqualTo("umbTextpage")); + Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(1)); + } + + [Test] + public void Cannot_Save_DataType_With_Empty_Name() + { + // Act + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService,LocalizationService, ShortStringHelper)) { Name = string.Empty, DatabaseType = ValueStorageType.Ntext }; + + // Act & Assert + Assert.Throws(() => DataTypeService.Save(dataTypeDefinition)); + } + } +} diff --git a/src/Umbraco.Tests/Services/EntityServiceTests.cs b/src/Umbraco.Tests.Integration/Services/EntityServiceTests.cs similarity index 52% rename from src/Umbraco.Tests/Services/EntityServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/EntityServiceTests.cs index fb802420d5..64e7cea8dc 100644 --- a/src/Umbraco.Tests/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/EntityServiceTests.cs @@ -4,15 +4,16 @@ using System.Linq; using System.Threading; using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence; using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering the EntityService @@ -20,65 +21,74 @@ namespace Umbraco.Tests.Services [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] - public class EntityServiceTests : TestWithSomeContentBase + public class EntityServiceTests : UmbracoIntegrationTest { private Language _langFr; private Language _langEs; - public override void SetUp() - { - base.SetUp(); + private ILocalizationService LocalizationService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private IEntityService EntityService => GetRequiredService(); + private ISqlContext SqlContext => GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); + private IMediaService MediaService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + [SetUp] + public void SetupTestData() + { if (_langFr == null && _langEs == null) { - _langFr = new Language(SettingsForTests.GenerateMockGlobalSettings(), "fr-FR"); - _langEs = new Language(SettingsForTests.GenerateMockGlobalSettings(), "es-ES"); - ServiceContext.LocalizationService.Save(_langFr); - ServiceContext.LocalizationService.Save(_langEs); + var globalSettings = new GlobalSettings(); + _langFr = new Language(globalSettings, "fr-FR"); + _langEs = new Language(globalSettings, "es-ES"); + LocalizationService.Save(_langFr); + LocalizationService.Save(_langEs); } + + CreateTestData(); } [Test] public void EntityService_Can_Get_Paged_Descendants_Ordering_Path() { - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); - var root = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(root); + var root = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(root); var rootId = root.Id; var ids = new List(); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); + ContentService.Save(c1); ids.Add(c1.Id); root = c1; // make a hierarchy } - var service = ServiceContext.EntityService; - long total; - var entities = service.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 0, 6, out total).ToArray(); + var entities = EntityService.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 0, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); Assert.AreEqual(ids[0], entities[0].Id); - entities = service.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 1, 6, out total).ToArray(); + entities = EntityService.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 1, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); Assert.AreEqual(ids[6], entities[0].Id); //Test ordering direction - entities = service.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 0, 6, out total, + entities = EntityService.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 0, 6, out total, ordering: Ordering.By("Path", Direction.Descending)).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); Assert.AreEqual(ids[ids.Count - 1], entities[0].Id); - entities = service.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 1, 6, out total, + entities = EntityService.GetPagedDescendants(rootId, UmbracoObjectTypes.Document, 1, 6, out total, ordering: Ordering.By("Path", Direction.Descending)).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); @@ -89,41 +99,39 @@ namespace Umbraco.Tests.Services public void EntityService_Can_Get_Paged_Content_Children() { - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); - var root = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(root); + var root = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(root); var ids = new List(); for (int i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); + ContentService.Save(c1); ids.Add(c1.Id); } - var service = ServiceContext.EntityService; - long total; - var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total).ToArray(); + var entities = EntityService.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); Assert.AreEqual(ids[0], entities[0].Id); - entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total).ToArray(); + entities = EntityService.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); Assert.AreEqual(ids[6], entities[0].Id); //Test ordering direction - entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total, + entities = EntityService.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total, ordering: Ordering.By("SortOrder", Direction.Descending)).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); Assert.AreEqual(ids[ids.Count - 1], entities[0].Id); - entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total, + entities = EntityService.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total, ordering: Ordering.By("SortOrder", Direction.Descending)).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); @@ -133,32 +141,30 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Content_Descendants() { - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); - var root = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(root); + var root = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(root); var count = 0; for (int i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); + ContentService.Save(c1); count++; for (int j = 0; j < 5; j++) { - var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1); - ServiceContext.ContentService.Save(c2); + var c2 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1); + ContentService.Save(c2); count++; } } - var service = ServiceContext.EntityService; - long total; - var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 31, out total).ToArray(); + var entities = EntityService.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 31, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(31)); Assert.That(total, Is.EqualTo(60)); - entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 1, 31, out total).ToArray(); + entities = EntityService.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 1, 31, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(29)); Assert.That(total, Is.EqualTo(60)); } @@ -166,15 +172,15 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Content_Descendants_Including_Recycled() { - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); - var root = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(root); + var root = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(root); var toDelete = new List(); for (int i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); + ContentService.Save(c1); if (i % 2 == 0) { @@ -183,21 +189,19 @@ namespace Umbraco.Tests.Services for (int j = 0; j < 5; j++) { - var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1); - ServiceContext.ContentService.Save(c2); + var c2 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1); + ContentService.Save(c2); } } foreach (var content in toDelete) { - ServiceContext.ContentService.MoveToRecycleBin(content); + ContentService.MoveToRecycleBin(content); } - var service = ServiceContext.EntityService; - long total; //search at root to see if it returns recycled - var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Document, 0, 1000, out total) + var entities = EntityService.GetPagedDescendants(-1, UmbracoObjectTypes.Document, 0, 1000, out total) .Select(x => x.Id) .ToArray(); @@ -210,15 +214,15 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Content_Descendants_Without_Recycled() { - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); - var root = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(root); + var root = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(root); var toDelete = new List(); for (int i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); + ContentService.Save(c1); if (i % 2 == 0) { @@ -227,21 +231,19 @@ namespace Umbraco.Tests.Services for (int j = 0; j < 5; j++) { - var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1); - ServiceContext.ContentService.Save(c2); + var c2 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1); + ContentService.Save(c2); } } foreach (var content in toDelete) { - ServiceContext.ContentService.MoveToRecycleBin(content); + ContentService.MoveToRecycleBin(content); } - var service = ServiceContext.EntityService; - long total; //search at root to see if it returns recycled - var entities = service.GetPagedDescendants(UmbracoObjectTypes.Document, 0, 1000, out total, includeTrashed: false) + var entities = EntityService.GetPagedDescendants(UmbracoObjectTypes.Document, 0, 1000, out total, includeTrashed: false) .Select(x => x.Id) .ToArray(); @@ -254,31 +256,29 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Content_Descendants_With_Search() { - var contentType = ServiceContext.ContentTypeService.Get("umbTextpage"); + var contentType = ContentTypeService.Get("umbTextpage"); - var root = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(root); + var root = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(root); for (int i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType, "ssss" + Guid.NewGuid(), root); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateSimpleContent(contentType, "ssss" + Guid.NewGuid(), root); + ContentService.Save(c1); for (int j = 0; j < 5; j++) { - var c2 = MockedContent.CreateSimpleContent(contentType, "tttt" + Guid.NewGuid(), c1); - ServiceContext.ContentService.Save(c2); + var c2 = ContentBuilder.CreateSimpleContent(contentType, "tttt" + Guid.NewGuid(), c1); + ContentService.Save(c2); } } - var service = ServiceContext.EntityService; - long total; - var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 10, out total, + var entities = EntityService.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 10, out total, filter: SqlContext.Query().Where(x => x.Name.Contains("ssss"))).ToArray(); Assert.That(entities.Length, Is.EqualTo(10)); Assert.That(total, Is.EqualTo(10)); - entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 50, out total, + entities = EntityService.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 50, out total, filter: SqlContext.Query().Where(x => x.Name.Contains("tttt"))).ToArray(); Assert.That(entities.Length, Is.EqualTo(50)); Assert.That(total, Is.EqualTo(50)); @@ -287,24 +287,22 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Media_Children() { - var folderType = ServiceContext.MediaTypeService.Get(1031); - var imageMediaType = ServiceContext.MediaTypeService.Get(1032); + var folderType = MediaTypeService.Get(1031); + var imageMediaType = MediaTypeService.Get(1032); - var root = MockedMedia.CreateMediaFolder(folderType, -1); - ServiceContext.MediaService.Save(root); + var root = MediaBuilder.CreateMediaFolder(folderType, -1); + MediaService.Save(root); for (int i = 0; i < 10; i++) { - var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id); - ServiceContext.MediaService.Save(c1); + var c1 = MediaBuilder.CreateMediaImage(imageMediaType, root.Id); + MediaService.Save(c1); } - var service = ServiceContext.EntityService; - long total; - var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 0, 6, out total).ToArray(); + var entities = EntityService.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 0, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(6)); Assert.That(total, Is.EqualTo(10)); - entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 1, 6, out total).ToArray(); + entities = EntityService.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 1, 6, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(4)); Assert.That(total, Is.EqualTo(10)); } @@ -312,33 +310,31 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Media_Descendants() { - var folderType = ServiceContext.MediaTypeService.Get(1031); - var imageMediaType = ServiceContext.MediaTypeService.Get(1032); + var folderType = MediaTypeService.Get(1031); + var imageMediaType = MediaTypeService.Get(1032); - var root = MockedMedia.CreateMediaFolder(folderType, -1); - ServiceContext.MediaService.Save(root); + var root = MediaBuilder.CreateMediaFolder(folderType, -1); + MediaService.Save(root); var count = 0; for (int i = 0; i < 10; i++) { - var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id); - ServiceContext.MediaService.Save(c1); + var c1 = MediaBuilder.CreateMediaImage(imageMediaType, root.Id); + MediaService.Save(c1); count++; for (int j = 0; j < 5; j++) { - var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id); - ServiceContext.MediaService.Save(c2); + var c2 = MediaBuilder.CreateMediaImage(imageMediaType, c1.Id); + MediaService.Save(c2); count++; } } - var service = ServiceContext.EntityService; - long total; - var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 31, out total).ToArray(); + var entities = EntityService.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 31, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(31)); Assert.That(total, Is.EqualTo(60)); - entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 1, 31, out total).ToArray(); + entities = EntityService.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 1, 31, out total).ToArray(); Assert.That(entities.Length, Is.EqualTo(29)); Assert.That(total, Is.EqualTo(60)); } @@ -346,16 +342,16 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Media_Descendants_Including_Recycled() { - var folderType = ServiceContext.MediaTypeService.Get(1031); - var imageMediaType = ServiceContext.MediaTypeService.Get(1032); + var folderType = MediaTypeService.Get(1031); + var imageMediaType = MediaTypeService.Get(1032); - var root = MockedMedia.CreateMediaFolder(folderType, -1); - ServiceContext.MediaService.Save(root); + var root = MediaBuilder.CreateMediaFolder(folderType, -1); + MediaService.Save(root); var toDelete = new List(); for (int i = 0; i < 10; i++) { - var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id); - ServiceContext.MediaService.Save(c1); + var c1 = MediaBuilder.CreateMediaImage(imageMediaType, root.Id); + MediaService.Save(c1); if (i % 2 == 0) { @@ -364,21 +360,19 @@ namespace Umbraco.Tests.Services for (int j = 0; j < 5; j++) { - var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id); - ServiceContext.MediaService.Save(c2); + var c2 = MediaBuilder.CreateMediaImage(imageMediaType, c1.Id); + MediaService.Save(c2); } } foreach (var content in toDelete) { - ServiceContext.MediaService.MoveToRecycleBin(content); + MediaService.MoveToRecycleBin(content); } - var service = ServiceContext.EntityService; - long total; //search at root to see if it returns recycled - var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Media, 0, 1000, out total) + var entities = EntityService.GetPagedDescendants(-1, UmbracoObjectTypes.Media, 0, 1000, out total) .Select(x => x.Id) .ToArray(); @@ -391,16 +385,16 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Media_Descendants_Without_Recycled() { - var folderType = ServiceContext.MediaTypeService.Get(1031); - var imageMediaType = ServiceContext.MediaTypeService.Get(1032); + var folderType = MediaTypeService.Get(1031); + var imageMediaType = MediaTypeService.Get(1032); - var root = MockedMedia.CreateMediaFolder(folderType, -1); - ServiceContext.MediaService.Save(root); + var root = MediaBuilder.CreateMediaFolder(folderType, -1); + MediaService.Save(root); var toDelete = new List(); for (int i = 0; i < 10; i++) { - var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id); - ServiceContext.MediaService.Save(c1); + var c1 = MediaBuilder.CreateMediaImage(imageMediaType, root.Id); + MediaService.Save(c1); if (i % 2 == 0) { @@ -409,21 +403,19 @@ namespace Umbraco.Tests.Services for (int j = 0; j < 5; j++) { - var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id); - ServiceContext.MediaService.Save(c2); + var c2 = MediaBuilder.CreateMediaImage(imageMediaType, c1.Id); + MediaService.Save(c2); } } foreach (var content in toDelete) { - ServiceContext.MediaService.MoveToRecycleBin(content); + MediaService.MoveToRecycleBin(content); } - var service = ServiceContext.EntityService; - long total; //search at root to see if it returns recycled - var entities = service.GetPagedDescendants(UmbracoObjectTypes.Media, 0, 1000, out total, includeTrashed: false) + var entities = EntityService.GetPagedDescendants(UmbracoObjectTypes.Media, 0, 1000, out total, includeTrashed: false) .Select(x => x.Id) .ToArray(); @@ -436,34 +428,32 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Paged_Media_Descendants_With_Search() { - var folderType = ServiceContext.MediaTypeService.Get(1031); - var imageMediaType = ServiceContext.MediaTypeService.Get(1032); + var folderType = MediaTypeService.Get(1031); + var imageMediaType = MediaTypeService.Get(1032); - var root = MockedMedia.CreateMediaFolder(folderType, -1); - ServiceContext.MediaService.Save(root); + var root = MediaBuilder.CreateMediaFolder(folderType, -1); + MediaService.Save(root); for (int i = 0; i < 10; i++) { - var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id); + var c1 = MediaBuilder.CreateMediaImage(imageMediaType, root.Id); c1.Name = "ssss" + Guid.NewGuid(); - ServiceContext.MediaService.Save(c1); + MediaService.Save(c1); for (int j = 0; j < 5; j++) { - var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id); + var c2 = MediaBuilder.CreateMediaImage(imageMediaType, c1.Id); c2.Name = "tttt" + Guid.NewGuid(); - ServiceContext.MediaService.Save(c2); + MediaService.Save(c2); } } - var service = ServiceContext.EntityService; - long total; - var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 10, out total, + var entities = EntityService.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 10, out total, filter: SqlContext.Query().Where(x => x.Name.Contains("ssss"))).ToArray(); Assert.That(entities.Length, Is.EqualTo(10)); Assert.That(total, Is.EqualTo(10)); - entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 50, out total, + entities = EntityService.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 50, out total, filter: SqlContext.Query().Where(x => x.Name.Contains("tttt"))).ToArray(); Assert.That(entities.Length, Is.EqualTo(50)); Assert.That(total, Is.EqualTo(50)); @@ -472,9 +462,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Find_All_Content_By_UmbracoObjectTypes() { - var service = ServiceContext.EntityService; - - var entities = service.GetAll(UmbracoObjectTypes.Document).ToArray(); + var entities = EntityService.GetAll(UmbracoObjectTypes.Document).ToArray(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Length, Is.EqualTo(4)); @@ -484,10 +472,8 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Find_All_Content_By_UmbracoObjectType_Id() { - var service = ServiceContext.EntityService; - var objectTypeId = Constants.ObjectTypes.Document; - var entities = service.GetAll(objectTypeId).ToArray(); + var entities = EntityService.GetAll(objectTypeId).ToArray(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Length, Is.EqualTo(4)); @@ -497,9 +483,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Find_All_Content_By_Type() { - var service = ServiceContext.EntityService; - - var entities = service.GetAll().ToArray(); + var entities = EntityService.GetAll().ToArray(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Length, Is.EqualTo(4)); @@ -509,9 +493,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Child_Content_By_ParentId_And_UmbracoObjectType() { - var service = ServiceContext.EntityService; - - var entities = service.GetChildren(-1, UmbracoObjectTypes.Document).ToArray(); + var entities = EntityService.GetChildren(-1, UmbracoObjectTypes.Document).ToArray(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Length, Is.EqualTo(1)); @@ -521,19 +503,19 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Content_By_UmbracoObjectType_With_Variant_Names() { - var service = ServiceContext.EntityService; - var alias = "test" + Guid.NewGuid(); - var contentType = MockedContentTypes.CreateSimpleContentType(alias, alias, false); + var template = TemplateBuilder.CreateTextPageTemplate(alias); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType("test2", "Test2", defaultTemplateId: template.Id); contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var c1 = MockedContent.CreateSimpleContent(contentType, "Test", -1); + var c1 = ContentBuilder.CreateSimpleContent(contentType, "Test", -1); c1.SetCultureName("Test - FR", _langFr.IsoCode); c1.SetCultureName("Test - ES", _langEs.IsoCode); - ServiceContext.ContentService.Save(c1); + ContentService.Save(c1); - var result = service.Get(c1.Id, UmbracoObjectTypes.Document); + var result = EntityService.Get(c1.Id, UmbracoObjectTypes.Document); Assert.AreEqual("Test - FR", result.Name); // got name from default culture Assert.IsNotNull(result as IDocumentEntitySlim); var doc = (IDocumentEntitySlim)result; @@ -545,19 +527,19 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Child_Content_By_ParentId_And_UmbracoObjectType_With_Variant_Names() { - var service = ServiceContext.EntityService; - - var contentType = MockedContentTypes.CreateSimpleContentType("test1", "Test1", false); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType("test1", "Test1", defaultTemplateId: template.Id); contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - var root = MockedContent.CreateSimpleContent(contentType); + var root = ContentBuilder.CreateSimpleContent(contentType); root.SetCultureName("Root", _langFr.IsoCode); // else cannot save - ServiceContext.ContentService.Save(root); + ContentService.Save(root); for (int i = 0; i < 10; i++) { - var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); + var c1 = ContentBuilder.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root); if (i % 2 == 0) { c1.SetCultureName("Test " + i + " - FR", _langFr.IsoCode); @@ -567,10 +549,10 @@ namespace Umbraco.Tests.Services { c1.SetCultureName("Test", _langFr.IsoCode); // else cannot save } - ServiceContext.ContentService.Save(c1); + ContentService.Save(c1); } - var entities = service.GetChildren(root.Id, UmbracoObjectTypes.Document).ToArray(); + var entities = EntityService.GetChildren(root.Id, UmbracoObjectTypes.Document).ToArray(); Assert.AreEqual(10, entities.Length); @@ -598,9 +580,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Children_By_ParentId() { - var service = ServiceContext.EntityService; - - var entities = service.GetChildren(folderId); + var entities = EntityService.GetChildren(folderId); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(3)); @@ -610,9 +590,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Descendants_By_ParentId() { - var service = ServiceContext.EntityService; - - var entities = service.GetDescendants(folderId); + var entities = EntityService.GetDescendants(folderId); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(4)); @@ -622,19 +600,16 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Throws_When_Getting_All_With_Invalid_Type() { - var service = ServiceContext.EntityService; var objectTypeId = Constants.ObjectTypes.ContentItem; - Assert.Throws(() => service.GetAll()); - Assert.Throws(() => service.GetAll(objectTypeId)); + Assert.Throws(() => EntityService.GetAll()); + Assert.Throws(() => EntityService.GetAll(objectTypeId)); } [Test] public void EntityService_Can_Find_All_ContentTypes_By_UmbracoObjectTypes() { - var service = ServiceContext.EntityService; - - var entities = service.GetAll(UmbracoObjectTypes.DocumentType).ToArray(); + var entities = EntityService.GetAll(UmbracoObjectTypes.DocumentType).ToArray(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); @@ -643,10 +618,8 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Find_All_ContentTypes_By_UmbracoObjectType_Id() { - var service = ServiceContext.EntityService; - var objectTypeId = Constants.ObjectTypes.DocumentType; - var entities = service.GetAll(objectTypeId).ToArray(); + var entities = EntityService.GetAll(objectTypeId).ToArray(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); @@ -655,9 +628,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Find_All_ContentTypes_By_Type() { - var service = ServiceContext.EntityService; - - var entities = service.GetAll().ToArray(); + var entities = EntityService.GetAll().ToArray(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Count(), Is.EqualTo(1)); @@ -666,9 +637,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Find_All_Media_By_UmbracoObjectTypes() { - var service = ServiceContext.EntityService; - - var entities = service.GetAll(UmbracoObjectTypes.Media).ToArray(); + var entities = EntityService.GetAll(UmbracoObjectTypes.Media).ToArray(); Assert.That(entities.Any(), Is.True); Assert.That(entities.Length, Is.EqualTo(5)); @@ -683,9 +652,8 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_ObjectType() - { - var service = ServiceContext.EntityService; - var mediaObjectType = service.GetObjectType(1031); + { ; + var mediaObjectType = EntityService.GetObjectType(1031); Assert.NotNull(mediaObjectType); Assert.AreEqual(mediaObjectType, UmbracoObjectTypes.MediaType); @@ -694,8 +662,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Key_For_Id_With_Unknown_Type() { - var service = ServiceContext.EntityService; - var result = service.GetKey(1061, UmbracoObjectTypes.Unknown); + var result = EntityService.GetKey(1052, UmbracoObjectTypes.Unknown); Assert.IsTrue(result.Success); Assert.AreEqual(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), result.Result); @@ -704,8 +671,7 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Key_For_Id() { - var service = ServiceContext.EntityService; - var result = service.GetKey(1061, UmbracoObjectTypes.DocumentType); + var result = EntityService.GetKey(1052, UmbracoObjectTypes.DocumentType); Assert.IsTrue(result.Success); Assert.AreEqual(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), result.Result); @@ -714,9 +680,8 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Cannot_Get_Key_For_Id_With_Incorrect_Object_Type() { - var service = ServiceContext.EntityService; - var result1 = service.GetKey(1061, UmbracoObjectTypes.DocumentType); - var result2 = service.GetKey(1061, UmbracoObjectTypes.MediaType); + var result1 = EntityService.GetKey(1052, UmbracoObjectTypes.DocumentType); + var result2 = EntityService.GetKey(1052, UmbracoObjectTypes.MediaType); Assert.IsTrue(result1.Success); Assert.IsFalse(result2.Success); @@ -725,29 +690,26 @@ namespace Umbraco.Tests.Services [Test] public void EntityService_Can_Get_Id_For_Key_With_Unknown_Type() { - var service = ServiceContext.EntityService; - var result = service.GetId(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.Unknown); + var result = EntityService.GetId(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.Unknown); Assert.IsTrue(result.Success); - Assert.AreEqual(1061, result.Result); + Assert.AreEqual(1052, result.Result); } [Test] public void EntityService_Can_Get_Id_For_Key() { - var service = ServiceContext.EntityService; - var result = service.GetId(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.DocumentType); + var result = EntityService.GetId(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.DocumentType); Assert.IsTrue(result.Success); - Assert.AreEqual(1061, result.Result); + Assert.AreEqual(1052, result.Result); } [Test] public void EntityService_Cannot_Get_Id_For_Key_With_Incorrect_Object_Type() { - var service = ServiceContext.EntityService; - var result1 = service.GetId(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.DocumentType); - var result2 = service.GetId(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.MediaType); + var result1 = EntityService.GetId(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.DocumentType); + var result2 = EntityService.GetId(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.MediaType); Assert.IsTrue(result1.Success); Assert.IsFalse(result2.Success); @@ -756,59 +718,85 @@ namespace Umbraco.Tests.Services [Test] public void ReserveId() { - var service = ServiceContext.EntityService; var guid = Guid.NewGuid(); // can reserve - var reservedId = service.ReserveId(guid); + var reservedId = EntityService.ReserveId(guid); Assert.IsTrue(reservedId > 0); // can get it back - var id = service.GetId(guid, UmbracoObjectTypes.DocumentType); + var id = EntityService.GetId(guid, UmbracoObjectTypes.DocumentType); Assert.IsTrue(id.Success); Assert.AreEqual(reservedId, id.Result); // anything goes - id = service.GetId(guid, UmbracoObjectTypes.Media); + id = EntityService.GetId(guid, UmbracoObjectTypes.Media); Assert.IsTrue(id.Success); Assert.AreEqual(reservedId, id.Result); // a random guid won't work - Assert.IsFalse(service.GetId(Guid.NewGuid(), UmbracoObjectTypes.DocumentType).Success); + Assert.IsFalse(EntityService.GetId(Guid.NewGuid(), UmbracoObjectTypes.DocumentType).Success); } private static bool _isSetup = false; private int folderId; - public override void CreateTestData() + public void CreateTestData() { if (_isSetup == false) { _isSetup = true; - base.CreateTestData(); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); // else, FK violation on contentType! - //Create and Save folder-Media -> 1050 - var folderMediaType = ServiceContext.MediaTypeService.Get(1031); - var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1); - ServiceContext.MediaService.Save(folder, 0); + //Create and Save ContentType "umbTextpage" -> 1052 + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id); + contentType.Key = new Guid("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"); + ContentTypeService.Save(contentType); + + //Create and Save Content "Homepage" based on "umbTextpage" -> 1053 + var textpage = ContentBuilder.CreateSimpleContent(contentType); + textpage.Key = new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0"); + ContentService.Save(textpage, 0); + + //Create and Save Content "Text Page 1" based on "umbTextpage" -> 1054 + var subpage = ContentBuilder.CreateSimpleContent(contentType, "Text Page 1", textpage.Id); + subpage.ContentSchedule.Add(DateTime.Now.AddMinutes(-5), null); + ContentService.Save(subpage, 0); + + //Create and Save Content "Text Page 2" based on "umbTextpage" -> 1055 + var subpage2 = ContentBuilder.CreateSimpleContent(contentType, "Text Page 2", textpage.Id); + ContentService.Save(subpage2, 0); + + //Create and Save Content "Text Page Deleted" based on "umbTextpage" -> 1056 + var trashed = ContentBuilder.CreateSimpleContent(contentType, "Text Page Deleted", -20); + trashed.Trashed = true; + ContentService.Save(trashed, 0); + + //Create and Save folder-Media -> 1057 + var folderMediaType = MediaTypeService.Get(1031); + var folder = MediaBuilder.CreateMediaFolder(folderMediaType, -1); + MediaService.Save(folder, 0); folderId = folder.Id; - //Create and Save image-Media -> 1051 - var imageMediaType = ServiceContext.MediaTypeService.Get(1032); - var image = MockedMedia.CreateMediaImage(imageMediaType, folder.Id); - ServiceContext.MediaService.Save(image, 0); + //Create and Save image-Media -> 1058 + var imageMediaType = MediaTypeService.Get(1032); + var image = MediaBuilder.CreateMediaImage(imageMediaType, folder.Id); + MediaService.Save(image, 0); - //Create and Save file-Media -> 1052 - var fileMediaType = ServiceContext.MediaTypeService.Get(1033); - var file = MockedMedia.CreateMediaFile(fileMediaType, folder.Id); - ServiceContext.MediaService.Save(file, 0); + //Create and Save file-Media -> 1059 + var fileMediaType = MediaTypeService.Get(1033); + var file = MediaBuilder.CreateMediaFile(fileMediaType, folder.Id); + MediaService.Save(file, 0); - var subfolder = MockedMedia.CreateMediaFolder(folderMediaType, folder.Id); - ServiceContext.MediaService.Save(subfolder, 0); - var subfolder2 = MockedMedia.CreateMediaFolder(folderMediaType, subfolder.Id); - ServiceContext.MediaService.Save(subfolder2, 0); + // Create and save sub folder -> 1060 + var subfolder = MediaBuilder.CreateMediaFolder(folderMediaType, folder.Id); + MediaService.Save(subfolder, 0); + // Create and save sub folder -> 1061 + var subfolder2 = MediaBuilder.CreateMediaFolder(folderMediaType, subfolder.Id); + MediaService.Save(subfolder2, 0); } } } diff --git a/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs b/src/Umbraco.Tests.Integration/Services/EntityXmlSerializerTests.cs similarity index 59% rename from src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs rename to src/Umbraco.Tests.Integration/Services/EntityXmlSerializerTests.cs index e10dd99482..5bc16a4cdb 100644 --- a/src/Umbraco.Tests/Services/EntityXmlSerializerTests.cs +++ b/src/Umbraco.Tests.Integration/Services/EntityXmlSerializerTests.cs @@ -3,27 +3,32 @@ using System.Diagnostics; using System.Linq; using System.Xml.Linq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Composing; using Umbraco.Core.Models; using Umbraco.Core.Services; -using Umbraco.Tests.Services.Importing; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; +using Umbraco.Tests.Integration.Services.Importing; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class EntityXmlSerializerTests : TestWithSomeContentBase + public class EntityXmlSerializerTests : UmbracoIntegrationTest { - private IEntityXmlSerializer Serializer => Factory.GetInstance(); + private IEntityXmlSerializer Serializer => GetRequiredService(); [Test] public void Can_Export_Macro() { // Arrange - var macro = new Macro(ShortStringHelper, "test1", "Test", "~/views/macropartials/test.cshtml"); - ServiceContext.MacroService.Save(macro); + var macroService = GetRequiredService(); + var macro = new MacroBuilder() + .WithAlias("test1") + .WithName("Test") + .Build(); + macroService.Save(macro); // Act var element = Serializer.Serialize(macro); @@ -40,7 +45,8 @@ namespace Umbraco.Tests.Services { // Arrange CreateDictionaryData(); - var dictionaryItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Parent"); + var localizationService = GetRequiredService(); + var dictionaryItem = localizationService.GetDictionaryItemByKey("Parent"); var newPackageXml = XElement.Parse(ImportResources.Dictionary_Package); var dictionaryItemsElement = newPackageXml.Elements("DictionaryItems").First(); @@ -56,11 +62,18 @@ namespace Umbraco.Tests.Services public void Can_Export_Languages() { // Arrange - var languageNbNo = new Language(TestObjects.GetGlobalSettings(), "nb-NO") { CultureName = "Norwegian" }; - ServiceContext.LocalizationService.Save(languageNbNo); + var localizationService = GetRequiredService(); - var languageEnGb = new Language(TestObjects.GetGlobalSettings(), "en-GB") { CultureName = "English (United Kingdom)" }; - ServiceContext.LocalizationService.Save(languageEnGb); + var languageNbNo = new LanguageBuilder() + .WithCultureInfo("nb-NO") + .WithCultureName("Norwegian") + .Build(); + localizationService.Save(languageNbNo); + + var languageEnGb = new LanguageBuilder() + .WithCultureInfo("en-GB") + .Build(); + localizationService.Save(languageEnGb); var newPackageXml = XElement.Parse(ImportResources.Dictionary_Package); var languageItemsElement = newPackageXml.Elements("Languages").First(); @@ -74,11 +87,18 @@ namespace Umbraco.Tests.Services private void CreateDictionaryData() { - var languageNbNo = new Language(TestObjects.GetGlobalSettings(), "nb-NO") { CultureName = "nb-NO" }; - ServiceContext.LocalizationService.Save(languageNbNo); + var localizationService = GetRequiredService(); - var languageEnGb = new Language(TestObjects.GetGlobalSettings(), "en-GB") { CultureName = "en-GB" }; - ServiceContext.LocalizationService.Save(languageEnGb); + var languageNbNo = new LanguageBuilder() + .WithCultureInfo("nb-NO") + .WithCultureName("Norwegian") + .Build(); + localizationService.Save(languageNbNo); + + var languageEnGb = new LanguageBuilder() + .WithCultureInfo("en-GB") + .Build(); + localizationService.Save(languageEnGb); var parentItem = new DictionaryItem("Parent"); var parentTranslations = new List @@ -87,7 +107,7 @@ namespace Umbraco.Tests.Services new DictionaryTranslation(languageEnGb, "ParentValue") }; parentItem.Translations = parentTranslations; - ServiceContext.LocalizationService.Save(parentItem); + localizationService.Save(parentItem); var childItem = new DictionaryItem(parentItem.Key, "Child"); var childTranslations = new List @@ -96,7 +116,7 @@ namespace Umbraco.Tests.Services new DictionaryTranslation(languageEnGb, "ChildValue") }; childItem.Translations = childTranslations; - ServiceContext.LocalizationService.Save(childItem); + localizationService.Save(childItem); } } } diff --git a/src/Umbraco.Tests.Integration/Services/FileServiceTests.cs b/src/Umbraco.Tests.Integration/Services/FileServiceTests.cs new file mode 100644 index 0000000000..8a4a0535b6 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Services/FileServiceTests.cs @@ -0,0 +1,74 @@ +using System; +using System.Linq; +using System.Threading; +using NUnit.Framework; +using Umbraco.Core.Services; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Integration.Services +{ + [TestFixture] + [Apartment(ApartmentState.STA)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class FileServiceTests : UmbracoIntegrationTest + { + private IFileService FileService => GetRequiredService(); + + [Test] + public void Create_Template_Then_Assign_Child() + { + var child = FileService.CreateTemplateWithIdentity("Child", "child", "test"); + var parent = FileService.CreateTemplateWithIdentity("Parent", "parent", "test"); + + child.SetMasterTemplate(parent); + FileService.SaveTemplate(child); + + child = FileService.GetTemplate(child.Id); + + Assert.AreEqual(parent.Alias, child.MasterTemplateAlias); + + } + + [Test] + public void Create_Template_With_Child_Then_Unassign() + { + var parent = FileService.CreateTemplateWithIdentity("Parent", "parent", "test"); + var child = FileService.CreateTemplateWithIdentity("Child", "child", "test", parent); + + child.SetMasterTemplate(null); + FileService.SaveTemplate(child); + + child = FileService.GetTemplate(child.Id); + + Assert.AreEqual(null, child.MasterTemplateAlias); + } + + [Test] + public void Can_Query_Template_Children() + { + var parent = FileService.CreateTemplateWithIdentity("Parent", "parent", "test"); + var child1 = FileService.CreateTemplateWithIdentity("Child1", "child1", "test", parent); + var child2 = FileService.CreateTemplateWithIdentity("Child2", "child2", "test", parent); + + var children = FileService.GetTemplates(parent.Id).Select(x => x.Id).ToArray(); + + Assert.IsTrue(children.Contains(child1.Id)); + Assert.IsTrue(children.Contains(child2.Id)); + } + + [Test] + public void Create_Template_With_Custom_Alias() + { + var template = FileService.CreateTemplateWithIdentity("Test template", "customTemplateAlias", "test"); + + FileService.SaveTemplate(template); + + template = FileService.GetTemplate(template.Id); + + Assert.AreEqual("Test template", template.Name); + Assert.AreEqual("customTemplateAlias", template.Alias); + } + + } +} diff --git a/src/Umbraco.Tests.Integration/Services/Importing/Dictionary-Package.xml b/src/Umbraco.Tests.Integration/Services/Importing/Dictionary-Package.xml new file mode 100644 index 0000000000..8324ea4ef4 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Services/Importing/Dictionary-Package.xml @@ -0,0 +1,36 @@ + + + + + + Dictionary-Package + 1.0 + MIT license + http://not.available + + 3 + 0 + 0 + + + + Test + http://not.available + + + + + + + + + + + + + + + + + + diff --git a/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.Designer.cs new file mode 100644 index 0000000000..4925956fb8 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.Designer.cs @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Umbraco.Tests.Integration.Services.Importing { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class ImportResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ImportResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Tests.Integration.Services.Importing.ImportResources", typeof(ImportResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>Dictionary-Package</name> + /// <version>1.0</version> + /// <license url="http://www.opensource.org/licenses/mit-license.php">MIT license</license> + /// <url>http://not.available</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>Test</name> + /// <website>http://not.available</w [rest of string was truncated]";. + /// + internal static string Dictionary_Package { + get { + return ResourceManager.GetString("Dictionary_Package", resourceCulture); + } + } + } +} diff --git a/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.resx b/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.resx new file mode 100644 index 0000000000..5823fa1245 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + dictionary-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/KeyValueServiceTests.cs b/src/Umbraco.Tests.Integration/Services/KeyValueServiceTests.cs similarity index 51% rename from src/Umbraco.Tests/Services/KeyValueServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/KeyValueServiceTests.cs index 5ab29258f5..8694e88395 100644 --- a/src/Umbraco.Tests/Services/KeyValueServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/KeyValueServiceTests.cs @@ -1,29 +1,26 @@ using System.Threading; using NUnit.Framework; -using NUnit.Framework.Internal; using Umbraco.Core.Services; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering methods in the KeyValueService class. - /// This is more of an integration test as it involves multiple layers - /// as well as configuration. /// [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class KeyValueServiceTests : TestWithSomeContentBase + public class KeyValueServiceTests : UmbracoIntegrationTest { + private IKeyValueService KeyValueService => GetRequiredService(); + [Test] public void GetValue_ForMissingKey_ReturnsNull() { - // Arrange - var keyValueService = ServiceContext.KeyValueService; - // Act - var value = keyValueService.GetValue("foo"); + var value = KeyValueService.GetValue("foo"); // Assert Assert.IsNull(value); @@ -32,12 +29,10 @@ namespace Umbraco.Tests.Services [Test] public void GetValue_ForExistingKey_ReturnsValue() { - // Arrange - var keyValueService = ServiceContext.KeyValueService; - keyValueService.SetValue("foo", "bar"); + KeyValueService.SetValue("foo", "bar"); // Act - var value = keyValueService.GetValue("foo"); + var value = KeyValueService.GetValue("foo"); // Assert Assert.AreEqual("bar", value); @@ -46,13 +41,11 @@ namespace Umbraco.Tests.Services [Test] public void SetValue_ForExistingKey_SavesValue() { - // Arrange - var keyValueService = ServiceContext.KeyValueService; - keyValueService.SetValue("foo", "bar"); + KeyValueService.SetValue("foo", "bar"); // Act - keyValueService.SetValue("foo", "buzz"); - var value = keyValueService.GetValue("foo"); + KeyValueService.SetValue("foo", "buzz"); + var value = KeyValueService.GetValue("foo"); // Assert Assert.AreEqual("buzz", value); @@ -61,13 +54,11 @@ namespace Umbraco.Tests.Services [Test] public void TrySetValue_ForExistingKeyWithProvidedValue_ReturnsTrueAndSetsValue() { - // Arrange - var keyValueService = ServiceContext.KeyValueService; - keyValueService.SetValue("foo", "bar"); + KeyValueService.SetValue("foo", "bar"); // Act - var result = keyValueService.TrySetValue("foo", "bar", "buzz"); - var value = keyValueService.GetValue("foo"); + var result = KeyValueService.TrySetValue("foo", "bar", "buzz"); + var value = KeyValueService.GetValue("foo"); // Assert Assert.IsTrue(result); @@ -77,13 +68,11 @@ namespace Umbraco.Tests.Services [Test] public void TrySetValue_ForExistingKeyWithoutProvidedValue_ReturnsFalseAndDoesNotSetValue() { - // Arrange - var keyValueService = ServiceContext.KeyValueService; - keyValueService.SetValue("foo", "bar"); + KeyValueService.SetValue("foo", "bar"); // Act - var result = keyValueService.TrySetValue("foo", "bang", "buzz"); - var value = keyValueService.GetValue("foo"); + var result = KeyValueService.TrySetValue("foo", "bang", "buzz"); + var value = KeyValueService.GetValue("foo"); // Assert Assert.IsFalse(result); diff --git a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs b/src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs similarity index 55% rename from src/Umbraco.Tests/Services/LocalizationServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs index c5ff549ee3..a2847b64fe 100644 --- a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs @@ -4,13 +4,15 @@ using System.Diagnostics; using System.Linq; using System.Threading; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Models; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; using Umbraco.Core.Persistence; +using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering all methods in the LocalizationService class. @@ -20,7 +22,7 @@ namespace Umbraco.Tests.Services [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class LocalizationServiceTests : TestWithSomeContentBase + public class LocalizationServiceTests : UmbracoIntegrationTest { private Guid _parentItemGuidId; private int _parentItemIntId; @@ -29,10 +31,18 @@ namespace Umbraco.Tests.Services private int _danishLangId; private int _englishLangId; + private ILocalizationService LocalizationService => GetRequiredService(); + + [SetUp] + public void SetUp() + { + CreateTestData(); + } + [Test] public void Can_Get_Root_Dictionary_Items() { - var rootItems = ServiceContext.LocalizationService.GetRootDictionaryItems(); + var rootItems = LocalizationService.GetRootDictionaryItems(); Assert.NotNull(rootItems); Assert.IsTrue(rootItems.Any()); @@ -41,14 +51,14 @@ namespace Umbraco.Tests.Services [Test] public void Can_Determint_If_DictionaryItem_Exists() { - var exists = ServiceContext.LocalizationService.DictionaryItemExists("Parent"); + var exists = LocalizationService.DictionaryItemExists("Parent"); Assert.IsTrue(exists); } [Test] public void Can_Get_All_Languages() { - var languages = ServiceContext.LocalizationService.GetAllLanguages(); + var languages = LocalizationService.GetAllLanguages(); Assert.NotNull(languages); Assert.IsTrue(languages.Any()); Assert.That(languages.Count(), Is.EqualTo(3)); @@ -57,37 +67,37 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_Dictionary_Item_By_Int_Id() { - var parentItem = ServiceContext.LocalizationService.GetDictionaryItemById(_parentItemIntId); + var parentItem = LocalizationService.GetDictionaryItemById(_parentItemIntId); Assert.NotNull(parentItem); - var childItem = ServiceContext.LocalizationService.GetDictionaryItemById(_childItemIntId); + var childItem = LocalizationService.GetDictionaryItemById(_childItemIntId); Assert.NotNull(childItem); } [Test] public void Can_Get_Dictionary_Item_By_Guid_Id() { - var parentItem = ServiceContext.LocalizationService.GetDictionaryItemById(_parentItemGuidId); + var parentItem = LocalizationService.GetDictionaryItemById(_parentItemGuidId); Assert.NotNull(parentItem); - var childItem = ServiceContext.LocalizationService.GetDictionaryItemById(_childItemGuidId); + var childItem = LocalizationService.GetDictionaryItemById(_childItemGuidId); Assert.NotNull(childItem); } [Test] public void Can_Get_Dictionary_Item_By_Key() { - var parentItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Parent"); + var parentItem = LocalizationService.GetDictionaryItemByKey("Parent"); Assert.NotNull(parentItem); - var childItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var childItem = LocalizationService.GetDictionaryItemByKey("Child"); Assert.NotNull(childItem); } [Test] public void Can_Get_Dictionary_Item_Children() { - var item = ServiceContext.LocalizationService.GetDictionaryItemChildren(_parentItemGuidId); + var item = LocalizationService.GetDictionaryItemChildren(_parentItemGuidId); Assert.NotNull(item); Assert.That(item.Count(), Is.EqualTo(1)); @@ -103,11 +113,11 @@ namespace Umbraco.Tests.Services { using (var scope = ScopeProvider.CreateScope()) { - var en = ServiceContext.LocalizationService.GetLanguageById(_englishLangId); - var dk = ServiceContext.LocalizationService.GetLanguageById(_danishLangId); + var en = LocalizationService.GetLanguageById(_englishLangId); + var dk = LocalizationService.GetLanguageById(_danishLangId); var currParentId = _childItemGuidId; - for (int i = 0; i < 25; i++) + for (var i = 0; i < 25; i++) { //Create 2 per level var desc1 = new DictionaryItem(currParentId, "D1" + i) @@ -126,8 +136,8 @@ namespace Umbraco.Tests.Services new DictionaryTranslation(dk, "BørnVærdi2 " + i) } }; - ServiceContext.LocalizationService.Save(desc1); - ServiceContext.LocalizationService.Save(desc2); + LocalizationService.Save(desc1); + LocalizationService.Save(desc2); currParentId = desc1.Key; } @@ -135,8 +145,7 @@ namespace Umbraco.Tests.Services scope.Database.AsUmbracoDatabase().EnableSqlTrace = true; scope.Database.AsUmbracoDatabase().EnableSqlCount = true; - var items = ServiceContext.LocalizationService.GetDictionaryItemDescendants(_parentItemGuidId) - .ToArray(); + var items = LocalizationService.GetDictionaryItemDescendants(_parentItemGuidId).ToArray(); Debug.WriteLine("SQL CALLS: " + scope.Database.AsUmbracoDatabase().SqlCount); @@ -149,8 +158,8 @@ namespace Umbraco.Tests.Services [Test] public void Can_GetLanguageById() { - var danish = ServiceContext.LocalizationService.GetLanguageById(_danishLangId); - var english = ServiceContext.LocalizationService.GetLanguageById(_englishLangId); + var danish = LocalizationService.GetLanguageById(_danishLangId); + var english = LocalizationService.GetLanguageById(_englishLangId); Assert.NotNull(danish); Assert.NotNull(english); } @@ -158,8 +167,8 @@ namespace Umbraco.Tests.Services [Test] public void Can_GetLanguageByIsoCode() { - var danish = ServiceContext.LocalizationService.GetLanguageByIsoCode("da-DK"); - var english = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-GB"); + var danish = LocalizationService.GetLanguageByIsoCode("da-DK"); + var english = LocalizationService.GetLanguageByIsoCode("en-GB"); Assert.NotNull(danish); Assert.NotNull(english); } @@ -167,49 +176,54 @@ namespace Umbraco.Tests.Services [Test] public void Does_Not_Fail_When_Language_Doesnt_Exist() { - var language = ServiceContext.LocalizationService.GetLanguageByIsoCode("sv-SE"); + var language = LocalizationService.GetLanguageByIsoCode("sv-SE"); Assert.Null(language); } [Test] public void Does_Not_Fail_When_DictionaryItem_Doesnt_Exist() { - var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("RandomKey"); + var item = LocalizationService.GetDictionaryItemByKey("RandomKey"); Assert.Null(item); } [Test] public void Can_Delete_Language() { - var norwegian = new Language(TestObjects.GetGlobalSettings(), "nb-NO") { CultureName = "Norwegian" }; - ServiceContext.LocalizationService.Save(norwegian, 0); - Assert.That(norwegian.HasIdentity, Is.True); - var languageId = norwegian.Id; + var languageNbNo = new LanguageBuilder() + .WithCultureInfo("nb-NO") + .Build(); + LocalizationService.Save(languageNbNo, 0); + Assert.That(languageNbNo.HasIdentity, Is.True); + var languageId = languageNbNo.Id; - ServiceContext.LocalizationService.Delete(norwegian); + LocalizationService.Delete(languageNbNo); - var language = ServiceContext.LocalizationService.GetLanguageById(languageId); + var language = LocalizationService.GetLanguageById(languageId); Assert.Null(language); } [Test] 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 }; - ServiceContext.LocalizationService.Save(norwegian, 0); - var languageId = danish.Id; + var languageDaDk = LocalizationService.GetLanguageByIsoCode("da-DK"); + var languageNbNo = new LanguageBuilder() + .WithCultureInfo("nb-NO") + .WithFallbackLanguageId(languageDaDk.Id) + .Build(); + LocalizationService.Save(languageNbNo, 0); + var languageId = languageDaDk.Id; - ServiceContext.LocalizationService.Delete(danish); + LocalizationService.Delete(languageDaDk); - var language = ServiceContext.LocalizationService.GetLanguageById(languageId); + var language = LocalizationService.GetLanguageById(languageId); Assert.Null(language); } [Test] public void Can_Create_DictionaryItem_At_Root() { - var english = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-US"); + var english = LocalizationService.GetLanguageByIsoCode("en-US"); var item = (IDictionaryItem)new DictionaryItem("Testing123") { @@ -218,10 +232,10 @@ namespace Umbraco.Tests.Services new DictionaryTranslation(english, "Hello world") } }; - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); //re-get - item = ServiceContext.LocalizationService.GetDictionaryItemById(item.Id); + item = LocalizationService.GetDictionaryItemById(item.Id); Assert.Greater(item.Id, 0); Assert.IsTrue(item.HasIdentity); @@ -233,44 +247,42 @@ namespace Umbraco.Tests.Services [Test] public void Can_Create_DictionaryItem_At_Root_With_Identity() { - - var item = ServiceContext.LocalizationService.CreateDictionaryItemWithIdentity( + var item = LocalizationService.CreateDictionaryItemWithIdentity( "Testing12345", null, "Hellooooo"); //re-get - item = ServiceContext.LocalizationService.GetDictionaryItemById(item.Id); + item = LocalizationService.GetDictionaryItemById(item.Id); Assert.IsNotNull(item); Assert.Greater(item.Id, 0); Assert.IsTrue(item.HasIdentity); Assert.IsFalse(item.ParentId.HasValue); Assert.AreEqual("Testing12345", item.ItemKey); - var allLangs = ServiceContext.LocalizationService.GetAllLanguages(); + var allLangs = LocalizationService.GetAllLanguages(); Assert.Greater(allLangs.Count(), 0); foreach (var language in allLangs) { Assert.AreEqual("Hellooooo", item.Translations.Single(x => x.Language.CultureName == language.CultureName).Value); } - } [Test] public void Can_Add_Translation_To_Existing_Dictionary_Item() { - var english = ServiceContext.LocalizationService.GetLanguageByIsoCode("en-US"); + var english = LocalizationService.GetLanguageByIsoCode("en-US"); var item = (IDictionaryItem) new DictionaryItem("Testing123"); - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); //re-get - item = ServiceContext.LocalizationService.GetDictionaryItemById(item.Id); + item = LocalizationService.GetDictionaryItemById(item.Id); item.Translations = new List { new DictionaryTranslation(english, "Hello world") }; - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); Assert.AreEqual(1, item.Translations.Count()); foreach (var translation in item.Translations) @@ -281,14 +293,14 @@ namespace Umbraco.Tests.Services item.Translations = new List(item.Translations) { new DictionaryTranslation( - ServiceContext.LocalizationService.GetLanguageByIsoCode("en-GB"), + LocalizationService.GetLanguageByIsoCode("en-GB"), "My new value") }; - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); //re-get - item = ServiceContext.LocalizationService.GetDictionaryItemById(item.Id); + item = LocalizationService.GetDictionaryItemById(item.Id); Assert.AreEqual(2, item.Translations.Count()); Assert.AreEqual("Hello world", item.Translations.First().Value); @@ -298,27 +310,27 @@ namespace Umbraco.Tests.Services [Test] public void Can_Delete_DictionaryItem() { - var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var item = LocalizationService.GetDictionaryItemByKey("Child"); Assert.NotNull(item); - ServiceContext.LocalizationService.Delete(item); + LocalizationService.Delete(item); - var deletedItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var deletedItem = LocalizationService.GetDictionaryItemByKey("Child"); Assert.Null(deletedItem); } [Test] public void Can_Update_Existing_DictionaryItem() { - var item = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var item = LocalizationService.GetDictionaryItemByKey("Child"); foreach (var translation in item.Translations) { translation.Value = translation.Value + "UPDATED"; } - ServiceContext.LocalizationService.Save(item); + LocalizationService.Save(item); - var updatedItem = ServiceContext.LocalizationService.GetDictionaryItemByKey("Child"); + var updatedItem = LocalizationService.GetDictionaryItemByKey("Child"); Assert.NotNull(updatedItem); foreach (var translation in updatedItem.Translations) @@ -330,11 +342,8 @@ namespace Umbraco.Tests.Services [Test] public void Find_BaseData_Language() { - // Arrange - var localizationService = ServiceContext.LocalizationService; - // Act - var languages = localizationService.GetAllLanguages(); + var languages = LocalizationService.GetAllLanguages(); // Assert Assert.That(3, Is.EqualTo(languages.Count())); @@ -344,13 +353,14 @@ namespace Umbraco.Tests.Services public void Save_Language_And_GetLanguageByIsoCode() { // Arrange - var localizationService = ServiceContext.LocalizationService; var isoCode = "en-AU"; - var language = new Core.Models.Language(TestObjects.GetGlobalSettings(), isoCode); + var languageEnAu = new LanguageBuilder() + .WithCultureInfo(isoCode) + .Build(); // Act - localizationService.Save(language); - var result = localizationService.GetLanguageByIsoCode(isoCode); + LocalizationService.Save(languageEnAu); + var result = LocalizationService.GetLanguageByIsoCode(isoCode); // Assert Assert.NotNull(result); @@ -359,13 +369,14 @@ namespace Umbraco.Tests.Services [Test] public void Save_Language_And_GetLanguageById() { - var localizationService = ServiceContext.LocalizationService; - var isoCode = "en-AU"; - var language = new Core.Models.Language(TestObjects.GetGlobalSettings(), isoCode); + // Arrange + var languageEnAu = new LanguageBuilder() + .WithCultureInfo("en-AU") + .Build(); // Act - localizationService.Save(language); - var result = localizationService.GetLanguageById(language.Id); + LocalizationService.Save(languageEnAu); + var result = LocalizationService.GetLanguageById(languageEnAu.Id); // Assert Assert.NotNull(result); @@ -374,20 +385,24 @@ namespace Umbraco.Tests.Services [Test] public void Set_Default_Language() { - var localizationService = ServiceContext.LocalizationService; - var language = new Core.Models.Language(TestObjects.GetGlobalSettings(), "en-AU"); - language.IsDefault = true; - localizationService.Save(language); - var result = localizationService.GetLanguageById(language.Id); + var languageEnAu = new LanguageBuilder() + .WithCultureInfo("en-AU") + .WithIsDefault(true) + .Build(); + LocalizationService.Save(languageEnAu); + var result = LocalizationService.GetLanguageById(languageEnAu.Id); Assert.IsTrue(result.IsDefault); - var language2 = new Core.Models.Language(TestObjects.GetGlobalSettings(), "en-NZ"); - language2.IsDefault = true; - localizationService.Save(language2); - var result2 = localizationService.GetLanguageById(language2.Id); + var languageEnNz = new LanguageBuilder() + .WithCultureInfo("en-NZ") + .WithIsDefault(true) + .Build(); + LocalizationService.Save(languageEnNz); + var result2 = LocalizationService.GetLanguageById(languageEnNz.Id); + //re-get - result = localizationService.GetLanguageById(language.Id); + result = LocalizationService.GetLanguageById(languageEnAu.Id); Assert.IsTrue(result2.IsDefault); Assert.IsFalse(result.IsDefault); @@ -396,52 +411,57 @@ namespace Umbraco.Tests.Services [Test] public void Deleted_Language_Should_Not_Exist() { - var localizationService = ServiceContext.LocalizationService; var isoCode = "en-AU"; - var language = new Core.Models.Language(TestObjects.GetGlobalSettings(), isoCode); - localizationService.Save(language); + var languageEnAu = new LanguageBuilder() + .WithCultureInfo(isoCode) + .Build(); + LocalizationService.Save(languageEnAu); // Act - localizationService.Delete(language); - var result = localizationService.GetLanguageByIsoCode(isoCode); + LocalizationService.Delete(languageEnAu); + var result = LocalizationService.GetLanguageByIsoCode(isoCode); // Assert Assert.Null(result); } - public override void CreateTestData() + public void CreateTestData() { - var danish = new Language(TestObjects.GetGlobalSettings(), "da-DK") { CultureName = "Danish" }; - var english = new Language(TestObjects.GetGlobalSettings(), "en-GB") { CultureName = "English" }; - ServiceContext.LocalizationService.Save(danish, 0); - ServiceContext.LocalizationService.Save(english, 0); - _danishLangId = danish.Id; - _englishLangId = english.Id; + var languageDaDk = new LanguageBuilder() + .WithCultureInfo("da-DK") + .Build(); + var languageEnGb = new LanguageBuilder() + .WithCultureInfo("en-GB") + .Build(); + + LocalizationService.Save(languageDaDk, 0); + LocalizationService.Save(languageEnGb, 0); + _danishLangId = languageDaDk.Id; + _englishLangId = languageEnGb.Id; var parentItem = new DictionaryItem("Parent") { Translations = new List - { - new DictionaryTranslation(english, "ParentValue"), - new DictionaryTranslation(danish, "ForældreVærdi") - } + { + new DictionaryTranslation(languageEnGb, "ParentValue"), + new DictionaryTranslation(languageDaDk, "ForældreVærdi") + } }; - ServiceContext.LocalizationService.Save(parentItem); + LocalizationService.Save(parentItem); _parentItemGuidId = parentItem.Key; _parentItemIntId = parentItem.Id; var childItem = new DictionaryItem(parentItem.Key, "Child") { Translations = new List - { - new DictionaryTranslation(english, "ChildValue"), - new DictionaryTranslation(danish, "BørnVærdi") - } + { + new DictionaryTranslation(languageEnGb, "ChildValue"), + new DictionaryTranslation(languageDaDk, "BørnVærdi") + } }; - ServiceContext.LocalizationService.Save(childItem); + LocalizationService.Save(childItem); _childItemGuidId = childItem.Key; _childItemIntId = childItem.Id; } - } } diff --git a/src/Umbraco.Tests/Services/MacroServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MacroServiceTests.cs similarity index 63% rename from src/Umbraco.Tests/Services/MacroServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/MacroServiceTests.cs index ceecb72156..ed663207b4 100644 --- a/src/Umbraco.Tests/Services/MacroServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/MacroServiceTests.cs @@ -1,32 +1,35 @@ using System; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; - -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; +using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class MacroServiceTests : TestWithSomeContentBase + public class MacroServiceTests : UmbracoIntegrationTest { - public override void CreateTestData() - { - base.CreateTestData(); + private IMacroService MacroService => GetRequiredService(); - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + [SetUp] + public void SetupTest() + { + var scopeProvider = ScopeProvider; + using (var scope = scopeProvider.CreateScope()) { - var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of(), ShortStringHelper); + var repository = new MacroRepository((IScopeAccessor) scopeProvider, AppCaches.Disabled, Mock.Of>(), ShortStringHelper); repository.Save(new Macro(ShortStringHelper, "test1", "Test1", "~/views/macropartials/test1.cshtml")); repository.Save(new Macro(ShortStringHelper, "test2", "Test2", "~/views/macropartials/test2.cshtml")); @@ -35,22 +38,13 @@ namespace Umbraco.Tests.Services } } - [TearDown] - public override void TearDown() - { - base.TearDown(); - } - [Test] public void Can_Get_By_Alias() { - // Arrange - var macroService = ServiceContext.MacroService; - // Act - var macro = macroService.GetByAlias("test1"); + var macro = MacroService.GetByAlias("test1"); - //assert + // Assert Assert.IsNotNull(macro); Assert.AreEqual("Test1", macro.Name); } @@ -58,37 +52,31 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_All() { - // Arrange - var macroService = ServiceContext.MacroService; - // Act - var result = macroService.GetAll(); + var result = MacroService.GetAll(); - //assert + // Assert Assert.AreEqual(3, result.Count()); } [Test] public void Can_Create() { - // Arrange - var macroService = ServiceContext.MacroService; - // Act - var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234); - macroService.Save(macro); + var macro = CreateMacro(); + MacroService.Save(macro); - //assert + // Assert Assert.IsTrue(macro.HasIdentity); Assert.Greater(macro.Id, 0); Assert.AreNotEqual(Guid.Empty, macro.Key); - var result = macroService.GetById(macro.Id); + var result = MacroService.GetById(macro.Id); Assert.AreEqual("test", result.Alias); Assert.AreEqual("Test", result.Name); Assert.AreEqual("~/Views/MacroPartials/Test.cshtml", result.MacroSource); Assert.AreEqual(1234, result.CacheDuration); - result = macroService.GetById(macro.Key); + result = MacroService.GetById(macro.Key); Assert.AreEqual("test", result.Alias); Assert.AreEqual("Test", result.Name); Assert.AreEqual("~/Views/MacroPartials/Test.cshtml", result.MacroSource); @@ -99,18 +87,17 @@ namespace Umbraco.Tests.Services public void Can_Delete() { // Arrange - var macroService = ServiceContext.MacroService; var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234); - macroService.Save(macro); + MacroService.Save(macro); // Act - macroService.Delete(macro); + MacroService.Delete(macro); - //assert - var result = macroService.GetById(macro.Id); + // Assert + var result = MacroService.GetById(macro.Id); Assert.IsNull(result); - result = macroService.GetById(macro.Key); + result = MacroService.GetById(macro.Key); Assert.IsNull(result); } @@ -118,20 +105,18 @@ namespace Umbraco.Tests.Services public void Can_Update() { // Arrange - var macroService = ServiceContext.MacroService; - IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234); - macroService.Save(macro); + var macro = CreateMacro(); + MacroService.Save(macro); // Act var currKey = macro.Key; macro.Name = "New name"; macro.Alias = "NewAlias"; - macroService.Save(macro); + MacroService.Save(macro); + macro = MacroService.GetById(macro.Id); - macro = macroService.GetById(macro.Id); - - //assert + // Assert Assert.AreEqual("New name", macro.Name); Assert.AreEqual("NewAlias", macro.Alias); Assert.AreEqual(currKey, macro.Key); @@ -142,10 +127,9 @@ namespace Umbraco.Tests.Services public void Can_Update_Property() { // Arrange - var macroService = ServiceContext.MacroService; - IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234); + var macro = CreateMacro(); macro.Properties.Add(new MacroProperty("blah", "Blah", 0, "blah")); - macroService.Save(macro); + MacroService.Save(macro); Assert.AreNotEqual(Guid.Empty, macro.Properties[0].Key); @@ -155,11 +139,11 @@ namespace Umbraco.Tests.Services macro.Properties[0].Name = "new Name"; macro.Properties[0].SortOrder = 1; macro.Properties[0].EditorAlias = "new"; - macroService.Save(macro); + MacroService.Save(macro); - macro = macroService.GetById(macro.Id); + macro = MacroService.GetById(macro.Id); - //assert + // Assert Assert.AreEqual(1, macro.Properties.Count); Assert.AreEqual(currPropKey, macro.Properties[0].Key); Assert.AreEqual("new Alias", macro.Properties[0].Alias); @@ -173,12 +157,11 @@ namespace Umbraco.Tests.Services public void Can_Update_Remove_Property() { // Arrange - var macroService = ServiceContext.MacroService; - IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234); + var macro = CreateMacro(); macro.Properties.Add(new MacroProperty("blah1", "Blah1", 0, "blah1")); macro.Properties.Add(new MacroProperty("blah2", "Blah2", 1, "blah2")); macro.Properties.Add(new MacroProperty("blah3", "Blah3", 2, "blah3")); - macroService.Save(macro); + MacroService.Save(macro); var lastKey = macro.Properties[0].Key; for (var i = 1; i < macro.Properties.Count; i++) @@ -197,11 +180,11 @@ namespace Umbraco.Tests.Services var allPropKeys = macro.Properties.Values.Select(x => new { x.Alias, x.Key }).ToArray(); - macroService.Save(macro); + MacroService.Save(macro); - macro = macroService.GetById(macro.Id); + macro = MacroService.GetById(macro.Id); - //assert + // Assert Assert.AreEqual(2, macro.Properties.Count); Assert.AreEqual("newAlias", macro.Properties["newAlias"].Alias); Assert.AreEqual("new Name", macro.Properties["newAlias"].Name); @@ -211,39 +194,36 @@ namespace Umbraco.Tests.Services { Assert.AreEqual(propKey.Key, macro.Properties[propKey.Alias].Key); } - } [Test] public void Can_Add_And_Remove_Properties() { - var macroService = ServiceContext.MacroService; - var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234); + var macro = CreateMacro(); - //adds some properties + // Adds some properties macro.Properties.Add(new MacroProperty("blah1", "Blah1", 0, "blah1")); macro.Properties.Add(new MacroProperty("blah2", "Blah2", 0, "blah2")); macro.Properties.Add(new MacroProperty("blah3", "Blah3", 0, "blah3")); macro.Properties.Add(new MacroProperty("blah4", "Blah4", 0, "blah4")); - macroService.Save(macro); + MacroService.Save(macro); - var result1 = macroService.GetById(macro.Id); + var result1 = MacroService.GetById(macro.Id); Assert.AreEqual(4, result1.Properties.Values.Count()); - //simulate clearing the sections + // Simulate clearing the sections foreach (var s in result1.Properties.Values.ToArray()) { result1.Properties.Remove(s.Alias); } - //now just re-add a couple + + // Now just re-add a couple result1.Properties.Add(new MacroProperty("blah3", "Blah3", 0, "blah3")); result1.Properties.Add(new MacroProperty("blah4", "Blah4", 0, "blah4")); - macroService.Save(result1); + MacroService.Save(result1); - //assert - - //re-get - result1 = macroService.GetById(result1.Id); + // Assert + result1 = MacroService.GetById(result1.Id); Assert.AreEqual(2, result1.Properties.Values.Count()); } @@ -252,25 +232,20 @@ namespace Umbraco.Tests.Services public void Cannot_Save_Macro_With_Empty_Name() { // Arrange - var macroService = ServiceContext.MacroService; - var macro = new Macro(ShortStringHelper, "test", string.Empty, "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234); + var macro = CreateMacro(name: string.Empty); // Act & Assert - Assert.Throws(() => macroService.Save(macro)); + Assert.Throws(() => MacroService.Save(macro)); } - //[Test] - //public void Can_Get_Many_By_Alias() - //{ - // // Arrange - // var macroService = ServiceContext.MacroService; - - // // Act - // var result = macroService.GetAll("test1", "test2"); - - // //assert - // Assert.AreEqual(2, result.Count()); - //} - + private static IMacro CreateMacro(string name = "Test") + { + return new MacroBuilder() + .WithAlias("test") + .WithName(name) + .WithSource("~/Views/MacroPartials/Test.cshtml") + .WithCacheDuration(1234) + .Build(); + } } } diff --git a/src/Umbraco.Tests/Services/MediaServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs similarity index 52% rename from src/Umbraco.Tests/Services/MediaServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs index b3dc274c5e..a6b67c8b59 100644 --- a/src/Umbraco.Tests/Services/MediaServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs @@ -1,38 +1,35 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Text; using System.Threading; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Events; using Umbraco.Core.Models; -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] - public class MediaServiceTests : TestWithSomeContentBase + public class MediaServiceTests : UmbracoIntegrationTest { + private IMediaService MediaService => GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); + /// /// Used to list out all ambiguous events that will require dispatching with a name /// [Test, Explicit] public void List_Ambiguous_Events() { - var events = ServiceContext.MediaService.GetType().GetEvents(BindingFlags.Static | BindingFlags.Public); + var events = MediaService.GetType().GetEvents(BindingFlags.Static | BindingFlags.Public); var typedEventHandler = typeof(TypedEventHandler<,>); foreach (var e in events) { @@ -55,32 +52,37 @@ namespace Umbraco.Tests.Services [Test] public void Get_Paged_Children_With_Media_Type_Filter() { - var mediaService = ServiceContext.MediaService; - var mediaType1 = MockedContentTypes.CreateImageMediaType("Image2"); - ServiceContext.MediaTypeService.Save(mediaType1); - var mediaType2 = MockedContentTypes.CreateImageMediaType("Image3"); - ServiceContext.MediaTypeService.Save(mediaType2); + var mediaType1 = MediaTypeBuilder.CreateImageMediaType("Image2"); + MediaTypeService.Save(mediaType1); + var mediaType2 = MediaTypeBuilder.CreateImageMediaType("Image3"); + MediaTypeService.Save(mediaType2); - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { - var m1 = MockedMedia.CreateMediaImage(mediaType1, -1); - mediaService.Save(m1); - var m2 = MockedMedia.CreateMediaImage(mediaType2, -1); - mediaService.Save(m2); + var m1 = MediaBuilder.CreateMediaImage(mediaType1, -1); + MediaService.Save(m1); + var m2 = MediaBuilder.CreateMediaImage(mediaType2, -1); + MediaService.Save(m2); } long total; - var result = ServiceContext.MediaService.GetPagedChildren(-1, 0, 11, out total, - SqlContext.Query().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), - Ordering.By("SortOrder", Direction.Ascending)); - Assert.AreEqual(11, result.Count()); - Assert.AreEqual(20, total); + var provider = ScopeProvider; + using (provider.CreateScope()) + { + var result = MediaService.GetPagedChildren(-1, 0, 11, out total, + provider.SqlContext.Query() + .Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), + Ordering.By("SortOrder", Direction.Ascending)); + Assert.AreEqual(11, result.Count()); + Assert.AreEqual(20, total); - result = ServiceContext.MediaService.GetPagedChildren(-1, 1, 11, out total, - SqlContext.Query().Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), - Ordering.By("SortOrder", Direction.Ascending)); - Assert.AreEqual(9, result.Count()); - Assert.AreEqual(20, total); + result = MediaService.GetPagedChildren(-1, 1, 11, out total, + provider.SqlContext.Query() + .Where(x => new[] { mediaType1.Id, mediaType2.Id }.Contains(x.ContentTypeId)), + Ordering.By("SortOrder", Direction.Ascending)); + Assert.AreEqual(9, result.Count()); + Assert.AreEqual(20, total); + } } [Test] @@ -88,11 +90,10 @@ namespace Umbraco.Tests.Services { // Arrange var mediaItems = CreateTrashedTestMedia(); - var mediaService = ServiceContext.MediaService; - var media = mediaService.GetById(mediaItems.Item3.Id); + var media = MediaService.GetById(mediaItems.Item3.Id); // Act - mediaService.Move(media, mediaItems.Item2.Id); + MediaService.Move(media, mediaItems.Item2.Id); // Assert Assert.That(media.ParentId, Is.EqualTo(mediaItems.Item2.Id)); @@ -104,11 +105,10 @@ namespace Umbraco.Tests.Services { // Arrange var mediaItems = CreateTrashedTestMedia(); - var mediaService = ServiceContext.MediaService; - var media = mediaService.GetById(mediaItems.Item1.Id); + var media = MediaService.GetById(mediaItems.Item1.Id); // Act - mediaService.MoveToRecycleBin(media); + MediaService.MoveToRecycleBin(media); // Assert Assert.That(media.ParentId, Is.EqualTo(-21)); @@ -120,12 +120,11 @@ namespace Umbraco.Tests.Services { // Arrange var mediaItems = CreateTrashedTestMedia(); - var mediaService = ServiceContext.MediaService; - var media = mediaService.GetById(mediaItems.Item4.Id); + var media = MediaService.GetById(mediaItems.Item4.Id); // Act - moving out of recycle bin - mediaService.Move(media, mediaItems.Item1.Id); - var mediaChild = mediaService.GetById(mediaItems.Item5.Id); + MediaService.Move(media, mediaItems.Item1.Id); + var mediaChild = MediaService.GetById(mediaItems.Item5.Id); // Assert Assert.That(media.ParentId, Is.EqualTo(mediaItems.Item1.Id)); @@ -138,43 +137,40 @@ namespace Umbraco.Tests.Services public void Cannot_Save_Media_With_Empty_Name() { // Arrange - var mediaService = ServiceContext.MediaService; - var mediaType = MockedContentTypes.CreateVideoMediaType(); - ServiceContext.MediaTypeService.Save(mediaType); - var media = mediaService.CreateMedia(string.Empty, -1, "video"); + var mediaType = MediaTypeBuilder.CreateVideoMediaType(); + MediaTypeService.Save(mediaType); + var media = MediaService.CreateMedia(string.Empty, -1, "video"); // Act & Assert - Assert.Throws(() => mediaService.Save(media)); + Assert.Throws(() => MediaService.Save(media)); } - + /* [Test] public void Ensure_Content_Xml_Created() { - var mediaService = ServiceContext.MediaService; var mediaType = MockedContentTypes.CreateVideoMediaType(); - ServiceContext.MediaTypeService.Save(mediaType); - var media = mediaService.CreateMedia("Test", -1, "video"); + MediaTypeService.Save(mediaType); + var media = MediaService.CreateMedia("Test", -1, "video"); - mediaService.Save(media); + MediaService.Save(media); using (var scope = ScopeProvider.CreateScope()) { Assert.IsTrue(scope.Database.Exists(media.Id)); } - } + }*/ [Test] public void Can_Get_Media_By_Path() { - var mediaService = ServiceContext.MediaService; - var mediaType = MockedContentTypes.CreateImageMediaType("Image2"); - ServiceContext.MediaTypeService.Save(mediaType); + var mediaType = MediaTypeBuilder.CreateImageMediaType("Image2"); + MediaTypeService.Save(mediaType); - var media = MockedMedia.CreateMediaImage(mediaType, -1); - mediaService.Save(media); + var media = MediaBuilder.CreateMediaImage(mediaType, -1); + MediaService.Save(media); var mediaPath = "/media/test-image.png"; - var resolvedMedia = mediaService.GetMediaByPath(mediaPath); + var resolvedMedia = MediaService.GetMediaByPath(mediaPath); Assert.IsNotNull(resolvedMedia); Assert.That(resolvedMedia.GetValue(Constants.Conventions.Media.File).ToString() == mediaPath); @@ -183,15 +179,14 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_Media_With_Crop_By_Path() { - var mediaService = ServiceContext.MediaService; - var mediaType = MockedContentTypes.CreateImageMediaTypeWithCrop("Image2"); - ServiceContext.MediaTypeService.Save(mediaType); + var mediaType = MediaTypeBuilder.CreateImageMediaTypeWithCrop("Image2"); + MediaTypeService.Save(mediaType); - var media = MockedMedia.CreateMediaImageWithCrop(mediaType, -1); - mediaService.Save(media); + var media = MediaBuilder.CreateMediaImageWithCrop(mediaType, -1); + MediaService.Save(media); var mediaPath = "/media/test-image.png"; - var resolvedMedia = mediaService.GetMediaByPath(mediaPath); + var resolvedMedia = MediaService.GetMediaByPath(mediaPath); Assert.IsNotNull(resolvedMedia); Assert.That(resolvedMedia.GetValue(Constants.Conventions.Media.File).ToString().Contains(mediaPath)); @@ -200,15 +195,15 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_Paged_Children() { - var mediaType = MockedContentTypes.CreateImageMediaType("Image2"); - ServiceContext.MediaTypeService.Save(mediaType); - for (int i = 0; i < 10; i++) + var mediaType = MediaTypeBuilder.CreateImageMediaType("Image2"); + MediaTypeService.Save(mediaType); + for (var i = 0; i < 10; i++) { - var c1 = MockedMedia.CreateMediaImage(mediaType, -1); - ServiceContext.MediaService.Save(c1); + var c1 = MediaBuilder.CreateMediaImage(mediaType, -1); + MediaService.Save(c1); } - var service = ServiceContext.MediaService; + var service = MediaService; long total; var entities = service.GetPagedChildren(-1, 0, 6, out total).ToArray(); @@ -222,26 +217,26 @@ namespace Umbraco.Tests.Services [Test] public void Can_Get_Paged_Children_Dont_Get_Descendants() { - var mediaType = MockedContentTypes.CreateImageMediaType("Image2"); - ServiceContext.MediaTypeService.Save(mediaType); + var mediaType = MediaTypeBuilder.CreateImageMediaType("Image2"); + MediaTypeService.Save(mediaType); // only add 9 as we also add a folder with children - for (int i = 0; i < 9; i++) + for (var i = 0; i < 9; i++) { - var m1 = MockedMedia.CreateMediaImage(mediaType, -1); - ServiceContext.MediaService.Save(m1); + var m1 = MediaBuilder.CreateMediaImage(mediaType, -1); + MediaService.Save(m1); } - var mediaTypeForFolder = MockedContentTypes.CreateImageMediaType("Folder2"); - ServiceContext.MediaTypeService.Save(mediaTypeForFolder); - var mediaFolder = MockedMedia.CreateMediaFolder(mediaTypeForFolder, -1); - ServiceContext.MediaService.Save(mediaFolder); - for (int i = 0; i < 10; i++) + var mediaTypeForFolder = MediaTypeBuilder.CreateImageMediaType("Folder2"); + MediaTypeService.Save(mediaTypeForFolder); + var mediaFolder = MediaBuilder.CreateMediaFolder(mediaTypeForFolder, -1); + MediaService.Save(mediaFolder); + for (var i = 0; i < 10; i++) { - var m1 = MockedMedia.CreateMediaImage(mediaType, mediaFolder.Id); - ServiceContext.MediaService.Save(m1); + var m1 = MediaBuilder.CreateMediaImage(mediaType, mediaFolder.Id); + MediaService.Save(m1); } - var service = ServiceContext.MediaService; + var service = MediaService; long total; // children in root including the folder - not the descendants in the folder @@ -264,29 +259,28 @@ namespace Umbraco.Tests.Services private Tuple CreateTrashedTestMedia() { //Create and Save folder-Media -> 1050 - var folderMediaType = ServiceContext.MediaTypeService.Get(1031); - var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1); - ServiceContext.MediaService.Save(folder); + var folderMediaType = MediaTypeService.Get(1031); + var folder = MediaBuilder.CreateMediaFolder(folderMediaType, -1); + MediaService.Save(folder); //Create and Save folder-Media -> 1051 - var folder2 = MockedMedia.CreateMediaFolder(folderMediaType, -1); - ServiceContext.MediaService.Save(folder2); + var folder2 = MediaBuilder.CreateMediaFolder(folderMediaType, -1); + MediaService.Save(folder2); //Create and Save image-Media -> 1052 - var imageMediaType = ServiceContext.MediaTypeService.Get(1032); - var image = (Media)MockedMedia.CreateMediaImage(imageMediaType, 1050); - ServiceContext.MediaService.Save(image); + var imageMediaType = MediaTypeService.Get(1032); + var image = MediaBuilder.CreateMediaImage(imageMediaType, 1050); + MediaService.Save(image); //Create and Save folder-Media that is trashed -> 1053 - var folderTrashed = (Media)MockedMedia.CreateMediaFolder(folderMediaType, -21); + var folderTrashed = MediaBuilder.CreateMediaFolder(folderMediaType, -21); folderTrashed.Trashed = true; - ServiceContext.MediaService.Save(folderTrashed); + MediaService.Save(folderTrashed); //Create and Save image-Media child of folderTrashed -> 1054 - var imageTrashed = (Media)MockedMedia.CreateMediaImage(imageMediaType, folderTrashed.Id); + var imageTrashed = MediaBuilder.CreateMediaImage(imageMediaType, folderTrashed.Id); imageTrashed.Trashed = true; - ServiceContext.MediaService.Save(imageTrashed); - + MediaService.Save(imageTrashed); return new Tuple(folder, folder2, image, folderTrashed, imageTrashed); } diff --git a/src/Umbraco.Tests/Services/MediaTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MediaTypeServiceTests.cs similarity index 63% rename from src/Umbraco.Tests/Services/MediaTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/MediaTypeServiceTests.cs index 915dc5ceec..3e4bbfa611 100644 --- a/src/Umbraco.Tests/Services/MediaTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/MediaTypeServiceTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using NUnit.Framework; @@ -6,26 +7,41 @@ using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] - public class MediaTypeServiceTests : TestWithSomeContentBase + public class MediaTypeServiceTests : UmbracoIntegrationTest { + private MediaService MediaService => (MediaService)GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); + + [Test] + public void Get_With_Missing_Guid() + { + // Arrange + //Act + var result = MediaTypeService.Get(Guid.NewGuid()); + + //Assert + Assert.IsNull(result); + } + [Test] public void Empty_Description_Is_Always_Null_After_Saving_Media_Type() { - var mediaType = MockedContentTypes.CreateSimpleMediaType("mediaType", "Media Type"); + var mediaType = MediaTypeBuilder.CreateSimpleMediaType("mediaType", "Media Type"); mediaType.Description = null; - ServiceContext.MediaTypeService.Save(mediaType); + MediaTypeService.Save(mediaType); - var mediaType2 = MockedContentTypes.CreateSimpleMediaType("mediaType2", "Media Type 2"); + var mediaType2 = MediaTypeBuilder.CreateSimpleMediaType("mediaType2", "Media Type 2"); mediaType2.Description = string.Empty; - ServiceContext.MediaTypeService.Save(mediaType2); + MediaTypeService.Save(mediaType2); Assert.IsNull(mediaType.Description); Assert.IsNull(mediaType2.Description); @@ -34,25 +50,25 @@ namespace Umbraco.Tests.Services [Test] public void Deleting_Media_Type_With_Hierarchy_Of_Media_Items_Moves_Orphaned_Media_To_Recycle_Bin() { - IMediaType contentType1 = MockedContentTypes.CreateSimpleMediaType("test1", "Test1"); - ServiceContext.MediaTypeService.Save(contentType1); - IMediaType contentType2 = MockedContentTypes.CreateSimpleMediaType("test2", "Test2"); - ServiceContext.MediaTypeService.Save(contentType2); - IMediaType contentType3 = MockedContentTypes.CreateSimpleMediaType("test3", "Test3"); - ServiceContext.MediaTypeService.Save(contentType3); + IMediaType contentType1 = MediaTypeBuilder.CreateSimpleMediaType("test1", "Test1"); + MediaTypeService.Save(contentType1); + IMediaType contentType2 = MediaTypeBuilder.CreateSimpleMediaType("test2", "Test2"); + MediaTypeService.Save(contentType2); + IMediaType contentType3 = MediaTypeBuilder.CreateSimpleMediaType("test3", "Test3"); + MediaTypeService.Save(contentType3); var contentTypes = new[] { contentType1, contentType2, contentType3 }; var parentId = -1; var ids = new List(); - for (int i = 0; i < 2; i++) + for (var i = 0; i < 2; i++) { for (var index = 0; index < contentTypes.Length; index++) { var contentType = contentTypes[index]; - var contentItem = MockedMedia.CreateSimpleMedia(contentType, "MyName_" + index + "_" + i, parentId); - ServiceContext.MediaService.Save(contentItem); + var contentItem = MediaBuilder.CreateSimpleMedia(contentType, "MyName_" + index + "_" + i, parentId); + MediaService.Save(contentItem); parentId = contentItem.Id; ids.Add(contentItem.Id); @@ -60,9 +76,9 @@ namespace Umbraco.Tests.Services } //delete the first content type, all other content of different content types should be in the recycle bin - ServiceContext.MediaTypeService.Delete(contentTypes[0]); + MediaTypeService.Delete(contentTypes[0]); - var found = ServiceContext.MediaService.GetByIds(ids); + var found = MediaService.GetByIds(ids); Assert.AreEqual(4, found.Count()); foreach (var content in found) @@ -78,25 +94,25 @@ namespace Umbraco.Tests.Services try { - IMediaType contentType1 = MockedContentTypes.CreateSimpleMediaType("test1", "Test1"); - ServiceContext.MediaTypeService.Save(contentType1); - IMediaType contentType2 = MockedContentTypes.CreateSimpleMediaType("test2", "Test2"); - ServiceContext.MediaTypeService.Save(contentType2); - IMediaType contentType3 = MockedContentTypes.CreateSimpleMediaType("test3", "Test3"); - ServiceContext.MediaTypeService.Save(contentType3); + IMediaType contentType1 = MediaTypeBuilder.CreateSimpleMediaType("test1", "Test1"); + MediaTypeService.Save(contentType1); + IMediaType contentType2 = MediaTypeBuilder.CreateSimpleMediaType("test2", "Test2"); + MediaTypeService.Save(contentType2); + IMediaType contentType3 = MediaTypeBuilder.CreateSimpleMediaType("test3", "Test3"); + MediaTypeService.Save(contentType3); var contentTypes = new[] { contentType1, contentType2, contentType3 }; var parentId = -1; var ids = new List(); - for (int i = 0; i < 2; i++) + for (var i = 0; i < 2; i++) { for (var index = 0; index < contentTypes.Length; index++) { var contentType = contentTypes[index]; - var contentItem = MockedMedia.CreateSimpleMedia(contentType, "MyName_" + index + "_" + i, parentId); - ServiceContext.MediaService.Save(contentItem); + var contentItem = MediaBuilder.CreateSimpleMedia(contentType, "MyName_" + index + "_" + i, parentId); + MediaService.Save(contentItem); parentId = contentItem.Id; ids.Add(contentItem.Id); @@ -105,7 +121,7 @@ namespace Umbraco.Tests.Services foreach (var contentType in contentTypes.Reverse()) { - ServiceContext.MediaTypeService.Delete(contentType); + MediaTypeService.Delete(contentType); } } finally @@ -119,7 +135,7 @@ namespace Umbraco.Tests.Services foreach (var item in e.MoveInfoCollection) { //if this item doesn't exist then Fail! - var exists = ServiceContext.MediaService.GetById(item.Entity.Id); + var exists = MediaService.GetById(item.Entity.Id); if (exists == null) Assert.Fail("The item doesn't exist"); } @@ -129,13 +145,13 @@ namespace Umbraco.Tests.Services public void Can_Copy_MediaType_By_Performing_Clone() { // Arrange - var mediaType = MockedContentTypes.CreateImageMediaType("Image2") as IMediaType; - ServiceContext.MediaTypeService.Save(mediaType); + var mediaType = MediaTypeBuilder.CreateImageMediaType("Image2") as IMediaType; + MediaTypeService.Save(mediaType); // Act var sut = mediaType.DeepCloneWithResetIdentities("Image2_2"); Assert.IsNotNull(sut); - ServiceContext.MediaTypeService.Save(sut); + MediaTypeService.Save(sut); // Assert Assert.That(sut.HasIdentity, Is.True); @@ -154,12 +170,12 @@ namespace Umbraco.Tests.Services public void Can_Copy_MediaType_To_New_Parent_By_Performing_Clone() { // Arrange - var parentMediaType1 = MockedContentTypes.CreateSimpleMediaType("parent1", "Parent1"); - ServiceContext.MediaTypeService.Save(parentMediaType1); - var parentMediaType2 = MockedContentTypes.CreateSimpleMediaType("parent2", "Parent2", null, true); - ServiceContext.MediaTypeService.Save(parentMediaType2); - var mediaType = MockedContentTypes.CreateImageMediaType("Image2") as IMediaType; - ServiceContext.MediaTypeService.Save(mediaType); + var parentMediaType1 = MediaTypeBuilder.CreateSimpleMediaType("parent1", "Parent1"); + MediaTypeService.Save(parentMediaType1); + var parentMediaType2 = MediaTypeBuilder.CreateSimpleMediaType("parent2", "Parent2", null, true); + MediaTypeService.Save(parentMediaType2); + var mediaType = MediaTypeBuilder.CreateImageMediaType("Image2") as IMediaType; + MediaTypeService.Save(mediaType); // Act var clone = mediaType.DeepCloneWithResetIdentities("newcategory"); @@ -167,13 +183,13 @@ namespace Umbraco.Tests.Services clone.RemoveContentType("parent1"); clone.AddContentType(parentMediaType2); clone.ParentId = parentMediaType2.Id; - ServiceContext.MediaTypeService.Save(clone); + MediaTypeService.Save(clone); // Assert Assert.That(clone.HasIdentity, Is.True); - var clonedMediaType = ServiceContext.MediaTypeService.Get(clone.Id); - var originalMediaType = ServiceContext.MediaTypeService.Get(mediaType.Id); + var clonedMediaType = MediaTypeService.Get(clone.Id); + var originalMediaType = MediaTypeService.Get(mediaType.Id); Assert.That(clonedMediaType.CompositionAliases().Any(x => x.Equals("parent2")), Is.True); Assert.That(clonedMediaType.CompositionAliases().Any(x => x.Equals("parent1")), Is.False); diff --git a/src/Umbraco.Tests.Integration/Services/MemberGroupServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MemberGroupServiceTests.cs new file mode 100644 index 0000000000..7bca819915 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Services/MemberGroupServiceTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading; +using NUnit.Framework; +using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Integration.Services +{ + [TestFixture] + [Apartment(ApartmentState.STA)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] + public class MemberGroupServiceTests : UmbracoIntegrationTest + { + private IMemberGroupService MemberGroupService => GetRequiredService(); + + /// + /// Used to list out all ambiguous events that will require dispatching with a name + /// + [Test, Explicit] + public void List_Ambiguous_Events() + { + var memberGroup = new MemberGroupBuilder() + .WithName(string.Empty) + .Build(); + Assert.Throws(() => MemberGroupService.Save(memberGroup)); + } + } +} diff --git a/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs new file mode 100644 index 0000000000..1da701bc23 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs @@ -0,0 +1,1246 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; +using Umbraco.Tests.Common; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; +using Umbraco.Web.PublishedCache.NuCache; + +namespace Umbraco.Tests.Integration.Services +{ + [TestFixture] + [Category("Slow")] + [Apartment(ApartmentState.STA)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] + public class MemberServiceTests : UmbracoIntegrationTest + { + private IMemberTypeService MemberTypeService => GetRequiredService(); + private IMemberService MemberService => GetRequiredService(); + + [SetUp] + public void SetupTest() + { + // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. + Umbraco.Core.Services.Implement.MemberTypeService.ClearScopeEvents(); + } + + [Test] + public void Can_Update_Member_Property_Value() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "hello", "helloworld@test123.com", "hello", "hello"); + member.SetValue("title", "title of mine"); + MemberService.Save(member); + + // re-get + member = MemberService.GetById(member.Id); + member.SetValue("title", "another title of mine"); + MemberService.Save(member); + + // re-get + member = MemberService.GetById(member.Id); + Assert.AreEqual("another title of mine", member.GetValue("title")); + } + + [Test] + public void Can_Get_By_Username() + { + var memberType = MemberTypeService.Get("member"); + IMember member = new Member("xname", "xemail", "xusername", "xrawpassword", memberType, true); + MemberService.Save(member); + + var member2 = MemberService.GetByUsername(member.Username); + + Assert.IsNotNull(member2); + Assert.AreEqual(member.Email, member2.Email); + } + + [Test] + public void Can_Set_Last_Login_Date() + { + var now = DateTime.Now; + var memberType = MemberTypeService.Get("member"); + IMember member = new Member("xname", "xemail", "xusername", "xrawpassword", memberType, true) + { + LastLoginDate = now, + UpdateDate = now + }; + MemberService.Save(member); + + var newDate = now.AddDays(10); + MemberService.SetLastLogin(member.Username, newDate); + + //re-get + member = MemberService.GetById(member.Id); + + Assert.That(member.LastLoginDate, Is.EqualTo(newDate).Within(1).Seconds); + Assert.That(member.UpdateDate, Is.EqualTo(newDate).Within(1).Seconds); + } + + [Test] + public void Can_Create_Member_With_Properties() + { + var memberType = MemberTypeService.Get("member"); + IMember member = new Member("xname", "xemail", "xusername", "xrawpassword", memberType, true); + MemberService.Save(member); + + member = MemberService.GetById(member.Id); + Assert.AreEqual("xemail", member.Email); + + var contentTypeFactory = new PublishedContentTypeFactory(new NoopPublishedModelFactory(), new PropertyValueConverterCollection(Enumerable.Empty()), GetRequiredService()); + var pmemberType = new PublishedContentType(memberType, contentTypeFactory); + + var publishedSnapshotAccessor = new TestPublishedSnapshotAccessor(); + var variationContextAccessor = new TestVariationContextAccessor(); + var pmember = PublishedMember.Create(member, pmemberType, false, publishedSnapshotAccessor, variationContextAccessor, GetRequiredService()); + + // contains the umbracoMember... properties created when installing, on the member type + // contains the other properties, that PublishedContentType adds (BuiltinMemberProperties) + // + // TODO: see TODO in PublishedContentType, this list contains duplicates + + var aliases = new[] + { + Constants.Conventions.Member.Comments, + Constants.Conventions.Member.FailedPasswordAttempts, + Constants.Conventions.Member.IsApproved, + Constants.Conventions.Member.IsLockedOut, + Constants.Conventions.Member.LastLockoutDate, + Constants.Conventions.Member.LastLoginDate, + Constants.Conventions.Member.LastPasswordChangeDate, + nameof(IMember.Email), + nameof(IMember.Username), + nameof(IMember.Comments), + nameof(IMember.IsApproved), + nameof(IMember.IsLockedOut), + nameof(IMember.LastLockoutDate), + nameof(IMember.CreateDate), + nameof(IMember.LastLoginDate), + nameof(IMember.LastPasswordChangeDate) + }; + + var properties = pmember.Properties.ToList(); + + Assert.IsTrue(properties.Select(x => x.Alias).ContainsAll(aliases)); + + var email = properties[aliases.IndexOf(nameof(IMember.Email))]; + Assert.AreEqual("xemail", email.GetSourceValue()); + } + + [Test] + public void Can_Create_Member() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + Assert.AreNotEqual(0, member.Id); + var foundMember = MemberService.GetById(member.Id); + Assert.IsNotNull(foundMember); + Assert.AreEqual("test@test.com", foundMember.Email); + } + + [Test] + public void Can_Create_Member_With_Long_TLD_In_Email() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.marketing", "pass", "test"); + MemberService.Save(member); + + Assert.AreNotEqual(0, member.Id); + var foundMember = MemberService.GetById(member.Id); + Assert.IsNotNull(foundMember); + Assert.AreEqual("test@test.marketing", foundMember.Email); + } + + [Test] + public void Can_Create_Role() + { + MemberService.AddRole("MyTestRole"); + + var found = MemberService.GetAllRoles(); + + Assert.AreEqual(1, found.Count()); + Assert.AreEqual("MyTestRole", found.Single()); + } + + [Test] + public void Can_Create_Duplicate_Role() + { + MemberService.AddRole("MyTestRole"); + MemberService.AddRole("MyTestRole"); + + var found = MemberService.GetAllRoles(); + + Assert.AreEqual(1, found.Count()); + Assert.AreEqual("MyTestRole", found.Single()); + } + + [Test] + public void Can_Get_All_Roles() + { + MemberService.AddRole("MyTestRole1"); + MemberService.AddRole("MyTestRole2"); + MemberService.AddRole("MyTestRole3"); + + var found = MemberService.GetAllRoles(); + + Assert.AreEqual(3, found.Count()); + } + [Test] + public void Can_Get_All_Roles_IDs() + { + MemberService.AddRole("MyTestRole1"); + MemberService.AddRole("MyTestRole2"); + MemberService.AddRole("MyTestRole3"); + + var found = MemberService.GetAllRolesIds(); + + Assert.AreEqual(3, found.Count()); + } + [Test] + public void Can_Get_All_Roles_By_Member_Id() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + MemberService.AddRole("MyTestRole1"); + MemberService.AddRole("MyTestRole2"); + MemberService.AddRole("MyTestRole3"); + MemberService.AssignRoles(new[] { member.Id }, new[] { "MyTestRole1", "MyTestRole2" }); + + var memberRoles = MemberService.GetAllRoles(member.Id); + + Assert.AreEqual(2, memberRoles.Count()); + + } + [Test] + public void Can_Get_All_Roles_Ids_By_Member_Id() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + MemberService.AddRole("MyTestRole1"); + MemberService.AddRole("MyTestRole2"); + MemberService.AddRole("MyTestRole3"); + MemberService.AssignRoles(new[] { member.Id }, new[] { "MyTestRole1", "MyTestRole2" }); + + var memberRoles = MemberService.GetAllRolesIds(member.Id); + + Assert.AreEqual(2, memberRoles.Count()); + + } + [Test] + public void Can_Get_All_Roles_By_Member_Username() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + //need to test with '@' symbol in the lookup + IMember member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2@test.com"); + MemberService.Save(member2); + + MemberService.AddRole("MyTestRole1"); + MemberService.AddRole("MyTestRole2"); + MemberService.AddRole("MyTestRole3"); + MemberService.AssignRoles(new[] { member.Id, member2.Id }, new[] { "MyTestRole1", "MyTestRole2" }); + + var memberRoles = MemberService.GetAllRoles("test"); + Assert.AreEqual(2, memberRoles.Count()); + + var memberRoles2 = MemberService.GetAllRoles("test2@test.com"); + Assert.AreEqual(2, memberRoles2.Count()); + } + + [Test] + public void Can_Delete_Role() + { + MemberService.AddRole("MyTestRole1"); + + MemberService.DeleteRole("MyTestRole1", false); + + var memberRoles = MemberService.GetAllRoles(); + + Assert.AreEqual(0, memberRoles.Count()); + } + + [Test] + public void Throws_When_Deleting_Assigned_Role() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + MemberService.AddRole("MyTestRole1"); + MemberService.AssignRoles(new[] { member.Id }, new[] { "MyTestRole1", "MyTestRole2" }); + + Assert.Throws(() => MemberService.DeleteRole("MyTestRole1", true)); + } + + [Test] + public void Can_Get_Members_In_Role() + { + MemberService.AddRole("MyTestRole1"); + int roleId; + using (var scope = ScopeProvider.CreateScope()) + { + roleId = scope.Database.ExecuteScalar("SELECT id from umbracoNode where [text] = 'MyTestRole1'"); + scope.Complete(); + } + + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + MemberService.Save(member2); + + using (var scope = ScopeProvider.CreateScope()) + { + scope.Database.Insert(new Member2MemberGroupDto { MemberGroup = roleId, Member = member1.Id }); + scope.Database.Insert(new Member2MemberGroupDto { MemberGroup = roleId, Member = member2.Id }); + scope.Complete(); + } + + var membersInRole = MemberService.GetMembersInRole("MyTestRole1"); + Assert.AreEqual(2, membersInRole.Count()); + } + + [Test] + public void Cannot_Save_Member_With_Empty_Name() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, string.Empty, "test@test.com", "pass", "test"); + + // Act & Assert + Assert.Throws(() => MemberService.Save(member)); + + } + + [TestCase("MyTestRole1", "test1", StringPropertyMatchType.StartsWith, 1)] + [TestCase("MyTestRole1", "test", StringPropertyMatchType.StartsWith, 3)] + [TestCase("MyTestRole1", "test1", StringPropertyMatchType.Exact, 1)] + [TestCase("MyTestRole1", "test", StringPropertyMatchType.Exact, 0)] + [TestCase("MyTestRole1", "st2", StringPropertyMatchType.EndsWith, 1)] + [TestCase("MyTestRole1", "test%", StringPropertyMatchType.Wildcard, 3)] + public void Find_Members_In_Role(string roleName1, string usernameToMatch, StringPropertyMatchType matchType, int resultCount) + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + MemberService.Save(member2); + var member3 = MemberBuilder.CreateSimpleMember(memberType, "test3", "test3@test.com", "pass", "test3"); + MemberService.Save(member3); + + MemberService.AssignRoles(new[] { member1.Id, member2.Id, member3.Id }, new[] { roleName1 }); + + var result = MemberService.FindMembersInRole(roleName1, usernameToMatch, matchType); + Assert.AreEqual(resultCount, result.Count()); + } + + [Test] + public void Associate_Members_To_Roles_With_Member_Id() + { + MemberService.AddRole("MyTestRole1"); + + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + MemberService.Save(member2); + + // temp make sure they exist + Assert.IsNotNull(MemberService.GetById(member1.Id)); + Assert.IsNotNull(MemberService.GetById(member2.Id)); + + MemberService.AssignRoles(new[] { member1.Id, member2.Id }, new[] { "MyTestRole1" }); + + var membersInRole = MemberService.GetMembersInRole("MyTestRole1"); + + Assert.AreEqual(2, membersInRole.Count()); + } + + [Test] + public void Associate_Members_To_Roles_With_Member_Id_Casing() + { + MemberService.AddRole("MyTestRole1"); + + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + MemberService.Save(member2); + + // temp make sure they exist + Assert.IsNotNull(MemberService.GetById(member1.Id)); + Assert.IsNotNull(MemberService.GetById(member2.Id)); + + MemberService.AssignRoles(new[] { member1.Id, member2.Id }, new[] { "mytestrole1" }); + + var membersInRole = MemberService.GetMembersInRole("MyTestRole1"); + + Assert.AreEqual(2, membersInRole.Count()); + } + + [Test] + public void Associate_Members_To_Roles_With_Member_Username() + { + MemberService.AddRole("MyTestRole1"); + + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + MemberService.Save(member2); + + MemberService.AssignRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole1" }); + + var membersInRole = MemberService.GetMembersInRole("MyTestRole1"); + + Assert.AreEqual(2, membersInRole.Count()); + } + + [Test] + public void Associate_Members_To_Roles_With_Member_Username_Containing_At_Symbols() + { + MemberService.AddRole("MyTestRole1"); + + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1@test.com"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2@test.com"); + MemberService.Save(member2); + + MemberService.AssignRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole1" }); + + var membersInRole = MemberService.GetMembersInRole("MyTestRole1"); + + Assert.AreEqual(2, membersInRole.Count()); + } + + [Test] + public void Associate_Members_To_Roles_With_New_Role() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + MemberService.Save(member2); + + //implicitly create the role + MemberService.AssignRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole1" }); + + var membersInRole = MemberService.GetMembersInRole("MyTestRole1"); + + Assert.AreEqual(2, membersInRole.Count()); + } + + [Test] + public void Remove_Members_From_Roles_With_Member_Id() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + MemberService.Save(member2); + + MemberService.AssignRoles(new[] { member1.Id, member2.Id }, new[] { "MyTestRole1", "MyTestRole2" }); + + MemberService.DissociateRoles(new[] {member1.Id }, new[] {"MyTestRole1"}); + MemberService.DissociateRoles(new[] { member1.Id, member2.Id }, new[] { "MyTestRole2" }); + + var membersInRole = MemberService.GetMembersInRole("MyTestRole1"); + Assert.AreEqual(1, membersInRole.Count()); + membersInRole = MemberService.GetMembersInRole("MyTestRole2"); + Assert.AreEqual(0, membersInRole.Count()); + } + + [Test] + public void Remove_Members_From_Roles_With_Member_Username() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member1 = MemberBuilder.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); + MemberService.Save(member1); + var member2 = MemberBuilder.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); + MemberService.Save(member2); + + MemberService.AssignRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole1", "MyTestRole2" }); + + MemberService.DissociateRoles(new[] { member1.Username }, new[] { "MyTestRole1" }); + MemberService.DissociateRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole2" }); + + var membersInRole = MemberService.GetMembersInRole("MyTestRole1"); + Assert.AreEqual(1, membersInRole.Count()); + membersInRole = MemberService.GetMembersInRole("MyTestRole2"); + Assert.AreEqual(0, membersInRole.Count()); + } + + [Test] + public void Can_Delete_member() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + MemberService.Delete(member); + var deleted = MemberService.GetById(member.Id); + + // Assert + Assert.That(deleted, Is.Null); + } + + [Test] + public void Exists_By_Username() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + IMember member2 = MemberBuilder.CreateSimpleMember(memberType, "test", "test2@test.com", "pass", "test2@test.com"); + MemberService.Save(member2); + + Assert.IsTrue(MemberService.Exists("test")); + Assert.IsFalse(MemberService.Exists("notFound")); + Assert.IsTrue(MemberService.Exists("test2@test.com")); + } + + [Test] + public void Exists_By_Id() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + Assert.IsTrue(MemberService.Exists(member.Id)); + Assert.IsFalse(MemberService.Exists(9876)); + } + + [Test] + public void Tracks_Dirty_Changes() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + var resolved = MemberService.GetByEmail(member.Email); + + //NOTE: This will not trigger a property isDirty because this is not based on a 'Property', it is + // just a c# property of the Member object + resolved.Email = "changed@test.com"; + + //NOTE: this WILL trigger a property isDirty because setting this c# property actually sets a value of + // the underlying 'Property' + resolved.FailedPasswordAttempts = 1234; + + var dirtyMember = (ICanBeDirty) resolved; + var dirtyProperties = resolved.Properties.Where(x => x.IsDirty()).ToList(); + Assert.IsTrue(dirtyMember.IsDirty()); + Assert.AreEqual(1, dirtyProperties.Count); + } + + [Test] + public void Get_By_Email() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + Assert.IsNotNull(MemberService.GetByEmail(member.Email)); + Assert.IsNull(MemberService.GetByEmail("do@not.find")); + } + + [Test] + public void Get_Member_Name() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "Test Real Name", "test@test.com", "pass", "testUsername"); + MemberService.Save(member); + + + Assert.AreEqual("Test Real Name", member.Name); + } + + [Test] + public void Get_By_Username() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + Assert.IsNotNull(MemberService.GetByUsername(member.Username)); + Assert.IsNull(MemberService.GetByUsername("notFound")); + } + + [Test] + public void Get_By_Object_Id() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); + + Assert.IsNotNull(MemberService.GetById(member.Id)); + Assert.IsNull(MemberService.GetById(9876)); + } + + [Test] + public void Get_All_Paged_Members() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + + long totalRecs; + var found = MemberService.GetAll(0, 2, out totalRecs); + + Assert.AreEqual(2, found.Count()); + Assert.AreEqual(10, totalRecs); + Assert.AreEqual("test0", found.First().Username); + Assert.AreEqual("test1", found.Last().Username); + } + + [Test] + public void Get_All_Paged_Members_With_Filter() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + + long totalRecs; + var found = MemberService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, true, null, "Member No-"); + + Assert.AreEqual(2, found.Count()); + Assert.AreEqual(10, totalRecs); + Assert.AreEqual("test0", found.First().Username); + Assert.AreEqual("test1", found.Last().Username); + + found = MemberService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, true, null, "Member No-5"); + + Assert.AreEqual(1, found.Count()); + Assert.AreEqual(1, totalRecs); + Assert.AreEqual("test5", found.First().Username); + } + + [Test] + public void Find_By_Name_Starts_With() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "Bob", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindMembersByDisplayName("B", 0, 100, out totalRecs, StringPropertyMatchType.StartsWith); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Find_By_Email_Starts_With() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + //don't find this + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello","hello"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindByEmail("tes", 0, 100, out totalRecs, StringPropertyMatchType.StartsWith); + + Assert.AreEqual(10, found.Count()); + } + + [Test] + public void Find_By_Email_Ends_With() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + //include this + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindByEmail("test.com", 0, 100, out totalRecs, StringPropertyMatchType.EndsWith); + + Assert.AreEqual(11, found.Count()); + } + + [Test] + public void Find_By_Email_Contains() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + //include this + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindByEmail("test", 0, 100, out totalRecs, StringPropertyMatchType.Contains); + + Assert.AreEqual(11, found.Count()); + } + + [Test] + public void Find_By_Email_Exact() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + //include this + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindByEmail("hello@test.com", 0, 100, out totalRecs, StringPropertyMatchType.Exact); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Find_By_Login_Starts_With() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + //don't find this + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindByUsername("tes", 0, 100, out totalRecs, StringPropertyMatchType.StartsWith); + + Assert.AreEqual(10, found.Count()); + } + + [Test] + public void Find_By_Login_Ends_With() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + //include this + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindByUsername("llo", 0, 100, out totalRecs, StringPropertyMatchType.EndsWith); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Find_By_Login_Contains() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + //include this + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hellotest"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindByUsername("test", 0, 100, out totalRecs, StringPropertyMatchType.Contains); + + Assert.AreEqual(11, found.Count()); + } + + [Test] + public void Find_By_Login_Exact() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + //include this + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + long totalRecs; + var found = MemberService.FindByUsername("hello", 0, 100, out totalRecs, StringPropertyMatchType.Exact); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Get_By_Property_String_Value_Exact() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "title", "hello member", StringPropertyMatchType.Exact); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Get_By_Property_String_Value_Contains() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "title", " member", StringPropertyMatchType.Contains); + + Assert.AreEqual(11, found.Count()); + } + + [Test] + public void Get_By_Property_String_Value_Starts_With() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "title", "Member No", StringPropertyMatchType.StartsWith); + + Assert.AreEqual(10, found.Count()); + } + + [Test] + public void Get_By_Property_String_Value_Ends_With() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("title", "title of mine"); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "title", "mine", StringPropertyMatchType.EndsWith); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Get_By_Property_Int_Value_Exact() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "number") + { + Name = "Number", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -51 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("number", 2); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "number", 2, ValuePropertyMatchType.Exact); + + Assert.AreEqual(2, found.Count()); + } + + [Test] + public void Get_By_Property_Int_Value_Greater_Than() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "number") + { + Name = "Number", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -51 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("number", 10); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "number", 3, ValuePropertyMatchType.GreaterThan); + + Assert.AreEqual(7, found.Count()); + } + + [Test] + public void Get_By_Property_Int_Value_Greater_Than_Equal_To() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "number") + { + Name = "Number", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -51 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("number", 10); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "number", 3, ValuePropertyMatchType.GreaterThanOrEqualTo); + + Assert.AreEqual(8, found.Count()); + } + + [Test] + public void Get_By_Property_Int_Value_Less_Than() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.DateTime, ValueStorageType.Date, "number") + { + Name = "Number", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -51 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("number", 1); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "number", 5, ValuePropertyMatchType.LessThan); + + Assert.AreEqual(6, found.Count()); + } + + [Test] + public void Get_By_Property_Int_Value_Less_Than_Or_Equal() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "number") + { + Name = "Number", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -51 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("number", i)); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("number", 1); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "number", 5, ValuePropertyMatchType.LessThanOrEqualTo); + + Assert.AreEqual(7, found.Count()); + } + + [Test] + public void Get_By_Property_Date_Value_Exact() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") + { + Name = "Date", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -36 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 2, 0)); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "date", new DateTime(2013, 12, 20, 1, 2, 0), ValuePropertyMatchType.Exact); + + Assert.AreEqual(2, found.Count()); + } + + [Test] + public void Get_By_Property_Date_Value_Greater_Than() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") + { + Name = "Date", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -36 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 10, 0)); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "date", new DateTime(2013, 12, 20, 1, 3, 0), ValuePropertyMatchType.GreaterThan); + + Assert.AreEqual(7, found.Count()); + } + + [Test] + public void Get_By_Property_Date_Value_Greater_Than_Equal_To() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") + { + Name = "Date", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -36 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 10, 0)); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "date", new DateTime(2013, 12, 20, 1, 3, 0), ValuePropertyMatchType.GreaterThanOrEqualTo); + + Assert.AreEqual(8, found.Count()); + } + + [Test] + public void Get_By_Property_Date_Value_Less_Than() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") + { + Name = "Date", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -36 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 1, 0)); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "date", new DateTime(2013, 12, 20, 1, 5, 0), ValuePropertyMatchType.LessThan); + + Assert.AreEqual(6, found.Count()); + } + + [Test] + public void Get_By_Property_Date_Value_Less_Than_Or_Equal() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") + { + Name = "Date", + //NOTE: This is what really determines the db type - the above definition doesn't really do anything + DataTypeId = -36 + }, "Content"); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 1, 0)); + MemberService.Save(customMember); + + var found = MemberService.GetMembersByPropertyValue( + "date", new DateTime(2013, 12, 20, 1, 5, 0), ValuePropertyMatchType.LessThanOrEqualTo); + + Assert.AreEqual(7, found.Count()); + } + + [Test] + public void Count_All_Members() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10); + MemberService.Save(members); + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + var found = MemberService.GetCount(MemberCountType.All); + + Assert.AreEqual(11, found); + } + + [Test] + public void Count_All_Locked_Members() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.IsLockedOut = i % 2 == 0); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue(Constants.Conventions.Member.IsLockedOut, true); + MemberService.Save(customMember); + + var found = MemberService.GetCount(MemberCountType.LockedOut); + + Assert.AreEqual(6, found); + } + + [Test] + public void Count_All_Approved_Members() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var members = MemberBuilder.CreateMultipleSimpleMembers(memberType, 10, (i, member) => member.IsApproved = i % 2 == 0); + MemberService.Save(members); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue(Constants.Conventions.Member.IsApproved, false); + MemberService.Save(customMember); + + var found = MemberService.GetCount(MemberCountType.Approved); + + Assert.AreEqual(5, found); + } + + [Test] + public void Setting_Property_On_Built_In_Member_Property_When_Property_Doesnt_Exist_On_Type_Is_Ok() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + memberType.RemovePropertyType(Constants.Conventions.Member.Comments); + MemberTypeService.Save(memberType); + Assert.IsFalse(memberType.PropertyTypes.Any(x => x.Alias == Constants.Conventions.Member.Comments)); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + //this should not throw an exception + customMember.Comments = "hello world"; + MemberService.Save(customMember); + + var found = MemberService.GetById(customMember.Id); + + Assert.IsTrue(found.Comments.IsNullOrWhiteSpace()); + } + + /// + /// Because we are forcing some of the built-ins to be Labels which have an underlying db type as nvarchar but we need + /// to ensure that the dates/int get saved to the correct column anyways. + /// + [Test] + public void Setting_DateTime_Property_On_Built_In_Member_Property_Saves_To_Correct_Column() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + var member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "test", "test"); + var date = DateTime.Now; + member.LastLoginDate = DateTime.Now; + MemberService.Save(member); + + var result = MemberService.GetById(member.Id); + Assert.AreEqual( + date.TruncateTo(DateTimeExtensions.DateTruncate.Second), + result.LastLoginDate.TruncateTo(DateTimeExtensions.DateTruncate.Second)); + + //now ensure the col is correct + var sqlContext = GetRequiredService(); + var sql = sqlContext.Sql().Select() + .From() + .InnerJoin().On(dto => dto.PropertyTypeId, dto => dto.Id) + .InnerJoin().On((left, right) => left.VersionId == right.Id) + .Where(dto => dto.NodeId == member.Id) + .Where(dto => dto.Alias == Constants.Conventions.Member.LastLoginDate); + + List colResult; + using (var scope = ScopeProvider.CreateScope()) + { + colResult = scope.Database.Fetch(sql); + scope.Complete(); + } + + Assert.AreEqual(1, colResult.Count); + Assert.IsTrue(colResult.First().DateValue.HasValue); + Assert.IsFalse(colResult.First().IntegerValue.HasValue); + Assert.IsNull(colResult.First().TextValue); + Assert.IsNull(colResult.First().VarcharValue); + } + + [Test] + public void New_Member_Approved_By_Default() + { + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + + var customMember = MemberBuilder.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + MemberService.Save(customMember); + + var found = MemberService.GetById(customMember.Id); + + Assert.IsTrue(found.IsApproved); + } + } +} diff --git a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs similarity index 65% rename from src/Umbraco.Tests/Services/MemberTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs index 108c9e9bec..3c269080a5 100644 --- a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs @@ -4,25 +4,35 @@ using System.Threading; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] - public class MemberTypeServiceTests : TestWithSomeContentBase + public class MemberTypeServiceTests : UmbracoIntegrationTest { + private IMemberService MemberService => GetRequiredService(); + private IMemberTypeService MemberTypeService => GetRequiredService(); + + [SetUp] + public void SetupTest() + { + // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. + Umbraco.Core.Services.Implement.MemberTypeService.ClearScopeEvents(); + } + [Test] public void Member_Cannot_Edit_Property() { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); //re-get - memberType = ServiceContext.MemberTypeService.Get(memberType.Id); + memberType = MemberTypeService.Get(memberType.Id); foreach (var p in memberType.PropertyTypes) { Assert.IsFalse(memberType.MemberCanEditProperty(p.Alias)); @@ -32,13 +42,13 @@ namespace Umbraco.Tests.Services [Test] public void Member_Can_Edit_Property() { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); var prop = memberType.PropertyTypes.First().Alias; memberType.SetMemberCanEditProperty(prop, true); - ServiceContext.MemberTypeService.Save(memberType); + MemberTypeService.Save(memberType); //re-get - memberType = ServiceContext.MemberTypeService.Get(memberType.Id); + memberType = MemberTypeService.Get(memberType.Id); foreach (var p in memberType.PropertyTypes.Where(x => x.Alias != prop)) { Assert.IsFalse(memberType.MemberCanEditProperty(p.Alias)); @@ -49,10 +59,10 @@ namespace Umbraco.Tests.Services [Test] public void Member_Cannot_View_Property() { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); //re-get - memberType = ServiceContext.MemberTypeService.Get(memberType.Id); + memberType = MemberTypeService.Get(memberType.Id); foreach (var p in memberType.PropertyTypes) { Assert.IsFalse(memberType.MemberCanViewProperty(p.Alias)); @@ -62,13 +72,13 @@ namespace Umbraco.Tests.Services [Test] public void Member_Can_View_Property() { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); var prop = memberType.PropertyTypes.First().Alias; memberType.SetMemberCanViewProperty(prop, true); - ServiceContext.MemberTypeService.Save(memberType); + MemberTypeService.Save(memberType); //re-get - memberType = ServiceContext.MemberTypeService.Get(memberType.Id); + memberType = MemberTypeService.Get(memberType.Id); foreach (var p in memberType.PropertyTypes.Where(x => x.Alias != prop)) { Assert.IsFalse(memberType.MemberCanViewProperty(p.Alias)); @@ -79,117 +89,42 @@ namespace Umbraco.Tests.Services [Test] public void Deleting_PropertyType_Removes_The_Property_From_Member() { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); + MemberTypeService.Save(memberType); + IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + MemberService.Save(member); var initProps = member.Properties.Count; //remove a property (NOT ONE OF THE DEFAULTS) var standardProps = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper); memberType.RemovePropertyType(memberType.PropertyTypes.First(x => standardProps.ContainsKey(x.Alias) == false).Alias); - ServiceContext.MemberTypeService.Save(memberType); + MemberTypeService.Save(memberType); //re-load it from the db - member = ServiceContext.MemberService.GetById(member.Id); + member = MemberService.GetById(member.Id); Assert.AreEqual(initProps - 1, member.Properties.Count); } - [Test] - public void Rebuild_Member_Xml_On_Alias_Change() - { - var contentType1 = MockedContentTypes.CreateSimpleMemberType("test1", "Test1"); - var contentType2 = MockedContentTypes.CreateSimpleMemberType("test2", "Test2"); - ServiceContext.MemberTypeService.Save(contentType1); - ServiceContext.MemberTypeService.Save(contentType2); - var contentItems1 = MockedMember.CreateSimpleMember(contentType1, 10).ToArray(); - foreach (var x in contentItems1) ServiceContext.MemberService.Save(x); - var contentItems2 = MockedMember.CreateSimpleMember(contentType2, 5).ToArray(); - foreach (var x in contentItems2) ServiceContext.MemberService.Save(x); - //only update the contentType1 alias which will force an xml rebuild for all content of that type - contentType1.Alias = "newAlias"; - ServiceContext.MemberTypeService.Save(contentType1); - - using (var scope = ScopeProvider.CreateScope()) - { - foreach (var c in contentItems1) - { - var xml = scope.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsTrue(xml.Xml.StartsWith("("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsTrue(xml.Xml.StartsWith(" standardProps.ContainsKey(x.Alias) == false).Alias; - var elementToMatch = "<" + alias + ">"; - - using (var scope = ScopeProvider.CreateScope()) - { - foreach (var c in contentItems1) - { - var xml = scope.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsTrue(xml.Xml.Contains(elementToMatch)); //verify that it is there before we remove the property - } - scope.Complete(); - } - - //remove a property (NOT ONE OF THE DEFAULTS) - contentType1.RemovePropertyType(alias); - ServiceContext.MemberTypeService.Save(contentType1); - - var reQueried = ServiceContext.MemberTypeService.Get(contentType1.Id); - var reContent = ServiceContext.MemberService.GetById(contentItems1.First().Id); - using (var scope = ScopeProvider.CreateScope()) - { - foreach (var c in contentItems1) - { - var xml = scope.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); - Assert.IsNotNull(xml); - Assert.IsFalse(xml.Xml.Contains(elementToMatch)); //verify that it is no longer there - } - scope.Complete(); - } - } - [Test] public void Cannot_Save_MemberType_With_Empty_Name() { // Arrange - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType("memberTypeAlias", string.Empty); + IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType("memberTypeAlias", string.Empty); // Act & Assert - Assert.Throws(() => ServiceContext.MemberTypeService.Save(memberType)); + Assert.Throws(() => MemberTypeService.Save(memberType)); } [Test] public void Empty_Description_Is_Always_Null_After_Saving_Member_Type() { - var service = ServiceContext.MemberTypeService; - var memberType = MockedContentTypes.CreateSimpleMemberType(); + var service = MemberTypeService; + var memberType = MemberTypeBuilder.CreateSimpleMemberType(); memberType.Description = null; service.Save(memberType); - var memberType2 = MockedContentTypes.CreateSimpleMemberType("memberType2", "Member Type 2"); + var memberType2 = MemberTypeBuilder.CreateSimpleMemberType("memberType2", "Member Type 2"); memberType2.Description = string.Empty; service.Save(memberType2); @@ -201,9 +136,9 @@ namespace Umbraco.Tests.Services //public void Can_Save_MemberType_Structure_And_Create_A_Member_Based_On_It() //{ // // Arrange - // var cs = ServiceContext.MemberService; - // var cts = ServiceContext.MemberTypeService; - // var dtdYesNo = ServiceContext.DataTypeService.GetDataTypeDefinitionById(-49); + // var cs = MemberService; + // var cts = MemberTypeService; + // var dtdYesNo = DataTypeService.GetDataTypeDefinitionById(-49); // var ctBase = new MemberType(-1) { Name = "Base", Alias = "Base", Icon = "folder.gif", Thumbnail = "folder.png" }; // ctBase.AddPropertyType(new PropertyType(dtdYesNo) // { @@ -243,17 +178,17 @@ namespace Umbraco.Tests.Services // * - Components // * - Category // */ - // var service = ServiceContext.ContentTypeService; - // var global = MockedContentTypes.CreateSimpleContentType("global", "Global"); + // var service = ContentTypeService; + // var global = MemberTypeBuilder.CreateSimpleContentType("global", "Global"); // service.Save(global); - // var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global); + // var components = MemberTypeBuilder.CreateSimpleContentType("components", "Components", global); // service.Save(components); - // var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components); + // var component = MemberTypeBuilder.CreateSimpleContentType("component", "Component", components); // service.Save(component); - // var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global); + // var category = MemberTypeBuilder.CreateSimpleContentType("category", "Category", global); // service.Save(category); // var success = category.AddContentType(component); @@ -265,7 +200,7 @@ namespace Umbraco.Tests.Services //public void Can_Remove_ContentType_Composition_From_ContentType() //{ // //Test for U4-2234 - // var cts = ServiceContext.ContentTypeService; + // var cts = ContentTypeService; // //Arrange // var component = CreateComponent(); // cts.Save(component); @@ -305,11 +240,11 @@ namespace Umbraco.Tests.Services //public void Can_Copy_ContentType_By_Performing_Clone() //{ // // Arrange - // var service = ServiceContext.ContentTypeService; - // var metaContentType = MockedContentTypes.CreateMetaContentType(); + // var service = ContentTypeService; + // var metaContentType = MemberTypeBuilder.CreateMetaContentType(); // service.Save(metaContentType); - // var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType); + // var simpleContentType = MemberTypeBuilder.CreateSimpleContentType("category", "Category", metaContentType); // service.Save(simpleContentType); // var categoryId = simpleContentType.Id; @@ -433,16 +368,16 @@ namespace Umbraco.Tests.Services //private IEnumerable CreateContentTypeHierarchy() //{ // //create the master type - // var masterContentType = MockedContentTypes.CreateSimpleContentType("masterContentType", "MasterContentType"); + // var masterContentType = MemberTypeBuilder.CreateSimpleContentType("masterContentType", "MasterContentType"); // masterContentType.Key = new Guid("C00CA18E-5A9D-483B-A371-EECE0D89B4AE"); - // ServiceContext.ContentTypeService.Save(masterContentType); + // ContentTypeService.Save(masterContentType); // //add the one we just created // var list = new List { masterContentType }; // for (var i = 0; i < 10; i++) // { - // var contentType = MockedContentTypes.CreateSimpleContentType("childType" + i, "ChildType" + i, + // var contentType = MemberTypeBuilder.CreateSimpleContentType("childType" + i, "ChildType" + i, // //make the last entry in the list, this one's parent // list.Last()); diff --git a/src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs b/src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs new file mode 100644 index 0000000000..b02bdb9b70 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs @@ -0,0 +1,149 @@ +using System; +using System.Linq; +using System.Threading; +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Integration.Services +{ + [TestFixture] + [Apartment(ApartmentState.STA)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class PublicAccessServiceTests : UmbracoIntegrationTest + { + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + private IPublicAccessService PublicAccessService => GetRequiredService(); + + private Content _content; + + [SetUp] + public void CreateTestData() + { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); // else, FK violation on contentType! + + var ct = ContentTypeBuilder.CreateSimpleContentType("blah", "Blah", defaultTemplateId: template.Id); + ContentTypeService.Save(ct); + + _content = ContentBuilder.CreateSimpleContent(ct, "Test", -1); + ContentService.Save(_content); + } + + [Test] + public void Can_Add_New_Entry() + { + // Arrange + + // Act + var entry = new PublicAccessEntry(_content, _content, _content, new[] + { + new PublicAccessRule() + { + RuleType = "TestType", + RuleValue = "TestVal" + }, + }); + var result = PublicAccessService.Save(entry); + + // Assert + Assert.IsTrue(result.Success); + Assert.AreEqual(OperationResultType.Success, result.Result.Result); + Assert.IsTrue(entry.HasIdentity); + Assert.AreNotEqual(entry.Key, Guid.Empty); + Assert.AreEqual(_content.Id, entry.LoginNodeId); + Assert.AreEqual(_content.Id, entry.NoAccessNodeId); + Assert.AreEqual(_content.Id, entry.ProtectedNodeId); + } + + [Test] + public void Can_Add_Rule() + { + // Arrange + var entry = new PublicAccessEntry(_content, _content, _content, new[] + { + new PublicAccessRule() + { + RuleType = "TestType", + RuleValue = "TestVal" + }, + }); + PublicAccessService.Save(entry); + + // Act + var updated = PublicAccessService.AddRule(_content, "TestType2", "AnotherVal"); + //re-get + entry = PublicAccessService.GetEntryForContent(_content); + + // Assert + Assert.IsTrue(updated.Success); + Assert.AreEqual(OperationResultType.Success, updated.Result.Result); + Assert.AreEqual(2, entry.Rules.Count()); + } + + [Test] + public void Can_Add_Multiple_Value_For_Same_Rule_Type() + { + // Arrange + var entry = new PublicAccessEntry(_content, _content, _content, new[] + { + new PublicAccessRule() + { + RuleType = "TestType", + RuleValue = "TestVal" + }, + }); + PublicAccessService.Save(entry); + + // Act + var updated1 = PublicAccessService.AddRule(_content, "TestType", "AnotherVal1"); + var updated2 = PublicAccessService.AddRule(_content, "TestType", "AnotherVal2"); + + //re-get + entry = PublicAccessService.GetEntryForContent(_content); + + // Assert + Assert.IsTrue(updated1.Success); + Assert.IsTrue(updated2.Success); + Assert.AreEqual(OperationResultType.Success, updated1.Result.Result); + Assert.AreEqual(OperationResultType.Success, updated2.Result.Result); + Assert.AreEqual(3, entry.Rules.Count()); + } + + [Test] + public void Can_Remove_Rule() + { + // Arrange + var entry = new PublicAccessEntry(_content, _content, _content, new[] + { + new PublicAccessRule() + { + RuleType = "TestType", + RuleValue = "TestValue1" + }, + new PublicAccessRule() + { + RuleType = "TestType", + RuleValue = "TestValue2" + }, + }); + PublicAccessService.Save(entry); + + // Act + var removed = PublicAccessService.RemoveRule(_content, "TestType", "TestValue1"); + //re-get + entry = PublicAccessService.GetEntryForContent(_content); + + // Assert + Assert.IsTrue(removed.Success); + Assert.AreEqual(OperationResultType.Success, removed.Result.Result); + Assert.AreEqual(1, entry.Rules.Count()); + Assert.AreEqual("TestValue2", entry.Rules.ElementAt(0).RuleValue); + } + } +} diff --git a/src/Umbraco.Tests/Services/RelationServiceTests.cs b/src/Umbraco.Tests.Integration/Services/RelationServiceTests.cs similarity index 59% rename from src/Umbraco.Tests/Services/RelationServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/RelationServiceTests.cs index 06de405cec..9fe4867fc2 100644 --- a/src/Umbraco.Tests/Services/RelationServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/RelationServiceTests.cs @@ -5,6 +5,10 @@ using System.Threading; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -14,51 +18,56 @@ namespace Umbraco.Tests.Services [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class RelationServiceTests : TestWithSomeContentBase + public class RelationServiceTests : UmbracoIntegrationTest { - + private IContentTypeService ContentTypeService => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private IMediaTypeService MediaTypeService => GetRequiredService(); + private IMediaService MediaService => GetRequiredService(); + private IRelationService RelationService => GetRequiredService(); + [Test] public void Get_Paged_Relations_By_Relation_Type() { //Create content var createdContent = new List(); - var contentType = MockedContentTypes.CreateBasicContentType("blah"); - ServiceContext.ContentTypeService.Save(contentType); - for (int i = 0; i < 10; i++) + var contentType = ContentTypeBuilder.CreateBasicContentType("blah"); + ContentTypeService.Save(contentType); + for (int i = 0; i < 3; i++) { - var c1 = MockedContent.CreateBasicContent(contentType); - ServiceContext.ContentService.Save(c1); + var c1 = ContentBuilder.CreateBasicContent(contentType); + ContentService.Save(c1); createdContent.Add(c1); } //Create media var createdMedia = new List(); - var imageType = MockedContentTypes.CreateImageMediaType("myImage"); - ServiceContext.MediaTypeService.Save(imageType); - for (int i = 0; i < 10; i++) + var imageType = MediaTypeBuilder.CreateImageMediaType("myImage"); + MediaTypeService.Save(imageType); + for (int i = 0; i < 3; i++) { - var c1 = MockedMedia.CreateMediaImage(imageType, -1); - ServiceContext.MediaService.Save(c1); + var c1 = MediaBuilder.CreateMediaImage(imageType, -1); + MediaService.Save(c1); createdMedia.Add(c1); } - var relType = ServiceContext.RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); + var relType = RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias); // Relate content to media foreach (var content in createdContent) foreach (var media in createdMedia) - ServiceContext.RelationService.Relate(content.Id, media.Id, relType); + RelationService.Relate(content.Id, media.Id, relType); - var paged = ServiceContext.RelationService.GetPagedByRelationTypeId(relType.Id, 0, 51, out var totalRecs).ToList(); + var paged = RelationService.GetPagedByRelationTypeId(relType.Id, 0, 4, out var totalRecs).ToList(); - Assert.AreEqual(100, totalRecs); - Assert.AreEqual(51, paged.Count); + Assert.AreEqual(9, totalRecs); + Assert.AreEqual(4, paged.Count); //next page - paged.AddRange(ServiceContext.RelationService.GetPagedByRelationTypeId(relType.Id, 1, 51, out totalRecs)); + paged.AddRange(RelationService.GetPagedByRelationTypeId(relType.Id, 1, 4, out totalRecs)); - Assert.AreEqual(100, totalRecs); - Assert.AreEqual(100, paged.Count); + Assert.AreEqual(9, totalRecs); + Assert.AreEqual(8, paged.Count); Assert.IsTrue(createdContent.Select(x => x.Id).ContainsAll(paged.Select(x => x.ParentId))); Assert.IsTrue(createdMedia.Select(x => x.Id).ContainsAll(paged.Select(x => x.ChildId))); @@ -67,45 +76,45 @@ namespace Umbraco.Tests.Services [Test] public void Return_List_Of_Content_Items_Where_Media_Item_Referenced() { - var mt = MockedContentTypes.CreateSimpleMediaType("testMediaType", "Test Media Type"); - ServiceContext.MediaTypeService.Save(mt); - var m1 = MockedMedia.CreateSimpleMedia(mt, "hello 1", -1); - ServiceContext.MediaService.Save(m1); + var mt = MediaTypeBuilder.CreateSimpleMediaType("testMediaType", "Test Media Type"); + MediaTypeService.Save(mt); + var m1 = MediaBuilder.CreateSimpleMedia(mt, "hello 1", -1); + MediaService.Save(m1); - var ct = MockedContentTypes.CreateTextPageContentType("richTextTest"); + var ct = ContentTypeBuilder.CreateTextPageContentType("richTextTest"); ct.AllowedTemplates = Enumerable.Empty(); - ServiceContext.ContentTypeService.Save(ct); + ContentTypeService.Save(ct); void createContentWithMediaRefs() { - var content = MockedContent.CreateTextpageContent(ct, "my content 2", -1); + var content = ContentBuilder.CreateTextpageContent(ct, "my content 2", -1); //'bodyText' is a property with a RTE property editor which we knows automatically tracks relations content.Properties["bodyText"].SetValue(@"

"); - ServiceContext.ContentService.Save(content); + ContentService.Save(content); } for (var i = 0; i < 6; i++) createContentWithMediaRefs(); //create 6 content items referencing the same media - var relations = ServiceContext.RelationService.GetByChildId(m1.Id, Constants.Conventions.RelationTypes.RelatedMediaAlias).ToList(); + var relations = RelationService.GetByChildId(m1.Id, Constants.Conventions.RelationTypes.RelatedMediaAlias).ToList(); Assert.AreEqual(6, relations.Count); - var entities = ServiceContext.RelationService.GetParentEntitiesFromRelations(relations).ToList(); + var entities = RelationService.GetParentEntitiesFromRelations(relations).ToList(); Assert.AreEqual(6, entities.Count); } [Test] public void Can_Create_RelationType_Without_Name() { - var rs = ServiceContext.RelationService; + var rs = RelationService; IRelationType rt = new RelationType("Test", "repeatedEventOccurence", false, Constants.ObjectTypes.Document, Constants.ObjectTypes.Media); Assert.DoesNotThrow(() => rs.Save(rt)); //re-get - rt = ServiceContext.RelationService.GetRelationTypeById(rt.Id); + rt = RelationService.GetRelationTypeById(rt.Id); Assert.AreEqual("Test", rt.Name); Assert.AreEqual("repeatedEventOccurence", rt.Alias); @@ -117,13 +126,13 @@ namespace Umbraco.Tests.Services [Test] public void Create_Relation_Type_Without_Object_Types() { - var rs = ServiceContext.RelationService; + var rs = RelationService; IRelationType rt = new RelationType("repeatedEventOccurence", "repeatedEventOccurence", false, null, null); Assert.DoesNotThrow(() => rs.Save(rt)); //re-get - rt = ServiceContext.RelationService.GetRelationTypeById(rt.Id); + rt = RelationService.GetRelationTypeById(rt.Id); Assert.IsNull(rt.ChildObjectType); Assert.IsNull(rt.ParentObjectType); @@ -144,7 +153,7 @@ namespace Umbraco.Tests.Services var r = CreateAndSaveRelation("Test", "test"); // re-get - r = ServiceContext.RelationService.GetById(r.Id); + r = RelationService.GetById(r.Id); Assert.AreEqual(Constants.ObjectTypes.Document, r.ParentObjectType); Assert.AreEqual(Constants.ObjectTypes.Media, r.ChildObjectType); @@ -153,13 +162,13 @@ namespace Umbraco.Tests.Services [Test] public void Insert_Bulk_Relations() { - var rs = ServiceContext.RelationService; + var rs = RelationService; var newRelations = CreateRelations(10); Assert.IsTrue(newRelations.All(x => !x.HasIdentity)); - ServiceContext.RelationService.Save(newRelations); + RelationService.Save(newRelations); Assert.IsTrue(newRelations.All(x => x.HasIdentity)); } @@ -167,7 +176,7 @@ namespace Umbraco.Tests.Services [Test] public void Update_Bulk_Relations() { - var rs = ServiceContext.RelationService; + var rs = RelationService; var date = DateTime.Now.AddDays(-10); var newRelations = CreateRelations(10); @@ -175,10 +184,10 @@ namespace Umbraco.Tests.Services { r.CreateDate = date; r.UpdateDate = date; - } + } //insert - ServiceContext.RelationService.Save(newRelations); + RelationService.Save(newRelations); Assert.IsTrue(newRelations.All(x => x.UpdateDate == date)); var newDate = DateTime.Now.AddDays(-5); @@ -186,29 +195,29 @@ namespace Umbraco.Tests.Services r.UpdateDate = newDate; //update - ServiceContext.RelationService.Save(newRelations); + RelationService.Save(newRelations); Assert.IsTrue(newRelations.All(x => x.UpdateDate == newDate)); } private IRelation CreateAndSaveRelation(string name, string alias) { - var rs = ServiceContext.RelationService; + var rs = RelationService; var rt = new RelationType(name, alias, false, null, null); rs.Save(rt); - var ct = MockedContentTypes.CreateBasicContentType(); - ServiceContext.ContentTypeService.Save(ct); + var ct = ContentTypeBuilder.CreateBasicContentType(); + ContentTypeService.Save(ct); - var mt = MockedContentTypes.CreateImageMediaType("img"); - ServiceContext.MediaTypeService.Save(mt); + var mt = MediaTypeBuilder.CreateImageMediaType("img"); + MediaTypeService.Save(mt); - var c1 = MockedContent.CreateBasicContent(ct); - var c2 = MockedMedia.CreateMediaImage(mt, -1); - ServiceContext.ContentService.Save(c1); - ServiceContext.MediaService.Save(c2); + var c1 = ContentBuilder.CreateBasicContent(ct); + var c2 = MediaBuilder.CreateMediaImage(mt, -1); + ContentService.Save(c1); + MediaService.Save(c2); var r = new Relation(c1.Id, c2.Id, rt); - ServiceContext.RelationService.Save(r); + RelationService.Save(r); return r; } @@ -220,23 +229,23 @@ namespace Umbraco.Tests.Services /// private IEnumerable CreateRelations(int count) { - var rs = ServiceContext.RelationService; + var rs = RelationService; var rtName = Guid.NewGuid().ToString(); var rt = new RelationType(rtName, rtName, false, null, null); rs.Save(rt); - var ct = MockedContentTypes.CreateBasicContentType(); - ServiceContext.ContentTypeService.Save(ct); + var ct = ContentTypeBuilder.CreateBasicContentType(); + ContentTypeService.Save(ct); - var mt = MockedContentTypes.CreateImageMediaType("img"); - ServiceContext.MediaTypeService.Save(mt); + var mt = MediaTypeBuilder.CreateImageMediaType("img"); + MediaTypeService.Save(mt); return Enumerable.Range(1, count).Select(index => { - var c1 = MockedContent.CreateBasicContent(ct); - var c2 = MockedMedia.CreateMediaImage(mt, -1); - ServiceContext.ContentService.Save(c1); - ServiceContext.MediaService.Save(c2); + var c1 = ContentBuilder.CreateBasicContent(ct); + var c2 = MediaBuilder.CreateMediaImage(mt, -1); + ContentService.Save(c1); + MediaService.Save(c2); return new Relation(c1.Id, c2.Id, rt); }).ToList(); diff --git a/src/Umbraco.Tests/Services/SectionServiceTests.cs b/src/Umbraco.Tests.Integration/Services/SectionServiceTests.cs similarity index 65% rename from src/Umbraco.Tests/Services/SectionServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/SectionServiceTests.cs index 80a4de4bfe..f34ea32cff 100644 --- a/src/Umbraco.Tests/Services/SectionServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/SectionServiceTests.cs @@ -1,23 +1,25 @@ -using NUnit.Framework; -using System.Linq; +using System.Linq; using System.Threading; -using Umbraco.Core; -using Umbraco.Core.Composing; +using NUnit.Framework; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Services; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.Services; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering the SectionService /// [TestFixture] [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] - public class SectionServiceTests : TestWithSomeContentBase + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class SectionServiceTests : UmbracoIntegrationTest { - private ISectionService SectionService => Factory.GetInstance(); + private ISectionService SectionService => GetRequiredService(); + private IUserService UserService => GetRequiredService(); [Test] public void SectionService_Can_Get_Allowed_Sections_For_User() @@ -34,13 +36,14 @@ namespace Umbraco.Tests.Services private IUser CreateTestUser() { - var user = new User(TestObjects.GetGlobalSettings()) + var globalSettings = new GlobalSettings(); + var user = new User(globalSettings) { Name = "Test user", Username = "testUser", Email = "testuser@test.com", }; - ServiceContext.UserService.Save(user, false); + UserService.Save(user, false); var userGroupA = new UserGroup(ShortStringHelper) { @@ -50,7 +53,7 @@ namespace Umbraco.Tests.Services userGroupA.AddAllowedSection("media"); userGroupA.AddAllowedSection("settings"); // TODO: This is failing the test - ServiceContext.UserService.Save(userGroupA, new[] { user.Id }, false); + UserService.Save(userGroupA, new[] { user.Id }, false); var userGroupB = new UserGroup(ShortStringHelper) { @@ -59,9 +62,9 @@ namespace Umbraco.Tests.Services }; userGroupB.AddAllowedSection("settings"); userGroupB.AddAllowedSection("member"); - ServiceContext.UserService.Save(userGroupB, new[] { user.Id }, false); + UserService.Save(userGroupB, new[] { user.Id }, false); - return ServiceContext.UserService.GetUserById(user.Id); + return UserService.GetUserById(user.Id); } } } diff --git a/src/Umbraco.Tests/Services/TagServiceTests.cs b/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs similarity index 56% rename from src/Umbraco.Tests/Services/TagServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/TagServiceTests.cs index f4916168d4..f84dbfb74a 100644 --- a/src/Umbraco.Tests/Services/TagServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs @@ -2,16 +2,16 @@ using System.Threading; using Newtonsoft.Json; using NUnit.Framework; -using NUnit.Framework.Internal; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering methods in the TagService class. @@ -21,41 +21,51 @@ namespace Umbraco.Tests.Services [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class TagServiceTests : TestWithSomeContentBase + public class TagServiceTests : UmbracoIntegrationTest { - public PropertyEditorCollection PropertyEditorCollection => Factory.GetInstance(); + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + private ITagService TagService => GetRequiredService(); + private IDataTypeService DataTypeService => GetRequiredService(); + private PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); + private IContentType _contentType; + + [SetUp] + public void CreateTestData() + { + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); // else, FK violation on contentType! + + _contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", defaultTemplateId: template.Id); + _contentType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") + { + DataTypeId = Constants.DataTypes.Tags, + }); + ContentTypeService.Save(_contentType); + } [Test] public void TagApiConsistencyTest() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "tags") - { - DataTypeId = 1041 - }); - contentTypeService.Save(contentType); - - IContent content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + IContent content1 = ContentBuilder.CreateSimpleContent(_contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig", "goat" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); // change content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "elephant" }, true); content1.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); // more changes content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "mouse" }, true); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); content1.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "mouse" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); // get it back - content1 = contentService.GetById(content1.Id); + content1 = ContentService.GetById(content1.Id); var tagsValue = content1.GetValue("tags").ToString(); var tagsValues = JsonConvert.DeserializeObject(tagsValue); Assert.AreEqual(3, tagsValues.Length); @@ -63,7 +73,7 @@ namespace Umbraco.Tests.Services Assert.Contains("goat", tagsValues); Assert.Contains("elephant", tagsValues); - var tags = tagService.GetTagsForProperty(content1.Id, "tags").ToArray(); + var tags = TagService.GetTagsForProperty(content1.Id, "tags").ToArray(); Assert.IsTrue(tags.All(x => x.Group == "default")); tagsValues = tags.Select(x => x.Text).ToArray(); @@ -76,31 +86,20 @@ namespace Umbraco.Tests.Services [Test] public void TagList_Contains_NodeCount() { - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var tagService = ServiceContext.TagService; - var contentType = MockedContentTypes.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", true); - contentType.PropertyGroups.First().PropertyTypes.Add( - new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Ntext, "tags") - { - DataTypeId = Constants.DataTypes.Tags - }); - contentTypeService.Save(contentType); - - var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); + var content1 = ContentBuilder.CreateSimpleContent(_contentType, "Tagged content 1", -1); content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig", "goat" }); - contentService.SaveAndPublish(content1); + ContentService.SaveAndPublish(content1); - var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); + var content2 = ContentBuilder.CreateSimpleContent(_contentType, "Tagged content 2", -1); content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig" }); - contentService.SaveAndPublish(content2); + ContentService.SaveAndPublish(content2); - var content3 = MockedContent.CreateSimpleContent(contentType, "Tagged content 3", -1); + var content3 = ContentBuilder.CreateSimpleContent(_contentType, "Tagged content 3", -1); content3.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow" }); - contentService.SaveAndPublish(content3); + ContentService.SaveAndPublish(content3); // Act - var tags = tagService.GetAllContentTags() + var tags = TagService.GetAllContentTags() .OrderByDescending(x => x.NodeCount) .ToList(); diff --git a/src/Umbraco.Tests/Services/UserServiceTests.cs b/src/Umbraco.Tests.Integration/Services/UserServiceTests.cs similarity index 58% rename from src/Umbraco.Tests/Services/UserServiceTests.cs rename to src/Umbraco.Tests.Integration/Services/UserServiceTests.cs index cedb329f13..802bfd9e1b 100644 --- a/src/Umbraco.Tests/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Services/UserServiceTests.cs @@ -6,51 +6,57 @@ using System.Text; using System.Threading; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Exceptions; +using Umbraco.Core.Configuration.Models; 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.Common.Builders.Extensions; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; using Umbraco.Web.Actions; -using MockedUser = Umbraco.Tests.TestHelpers.Entities.MockedUser; - -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Services { /// /// Tests covering the UserService /// [TestFixture] [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)] - public class UserServiceTests : TestWithSomeContentBase + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class UserServiceTests : UmbracoIntegrationTest { + private UserService UserService => (UserService) GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IFileService FileService => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + [Test] public void Get_User_Permissions_For_Unassigned_Permission_Nodes() { // Arrange - var userService = ServiceContext.UserService; - var user = CreateTestUser(out var userGroup); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + var user = CreateTestUser(out _); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var content = new[] { - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType) + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); // Act - var permissions = userService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id) - .ToArray(); + var permissions = UserService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id).ToArray(); - //assert + // Assert Assert.AreEqual(3, permissions.Length); Assert.AreEqual(17, permissions[0].AssignedPermissions.Length); Assert.AreEqual(17, permissions[1].AssignedPermissions.Length); @@ -61,30 +67,31 @@ namespace Umbraco.Tests.Services public void Get_User_Permissions_For_Assigned_Permission_Nodes() { // Arrange - var userService = ServiceContext.UserService; - IUserGroup userGroup; - var user = CreateTestUser(out userGroup); + var user = CreateTestUser(out var userGroup); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); var content = new[] { - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType) + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.Save(content); + ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[2], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); // Act - var permissions = userService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id).ToArray(); + var permissions = UserService.GetPermissions(user, content[0].Id, content[1].Id, content[2].Id).ToArray(); - //assert + // Assert Assert.AreEqual(3, permissions.Length); Assert.AreEqual(3, permissions[0].AssignedPermissions.Length); Assert.AreEqual(2, permissions[1].AssignedPermissions.Length); @@ -95,29 +102,31 @@ namespace Umbraco.Tests.Services public void Get_UserGroup_Assigned_Permissions() { // Arrange - var userService = ServiceContext.UserService; var userGroup = CreateTestUserGroup(); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var content = new[] { - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType) + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(0), ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(1), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(1), ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content.ElementAt(2), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.Save(content); + ContentService.SetPermission(content.ElementAt(0), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(0), ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(0), ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(1), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(1), ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content.ElementAt(2), ActionBrowse.ActionLetter, new int[] { userGroup.Id }); // Act - var permissions = userService.GetPermissions(userGroup, false, content[0].Id, content[1].Id, content[2].Id).ToArray(); + var permissions = UserService.GetPermissions(userGroup, false, content[0].Id, content[1].Id, content[2].Id).ToArray(); - //assert + // Assert Assert.AreEqual(3, permissions.Length); Assert.AreEqual(3, permissions[0].AssignedPermissions.Length); Assert.AreEqual(2, permissions[1].AssignedPermissions.Length); @@ -128,29 +137,31 @@ namespace Umbraco.Tests.Services public void Get_UserGroup_Assigned_And_Default_Permissions() { // Arrange - var userService = ServiceContext.UserService; var userGroup = CreateTestUserGroup(); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var content = new[] { - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType) + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.Save(content); + ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act - var permissions = userService.GetPermissions(userGroup, true, content[0].Id, content[1].Id, content[2].Id) + var permissions = UserService.GetPermissions(userGroup, true, content[0].Id, content[1].Id, content[2].Id) .ToArray(); - //assert + // Assert Assert.AreEqual(3, permissions.Length); Assert.AreEqual(3, permissions[0].AssignedPermissions.Length); Assert.AreEqual(2, permissions[1].AssignedPermissions.Length); @@ -161,44 +172,46 @@ namespace Umbraco.Tests.Services public void Get_All_User_Permissions_For_All_Nodes_With_Explicit_Permission() { // Arrange - var userService = ServiceContext.UserService; var userGroup1 = CreateTestUserGroup(); var userGroup2 = CreateTestUserGroup("test2", "Test 2"); var userGroup3 = CreateTestUserGroup("test3", "Test 3"); - var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); var defaultPermissionCount = userGroup3.Permissions.Count(); user.AddGroup(userGroup1); user.AddGroup(userGroup2); user.AddGroup(userGroup3); - userService.Save(user); + UserService.Save(user); + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); var content = new[] { - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType) + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); + ContentService.Save(content); //assign permissions - we aren't assigning anything explicit for group3 and nothing explicit for content[2] /w group2 - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup2.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup2.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); + ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); + ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); + ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup2.Id }); + ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup1.Id }); + ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup2.Id }); + ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup1.Id }); // Act //we don't pass in any nodes so it will return all of them - var result = userService.GetPermissions(user).ToArray(); + var result = UserService.GetPermissions(user).ToArray(); var permissions = result .GroupBy(x => x.EntityId) .ToDictionary(x => x.Key, x => x.GroupBy(a => a.UserGroupId).ToDictionary(a => a.Key, a => a.ToArray())); - //assert + // Assert //there will be 3 since that is how many content items there are Assert.AreEqual(3, permissions.Count); @@ -241,32 +254,34 @@ namespace Umbraco.Tests.Services public void Get_All_User_Group_Permissions_For_All_Nodes() { // Arrange - var userService = ServiceContext.UserService; var userGroup = CreateTestUserGroup(); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); + var content = new[] { - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType), - MockedContent.CreateSimpleContent(contentType) + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType), + ContentBuilder.CreateSimpleContent(contentType) }; - ServiceContext.ContentService.Save(content); - ServiceContext.ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.Save(content); + ContentService.SetPermission(content[0], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[0], ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[1], ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(content[2], ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act //we don't pass in any nodes so it will return all of them - var permissions = userService.GetPermissions(userGroup, true) + var permissions = UserService.GetPermissions(userGroup, true) .GroupBy(x => x.EntityId) .ToDictionary(x => x.Key, x => x); - //assert + // Assert Assert.AreEqual(3, permissions.Count); Assert.IsTrue(permissions.ContainsKey(content[0].Id)); Assert.AreEqual(3, permissions[content[0].Id].SelectMany(x => x.AssignedPermissions).Count()); @@ -341,7 +356,6 @@ namespace Umbraco.Tests.Services allPermissions = result.GetAllPermissions().ToArray(); Assert.AreEqual(5, allPermissions.Length, string.Join(",", allPermissions)); Assert.IsTrue(allPermissions.ContainsAll(new[] { "S", "D", "F", "G", "K" })); - } [Test] @@ -404,28 +418,30 @@ namespace Umbraco.Tests.Services public void Get_User_Implicit_Permissions() { // Arrange - var userService = ServiceContext.UserService; var userGroup = CreateTestUserGroup(); - var contentType = MockedContentTypes.CreateSimpleContentType(); - ServiceContext.ContentTypeService.Save(contentType); - var parent = MockedContent.CreateSimpleContent(contentType); - ServiceContext.ContentService.Save(parent); - var child1 = MockedContent.CreateSimpleContent(contentType, "child1", parent); - ServiceContext.ContentService.Save(child1); - var child2 = MockedContent.CreateSimpleContent(contentType, "child2", child1); - ServiceContext.ContentService.Save(child2); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); - ServiceContext.ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionMove.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); - ServiceContext.ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); + var parent = ContentBuilder.CreateSimpleContent(contentType); + ContentService.Save(parent); + var child1 = ContentBuilder.CreateSimpleContent(contentType, "child1", parent.Id); + ContentService.Save(child1); + var child2 = ContentBuilder.CreateSimpleContent(contentType, "child2", child1.Id); + ContentService.Save(child2); + + ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionMove.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionBrowse.ActionLetter, new int[] { userGroup.Id }); + ContentService.SetPermission(parent, ActionDelete.ActionLetter, new int[] { userGroup.Id }); // Act - var permissions = userService.GetPermissionsForPath(userGroup, child2.Path); + var permissions = UserService.GetPermissionsForPath(userGroup, child2.Path); - //assert + // Assert var allPermissions = permissions.GetAllPermissions().ToArray(); Assert.AreEqual(3, allPermissions.Length); } @@ -433,10 +449,10 @@ namespace Umbraco.Tests.Services [Test] public void Can_Delete_User() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - ServiceContext.UserService.Delete(user, true); - var deleted = ServiceContext.UserService.GetUserById(user.Id); + UserService.Delete(user, true); + var deleted = UserService.GetUserById(user.Id); // Assert Assert.That(deleted, Is.Null); @@ -445,10 +461,10 @@ namespace Umbraco.Tests.Services [Test] public void Disables_User_Instead_Of_Deleting_If_Flag_Not_Set() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - ServiceContext.UserService.Delete(user); - var deleted = ServiceContext.UserService.GetUserById(user.Id); + UserService.Delete(user); + var deleted = UserService.GetUserById(user.Id); // Assert Assert.That(deleted, Is.Not.Null); @@ -457,60 +473,60 @@ namespace Umbraco.Tests.Services [Test] public void Exists_By_Username() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - var user2 = ServiceContext.UserService.CreateUserWithIdentity("john2@umbraco.io", "john2@umbraco.io"); - Assert.IsTrue(ServiceContext.UserService.Exists("JohnDoe")); - Assert.IsFalse(ServiceContext.UserService.Exists("notFound")); - Assert.IsTrue(ServiceContext.UserService.Exists("john2@umbraco.io")); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user2 = UserService.CreateUserWithIdentity("john2@umbraco.io", "john2@umbraco.io"); + Assert.IsTrue(UserService.Exists("JohnDoe")); + Assert.IsFalse(UserService.Exists("notFound")); + Assert.IsTrue(UserService.Exists("john2@umbraco.io")); } [Test] public void Get_By_Email() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - Assert.IsNotNull(ServiceContext.UserService.GetByEmail(user.Email)); - Assert.IsNull(ServiceContext.UserService.GetByEmail("do@not.find")); + Assert.IsNotNull(UserService.GetByEmail(user.Email)); + Assert.IsNull(UserService.GetByEmail("do@not.find")); } [Test] public void Get_By_Username() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - Assert.IsNotNull(ServiceContext.UserService.GetByUsername(user.Username)); - Assert.IsNull(ServiceContext.UserService.GetByUsername("notFound")); + Assert.IsNotNull(UserService.GetByUsername(user.Username)); + Assert.IsNull(UserService.GetByUsername("notFound")); } [Test] public void Get_By_Username_With_Backslash() { - var user = ServiceContext.UserService.CreateUserWithIdentity("mydomain\\JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("mydomain\\JohnDoe", "john@umbraco.io"); - Assert.IsNotNull(ServiceContext.UserService.GetByUsername(user.Username)); - Assert.IsNull(ServiceContext.UserService.GetByUsername("notFound")); + Assert.IsNotNull(UserService.GetByUsername(user.Username)); + Assert.IsNull(UserService.GetByUsername("notFound")); } [Test] public void Get_By_Object_Id() { - var user = ServiceContext.UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); - Assert.IsNotNull(ServiceContext.UserService.GetUserById(user.Id)); - Assert.IsNull(ServiceContext.UserService.GetUserById(9876)); + Assert.IsNotNull(UserService.GetUserById(user.Id)); + Assert.IsNull(UserService.GetUserById(9876)); } [Test] public void Find_By_Email_Starts_With() { - var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + var users = UserBuilder. CreateMulipleUsers(10); + UserService.Save(users); //don't find this - var customUser = MockedUser.CreateUser(); + var customUser = UserBuilder.CreateUser(); customUser.Email = "hello@hello.com"; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.FindByEmail("tes", 0, 100, out _, StringPropertyMatchType.StartsWith); + var found = UserService.FindByEmail("tes", 0, 100, out _, StringPropertyMatchType.StartsWith); Assert.AreEqual(10, found.Count()); } @@ -518,14 +534,14 @@ namespace Umbraco.Tests.Services [Test] public void Find_By_Email_Ends_With() { - var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + var users = UserBuilder. CreateMulipleUsers(10); + UserService.Save(users); //include this - var customUser = MockedUser.CreateUser(); + var customUser = UserBuilder.CreateUser(); customUser.Email = "hello@test.com"; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.FindByEmail("test.com", 0, 100, out _, StringPropertyMatchType.EndsWith); + var found = UserService.FindByEmail("test.com", 0, 100, out _, StringPropertyMatchType.EndsWith); Assert.AreEqual(11, found.Count()); } @@ -533,14 +549,14 @@ namespace Umbraco.Tests.Services [Test] public void Find_By_Email_Contains() { - var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + var users = UserBuilder. CreateMulipleUsers(10); + UserService.Save(users); //include this - var customUser = MockedUser.CreateUser(); + var customUser = UserBuilder.CreateUser(); customUser.Email = "hello@test.com"; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.FindByEmail("test", 0, 100, out _, StringPropertyMatchType.Contains); + var found = UserService.FindByEmail("test", 0, 100, out _, StringPropertyMatchType.Contains); Assert.AreEqual(11, found.Count()); } @@ -548,14 +564,14 @@ namespace Umbraco.Tests.Services [Test] public void Find_By_Email_Exact() { - var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + var users = UserBuilder. CreateMulipleUsers(10); + UserService.Save(users); //include this - var customUser = MockedUser.CreateUser(); + var customUser = UserBuilder.CreateUser(); customUser.Email = "hello@test.com"; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.FindByEmail("hello@test.com", 0, 100, out _, StringPropertyMatchType.Exact); + var found = UserService.FindByEmail("hello@test.com", 0, 100, out _, StringPropertyMatchType.Exact); Assert.AreEqual(1, found.Count()); } @@ -563,10 +579,10 @@ namespace Umbraco.Tests.Services [Test] public void Get_All_Paged_Users() { - var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); + var users = UserBuilder. CreateMulipleUsers(10); + UserService.Save(users); - var found = ServiceContext.UserService.GetAll(0, 2, out var totalRecs); + var found = UserService.GetAll(0, 2, out var totalRecs); Assert.AreEqual(2, found.Count()); // + 1 because of the built in admin user @@ -578,10 +594,10 @@ namespace Umbraco.Tests.Services [Test] public void Get_All_Paged_Users_With_Filter() { - var users = MockedUser.CreateMulipleUsers(10).ToArray(); - ServiceContext.UserService.Save(users); + var users = UserBuilder. CreateMulipleUsers(10).ToArray(); + UserService.Save(users); - var found = ServiceContext.UserService.GetAll(0, 2, out var totalRecs, "username", Direction.Ascending, filter: "test"); + var found = UserService.GetAll(0, 2, out var totalRecs, "username", Direction.Ascending, filter: "test"); Assert.AreEqual(2, found.Count()); Assert.AreEqual(10, totalRecs); @@ -592,19 +608,19 @@ namespace Umbraco.Tests.Services [Test] public void Get_All_Paged_Users_For_Group() { - var userGroup = MockedUserGroup.CreateUserGroup(); - ServiceContext.UserService.Save(userGroup); + var userGroup = UserGroupBuilder.CreateUserGroup(); + UserService.Save(userGroup); - var users = MockedUser.CreateMulipleUsers(10).ToArray(); + var users = UserBuilder. CreateMulipleUsers(10).ToArray(); for (var i = 0; i < 10;) { users[i].AddGroup(userGroup.ToReadOnlyGroup()); i = i + 2; } - ServiceContext.UserService.Save(users); + UserService.Save(users); long totalRecs; - var found = ServiceContext.UserService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, includeUserGroups: new[] {userGroup.Alias}); + var found = UserService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, includeUserGroups: new[] { userGroup.Alias }); Assert.AreEqual(2, found.Count()); Assert.AreEqual(5, totalRecs); @@ -615,10 +631,10 @@ namespace Umbraco.Tests.Services [Test] public void Get_All_Paged_Users_For_Group_With_Filter() { - var userGroup = MockedUserGroup.CreateUserGroup(); - ServiceContext.UserService.Save(userGroup); + var userGroup = UserGroupBuilder.CreateUserGroup(); + UserService.Save(userGroup); - var users = MockedUser.CreateMulipleUsers(10).ToArray(); + var users = UserBuilder. CreateMulipleUsers(10).ToArray(); for (var i = 0; i < 10;) { users[i].AddGroup(userGroup.ToReadOnlyGroup()); @@ -629,10 +645,10 @@ namespace Umbraco.Tests.Services users[i].Name = "blah" + users[i].Name; i = i + 3; } - ServiceContext.UserService.Save(users); + UserService.Save(users); long totalRecs; - var found = ServiceContext.UserService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, userGroups: new[] { userGroup.Alias }, filter: "blah"); + var found = UserService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, userGroups: new[] { userGroup.Alias }, filter: "blah"); Assert.AreEqual(2, found.Count()); Assert.AreEqual(2, totalRecs); @@ -643,12 +659,12 @@ namespace Umbraco.Tests.Services [Test] public void Count_All_Users() { - var users = MockedUser.CreateMulipleUsers(10); - ServiceContext.UserService.Save(users); - var customUser = MockedUser.CreateUser(); - ServiceContext.UserService.Save(customUser); + var users = UserBuilder. CreateMulipleUsers(10); + UserService.Save(users); + var customUser = UserBuilder.CreateUser(); + UserService.Save(customUser); - var found = ServiceContext.UserService.GetCount(MemberCountType.All); + var found = UserService.GetCount(MemberCountType.All); // + 1 because of the built in admin user Assert.AreEqual(12, found); @@ -658,24 +674,24 @@ namespace Umbraco.Tests.Services [Test] public void Count_All_Online_Users() { - var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.LastLoginDate = DateTime.Now.AddMinutes(i * -2)); - ServiceContext.UserService.Save(users); + var users = UserBuilder. CreateMulipleUsers(10, (i, member) => member.LastLoginDate = DateTime.Now.AddMinutes(i * -2)); + UserService.Save(users); - var customUser = MockedUser.CreateUser(); + var customUser = UserBuilder.CreateUser(); throw new NotImplementedException(); } [Test] public void Count_All_Locked_Users() { - var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.IsLockedOut = i % 2 == 0); - ServiceContext.UserService.Save(users); + var users = UserBuilder.CreateMulipleUsers(10, (i, member) => member.IsLockedOut = i % 2 == 0); + UserService.Save(users); - var customUser = MockedUser.CreateUser(); + var customUser = UserBuilder.CreateUser(); customUser.IsLockedOut = true; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.GetCount(MemberCountType.LockedOut); + var found = UserService.GetCount(MemberCountType.LockedOut); Assert.AreEqual(6, found); } @@ -683,14 +699,14 @@ namespace Umbraco.Tests.Services [Test] public void Count_All_Approved_Users() { - var users = MockedUser.CreateMulipleUsers(10, (i, member) => member.IsApproved = i % 2 == 0); - ServiceContext.UserService.Save(users); + var users = UserBuilder.CreateMulipleUsers(10, (i, member) => member.IsApproved = i % 2 == 0); + UserService.Save(users); - var customUser = MockedUser.CreateUser(); + var customUser = UserBuilder.CreateUser(); customUser.IsApproved = false; - ServiceContext.UserService.Save(customUser); + UserService.Save(customUser); - var found = ServiceContext.UserService.GetCount(MemberCountType.Approved); + var found = UserService.GetCount(MemberCountType.Approved); // + 1 because of the built in admin user Assert.AreEqual(6, found); @@ -699,11 +715,8 @@ namespace Umbraco.Tests.Services [Test] public void Can_Persist_New_User() { - // Arrange - var userService = ServiceContext.UserService; - // Act - var membershipUser = userService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); + var membershipUser = UserService.CreateUserWithIdentity("JohnDoe", "john@umbraco.io"); // Assert Assert.That(membershipUser.HasIdentity, Is.True); @@ -715,17 +728,15 @@ namespace Umbraco.Tests.Services [Test] public void Can_Persist_New_User_With_Hashed_Password() { - // Arrange - var userService = ServiceContext.UserService; - // Act // NOTE: Normally the hash'ing would be handled in the membership provider, so the service just saves the password var password = "123456"; 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); - userService.Save(membershipUser); + var globalSettings = new GlobalSettings(); + var membershipUser = new User(globalSettings, "JohnDoe", "john@umbraco.io", encodedPassword, encodedPassword); + UserService.Save(membershipUser); // Assert Assert.That(membershipUser.HasIdentity, Is.True); @@ -745,9 +756,9 @@ namespace Umbraco.Tests.Services }; userGroup.AddAllowedSection("content"); userGroup.AddAllowedSection("mediat"); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); - var result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); + var result1 = UserService.GetUserGroupById(userGroup.Id); Assert.AreEqual(2, result1.AllowedSections.Count()); @@ -756,9 +767,9 @@ namespace Umbraco.Tests.Services userGroup.AddAllowedSection("test2"); userGroup.AddAllowedSection("test3"); userGroup.AddAllowedSection("test4"); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); - result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); + result1 = UserService.GetUserGroupById(userGroup.Id); Assert.AreEqual(6, result1.AllowedSections.Count()); @@ -771,11 +782,11 @@ namespace Umbraco.Tests.Services //now just re-add a couple result1.AddAllowedSection("test3"); result1.AddAllowedSection("test4"); - ServiceContext.UserService.Save(result1); + UserService.Save(result1); - //assert + // Assert //re-get - result1 = ServiceContext.UserService.GetUserGroupById(userGroup.Id); + result1 = UserService.GetUserGroupById(userGroup.Id); Assert.AreEqual(2, result1.AllowedSections.Count()); } @@ -792,21 +803,21 @@ namespace Umbraco.Tests.Services Alias = "Group2", Name = "Group 2" }; - ServiceContext.UserService.Save(userGroup1); - ServiceContext.UserService.Save(userGroup2); + UserService.Save(userGroup1); + UserService.Save(userGroup2); //adds some allowed sections userGroup1.AddAllowedSection("test"); userGroup2.AddAllowedSection("test"); - ServiceContext.UserService.Save(userGroup1); - ServiceContext.UserService.Save(userGroup2); + UserService.Save(userGroup1); + UserService.Save(userGroup2); //now clear the section from all users - ServiceContext.UserService.DeleteSectionFromAllUserGroups("test"); + UserService.DeleteSectionFromAllUserGroups("test"); - //assert - var result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); - var result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); + // Assert + var result1 = UserService.GetUserGroupById(userGroup1.Id); + var result2 = UserService.GetUserGroupById(userGroup2.Id); Assert.IsFalse(result1.AllowedSections.Contains("test")); Assert.IsFalse(result2.AllowedSections.Contains("test")); } @@ -833,14 +844,14 @@ namespace Umbraco.Tests.Services Alias = "Group3", Name = "Group 3" }; - ServiceContext.UserService.Save(userGroup1); - ServiceContext.UserService.Save(userGroup2); - ServiceContext.UserService.Save(userGroup3); + UserService.Save(userGroup1); + UserService.Save(userGroup2); + UserService.Save(userGroup3); - //assert - var result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); - var result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); - var result3 = ServiceContext.UserService.GetUserGroupById(userGroup3.Id); + // Assert + var result1 = UserService.GetUserGroupById(userGroup1.Id); + var result2 = UserService.GetUserGroupById(userGroup2.Id); + var result3 = UserService.GetUserGroupById(userGroup3.Id); Assert.IsTrue(result1.AllowedSections.Contains("test")); Assert.IsTrue(result2.AllowedSections.Contains("test")); Assert.IsFalse(result3.AllowedSections.Contains("test")); @@ -849,13 +860,13 @@ namespace Umbraco.Tests.Services foreach (var userGroup in new[] { userGroup1, userGroup2, userGroup3 }) { userGroup.AddAllowedSection("test"); - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); } - //assert - result1 = ServiceContext.UserService.GetUserGroupById(userGroup1.Id); - result2 = ServiceContext.UserService.GetUserGroupById(userGroup2.Id); - result3 = ServiceContext.UserService.GetUserGroupById(userGroup3.Id); + // Assert + result1 = UserService.GetUserGroupById(userGroup1.Id); + result2 = UserService.GetUserGroupById(userGroup2.Id); + result3 = UserService.GetUserGroupById(userGroup3.Id); Assert.IsTrue(result1.AllowedSections.Contains("test")); Assert.IsTrue(result2.AllowedSections.Contains("test")); Assert.IsTrue(result3.AllowedSections.Contains("test")); @@ -864,46 +875,40 @@ namespace Umbraco.Tests.Services [Test] public void Cannot_Create_User_With_Empty_Username() { - // Arrange - var userService = ServiceContext.UserService; - // Act & Assert - Assert.Throws(() => userService.CreateUserWithIdentity(string.Empty, "john@umbraco.io")); + Assert.Throws(() => UserService.CreateUserWithIdentity(string.Empty, "john@umbraco.io")); } [Test] public void Cannot_Save_User_With_Empty_Username() { // Arrange - var userService = ServiceContext.UserService; - var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); user.Username = string.Empty; // Act & Assert - Assert.Throws(() => userService.Save(user)); + Assert.Throws(() => UserService.Save(user)); } [Test] public void Cannot_Save_User_With_Empty_Name() { // Arrange - var userService = ServiceContext.UserService; - var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); + var user = UserService.CreateUserWithIdentity("John Doe", "john@umbraco.io"); user.Name = string.Empty; // Act & Assert - Assert.Throws(() => userService.Save(user)); + Assert.Throws(() => UserService.Save(user)); } [Test] public void Get_By_Profile_Username() { // Arrange - var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); + var user = UserService.CreateUserWithIdentity("test1", "test1@test.com"); // Act - - var profile = ServiceContext.UserService.GetProfileByUserName(user.Username); + var profile = UserService.GetProfileByUserName(user.Username); // Assert Assert.IsNotNull(profile); @@ -915,11 +920,10 @@ namespace Umbraco.Tests.Services public void Get_By_Profile_Id() { // Arrange - var user = (IUser)ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); + var user = UserService.CreateUserWithIdentity("test1", "test1@test.com"); // Act - - var profile = ServiceContext.UserService.GetProfileById((int)user.Id); + var profile = UserService.GetProfileById((int)user.Id); // Assert Assert.IsNotNull(profile); @@ -928,18 +932,18 @@ namespace Umbraco.Tests.Services } [Test] - public void Get_By_Profile_Id_Must_return_null_if_user_not_exists() + public void Get_By_Profile_Id_Must_Return_Null_If_User_Does_Not_Exist() { - var profile = ServiceContext.UserService.GetProfileById(42); + var profile = UserService.GetProfileById(42); // Assert Assert.IsNull(profile); } [Test] - public void GetProfilesById_Must_empty_if_users_not_exists() + public void GetProfilesById_Must_Return_Empty_If_User_Does_Not_Exist() { - var profiles = ServiceContext.UserService.GetProfilesById(42); + var profiles = UserService.GetProfilesById(42); // Assert CollectionAssert.IsEmpty(profiles); @@ -949,12 +953,11 @@ namespace Umbraco.Tests.Services public void Get_User_By_Username() { // Arrange - IUserGroup userGroup; - var originalUser = CreateTestUser(out userGroup); + var originalUser = CreateTestUser(out _); // Act - var updatedItem = (User) ServiceContext.UserService.GetByUsername(originalUser.Username); + var updatedItem = (User)UserService.GetByUsername(originalUser.Username); // Assert Assert.IsNotNull(updatedItem); @@ -982,7 +985,7 @@ namespace Umbraco.Tests.Services CreateTestUsers(startContentItems.Select(x => x.Id).ToArray(), testUserGroup, 3); - var usersInGroup = ServiceContext.UserService.GetAllInGroup(userGroupId); + var usersInGroup = UserService.GetAllInGroup(userGroupId); foreach (var user in usersInGroup) Assert.AreEqual(user.StartContentIds.Length, startContentItems.Length); @@ -990,16 +993,17 @@ namespace Umbraco.Tests.Services private Content[] BuildContentItems(int numberToCreate) { - var contentType = MockedContentTypes.CreateSimpleContentType(); - - ServiceContext.ContentTypeService.Save(contentType); + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + var contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); + ContentTypeService.Save(contentType); var startContentItems = new List(); for (var i = 0; i < numberToCreate; i++) - startContentItems.Add(MockedContent.CreateSimpleContent(contentType)); + startContentItems.Add(ContentBuilder.CreateSimpleContent(contentType)); - ServiceContext.ContentService.Save(startContentItems); + ContentService.Save(startContentItems); return startContentItems.ToArray(); } @@ -1008,11 +1012,11 @@ namespace Umbraco.Tests.Services { userGroup = CreateTestUserGroup(); - var user = ServiceContext.UserService.CreateUserWithIdentity("test1", "test1@test.com"); + var user = UserService.CreateUserWithIdentity("test1", "test1@test.com"); user.AddGroup(userGroup.ToReadOnlyGroup()); - ServiceContext.UserService.Save(user); + UserService.Save(user); return user; } @@ -1023,13 +1027,13 @@ namespace Umbraco.Tests.Services for (var i = 0; i < numberToCreate; i++) { - var user = ServiceContext.UserService.CreateUserWithIdentity($"test{i}", $"test{i}@test.com"); + var user = UserService.CreateUserWithIdentity($"test{i}", $"test{i}@test.com"); user.AddGroup(userGroup.ToReadOnlyGroup()); var updateable = (User)user; updateable.StartContentIds = startContentIds; - ServiceContext.UserService.Save(user); + UserService.Save(user); users.Add(user); } @@ -1039,17 +1043,10 @@ namespace Umbraco.Tests.Services private UserGroup CreateTestUserGroup(string alias = "testGroup", string name = "Test Group") { - var userGroup = new UserGroup(ShortStringHelper) - { - Alias = alias, - Name = name, - Permissions = "ABCDEFGHIJ1234567".ToCharArray().Select(x => x.ToString()) - }; + var permissions = "ABCDEFGHIJ1234567".ToCharArray().Select(x => x.ToString()).ToArray(); + var userGroup = UserGroupBuilder.CreateUserGroup(alias, name, permissions: permissions); - userGroup.AddAllowedSection("content"); - userGroup.AddAllowedSection("media"); - - ServiceContext.UserService.Save(userGroup); + UserService.Save(userGroup); return userGroup; } diff --git a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs index a9a272ac59..731079da7c 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/Controllers/ContentControllerTests.cs @@ -5,20 +5,17 @@ using System.Threading.Tasks; using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -using Umbraco.Tests.Testing; +using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Formatters; -using Umbraco.Web.Editors; 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..f7e451b03f --- /dev/null +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoBuilderExtensions.cs @@ -0,0 +1,58 @@ +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(), + builder.Config, + // TODO: Yep that's extremely ugly + (globalSettings, connectionStrings, umbVersion, ioHelper, loggerFactory, profiler, hostingEnv, backOfficeInfo, typeFinder, appCaches, dbProviderFactoryCreator) => + { + var runtime = UmbracoIntegrationTest.CreateTestRuntime( + globalSettings, + connectionStrings, + umbVersion, + ioHelper, + loggerFactory, + 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..2aacd7b8fb 100644 --- a/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs +++ b/src/Umbraco.Tests.Integration/TestServerTest/UmbracoTestServerTestBase.cs @@ -2,20 +2,27 @@ 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; +using Umbraco.Web.BackOffice.Controllers; namespace Umbraco.Tests.Integration.TestServerTest { @@ -24,19 +31,53 @@ namespace Umbraco.Tests.Integration.TestServerTest public abstract class UmbracoTestServerTestBase : UmbracoIntegrationTest { [SetUp] - public void SetUp() + public override void 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(); } - /// - /// 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 +89,7 @@ namespace Umbraco.Tests.Integration.TestServerTest { var url = LinkGenerator.GetUmbracoApiService(methodSelector); + var backofficeSecurityFactory = GetRequiredService(); var umbracoContextFactory = GetRequiredService(); var httpContextAccessor = GetRequiredService(); @@ -62,18 +104,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 +125,37 @@ 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() + .WithPreview() + //.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..6e83e57c2c 100644 --- a/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs +++ b/src/Umbraco.Tests.Integration/Testing/IntegrationTestComposer.cs @@ -1,7 +1,29 @@ using Moq; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Extensions.Logging; +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.Sync; using Umbraco.Core.WebAssets; +using Umbraco.Examine; +using Umbraco.Tests.TestHelpers.Stubs; +using Umbraco.Web.Compose; +using Umbraco.Web.PublishedCache.NuCache; +using Umbraco.Web.Scheduling; +using Umbraco.Web.Search; namespace Umbraco.Tests.Integration.Testing { @@ -13,11 +35,125 @@ 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); + + composition.RegisterUnique(); + composition.RegisterUnique(); + + } + + /// + /// 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 loggerFactory = 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( + loggerFactory.CreateLogger(), + appCaches, + mainLangFolder); + + }), + loggerFactory.CreateLogger()); + + return localizedTextService; + } + + // replace the default so there is no background index rebuilder + private class TestBackgroundIndexRebuilder : BackgroundIndexRebuilder + { + public TestBackgroundIndexRebuilder(IMainDom mainDom, IProfilingLogger profilingLogger , ILoggerFactory loggerFactory, IApplicationShutdownRegistry hostingEnvironment, IndexRebuilder indexRebuilder) + : base(mainDom, profilingLogger , loggerFactory, hostingEnvironment, indexRebuilder) + { + } + + public override void RebuildIndexes(bool onlyEmptyIndexes, int waitMilliseconds = 0) + { + // noop + } + } + + private class NoopServerMessenger : IServerMessenger + { + public NoopServerMessenger() + { } + + public void PerformRefresh(ICacheRefresher refresher, TPayload[] payload) + { + + } + + public void PerformRefresh(ICacheRefresher refresher, Func getNumericId, params T[] instances) + { + + } + + public void PerformRefresh(ICacheRefresher refresher, Func getGuidId, params T[] instances) + { + + } + + public void PerformRemove(ICacheRefresher refresher, Func getNumericId, params T[] instances) + { + + } + + public void PerformRemove(ICacheRefresher refresher, params int[] numericIds) + { + + } + + public void PerformRefresh(ICacheRefresher refresher, params int[] numericIds) + { + + } + + public void PerformRefresh(ICacheRefresher refresher, params Guid[] guidIds) + { + + } + + public void PerformRefreshAll(ICacheRefresher refresher) + { + + } + } + } } diff --git a/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs b/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs index 9988362d3b..39f9ca5592 100644 --- a/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs +++ b/src/Umbraco.Tests.Integration/Testing/LocalDbTestDatabase.cs @@ -8,9 +8,10 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Persistence; @@ -24,8 +25,7 @@ namespace Umbraco.Tests.Integration.Testing public const string InstanceName = "UmbracoTests"; public const string DatabaseName = "UmbracoTests"; - private readonly ILogger _logger; - private readonly IGlobalSettings _globalSettings; + private readonly ILoggerFactory _loggerFactory; 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(ILoggerFactory loggerFactory, LocalDb localDb, string filesPath, IUmbracoDatabaseFactory dbFactory) { _umbracoVersion = new UmbracoVersion(); - _logger = logger; - _globalSettings = globalSettings; + _loggerFactory = loggerFactory; _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, _loggerFactory.CreateLogger(), _loggerFactory, _umbracoVersion); creator.InitializeDatabaseSchema(); trans.Complete(); // commit it @@ -237,10 +236,10 @@ namespace Umbraco.Tests.Integration.Testing action(); return; } - catch (SqlException e) + catch (SqlException) { - Console.Error.WriteLine($"SqlException occured, but we try again {i+1}/{maxIterations}.\n{e}"); + //Console.Error.WriteLine($"SqlException occured, but we try again {i+1}/{maxIterations}.\n{e}"); // This can occur when there's a transaction deadlock which means (i think) that the database is still in use and hasn't been closed properly yet // so we need to just wait a little bit Thread.Sleep(100 * i); @@ -250,6 +249,10 @@ namespace Umbraco.Tests.Integration.Testing throw; } } + catch (InvalidOperationException) + { + + } } } diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 89cbfa992d..795fc07f79 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; @@ -21,10 +20,26 @@ using Umbraco.Tests.Integration.Implementations; 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 Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Serilog; +using Umbraco.Core.Logging.Serilog; +using ConnectionStrings = Umbraco.Core.Configuration.Models.ConnectionStrings; +using ILogger = Microsoft.Extensions.Logging.ILogger; namespace Umbraco.Tests.Integration.Testing { + /// /// Abstract class for integration tests /// @@ -35,7 +50,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,18 +58,269 @@ 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; + FirstTestInFixture = false; + FirstTestInSession = false; + } + + [SetUp] + public virtual void Setup() + { + var hostBuilder = CreateHostBuilder(); + var host = hostBuilder.StartAsync().GetAwaiter().GetResult(); + Services = host.Services; + var app = new ApplicationBuilder(host.Services); + Configure(app); + + OnFixtureTearDown(() => host.Dispose()); + } + + #region Generic Host Builder and Runtime + + private ILoggerFactory CreateLoggerFactory() + { + ILoggerFactory factory; + var testOptions = TestOptionAttributeBase.GetTestOptions(); + switch (testOptions.Logger) + { + case UmbracoTestOptions.Logger.Mock: + factory = NullLoggerFactory.Instance; + break; + case UmbracoTestOptions.Logger.Serilog: + factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(); }); + break; + case UmbracoTestOptions.Logger.Console: + factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); }); + break; + default: + throw new NotSupportedException($"Logger option {testOptions.Logger} is not supported."); + } + + return factory; + } + /// + /// 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) => + { + services.AddTransient(_ => CreateLoggerFactory()); + 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, + ILoggerFactory loggerFactory, IProfiler profiler, Core.Hosting.IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo, + ITypeFinder typeFinder, AppCaches appCaches, IDbProviderFactoryCreator dbProviderFactoryCreator) + { + var runtime = CreateTestRuntime( + globalSettings, + connectionStrings, + umbracoVersion, + ioHelper, + loggerFactory, + 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, + ILoggerFactory loggerFactory, 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, + loggerFactory, + 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(), + Configuration, + CreateTestRuntime, + out _); + + services.AddSignalR(); + + services.AddUmbracoWebComponents(); + services.AddUmbracoRuntimeMinifier(Configuration); + services.AddUmbracoBackOffice(); + services.AddUmbracoBackOfficeIdentity(); + + services.AddMvc(); + + CustomTestSetup(services); + } + + public virtual void Configure(IApplicationBuilder app) + { + Services.GetRequiredService().EnsureBackofficeSecurity(); + Services.GetRequiredService().EnsureUmbracoContext(); + + // get the currently set options + 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.RuntimeLoggerFactory, runtime.State, TestHelper.WorkingDirectory, out var connectionString); + TestDBConnectionString = connectionString; + InMemoryConfiguration["ConnectionStrings:" + Constants.System.UmbracoConnectionName] = TestDBConnectionString; + } + /// /// Get or create an instance of /// /// /// + /// /// /// /// /// /// 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, ILoggerFactory loggerFactory, IUmbracoDatabaseFactory dbFactory) { lock (_dbLocker) { @@ -63,91 +329,125 @@ 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(loggerFactory, 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, ILoggerFactory loggerFactory, + 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, loggerFactory, 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: + // Only attach schema once per fixture + // Doing it more than once will block the process since the old db hasn't been detached + // and it would be the same as NewSchemaPerTest even if it didn't block + if (FirstTestInFixture) + { + // New DB + Schema + var newSchemaFixtureDbId = db.AttachSchema(); + + // Add teardown callback + OnFixtureTearDown(() => db.Detach(newSchemaFixtureDbId)); + } + + // 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(); + + 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 +455,7 @@ namespace Umbraco.Tests.Integration.Testing /// /// Returns the DI container /// - protected IServiceProvider Services { get; private set; } + protected IServiceProvider Services { get; set; } /// /// Returns the @@ -168,24 +468,27 @@ namespace Umbraco.Tests.Integration.Testing protected IScopeAccessor ScopeAccessor => Services.GetRequiredService(); /// - /// Returns the + /// Returns the /// - protected ILogger Logger => Services.GetRequiredService(); + protected ILoggerFactory LoggerFactory => Services.GetRequiredService(); 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 #region Builders - protected GlobalSettingsBuilder GlobalSettingsBuilder = new GlobalSettingsBuilder(); - protected UserBuilder UserBuilder = new UserBuilder(); - protected UserGroupBuilder UserGroupBuilder = new UserGroupBuilder(); + protected UserBuilder UserBuilderInstance = new UserBuilder(); + protected UserGroupBuilder UserGroupBuilderInstance = new UserGroupBuilder(); #endregion + + protected static bool FirstTestInSession = true; + + protected bool FirstTestInFixture = true; } } diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTestWithContent.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTestWithContent.cs new file mode 100644 index 0000000000..6e39c858d5 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTestWithContent.cs @@ -0,0 +1,63 @@ +using System; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; +using Umbraco.Tests.Common.Builders; + +namespace Umbraco.Tests.Integration.Testing +{ + public abstract class UmbracoIntegrationTestWithContent : UmbracoIntegrationTest + { + protected IContentTypeService ContentTypeService => GetRequiredService(); + protected IFileService FileService => GetRequiredService(); + protected ContentService ContentService => (ContentService)GetRequiredService(); + + public override void Setup() + { + base.Setup(); + CreateTestData(); + } + + public virtual void CreateTestData() + { + //NOTE Maybe not the best way to create/save test data as we are using the services, which are being tested. + + var template = TemplateBuilder.CreateTextPageTemplate(); + FileService.SaveTemplate(template); + + // Create and Save ContentType "umbTextpage" -> 1051 (template), 1052 (content type) + ContentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id); + ContentType.Key = new Guid("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"); + ContentTypeService.Save(ContentType); + + // Create and Save Content "Homepage" based on "umbTextpage" -> 1053 + Textpage = ContentBuilder.CreateSimpleContent(ContentType); + Textpage.Key = new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0"); + ContentService.Save(Textpage, 0); + + // Create and Save Content "Text Page 1" based on "umbTextpage" -> 1054 + Subpage = ContentBuilder.CreateSimpleContent(ContentType, "Text Page 1", Textpage.Id); + Subpage.ContentSchedule.Add(DateTime.Now.AddMinutes(-5), null); + ContentService.Save(Subpage, 0); + + // Create and Save Content "Text Page 1" based on "umbTextpage" -> 1055 + Subpage2 = ContentBuilder.CreateSimpleContent(ContentType, "Text Page 2", Textpage.Id); + ContentService.Save(Subpage2, 0); + + // Create and Save Content "Text Page Deleted" based on "umbTextpage" -> 1056 + Trashed = ContentBuilder.CreateSimpleContent(ContentType, "Text Page Deleted", -20); + Trashed.Trashed = true; + ContentService.Save(Trashed, 0); + } + + protected Content Trashed { get; private set; } + + protected Content Subpage2 { get; private set; } + + protected Content Subpage { get; private set; } + + protected Content Textpage { get; private set; } + + protected ContentType ContentType { get; private set; } + } +} 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..84e0eebd18 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -11,20 +11,34 @@ + + + - + + + + + + + + + + - + + + - - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + @@ -49,4 +63,24 @@ + + + + + + + ImportResources.resx + True + True + + + + + + Designer + ImportResources.Designer.cs + ResXFileCodeGenerator + + + 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..83760bd177 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice.Security/BackOfficeCookieManagerTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice.Security/BackOfficeCookieManagerTests.cs @@ -1,12 +1,11 @@ - - +using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Moq; using NUnit.Framework; -using System; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Extensions; using Umbraco.Tests.Integration.Implementations; @@ -25,7 +24,7 @@ namespace Umbraco.Tests.Security var testHelper = new TestHelper(); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettings(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Install); var mgr = new BackOfficeCookieManager( @@ -50,8 +49,8 @@ namespace Umbraco.Tests.Security //hostingEnvironment.ToAbsolute(globalSettings.UmbracoPath); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); - + var globalSettings = new GlobalSettings(); + var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); var mgr = new BackOfficeCookieManager( Mock.Of(), @@ -72,7 +71,7 @@ namespace Umbraco.Tests.Security var testHelper = new TestHelper(); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettings(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); @@ -97,7 +96,7 @@ namespace Umbraco.Tests.Security var testHelper = new TestHelper(); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettings(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); @@ -119,7 +118,7 @@ namespace Umbraco.Tests.Security var testHelper = new TestHelper(); var httpContextAccessor = testHelper.GetHttpContextAccessor(); - var globalSettings = testHelper.SettingsForTests.GenerateMockGlobalSettings(); + var globalSettings = new GlobalSettings(); 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..75713c808b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs @@ -1,159 +1,158 @@ - using NUnit.Framework; - using System; - using System.Collections.Generic; - using System.Linq; - using Umbraco.Core.Services; - using Umbraco.Core.Logging; - using Umbraco.Web.Models.ContentEditing; - using Umbraco.Tests.Testing; - using Umbraco.Core.PropertyEditors; - using Umbraco.Core.Composing; - using Umbraco.Web.PropertyEditors; - using System.ComponentModel.DataAnnotations; - using Microsoft.AspNetCore.Mvc.ModelBinding; - using Microsoft.Extensions.DependencyInjection; - using Newtonsoft.Json; - using Newtonsoft.Json.Linq; - using Umbraco.Core; - using Umbraco.Core.IO; - using Umbraco.Core.Mapping; - using Umbraco.Core.Models; - using Umbraco.Core.Strings; - using Umbraco.Tests.Integration.Testing; - using Umbraco.Tests.TestHelpers.Entities; - using Umbraco.Web.BackOffice.Filters; - using Umbraco.Web.BackOffice.ModelBinders; - using Umbraco.Web.Security; - using DataType = Umbraco.Core.Models.DataType; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.IO; +using Umbraco.Core.Mapping; +using Umbraco.Core.Models; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; +using Umbraco.Tests.Testing; +using Umbraco.Web.BackOffice.Filters; +using Umbraco.Web.BackOffice.ModelBinders; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.PropertyEditors; +using DataType = Umbraco.Core.Models.DataType; - namespace Umbraco.Tests.Web.Validation - { - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Mapper = true, WithApplication = true, Logger = UmbracoTestOptions.Logger.Console)] - public class ContentModelValidatorTests : UmbracoIntegrationTest - { - private const string ContentTypeAlias = "textPage"; - private IContentType _contentType; - private ContentModelBinderHelper _modelBinderHelper = new ContentModelBinderHelper(); - private IShortStringHelper _shortStringHelper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); +namespace Umbraco.Tests.Web.Validation +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Mapper = true, WithApplication = true, Logger = UmbracoTestOptions.Logger.Console)] + public class ContentModelValidatorTests : UmbracoIntegrationTest + { + private const string ContentTypeAlias = "textPage"; + private IContentType _contentType; + private ContentModelBinderHelper _modelBinderHelper = new ContentModelBinderHelper(); + private IShortStringHelper _shortStringHelper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); - [SetUp] - public void SetUp() - { - var complexEditorConfig = new NestedContentConfiguration - { - ContentTypes = new[] - { + [SetUp] + public void SetUp() + { + var complexEditorConfig = new NestedContentConfiguration + { + ContentTypes = new[] + { new NestedContentConfiguration.ContentType { Alias = "feature" } } - }; + }; - var complexTestEditor = Services.GetRequiredService(); - var testEditor = Services.GetRequiredService(); - var dataTypeService = Services.GetRequiredService(); + var complexTestEditor = Services.GetRequiredService(); + var testEditor = Services.GetRequiredService(); + var dataTypeService = Services.GetRequiredService(); - var complexDataType = new DataType(complexTestEditor) - { - Name = "ComplexTest", - Configuration = complexEditorConfig - }; + var complexDataType = new DataType(complexTestEditor) + { + Name = "ComplexTest", + Configuration = complexEditorConfig + }; - var testDataType = new DataType(testEditor) - { - Name = "Test", - }; - dataTypeService.Save(complexDataType); - dataTypeService.Save(testDataType); + var testDataType = new DataType(testEditor) + { + Name = "Test", + }; + dataTypeService.Save(complexDataType); + dataTypeService.Save(testDataType); + var fileService = Services.GetRequiredService(); + var template = TemplateBuilder.CreateTextPageTemplate(); + fileService.SaveTemplate(template); + _contentType = ContentTypeBuilder.CreateTextPageContentType(ContentTypeAlias, defaultTemplateId: template.Id); - _contentType = MockedContentTypes.CreateTextPageContentType(ContentTypeAlias); - // add complex editor + // add complex editor + foreach (var pt in _contentType.PropertyTypes) + { + pt.DataTypeId = testDataType.Id; + } - foreach (var pt in _contentType.PropertyTypes) - { - pt.DataTypeId = testDataType.Id; - } + _contentType.AddPropertyType( + new PropertyType(_shortStringHelper, "complexTest", ValueStorageType.Ntext) { Alias = "complex", Name = "Complex", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = complexDataType.Id }, + "Content"); - _contentType.AddPropertyType( - new PropertyType(_shortStringHelper, "complexTest", ValueStorageType.Ntext) { Alias = "complex", Name = "Complex", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = complexDataType.Id }, - "Content"); + // make them all validate with a regex rule that will not pass + foreach (var prop in _contentType.PropertyTypes) + { + prop.ValidationRegExp = "^donotmatch$"; + prop.ValidationRegExpMessage = "Does not match!"; + } - // make them all validate with a regex rule that will not pass - foreach (var prop in _contentType.PropertyTypes) - { - prop.ValidationRegExp = "^donotmatch$"; - prop.ValidationRegExpMessage = "Does not match!"; - } + var contentTypeService = Services.GetRequiredService(); + contentTypeService.Save(_contentType); + } - var contentTypeService = Services.GetRequiredService(); + // + // protected override void Compose() + // { + // base.Compose(); + // + // var complexEditorConfig = new NestedContentConfiguration + // { + // ContentTypes = new[] + // { + // new NestedContentConfiguration.ContentType { Alias = "feature" } + // } + // }; + // var dataTypeService = new Mock(); + // dataTypeService.Setup(x => x.GetDataType(It.IsAny())) + // .Returns((int id) => id == ComplexDataTypeId + // ? Mock.Of(x => x.Configuration == complexEditorConfig) + // : Mock.Of()); + // + // var contentTypeService = new Mock(); + // contentTypeService.Setup(x => x.GetAll(It.IsAny())) + // .Returns(() => new List + // { + // _contentType + // }); + // + // var textService = new Mock(); + // textService.Setup(x => x.Localize("validation/invalidPattern", It.IsAny(), It.IsAny>())).Returns(() => "invalidPattern"); + // textService.Setup(x => x.Localize("validation/invalidNull", It.IsAny(), It.IsAny>())).Returns("invalidNull"); + // textService.Setup(x => x.Localize("validation/invalidEmpty", It.IsAny(), It.IsAny>())).Returns("invalidEmpty"); + // + // Composition.RegisterUnique(x => Mock.Of(x => x.GetDataType(It.IsAny()) == Mock.Of())); + // Composition.RegisterUnique(x => dataTypeService.Object); + // Composition.RegisterUnique(x => contentTypeService.Object); + // Composition.RegisterUnique(x => textService.Object); + // + // Composition.WithCollectionBuilder() + // .Add() + // .Add(); + // } + [Test] + public void Validating_ContentItemSave() + { + var logger = 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, backofficeSecurityAccessor.BackofficeSecurity, localizedTextService, propertyValidationService); - contentTypeService.Save(_contentType); + var content = ContentBuilder.CreateTextpageContent(_contentType, "test", -1); - } + var id1 = new Guid("c8df5136-d606-41f0-9134-dea6ae0c2fd9"); + var id2 = new Guid("f916104a-4082-48b2-a515-5c4bf2230f38"); + var id3 = new Guid("77E15DE9-1C79-47B2-BC60-4913BC4D4C6A"); - // - // protected override void Compose() - // { - // base.Compose(); - // - // var complexEditorConfig = new NestedContentConfiguration - // { - // ContentTypes = new[] - // { - // new NestedContentConfiguration.ContentType { Alias = "feature" } - // } - // }; - // var dataTypeService = new Mock(); - // dataTypeService.Setup(x => x.GetDataType(It.IsAny())) - // .Returns((int id) => id == ComplexDataTypeId - // ? Mock.Of(x => x.Configuration == complexEditorConfig) - // : Mock.Of()); - // - // var contentTypeService = new Mock(); - // contentTypeService.Setup(x => x.GetAll(It.IsAny())) - // .Returns(() => new List - // { - // _contentType - // }); - // - // var textService = new Mock(); - // textService.Setup(x => x.Localize("validation/invalidPattern", It.IsAny(), It.IsAny>())).Returns(() => "invalidPattern"); - // textService.Setup(x => x.Localize("validation/invalidNull", It.IsAny(), It.IsAny>())).Returns("invalidNull"); - // textService.Setup(x => x.Localize("validation/invalidEmpty", It.IsAny(), It.IsAny>())).Returns("invalidEmpty"); - // - // Composition.RegisterUnique(x => Mock.Of(x => x.GetDataType(It.IsAny()) == Mock.Of())); - // Composition.RegisterUnique(x => dataTypeService.Object); - // Composition.RegisterUnique(x => contentTypeService.Object); - // Composition.RegisterUnique(x => textService.Object); - // - // Composition.WithCollectionBuilder() - // .Add() - // .Add(); - // } + // TODO: Ok now test with a 4th level complex nested editor - [Test] - public void Validating_ContentItemSave() - { - var logger = Services.GetRequiredService(); - var webSecurity = Services.GetRequiredService(); - var localizedTextService = Services.GetRequiredService(); - var propertyValidationService = Services.GetRequiredService(); - var umbracoMapper = Services.GetRequiredService(); - - var validator = new ContentSaveModelValidator(logger, webSecurity, localizedTextService, propertyValidationService); - - var content = MockedContent.CreateTextpageContent(_contentType, "test", -1); - - var id1 = new Guid("c8df5136-d606-41f0-9134-dea6ae0c2fd9"); - var id2 = new Guid("f916104a-4082-48b2-a515-5c4bf2230f38"); - var id3 = new Guid("77E15DE9-1C79-47B2-BC60-4913BC4D4C6A"); - - // TODO: Ok now test with a 4th level complex nested editor - - var complexValue = @"[{ + var complexValue = @"[{ ""key"": """ + id1.ToString() + @""", ""name"": ""Hello world"", ""ncContentTypeAlias"": """ + ContentTypeAlias + @""", @@ -174,21 +173,21 @@ }] } ]"; - content.SetValue("complex", complexValue); + content.SetValue("complex", complexValue); - // map the persisted properties to a model representing properties to save - //var saveProperties = content.Properties.Select(x => Mapper.Map(x)).ToList(); - var saveProperties = content.Properties.Select(x => - { - return new ContentPropertyBasic - { - Alias = x.Alias, - Id = x.Id, - Value = x.GetValue() - }; - }).ToList(); + // map the persisted properties to a model representing properties to save + //var saveProperties = content.Properties.Select(x => Mapper.Map(x)).ToList(); + var saveProperties = content.Properties.Select(x => + { + return new ContentPropertyBasic + { + Alias = x.Alias, + Id = x.Id, + Value = x.GetValue() + }; + }).ToList(); - var saveVariants = new List + var saveVariants = new List { new ContentVariantSave { @@ -200,132 +199,132 @@ } }; - var save = new ContentItemSave - { - Id = content.Id, - Action = ContentSaveAction.Save, - ContentTypeAlias = _contentType.Alias, - ParentId = -1, - PersistedContent = content, - TemplateAlias = null, - Variants = saveVariants - }; + var save = new ContentItemSave + { + Id = content.Id, + Action = ContentSaveAction.Save, + ContentTypeAlias = _contentType.Alias, + ParentId = -1, + PersistedContent = content, + TemplateAlias = null, + Variants = saveVariants + }; - // This will map the ContentItemSave.Variants.PropertyCollectionDto and then map the values in the saved model - // back onto the persisted IContent model. - ContentItemBinder.BindModel(save, content, _modelBinderHelper, umbracoMapper); + // This will map the ContentItemSave.Variants.PropertyCollectionDto and then map the values in the saved model + // back onto the persisted IContent model. + ContentItemBinder.BindModel(save, content, _modelBinderHelper, umbracoMapper); - var modelState = new ModelStateDictionary(); - var isValid = validator.ValidatePropertiesData(save, saveVariants[0], saveVariants[0].PropertyCollectionDto, modelState); + var modelState = new ModelStateDictionary(); + var isValid = validator.ValidatePropertiesData(save, saveVariants[0], saveVariants[0].PropertyCollectionDto, modelState); - // list results for debugging - foreach (var state in modelState) - { - Console.WriteLine(state.Key); - foreach (var error in state.Value.Errors) - { - Console.WriteLine("\t" + error.ErrorMessage); - } - } + // list results for debugging + foreach (var state in modelState) + { + Console.WriteLine(state.Key); + foreach (var error in state.Value.Errors) + { + Console.WriteLine("\t" + error.ErrorMessage); + } + } - // assert - Assert.IsFalse(isValid); - Assert.AreEqual(11, modelState.Keys.Count()); - const string complexPropertyKey = "_Properties.complex.invariant.null"; - Assert.IsTrue(modelState.Keys.Contains(complexPropertyKey)); - foreach (var state in modelState.Where(x => x.Key != complexPropertyKey)) - { - foreach (var error in state.Value.Errors) - { - Assert.IsFalse(error.ErrorMessage.DetectIsJson()); // non complex is just an error message - } - } - var complexEditorErrors = modelState.Single(x => x.Key == complexPropertyKey).Value.Errors; - Assert.AreEqual(1, complexEditorErrors.Count); - var nestedError = complexEditorErrors[0]; - var jsonError = JsonConvert.DeserializeObject(nestedError.ErrorMessage); + // assert + Assert.IsFalse(isValid); + Assert.AreEqual(11, modelState.Keys.Count()); + const string complexPropertyKey = "_Properties.complex.invariant.null"; + Assert.IsTrue(modelState.Keys.Contains(complexPropertyKey)); + foreach (var state in modelState.Where(x => x.Key != complexPropertyKey)) + { + foreach (var error in state.Value.Errors) + { + Assert.IsFalse(error.ErrorMessage.DetectIsJson()); // non complex is just an error message + } + } + var complexEditorErrors = modelState.Single(x => x.Key == complexPropertyKey).Value.Errors; + Assert.AreEqual(1, complexEditorErrors.Count); + var nestedError = complexEditorErrors[0]; + var jsonError = JsonConvert.DeserializeObject(nestedError.ErrorMessage); - var modelStateKeys = new[] { "_Properties.title.invariant.null.innerFieldId", "_Properties.title.invariant.null.value", "_Properties.bodyText.invariant.null.innerFieldId", "_Properties.bodyText.invariant.null.value" }; - AssertNestedValidation(jsonError, 0, id1, modelStateKeys); - AssertNestedValidation(jsonError, 1, id2, modelStateKeys.Concat(new[] { "_Properties.complex.invariant.null.innerFieldId", "_Properties.complex.invariant.null.value" }).ToArray()); - var nestedJsonError = jsonError.SelectToken("$[1].complex") as JArray; - Assert.IsNotNull(nestedJsonError); - AssertNestedValidation(nestedJsonError, 0, id3, modelStateKeys); + var modelStateKeys = new[] { "_Properties.title.invariant.null.innerFieldId", "_Properties.title.invariant.null.value", "_Properties.bodyText.invariant.null.innerFieldId", "_Properties.bodyText.invariant.null.value" }; + AssertNestedValidation(jsonError, 0, id1, modelStateKeys); + AssertNestedValidation(jsonError, 1, id2, modelStateKeys.Concat(new[] { "_Properties.complex.invariant.null.innerFieldId", "_Properties.complex.invariant.null.value" }).ToArray()); + var nestedJsonError = jsonError.SelectToken("$[1].complex") as JArray; + Assert.IsNotNull(nestedJsonError); + AssertNestedValidation(nestedJsonError, 0, id3, modelStateKeys); - } + } - private void AssertNestedValidation(JArray jsonError, int index, Guid id, string[] modelStateKeys) - { - Assert.IsNotNull(jsonError.SelectToken("$[" + index + "]")); - Assert.AreEqual(id.ToString(), jsonError.SelectToken("$[" + index + "].$id").Value()); - Assert.AreEqual("textPage", jsonError.SelectToken("$[" + index + "].$elementTypeAlias").Value()); - Assert.IsNotNull(jsonError.SelectToken("$[" + index + "].ModelState")); - foreach (var key in modelStateKeys) - { - var error = jsonError.SelectToken("$[" + index + "].ModelState['" + key + "']") as JArray; - Assert.IsNotNull(error); - Assert.AreEqual(1, error.Count); - } - } + private void AssertNestedValidation(JArray jsonError, int index, Guid id, string[] modelStateKeys) + { + Assert.IsNotNull(jsonError.SelectToken("$[" + index + "]")); + Assert.AreEqual(id.ToString(), jsonError.SelectToken("$[" + index + "].$id").Value()); + Assert.AreEqual("textPage", jsonError.SelectToken("$[" + index + "].$elementTypeAlias").Value()); + Assert.IsNotNull(jsonError.SelectToken("$[" + index + "].ModelState")); + foreach (var key in modelStateKeys) + { + var error = jsonError.SelectToken("$[" + index + "].ModelState['" + key + "']") as JArray; + Assert.IsNotNull(error); + Assert.AreEqual(1, error.Count); + } + } - //[HideFromTypeFinder] - [DataEditor("complexTest", "test", "test")] - public class ComplexTestEditor : NestedContentPropertyEditor - { - public ComplexTestEditor(ILogger logger, Lazy propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, ILocalizationService localizationService, - IIOHelper ioHelper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) - : base(logger, propertyEditors, dataTypeService, localizationService, contentTypeService, ioHelper, shortStringHelper, localizedTextService) - { - } + //[HideFromTypeFinder] + [DataEditor("complexTest", "test", "test")] + public class ComplexTestEditor : NestedContentPropertyEditor + { + public ComplexTestEditor(ILoggerFactory loggerFactory, Lazy propertyEditors, IDataTypeService dataTypeService, IContentTypeService contentTypeService, ILocalizationService localizationService, + IIOHelper ioHelper, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper) + : base(loggerFactory, propertyEditors, dataTypeService, localizationService, contentTypeService, ioHelper, shortStringHelper, localizedTextService) + { + } - protected override IDataValueEditor CreateValueEditor() - { - var editor = base.CreateValueEditor(); - editor.Validators.Add(new NeverValidateValidator()); - return editor; - } - } + protected override IDataValueEditor CreateValueEditor() + { + var editor = base.CreateValueEditor(); + editor.Validators.Add(new NeverValidateValidator()); + return editor; + } + } //[HideFromTypeFinder] [DataEditor("test", "test", "test")] // This alias aligns with the prop editor alias for all properties created from MockedContentTypes.CreateTextPageContentType public class TestEditor : DataEditor { - public TestEditor(ILogger logger, - IDataTypeService dataTypeService, - ILocalizationService localizationService, - ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper) - : base(logger, dataTypeService, localizationService, localizedTextService, shortStringHelper) - { + public TestEditor(ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper) + : base(loggerFactory, dataTypeService, localizationService, localizedTextService, shortStringHelper) + { - } + } - protected override IDataValueEditor CreateValueEditor() => new TestValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute); + protected override IDataValueEditor CreateValueEditor() => new TestValueEditor(DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, Attribute); - private class TestValueEditor : DataValueEditor - { - public TestValueEditor( - IDataTypeService dataTypeService, - ILocalizationService localizationService, - ILocalizedTextService localizedTextService, - IShortStringHelper shortStringHelper, - DataEditorAttribute attribute) - : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) - { - Validators.Add(new NeverValidateValidator()); - } + private class TestValueEditor : DataValueEditor + { + public TestValueEditor( + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + DataEditorAttribute attribute) + : base(dataTypeService, localizationService, localizedTextService, shortStringHelper, attribute) + { + Validators.Add(new NeverValidateValidator()); + } - } - } + } + } - public class NeverValidateValidator : IValueValidator - { - public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration) - { - yield return new ValidationResult("WRONG!", new[] { "innerFieldId" }); - } - } + public class NeverValidateValidator : IValueValidator + { + public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration) + { + yield return new ValidationResult("WRONG!", new[] { "innerFieldId" }); + } + } - } - } + } +} 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..29e35139b9 100644 --- a/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs +++ b/src/Umbraco.Tests.UnitTests/AutoFixture/AutoMoqDataAttribute.cs @@ -1,18 +1,40 @@ 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.Core.Hosting; +using Umbraco.Tests.Common.Builders; using Umbraco.Web.BackOffice.Controllers; -using Umbraco.Core; +using Umbraco.Web.BackOffice.Routing; using Umbraco.Web.Common.Install; +using Umbraco.Web.WebApi; namespace Umbraco.Tests.UnitTests.AutoFixture { + + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple = true)] + public class InlineAutoMoqDataAttribute : InlineAutoDataAttribute + { + /// + /// Uses AutoFixture to automatically mock (using Moq) the injected types. E.g when injecting interfaces. + /// AutoFixture is used to generate concrete types. If the concrete type required some types injected, the + /// [Frozen] can be used to ensure the same variable is injected and available as parameter for the test + /// + public InlineAutoMoqDataAttribute(params object[] arguments) : base(() => AutoMoqDataAttribute.AutoMockCustomizations.Default, arguments) + { + } + } + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor)] public class AutoMoqDataAttribute : AutoDataAttribute { @@ -25,7 +47,7 @@ namespace Umbraco.Tests.UnitTests.AutoFixture { } - private static class AutoMockCustomizations + internal static class AutoMockCustomizations { public static IFixture Default => new Fixture().Customize(new UmbracoCustomization()); @@ -35,15 +57,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 GlobalSettings(),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 +77,22 @@ 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 )); + fixture.Customize(u => u.FromFactory( + () => new BackOfficeAreaRoutes( + Options.Create(new GlobalSettings()), + Mock.Of(x => x.ToAbsolute(It.IsAny()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty), + Mock.Of(x => x.Level == RuntimeLevel.Run), + new UmbracoApiControllerTypeCollection(Array.Empty())))); + + fixture.Customize(u => u.FromFactory( + () => new PreviewRoutes( + Options.Create(new GlobalSettings()), + Mock.Of(x => x.ToAbsolute(It.IsAny()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty), + Mock.Of(x => x.Level == RuntimeLevel.Run)))); + + var connectionStrings = new ConnectionStrings(); + fixture.Customize(x => x.FromFactory(() => connectionStrings )); + diff --git a/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs similarity index 57% rename from src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs rename to src/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs index cb20c56d6d..8960eb5319 100644 --- a/src/Umbraco.Tests/Testing/Objects/TestUmbracoContextFactory.cs +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs @@ -1,30 +1,33 @@ -using Moq; -using NUnit.Framework.Internal; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Moq; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Tests.Common; -using Umbraco.Tests.TestHelpers; using Umbraco.Web; +using Umbraco.Web.Common.AspNetCore; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; +using Umbraco.Web.Security; -namespace Umbraco.Tests.Testing.Objects +namespace Umbraco.Tests.UnitTests.TestHelpers.Objects { /// /// Simplify creating test UmbracoContext's /// 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(); + if (httpContextAccessor == null) httpContextAccessor = Mock.Of(); + if (publishedUrlProvider == null) publishedUrlProvider = Mock.Of(); var contentCache = new Mock(); var mediaCache = new Mock(); @@ -34,19 +37,25 @@ namespace Umbraco.Tests.Testing.Objects var snapshotService = new Mock(); snapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(snapshot.Object); - - + var hostingEnvironment = Mock.Of(); + var backofficeSecurityAccessorMock = new Mock(); + backofficeSecurityAccessorMock.Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); + + var umbracoContextFactory = new UmbracoContextFactory( umbracoContextAccessor, snapshotService.Object, new TestVariationContextAccessor(), new TestDefaultCultureAccessor(), - globalSettings, + Options.Create(globalSettings), Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, + hostingEnvironment, + new UriUtility(hostingEnvironment), httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); + new AspNetCoreCookieManager(httpContextAccessor), + Mock.Of(), + backofficeSecurityAccessorMock.Object + ); return umbracoContextFactory; } diff --git a/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs new file mode 100644 index 0000000000..9c619e05de --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/TestHelpers/TestHelper.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using Microsoft.AspNetCore.Hosting; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.Diagnostics; +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Net; +using Umbraco.Core.Persistence; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common; +using Umbraco.Web; +using Umbraco.Web.Routing; +using File = System.IO.File; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; +using Umbraco.Web.Common.AspNetCore; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; + +namespace Umbraco.Tests.TestHelpers +{ + /// + /// Common helper properties and methods useful to testing + /// + public static class TestHelper + { + private static readonly TestHelperInternal _testHelperInternal = new TestHelperInternal(); + private static IEmailSender _emailSender; + + private class TestHelperInternal : TestHelperBase + { + public TestHelperInternal() : base(typeof(TestHelperInternal).Assembly) + { + + } + + public override IDbProviderFactoryCreator DbProviderFactoryCreator { get; } = Mock.Of(); + + public override IBulkSqlInsertProvider BulkSqlInsertProvider { get; } = Mock.Of(); + + public override IMarchal Marchal { get; } = Mock.Of(); + + public override IBackOfficeInfo GetBackOfficeInfo() + => Mock.Of(); + + public override IHostingEnvironment GetHostingEnvironment() + { + return new AspNetCoreHostingEnvironment( + Mock.Of>(x=>x.CurrentValue == new HostingSettings()), + Mock.Of(x=>x.WebRootPath == "/")); + } + + public override IApplicationShutdownRegistry GetHostingEnvironmentLifetime() + => Mock.Of(); + + public override IIpResolver GetIpResolver() + => Mock.Of(); + } + + public static ITypeFinder GetTypeFinder() => _testHelperInternal.GetTypeFinder(); + + public static TypeLoader GetMockedTypeLoader() => _testHelperInternal.GetMockedTypeLoader(); + + //public static Configs GetConfigs() => _testHelperInternal.GetConfigs(); + + public static IBackOfficeInfo GetBackOfficeInfo() => _testHelperInternal.GetBackOfficeInfo(); + + // public static IConfigsFactory GetConfigsFactory() => _testHelperInternal.GetConfigsFactory(); + + /// + /// Gets the working directory of the test project. + /// + /// The assembly directory. + public static string WorkingDirectory => _testHelperInternal.WorkingDirectory; + + public static IShortStringHelper ShortStringHelper => _testHelperInternal.ShortStringHelper; + public static IJsonSerializer JsonSerializer => _testHelperInternal.JsonSerializer; + public static IVariationContextAccessor VariationContextAccessor => _testHelperInternal.VariationContextAccessor; + public static IDbProviderFactoryCreator DbProviderFactoryCreator => _testHelperInternal.DbProviderFactoryCreator; + public static IBulkSqlInsertProvider BulkSqlInsertProvider => _testHelperInternal.BulkSqlInsertProvider; + public static IMarchal Marchal => _testHelperInternal.Marchal; + public static CoreDebugSettings CoreDebugSettings => _testHelperInternal.CoreDebugSettings; + + + public static IIOHelper IOHelper => _testHelperInternal.IOHelper; + public static IMainDom MainDom => _testHelperInternal.MainDom; + public static UriUtility UriUtility => _testHelperInternal.UriUtility; + + public static IEmailSender EmailSender { get; } = new EmailSender(Options.Create(new GlobalSettings())); + + + /// + /// 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 + /// + /// + /// + public static string MapPathForTestFiles(string relativePath) => _testHelperInternal.MapPathForTestFiles(relativePath); + + public static void InitializeContentDirectories() + { + CreateDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath, Constants.SystemDirectories.AppPlugins }); + } + + public static void CleanContentDirectories() + { + CleanDirectories(new[] { Constants.SystemDirectories.MvcViews, new GlobalSettings().UmbracoMediaPath }); + } + + public static void CreateDirectories(string[] directories) + { + foreach (var directory in directories) + { + var directoryInfo = new DirectoryInfo(IOHelper.MapPath(directory)); + if (directoryInfo.Exists == false) + Directory.CreateDirectory(IOHelper.MapPath(directory)); + } + } + + public static void CleanDirectories(string[] directories) + { + var preserves = new Dictionary + { + { Constants.SystemDirectories.MvcViews, new[] {"dummy.txt"} } + }; + foreach (var directory in directories) + { + var directoryInfo = new DirectoryInfo(IOHelper.MapPath(directory)); + var preserve = preserves.ContainsKey(directory) ? preserves[directory] : null; + if (directoryInfo.Exists) + foreach (var x in directoryInfo.GetFiles().Where(x => preserve == null || preserve.Contains(x.Name) == false)) + x.Delete(); + } + } + + public static void CleanUmbracoSettingsConfig() + { + var currDir = new DirectoryInfo(WorkingDirectory); + + var umbracoSettingsFile = Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config"); + if (File.Exists(umbracoSettingsFile)) + File.Delete(umbracoSettingsFile); + } + + // TODO: Move to Assertions or AssertHelper + // FIXME: obsolete the dateTimeFormat thing and replace with dateDelta + public static void AssertPropertyValuesAreEqual(object actual, object expected, string dateTimeFormat = null, Func sorter = null, string[] ignoreProperties = null) + { + const int dateDeltaMilliseconds = 500; // .5s + + var properties = expected.GetType().GetProperties(); + foreach (var property in properties) + { + // ignore properties that are attributed with EditorBrowsableState.Never + var att = property.GetCustomAttribute(false); + if (att != null && att.State == EditorBrowsableState.Never) + continue; + + // ignore explicitely ignored properties + if (ignoreProperties != null && ignoreProperties.Contains(property.Name)) + continue; + + var actualValue = property.GetValue(actual, null); + var expectedValue = property.GetValue(expected, null); + + AssertAreEqual(property, expectedValue, actualValue, sorter, dateDeltaMilliseconds); + } + } + + private static void AssertAreEqual(PropertyInfo property, object expected, object actual, Func sorter = null, int dateDeltaMilliseconds = 0) + { + if (!(expected is string) && expected is IEnumerable) + { + // sort property collection by alias, not by property ids + // on members, built-in properties don't have ids (always zero) + if (expected is PropertyCollection) + sorter = e => ((PropertyCollection) e).OrderBy(x => x.Alias); + + // compare lists + AssertListsAreEqual(property, (IEnumerable) actual, (IEnumerable) expected, sorter, dateDeltaMilliseconds); + } + else if (expected is DateTime expectedDateTime) + { + // compare date & time with delta + var actualDateTime = (DateTime) actual; + var delta = (actualDateTime - expectedDateTime).TotalMilliseconds; + Assert.IsTrue(Math.Abs(delta) <= dateDeltaMilliseconds, "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expected, actual); + } + else if (expected is Property expectedProperty) + { + // compare values + var actualProperty = (Property) actual; + var expectedPropertyValues = expectedProperty.Values.OrderBy(x => x.Culture).ThenBy(x => x.Segment).ToArray(); + var actualPropertyValues = actualProperty.Values.OrderBy(x => x.Culture).ThenBy(x => x.Segment).ToArray(); + if (expectedPropertyValues.Length != actualPropertyValues.Length) + Assert.Fail($"{property.DeclaringType.Name}.{property.Name}: Expected {expectedPropertyValues.Length} but got {actualPropertyValues.Length}."); + for (var i = 0; i < expectedPropertyValues.Length; i++) + { + Assert.AreEqual(expectedPropertyValues[i].EditedValue, actualPropertyValues[i].EditedValue, $"{property.DeclaringType.Name}.{property.Name}: Expected draft value \"{expectedPropertyValues[i].EditedValue}\" but got \"{actualPropertyValues[i].EditedValue}\"."); + Assert.AreEqual(expectedPropertyValues[i].PublishedValue, actualPropertyValues[i].PublishedValue, $"{property.DeclaringType.Name}.{property.Name}: Expected published value \"{expectedPropertyValues[i].EditedValue}\" but got \"{actualPropertyValues[i].EditedValue}\"."); + } + } + else if (expected is IDataEditor expectedEditor) + { + Assert.IsInstanceOf(actual); + var actualEditor = (IDataEditor) actual; + Assert.AreEqual(expectedEditor.Alias, actualEditor.Alias); + // what else shall we test? + } + else + { + // directly compare values + Assert.AreEqual(expected, actual, "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, + expected?.ToString() ?? "", actual?.ToString() ?? ""); + } + } + + private static void AssertListsAreEqual(PropertyInfo property, IEnumerable expected, IEnumerable actual, Func sorter = null, int dateDeltaMilliseconds = 0) + { + + + if (sorter == null) + { + // this is pretty hackerific but saves us some code to write + sorter = enumerable => + { + // semi-generic way of ensuring any collection of IEntity are sorted by Ids for comparison + var entities = enumerable.OfType().ToList(); + return entities.Count > 0 ? (IEnumerable) entities.OrderBy(x => x.Id) : entities; + }; + } + + var expectedListEx = sorter(expected).Cast().ToList(); + var actualListEx = sorter(actual).Cast().ToList(); + + if (actualListEx.Count != expectedListEx.Count) + Assert.Fail("Collection {0}.{1} does not match. Expected IEnumerable containing {2} elements but was IEnumerable containing {3} elements", property.PropertyType.Name, property.Name, expectedListEx.Count, actualListEx.Count); + + for (var i = 0; i < actualListEx.Count; i++) + AssertAreEqual(property, expectedListEx[i], actualListEx[i], sorter, dateDeltaMilliseconds); + } + + public static void DeleteDirectory(string path) + { + Try(() => + { + if (Directory.Exists(path) == false) return; + foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)) + File.Delete(file); + }); + + Try(() => + { + if (Directory.Exists(path) == false) return; + Directory.Delete(path, true); + }); + } + + public static void TryAssert(Action action, int maxTries = 5, int waitMilliseconds = 200) + { + Try(action, maxTries, waitMilliseconds); + } + + public static void Try(Action action, int maxTries = 5, int waitMilliseconds = 200) + { + Try(action, maxTries, waitMilliseconds); + } + + public static void Try(Action action, int maxTries = 5, int waitMilliseconds = 200) + where T : Exception + { + var tries = 0; + while (true) + { + try + { + action(); + break; + } + catch (T) + { + if (tries++ > maxTries) + throw; + Thread.Sleep(waitMilliseconds); + } + } + } + + public static IUmbracoVersion GetUmbracoVersion() => _testHelperInternal.GetUmbracoVersion(); + + public static IRegister GetRegister() => _testHelperInternal.GetRegister(); + + public static IHostingEnvironment GetHostingEnvironment() => _testHelperInternal.GetHostingEnvironment(); + + public static ILoggingConfiguration GetLoggingConfiguration(IHostingEnvironment hostingEnv) => _testHelperInternal.GetLoggingConfiguration(hostingEnv); + + public static IApplicationShutdownRegistry GetHostingEnvironmentLifetime() => _testHelperInternal.GetHostingEnvironmentLifetime(); + + public static IIpResolver GetIpResolver() => _testHelperInternal.GetIpResolver(); + + public static IRequestCache GetRequestCache() => _testHelperInternal.GetRequestCache(); + + public static IPublishedUrlProvider GetPublishedUrlProvider() => _testHelperInternal.GetPublishedUrlProvider(); + } +} 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..13c73dfa96 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/BackOffice/BackOfficeClaimsPrincipalFactoryTests.cs @@ -9,8 +9,10 @@ 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.Extensions; +using Umbraco.Tests.Common.Builders; namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice { @@ -137,10 +139,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 GlobalSettings { DefaultUILanguage = "test" }; - _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/Components/ComponentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs similarity index 80% rename from src/Umbraco.Tests/Components/ComponentTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs index a20b220940..47a1b58abb 100644 --- a/src/Umbraco.Tests/Components/ComponentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Components/ComponentTests.cs @@ -2,12 +2,16 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; 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.Persistence; @@ -21,26 +25,29 @@ namespace Umbraco.Tests.Components public class ComponentTests { private static readonly List Composed = new List(); + private static readonly IIOHelper IOHelper = TestHelper.IOHelper; 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) { // FIXME: use IUmbracoDatabaseFactory vs UmbracoDatabaseFactory, clean it all up! var mock = new Mock(); - - var logger = Mock.Of(); + var loggerFactory = NullLoggerFactory.Instance; + var logger = loggerFactory.CreateLogger("GenericLogger"); 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 GlobalSettings(); + var connectionStrings = new ConnectionStrings(); + var f = new UmbracoDatabaseFactory(loggerFactory.CreateLogger(), loggerFactory, Options.Create(globalSettings), Options.Create(connectionStrings), new Lazy(() => new MapperCollection(Enumerable.Empty())), TestHelper.DbProviderFactoryCreator); + var fs = new FileSystems(mock.Object, loggerFactory.CreateLogger(), loggerFactory, IOHelper, Options.Create(globalSettings), Mock.Of()); + var coreDebug = new CoreDebugSettings(); var mediaFileSystem = Mock.Of(); - var p = new ScopeProvider(f, fs, coreDebug, mediaFileSystem, logger, typeFinder, NoAppCache.Instance); + var p = new ScopeProvider(f, fs, Options.Create(coreDebug), mediaFileSystem, loggerFactory.CreateLogger(), loggerFactory, 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())); + mock.Setup(x => x.GetInstance(typeof(ILoggerFactory))).Returns(loggerFactory); + mock.Setup(x => x.GetInstance(typeof (IProfilingLogger))).Returns(new ProfilingLogger(logger, Mock.Of())); mock.Setup(x => x.GetInstance(typeof (IUmbracoDatabaseFactory))).Returns(f); mock.Setup(x => x.GetInstance(typeof (IScopeProvider))).Returns(p); @@ -55,26 +62,21 @@ namespace Umbraco.Tests.Components private static TypeLoader MockTypeLoader() { - var ioHelper = TestHelper.IOHelper; - return new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of()); + var ioHelper = IOHelper; + return new TypeLoader(Mock.Of(), Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of>(), Mock.Of()); } - public static IRuntimeState MockRuntimeState(RuntimeLevel level) - { - var runtimeState = Mock.Of(); - Mock.Get(runtimeState).Setup(x => x.Level).Returns(level); - return runtimeState; - } + [Test] public void Boot1A() { 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); // 2 is Core and requires 4 // 3 is User - goes away with RuntimeLevel.Unknown @@ -91,6 +93,7 @@ namespace Umbraco.Tests.Components if (type == typeof(Composer5)) return new Composer5(); if (type == typeof(Component5)) return new Component5(new SomeResource()); if (type == typeof(IProfilingLogger)) return new ProfilingLogger(Mock.Of(), Mock.Of()); + if (type == typeof(ILogger)) return Mock.Of>(); throw new NotSupportedException(type.FullName); }); }); @@ -110,10 +113,10 @@ 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(), Mock.Of(x=>x.Level == RuntimeLevel.Run), IOHelper, AppCaches.NoCache); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); // 2 is Core and requires 4 // 3 is User - stays with RuntimeLevel.Run @@ -126,10 +129,10 @@ 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); // 21 is required by 20 // => reorder components accordingly @@ -141,10 +144,10 @@ 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); // i23 requires 22 // 24, 25 implement i23 @@ -158,10 +161,10 @@ 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); try { @@ -181,10 +184,10 @@ 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = TypeArray(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); // 2 is Core and requires 4 // 13 is required by 1 @@ -214,13 +217,14 @@ namespace Umbraco.Tests.Components if (type == typeof(Component5)) return new Component5(new SomeResource()); if (type == typeof(Component5a)) return new Component5a(); if (type == typeof(IProfilingLogger)) return new ProfilingLogger(Mock.Of(), Mock.Of()); + if (type == typeof(ILogger)) return Mock.Of>(); 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer1), typeof(Composer5), typeof(Composer5a) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Assert.IsEmpty(Composed); composers.Compose(); @@ -243,10 +247,10 @@ 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer6), typeof(Composer7), typeof(Composer8) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); composers.Compose(); Assert.AreEqual(2, Composed.Count); @@ -258,10 +262,10 @@ 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); composers.Compose(); Assert.AreEqual(2, Composed.Count); @@ -276,10 +280,10 @@ 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(), Mock.Of(x=>x.Level == RuntimeLevel.Run), IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); composers.Compose(); var builder = composition.WithCollectionBuilder(); @@ -295,35 +299,35 @@ 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer10) }; - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); composers.Compose(); Assert.AreEqual(1, Composed.Count); Assert.AreEqual(typeof(Composer10), Composed[0]); types = new[] { typeof(Composer11) }; - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); Assert.Throws(() => composers.Compose()); Console.WriteLine("throws:"); - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); var requirements = composers.GetRequirements(false); Console.WriteLine(Composers.GetComposersReport(requirements)); types = new[] { typeof(Composer2) }; - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); Assert.Throws(() => composers.Compose()); Console.WriteLine("throws:"); - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); requirements = composers.GetRequirements(false); Console.WriteLine(Composers.GetComposersReport(requirements)); types = new[] { typeof(Composer12) }; - composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); composers.Compose(); Assert.AreEqual(1, Composed.Count); @@ -334,10 +338,10 @@ 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(), Mock.Of(), 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()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); Composed.Clear(); composers.Compose(); Assert.AreEqual(2, Composed.Count); @@ -349,17 +353,17 @@ 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(), Mock.Of(), IOHelper, AppCaches.NoCache); var types = new[] { typeof(Composer26) }; var enableDisableAttributes = new[] { new DisableComposerAttribute(typeof(Composer26)) }; - var composers = new Composers(composition, types, enableDisableAttributes, Mock.Of()); + var composers = new Composers(composition, types, enableDisableAttributes, Mock.Of>(), Mock.Of()); Composed.Clear(); composers.Compose(); Assert.AreEqual(0, Composed.Count); // 26 gone types = new[] { typeof(Composer26), typeof(Composer27) }; // 26 disabled by assembly attribute, enabled by 27 - composers = new Composers(composition, types, enableDisableAttributes, Mock.Of()); + composers = new Composers(composition, types, enableDisableAttributes, Mock.Of>(), Mock.Of()); Composed.Clear(); composers.Compose(); Assert.AreEqual(2, Composed.Count); // both @@ -370,17 +374,17 @@ namespace Umbraco.Tests.Components [Test] public void AllComposers() { - var ioHelper = TestHelper.IOHelper; + var ioHelper = IOHelper; var typeFinder = TestHelper.GetTypeFinder(); - var typeLoader = new TypeLoader(typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of()); + var typeLoader = new TypeLoader(typeFinder, AppCaches.Disabled.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of>(), Mock.Of()); var register = MockRegister(); var composition = new Composition(register, typeLoader, Mock.Of(), - MockRuntimeState(RuntimeLevel.Run), Configs, TestHelper.IOHelper, AppCaches.NoCache); + Mock.Of(), IOHelper, AppCaches.NoCache); var allComposers = typeLoader.GetTypes().ToList(); var types = allComposers.Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web")).ToList(); - var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of()); + var composers = new Composers(composition, types, Enumerable.Empty(), Mock.Of>(), Mock.Of()); var requirements = composers.GetRequirements(); var report = Composers.GetComposersReport(requirements); Console.WriteLine(report); diff --git a/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs similarity index 96% rename from src/Umbraco.Tests/Composing/CollectionBuildersTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs index 2d977e89c7..266aa64803 100644 --- a/src/Umbraco.Tests/Composing/CollectionBuildersTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CollectionBuildersTests.cs @@ -9,7 +9,6 @@ using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Tests.Components; using Umbraco.Tests.TestHelpers; -using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Composing { @@ -21,16 +20,22 @@ namespace Umbraco.Tests.Composing [SetUp] public void Setup() { - Current.Reset(); + // var registerMock = new Mock(); + // var factoryMock = new Mock(); + // registerMock.Setup(x => x.CreateFactory()).Returns(factoryMock.Object); + // factoryMock.Setup(x => x.GetInstance(typeof(Resolved1))).Returns(new Resolved1()); + // factoryMock.Setup(x => x.GetInstance(typeof(Resolved2))).Returns(new Resolved2()); + // factoryMock.Setup(x => x.GetInstance(typeof(Resolved3))).Returns(new Resolved3()); + // factoryMock.Setup(x => x.GetInstance(typeof(Resolved4))).Returns(new Resolved4()); + 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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); } [TearDown] public void TearDown() { - Current.Reset(); } [Test] @@ -490,7 +495,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/ComposingTestBase.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs similarity index 84% rename from src/Umbraco.Tests/Composing/ComposingTestBase.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs index 1977a5dfc1..f15d28bd37 100644 --- a/src/Umbraco.Tests/Composing/ComposingTestBase.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ComposingTestBase.cs @@ -1,13 +1,13 @@ using System.Collections.Generic; using System.IO; using System.Reflection; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Tests.TestHelpers; -using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Composing { @@ -24,15 +24,9 @@ namespace Umbraco.Tests.Composing var typeFinder = TestHelper.GetTypeFinder(); var ioHelper = TestHelper.IOHelper; - TypeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), ProfilingLogger, false, AssembliesToScan); + TypeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of>(), ProfilingLogger, false, AssembliesToScan); } - - [TearDown] - public void TearDown() - { - Current.Reset(); - } - + protected virtual IEnumerable AssembliesToScan => new[] { diff --git a/src/Umbraco.Tests/Composing/CompositionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CompositionTests.cs similarity index 92% rename from src/Umbraco.Tests/Composing/CompositionTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CompositionTests.cs index 380511eaaa..a078a9bac5 100644 --- a/src/Umbraco.Tests/Composing/CompositionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/CompositionTests.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -40,8 +41,8 @@ namespace Umbraco.Tests.Composing var logger = new ProfilingLogger(Mock.Of(), Mock.Of()); 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 typeLoader = new TypeLoader(typeFinder, Mock.Of(), new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), Mock.Of>(), logger); + 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/ContainerConformingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ContainerConformingTests.cs similarity index 100% rename from src/Umbraco.Tests/Composing/ContainerConformingTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/ContainerConformingTests.cs diff --git a/src/Umbraco.Tests/Composing/LazyCollectionBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs similarity index 86% rename from src/Umbraco.Tests/Composing/LazyCollectionBuilderTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs index 4d0135d6c4..7f0af94d1e 100644 --- a/src/Umbraco.Tests/Composing/LazyCollectionBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/LazyCollectionBuilderTests.cs @@ -9,25 +9,12 @@ using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Tests.Components; using Umbraco.Tests.TestHelpers; -using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Composing { [TestFixture] public class LazyCollectionBuilderTests { - [SetUp] - public void Initialize() - { - Current.Reset(); - } - - [TearDown] - public void TearDown() - { - Current.Reset(); - } - private IRegister CreateRegister() { return TestHelper.GetRegister(); @@ -41,7 +28,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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add() @@ -67,7 +54,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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) }) @@ -92,7 +79,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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add() @@ -118,7 +105,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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add() @@ -140,7 +127,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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); composition.WithCollectionBuilder() .Add() diff --git a/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs similarity index 93% rename from src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/PackageActionCollectionTests.cs index 390997173b..4d1db92251 100644 --- a/src/Umbraco.Tests/Composing/PackageActionCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); var expectedPackageActions = TypeLoader.GetPackageActions(); composition.WithCollectionBuilder() diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeFinderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeFinderTests.cs index e0e87fb1ee..b8e391a072 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeFinderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeFinderTests.cs @@ -1,6 +1,8 @@ using System; using System.Linq; using System.Reflection; +using Microsoft.Extensions.Logging; +using Moq; using NUnit.Framework; using Umbraco.Core.Composing; using Umbraco.Core.Logging; @@ -39,7 +41,7 @@ namespace Umbraco.Tests.Composing [Test] public void Find_Class_Of_Type_With_Attribute() { - var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); + var typeFinder = new TypeFinder(Mock.Of>(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); var typesFound = typeFinder.FindClassesOfTypeWithAttribute(_assemblies); Assert.AreEqual(2, typesFound.Count()); } @@ -47,7 +49,7 @@ namespace Umbraco.Tests.Composing [Test] public void Find_Classes_With_Attribute() { - var typeFinder = new TypeFinder(GetTestProfilingLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); + var typeFinder = new TypeFinder(Mock.Of>(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); var typesFound = typeFinder.FindClassesWithAttribute(_assemblies); Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree] @@ -58,13 +60,6 @@ namespace Umbraco.Tests.Composing Assert.AreEqual(22, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree] } - private static IProfilingLogger GetTestProfilingLogger() - { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var profiler = new TestProfiler(); - return new ProfilingLogger(logger, profiler); - } - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class MyTestAttribute : Attribute { diff --git a/src/Umbraco.Tests/Composing/TypeHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeHelperTests.cs similarity index 99% rename from src/Umbraco.Tests/Composing/TypeHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeHelperTests.cs index 1f2477bf98..fb7f158804 100644 --- a/src/Umbraco.Tests/Composing/TypeHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeHelperTests.cs @@ -45,14 +45,14 @@ namespace Umbraco.Tests.Composing typeof (OdbcCommand), typeof (SqlCommand)); Assert.IsFalse(t1.Success); - + var t2 = TypeHelper.GetLowestBaseType(typeof (OleDbCommand), typeof (OdbcCommand), typeof (SqlCommand), typeof (Component)); Assert.IsTrue(t2.Success); Assert.AreEqual(typeof(Component), t2.Result); - + var t3 = TypeHelper.GetLowestBaseType(typeof (OleDbCommand), typeof (OdbcCommand), typeof (SqlCommand), @@ -60,7 +60,7 @@ namespace Umbraco.Tests.Composing typeof (Component).BaseType); Assert.IsTrue(t3.Success); Assert.AreEqual(typeof(MarshalByRefObject), t3.Result); - + var t4 = TypeHelper.GetLowestBaseType(typeof(OleDbCommand), typeof(OdbcCommand), typeof(SqlCommand), @@ -68,17 +68,17 @@ namespace Umbraco.Tests.Composing typeof(Component).BaseType, typeof(int)); Assert.IsFalse(t4.Success); - + var t5 = TypeHelper.GetLowestBaseType(typeof(PropertyAliasDto)); Assert.IsTrue(t5.Success); Assert.AreEqual(typeof(PropertyAliasDto), t5.Result); - + //var t6 = TypeHelper.GetLowestBaseType(typeof (IApplicationEventHandler), // typeof (SchedulerComponent), // typeof(CacheRefresherComponent)); //Assert.IsTrue(t6.Success); //Assert.AreEqual(typeof(IApplicationEventHandler), t6.Result); - + } [Test] diff --git a/src/Umbraco.Tests/Composing/TypeLoaderExtensions.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderExtensions.cs similarity index 100% rename from src/Umbraco.Tests/Composing/TypeLoaderExtensions.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderExtensions.cs diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs similarity index 97% rename from src/Umbraco.Tests/Composing/TypeLoaderTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs index 980878d6f2..64de9a70c9 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Composing/TypeLoaderTests.cs @@ -5,11 +5,10 @@ using System.Linq; using System.Reflection; using Moq; using NUnit.Framework; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Tests.TestHelpers; @@ -30,7 +29,7 @@ namespace Umbraco.Tests.Composing var typeFinder = TestHelper.GetTypeFinder(); _typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(TestHelper.IOHelper.MapPath("~/App_Data/TEMP")), - new ProfilingLogger(Mock.Of(), Mock.Of()), false, + Mock.Of>(), new ProfilingLogger(Mock.Of(), Mock.Of()), false, // for testing, we'll specify which assemblies are scanned for the PluginTypeResolver // TODO: Should probably update this so it only searches this assembly and add custom types to be found @@ -39,12 +38,9 @@ namespace Umbraco.Tests.Composing this.GetType().Assembly, typeof(System.Guid).Assembly, typeof(NUnit.Framework.Assert).Assembly, - typeof(Microsoft.CSharp.CSharpCodeProvider).Assembly, typeof(System.Xml.NameTable).Assembly, typeof(System.Configuration.GenericEnumConverter).Assembly, - typeof(System.Web.SiteMap).Assembly, //typeof(TabPage).Assembly, - typeof(System.Web.Mvc.ActionResult).Assembly, typeof(TypeFinder).Assembly, typeof(UmbracoContext).Assembly, typeof(CheckBoxListPropertyEditor).Assembly diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidatorTests.cs new file mode 100644 index 0000000000..c90e4e4c7d --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/ContentSettingsValidatorTests.cs @@ -0,0 +1,65 @@ +using NUnit.Framework; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.Models.Validation; +using Umbraco.Tests.Common.Builders; + +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configuration.Models.Validation +{ + [TestFixture] + public class ContentSettingsValidationTests + { + [Test] + public void Returns_Success_ForValid_Configuration() + { + var validator = new ContentSettingsValidator(); + var options = BuildContentSettings(); + var result = validator.Validate("settings", options); + Assert.True(result.Succeeded); + } + + [Test] + public void Returns_Fail_For_Configuration_With_Invalid_Error404Collection_Due_To_Duplicate_Id() + { + var validator = new ContentSettingsValidator(); + var options = BuildContentSettings(contentXPath: "/aaa/bbb"); + var result = validator.Validate("settings", options); + Assert.False(result.Succeeded); + } + + [Test] + public void Returns_Fail_For_Configuration_With_Invalid_Error404Collection_Due_To_Empty_Culture() + { + var validator = new ContentSettingsValidator(); + var options = BuildContentSettings(culture: string.Empty); + var result = validator.Validate("settings", options); + Assert.False(result.Succeeded); + } + + [Test] + public void Returns_Fail_For_Configuration_With_Invalid_AutoFillImageProperties_Collection() + { + var validator = new ContentSettingsValidator(); + var options = BuildContentSettings(culture: string.Empty); + var result = validator.Validate("settings", options); + Assert.False(result.Succeeded); + } + + private static ContentSettings BuildContentSettings(string culture = "en-US", string contentXPath = "", string autoFillImagePropertyAlias = "testAlias") + { + return new ContentSettings + { + Error404Collection = new ContentErrorPage[] + { + new ContentErrorPage { Culture = culture, ContentId = 1, ContentXPath = contentXPath }, + }, + Imaging = new ContentImagingSettings + { + AutoFillImageProperties = new ImagingAutoFillUploadField[] + { + new ImagingAutoFillUploadField { Alias = autoFillImagePropertyAlias, WidthFieldAlias = "w", HeightFieldAlias = "h", LengthFieldAlias = "l", ExtensionFieldAlias = "e" } + } + } + }; + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidatorTests.cs new file mode 100644 index 0000000000..3cc0532db2 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/GlobalSettingsValidatorTests.cs @@ -0,0 +1,39 @@ +using NUnit.Framework; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.Models.Validation; + +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configuration.Models.Validation +{ + [TestFixture] + public class GlobalSettingsValidationTests + { + [Test] + public void Returns_Success_ForValid_Configuration() + { + var validator = new GlobalSettingsValidator(); + var options = BuildGlobalSettings(); + var result = validator.Validate("settings", options); + Assert.True(result.Succeeded); + } + + [Test] + public void Returns_Fail_For_Configuration_With_Invalid_SmtpFrom_Field() + { + var validator = new GlobalSettingsValidator(); + var options = BuildGlobalSettings(smtpEmail: "invalid"); + var result = validator.Validate("settings", options); + Assert.False(result.Succeeded); + } + + private static GlobalSettings BuildGlobalSettings(string smtpEmail = "test@test.com") + { + return new GlobalSettings + { + Smtp = new SmtpSettings + { + From = smtpEmail, + } + }; + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/RequestHandlerSettingsValidatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/RequestHandlerSettingsValidatorTests.cs new file mode 100644 index 0000000000..f579fec695 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configuration/Models/Validation/RequestHandlerSettingsValidatorTests.cs @@ -0,0 +1,28 @@ +using NUnit.Framework; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.Models.Validation; + +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Configuration.Models.Validation +{ + [TestFixture] + public class RequestHandlerSettingsValidatorTests + { + [Test] + public void Returns_Success_ForValid_Configuration() + { + var validator = new RequestHandlerSettingsValidator(); + var options = new RequestHandlerSettings(); + var result = validator.Validate("settings", options); + Assert.True(result.Succeeded); + } + + [Test] + public void Returns_Fail_For_Configuration_With_Invalid_ConvertUrlsToAscii_Field() + { + var validator = new RequestHandlerSettingsValidator(); + var options = new RequestHandlerSettings { ConvertUrlsToAscii = "invalid" }; + var result = validator.Validate("settings", options); + Assert.False(result.Succeeded); + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/GlobalSettingsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/GlobalSettingsTests.cs new file mode 100644 index 0000000000..be040c221b --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Configurations/GlobalSettingsTests.cs @@ -0,0 +1,29 @@ +using AutoFixture.NUnit3; +using Microsoft.Extensions.Options; +using NUnit.Framework; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Tests.UnitTests.AutoFixture; +using Umbraco.Web.Common.AspNetCore; + + +namespace Umbraco.Tests.Configurations +{ + [TestFixture] + public class GlobalSettingsTests + { + [InlineAutoMoqData("~/umbraco", "/", "umbraco")] + [InlineAutoMoqData("~/umbraco", "/MyVirtualDir", "umbraco")] + [InlineAutoMoqData("~/customPath", "/MyVirtualDir/", "custompath")] + [InlineAutoMoqData("~/some-wacky/nestedPath", "/MyVirtualDir", "some-wacky-nestedpath")] + [InlineAutoMoqData("~/some-wacky/nestedPath", "/MyVirtualDir/NestedVDir/", "some-wacky-nestedpath")] + public void Umbraco_Mvc_Area(string path, string rootPath, string outcome, [Frozen] IOptionsMonitor hostingSettings, AspNetCoreHostingEnvironment hostingEnvironment) + { + hostingSettings.CurrentValue.ApplicationVirtualPath = rootPath; + + var globalSettings = new GlobalSettings { UmbracoPath = path }; + + Assert.AreEqual(outcome, globalSettings.GetUmbracoMvcAreaNoCache(hostingEnvironment)); + } + } +} 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..e832f13671 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 GlobalSettings(); } - 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 HostingSettings { ApplicationVirtualPath = virtualPath }; + 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/Manifest/ManifestContentAppTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestContentAppTests.cs similarity index 100% rename from src/Umbraco.Tests/Manifest/ManifestContentAppTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestContentAppTests.cs diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs similarity index 89% rename from src/Umbraco.Tests/Manifest/ManifestParserTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs index 661c9cff0e..1e26082453 100644 --- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs @@ -2,6 +2,8 @@ using System.Linq; using Moq; using System.Text; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -12,6 +14,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.Services; using Umbraco.Core.Dashboards; +using Umbraco.Core.IO; using Umbraco.Core.Serialization; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; @@ -22,6 +25,7 @@ namespace Umbraco.Tests.Manifest public class ManifestParserTests { private ManifestParser _parser; + private IIOHelper _ioHelper; [SetUp] public void Setup() @@ -32,7 +36,9 @@ namespace Umbraco.Tests.Manifest new RegexValidator(Mock.Of(), null), new DelimitedValueValidator(), }; - _parser = new ManifestParser(AppCaches.Disabled, new ManifestValueValidatorCollection(validators), new ManifestFilterCollection(Array.Empty()), Mock.Of(), TestHelper.IOHelper, Mock.Of(), Mock.Of(), new JsonNetSerializer(), Mock.Of(), Mock.Of()); + _ioHelper = TestHelper.IOHelper; + var loggerFactory = NullLoggerFactory.Instance; + _parser = new ManifestParser(AppCaches.Disabled, new ManifestValueValidatorCollection(validators), new ManifestFilterCollection(Array.Empty()), loggerFactory.CreateLogger(), loggerFactory, _ioHelper, Mock.Of(), Mock.Of(), new JsonNetSerializer(), Mock.Of(), Mock.Of()); } [Test] @@ -125,8 +131,8 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 manifest = _parser.ParseManifest(json); Assert.AreEqual(2, manifest.Scripts.Length); - Assert.AreEqual("/test.js", manifest.Scripts[0]); - Assert.AreEqual("/test2.js", manifest.Scripts[1]); + Assert.AreEqual(_ioHelper.ResolveUrl("/test.js"), manifest.Scripts[0]); + Assert.AreEqual(_ioHelper.ResolveUrl("/test2.js"), manifest.Scripts[1]); // kludge is gone - must filter before parsing json = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()) + "{propertyEditors: [], javascript: ['~/test.js', '~/test2.js']}"; @@ -218,7 +224,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.IsFalse((editor.Type & EditorType.MacroParameter) > 0); var valueEditor = editor.GetValueEditor(); - Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/MyEditor.html", valueEditor.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/MyEditor.html"), valueEditor.View); Assert.AreEqual("int", valueEditor.ValueType); Assert.IsTrue(valueEditor.HideLabel); @@ -250,7 +256,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 var f = preValueEditor.Fields[0]; Assert.AreEqual("key1", f.Key); Assert.AreEqual("Some config 1", f.Name); - Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val1.html", f.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val1.html"), f.View); var fvalidators = f.Validators; Assert.IsNotNull(fvalidators); Assert.AreEqual(1, fvalidators.Count); @@ -261,7 +267,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 f = preValueEditor.Fields[1]; Assert.AreEqual("key2", f.Key); Assert.AreEqual("Some config 2", f.Name); - Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val2.html", f.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/Views/pre-val2.html"), f.View); fvalidators = f.Validators; Assert.IsNotNull(fvalidators); Assert.AreEqual(0, fvalidators.Count); @@ -303,7 +309,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.AreEqual("some config val", config["key1"]); var valueEditor = editor.GetValueEditor(); - Assert.AreEqual("/App_Plugins/MyPackage/PropertyEditors/CsvEditor.html", valueEditor.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/PropertyEditors/CsvEditor.html"), valueEditor.View); editor = manifest.ParameterEditors[2]; Assert.Throws(() => @@ -353,8 +359,8 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 var editor = manifest.GridEditors[0]; Assert.AreEqual("small-hero", editor.Alias); Assert.AreEqual("Small Hero", editor.Name); - Assert.AreEqual("/App_Plugins/MyPlugin/small-hero/editortemplate.html", editor.View); - Assert.AreEqual("/Views/Partials/Grid/Editors/SmallHero.cshtml", editor.Render); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPlugin/small-hero/editortemplate.html"), editor.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/Views/Partials/Grid/Editors/SmallHero.cshtml"), editor.Render); Assert.AreEqual("icon-presentation", editor.Icon); var config = editor.Config; @@ -396,14 +402,14 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 Assert.AreEqual("myPackageApp1", app0.Alias); Assert.AreEqual("My App1", app0.Name); Assert.AreEqual("icon-foo", app0.Icon); - Assert.AreEqual("/App_Plugins/MyPackage/ContentApps/MyApp1.html", app0.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/ContentApps/MyApp1.html"), app0.View); Assert.IsInstanceOf(manifest.ContentApps[1]); var app1 = (ManifestContentAppDefinition)manifest.ContentApps[1]; Assert.AreEqual("myPackageApp2", app1.Alias); Assert.AreEqual("My App2", app1.Name); Assert.AreEqual("icon-bar", app1.Icon); - Assert.AreEqual("/App_Plugins/MyPackage/ContentApps/MyApp2.html", app1.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/ContentApps/MyApp2.html"), app1.View); } [Test] @@ -432,7 +438,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 var db0 = manifest.Dashboards[0]; Assert.AreEqual("something", db0.Alias); Assert.AreEqual(100, db0.Weight); - Assert.AreEqual("/App_Plugins/MyPackage/Dashboards/one.html", db0.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/Dashboards/one.html"), db0.View); Assert.AreEqual(1, db0.Sections.Length); Assert.AreEqual("content", db0.Sections[0]); Assert.AreEqual(2, db0.AccessRules.Length); @@ -445,7 +451,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2 var db1 = manifest.Dashboards[1]; Assert.AreEqual("something.else", db1.Alias); Assert.AreEqual(-1, db1.Weight); - Assert.AreEqual("/App_Plugins/MyPackage/Dashboards/two.html", db1.View); + Assert.AreEqual(_ioHelper.ResolveUrl("/App_Plugins/MyPackage/Dashboards/two.html"), db1.View); Assert.AreEqual(1, db1.Sections.Length); Assert.AreEqual("forms", db1.Sections[0]); } diff --git a/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs similarity index 76% rename from src/Umbraco.Tests/Packaging/PackageExtractionTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs index 20efc422f4..ad76b060ce 100644 --- a/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs @@ -1,11 +1,9 @@ -using System; -using System.IO; +using System.IO; using System.Linq; +using Moq; using NUnit.Framework; -using Umbraco.Core.Composing; -using Umbraco.Core.IO; +using Umbraco.Core.Hosting; using Umbraco.Core.Packaging; -using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Packaging { @@ -16,9 +14,9 @@ namespace Umbraco.Tests.Packaging private static FileInfo GetTestPackagePath(string packageName) { - const string testPackagesDirName = "Packaging\\Packages"; - var hosting = TestHelper.GetHostingEnvironment(); - string path = Path.Combine(hosting.ApplicationPhysicalPath, testPackagesDirName, packageName); + const string testPackagesDirName = "Umbraco.Core\\Packaging\\Packages"; + var testDir = TestContext.CurrentContext.TestDirectory.Split("bin")[0]; + var path = Path.Combine(testDir, testPackagesDirName, packageName); return new FileInfo(path); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/Packages/Document_Type_Picker_1.1.umb b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/Packages/Document_Type_Picker_1.1.umb new file mode 100644 index 0000000000..18449bd373 Binary files /dev/null and b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/Packages/Document_Type_Picker_1.1.umb differ 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 65% rename from src/Umbraco.Tests/PropertyEditors/ColorListValidatorTest.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs index f140e6a239..f96e265e1f 100644 --- a/src/Umbraco.Tests/PropertyEditors/ColorListValidatorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/ColorListValidatorTest.cs @@ -1,9 +1,13 @@ using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Newtonsoft.Json.Linq; -using Umbraco.Core.Logging; +using Umbraco.Core.IO; +using NUnit.Framework.Internal; using Umbraco.Core.Services; +using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; @@ -12,11 +16,13 @@ namespace Umbraco.Tests.PropertyEditors [TestFixture] public class ColorListValidatorTest { + private ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; + [Test] 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(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -24,7 +30,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(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -37,7 +43,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(_loggerFactory, 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 97% rename from src/Umbraco.Tests/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs index 24ac9cdbf4..a2224b0c5a 100644 --- a/src/Umbraco.Tests/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging.Abstractions; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -21,7 +22,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(); @@ -34,7 +35,7 @@ namespace Umbraco.Tests.PropertyEditors // label does not implement IDataValueReference var labelEditor = new LabelPropertyEditor( - Mock.Of(), + NullLoggerFactory.Instance, IOHelper, DataTypeService, LocalizedTextService, @@ -102,7 +103,7 @@ namespace Umbraco.Tests.PropertyEditors // mediaPicker does implement IDataValueReference var mediaPicker = new MediaPickerPropertyEditor( - Mock.Of(), + NullLoggerFactory.Instance, DataTypeService, LocalizationService, IOHelper, @@ -170,7 +171,7 @@ namespace Umbraco.Tests.PropertyEditors // mediaPicker does implement IDataValueReference var mediaPicker = new MediaPickerPropertyEditor( - Mock.Of(), + NullLoggerFactory.Instance, DataTypeService, LocalizationService, IOHelper, diff --git a/src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs similarity index 65% rename from src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs index f3c3fb4672..3383803c4a 100644 --- a/src/Umbraco.Tests/PropertyEditors/EnsureUniqueValuesValidatorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/EnsureUniqueValuesValidatorTest.cs @@ -1,9 +1,13 @@ using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; 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; @@ -12,11 +16,12 @@ namespace Umbraco.Tests.PropertyEditors [TestFixture] public class EnsureUniqueValuesValidatorTest { + private ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; [Test] 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(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -24,7 +29,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(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -32,7 +37,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(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(0, result.Count()); } @@ -41,7 +46,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(_loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())); Assert.AreEqual(1, result.Count()); } @@ -54,7 +59,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(_loggerFactory, 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 78% rename from src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs index 152a751a7b..de02ccc713 100644 --- a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs @@ -1,18 +1,15 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; +using Microsoft.Extensions.Logging.Abstractions; 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 +28,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(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Configuration = new ValueListConfiguration { @@ -45,14 +42,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 +60,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(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Configuration = new ValueListConfiguration { @@ -74,12 +74,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); } @@ -89,7 +92,6 @@ namespace Umbraco.Tests.PropertyEditors { // editor wants ApplicationContext.Current.Services.TextService // (that should be fixed with proper injection) - var logger = Mock.Of(); var textService = new Mock(); textService.Setup(x => x.Localize(It.IsAny(), It.IsAny(), It.IsAny>())).Returns("blah"); //var appContext = new ApplicationContext( @@ -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 62% rename from src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs index 6301be051d..e5d93a13da 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -1,5 +1,4 @@ using System; -using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -9,49 +8,27 @@ 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)); + } [TestCase("STRING", "hello", "hello")] @@ -61,7 +38,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 +50,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 +60,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 +70,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 +80,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 +94,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 +107,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 +119,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 +132,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..62d7f422fe --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Logging; +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 89% rename from src/Umbraco.Tests/Published/NestedContentTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs index b4b941733c..a3aae7b7dc 100644 --- a/src/Umbraco.Tests/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs @@ -2,37 +2,38 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; 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() { var logger = Mock.Of(); + var loggerFactory = NullLoggerFactory.Instance; var profiler = Mock.Of(); var proflog = new ProfilingLogger(logger, profiler); 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(loggerFactory, 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 +64,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(loggerFactory, 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 +125,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 +179,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 +211,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 +229,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..42a2234d64 100644 --- a/src/Umbraco.Tests/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs @@ -1,25 +1,22 @@ using System; using System.Collections.Generic; +using Microsoft.Extensions.Logging.Abstractions; 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 +31,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(NullLoggerFactory.Instance, 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 +62,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 +116,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(NullLoggerFactory.Instance, 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 +147,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 +164,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 +176,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 +196,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(NullLoggerFactory.Instance, 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..e577fc28fa 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UriUtilityTests.cs @@ -1,8 +1,7 @@ using System; using Moq; using NUnit.Framework; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Web; @@ -70,12 +69,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 RequestHandlerSettings { AddTrailingSlash = trailingSlash }; 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/Scoping/EventNameExtractorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/EventNameExtractorTests.cs similarity index 100% rename from src/Umbraco.Tests/Scoping/EventNameExtractorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Scoping/EventNameExtractorTests.cs diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/LegacyPasswordSecurityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/LegacyPasswordSecurityTests.cs new file mode 100644 index 0000000000..c070657dd5 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/LegacyPasswordSecurityTests.cs @@ -0,0 +1,109 @@ +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Security; + +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security +{ + [TestFixture] + public class LegacyPasswordSecurityTests + { + + [Test] + public void Check_Password_Hashed_Non_KeyedHashAlgorithm() + { + var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == "SHA256"); + var passwordSecurity = new LegacyPasswordSecurity(); + + string salt; + var pass = "ThisIsAHashedPassword"; + var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out salt); + var storedPassword = passwordSecurity.FormatPasswordForStorage(passwordConfiguration.HashAlgorithmType, hashed, salt); + + var result = passwordSecurity.VerifyPassword(passwordConfiguration.HashAlgorithmType, "ThisIsAHashedPassword", storedPassword); + + Assert.IsTrue(result); + } + + [Test] + public void Check_Password_Hashed_KeyedHashAlgorithm() + { + var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); + var passwordSecurity = new LegacyPasswordSecurity(); + + string salt; + var pass = "ThisIsAHashedPassword"; + var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out salt); + var storedPassword = passwordSecurity.FormatPasswordForStorage(passwordConfiguration.HashAlgorithmType, hashed, salt); + + var result = passwordSecurity.VerifyPassword(passwordConfiguration.HashAlgorithmType, "ThisIsAHashedPassword", storedPassword); + + Assert.IsTrue(result); + } + + [Test] + public void Check_Password_Legacy_v4_SHA1() + { + var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco4PasswordHashAlgorithmName); + var passwordSecurity = new LegacyPasswordSecurity(); + + string salt; + var pass = "ThisIsAHashedPassword"; + var hashed = passwordSecurity.HashNewPassword(passwordConfiguration.HashAlgorithmType, pass, out salt); + var storedPassword = passwordSecurity.FormatPasswordForStorage(passwordConfiguration.HashAlgorithmType, hashed, salt); + + var result = passwordSecurity.VerifyPassword(passwordConfiguration.HashAlgorithmType, "ThisIsAHashedPassword", storedPassword); + + Assert.IsTrue(result); + } + + [Test] + public void Format_Pass_For_Storage_Hashed() + { + var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); + var passwordSecurity = new LegacyPasswordSecurity(); + + var salt = LegacyPasswordSecurity.GenerateSalt(); + var stored = "ThisIsAHashedPassword"; + + var result = passwordSecurity.FormatPasswordForStorage(passwordConfiguration.HashAlgorithmType, stored, salt); + + Assert.AreEqual(salt + "ThisIsAHashedPassword", result); + } + + [Test] + public void Get_Stored_Password_Hashed() + { + var passwordConfiguration = Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName); + var passwordSecurity = new LegacyPasswordSecurity(); + + var salt = LegacyPasswordSecurity.GenerateSalt(); + var stored = salt + "ThisIsAHashedPassword"; + + string initSalt; + var result = passwordSecurity.ParseStoredHashPassword(passwordConfiguration.HashAlgorithmType, stored, out initSalt); + + Assert.AreEqual("ThisIsAHashedPassword", result); + } + + /// + /// The salt generated is always the same length + /// + [Test] + public void Check_Salt_Length() + { + var lastLength = 0; + for (var i = 0; i < 10000; i++) + { + var result = LegacyPasswordSecurity.GenerateSalt(); + + if (i > 0) + Assert.AreEqual(lastLength, result.Length); + + lastLength = result.Length; + } + } + + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/PasswordSecurityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/PasswordSecurityTests.cs deleted file mode 100644 index 0ef6063910..0000000000 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Security/PasswordSecurityTests.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Moq; -using NUnit.Framework; -using System.Security.Cryptography; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Security; - -namespace Umbraco.Tests.UnitTests.Umbraco.Core.Security -{ - [TestFixture] - public class PasswordSecurityTests - { - - [Test] - public void Check_Password_Hashed_Non_KeyedHashAlgorithm() - { - var passwordSecurity = new LegacyPasswordSecurity(Mock.Of(x => x.HashAlgorithmType == "SHA256")); - - string salt; - var pass = "ThisIsAHashedPassword"; - var hashed = passwordSecurity.HashNewPassword(pass, out salt); - var storedPassword = passwordSecurity.FormatPasswordForStorage(hashed, salt); - - var result = passwordSecurity.VerifyPassword("ThisIsAHashedPassword", storedPassword); - - Assert.IsTrue(result); - } - - [Test] - public void Check_Password_Hashed_KeyedHashAlgorithm() - { - var passwordSecurity = new LegacyPasswordSecurity(Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName)); - - string salt; - var pass = "ThisIsAHashedPassword"; - var hashed = passwordSecurity.HashNewPassword(pass, out salt); - var storedPassword = passwordSecurity.FormatPasswordForStorage(hashed, salt); - - var result = passwordSecurity.VerifyPassword("ThisIsAHashedPassword", storedPassword); - - Assert.IsTrue(result); - } - - [Test] - public void Format_Pass_For_Storage_Hashed() - { - var passwordSecurity = new LegacyPasswordSecurity(Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName)); - - var salt = LegacyPasswordSecurity.GenerateSalt(); - var stored = "ThisIsAHashedPassword"; - - var result = passwordSecurity.FormatPasswordForStorage(stored, salt); - - Assert.AreEqual(salt + "ThisIsAHashedPassword", result); - } - - [Test] - public void Get_Stored_Password_Hashed() - { - var passwordSecurity = new LegacyPasswordSecurity(Mock.Of(x => x.HashAlgorithmType == Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName)); - - var salt = LegacyPasswordSecurity.GenerateSalt(); - var stored = salt + "ThisIsAHashedPassword"; - - string initSalt; - var result = passwordSecurity.ParseStoredHashPassword(stored, out initSalt); - - Assert.AreEqual("ThisIsAHashedPassword", result); - } - - /// - /// The salt generated is always the same length - /// - [Test] - public void Check_Salt_Length() - { - var lastLength = 0; - for (var i = 0; i < 10000; i++) - { - var result = LegacyPasswordSecurity.GenerateSalt(); - - if (i > 0) - Assert.AreEqual(lastLength, result.Length); - - lastLength = result.Length; - } - } - - } -} diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentTypeServiceExtensionsTests.cs similarity index 79% rename from src/Umbraco.Tests/Services/ContentTypeServiceExtensionsTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentTypeServiceExtensionsTests.cs index d0f817542b..e1c82ced86 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentTypeServiceExtensionsTests.cs @@ -5,15 +5,17 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.Services { [TestFixture] - [UmbracoTest(WithApplication = true)] - public class ContentTypeServiceExtensionsTests : UmbracoTestBase + public class ContentTypeServiceExtensionsTests { + private IShortStringHelper ShortStringHelper => new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); + [Test] public void GetAvailableCompositeContentTypes_No_Overlap_By_Content_Type_And_Property_Type_Alias() { @@ -27,13 +29,13 @@ namespace Umbraco.Tests.Services ct.PropertyGroups.Add(pg); }; - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1", null); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2", null); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); addPropType("title", ct2); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3", null); + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); addPropType("title", ct3); - var ct4 = MockedContentTypes.CreateBasicContentType("ct4", "CT4", null); - var ct5 = MockedContentTypes.CreateBasicContentType("ct5", "CT5", null); + var ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); + var ct5 = ContentTypeBuilder.CreateBasicContentType("ct5", "CT5", null); addPropType("blah", ct5); ct1.Id = 1; ct2.Id = 2; @@ -67,12 +69,12 @@ namespace Umbraco.Tests.Services ct.PropertyGroups.Add(pg); }; - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1", null); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2", null); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); addPropType(ct2); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3", null); + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); addPropType(ct3); - var ct4 = MockedContentTypes.CreateBasicContentType("ct4", "CT4", null); + var ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -104,12 +106,12 @@ namespace Umbraco.Tests.Services ct.PropertyGroups.Add(pg); }; - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1", null); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2", null); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); addPropType(ct2); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3", null); + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); addPropType(ct3); - var ct4 = MockedContentTypes.CreateBasicContentType("ct4", "CT4", null); + var ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4", null); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -130,9 +132,9 @@ namespace Umbraco.Tests.Services [Test] public void GetAvailableCompositeContentTypes_Not_Itself() { - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1", null); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2", null); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3", null); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1", null); + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", null); + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3", null); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -153,11 +155,11 @@ namespace Umbraco.Tests.Services [Test] public void GetAvailableCompositeContentTypes_No_Results_If_Already_A_Composition_By_Parent() { - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1"); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2", ct1); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3"); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); ct1.Id = 1; + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2", ct1); ct2.Id = 2; + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); ct3.Id = 3; var service = new Mock(); @@ -173,9 +175,9 @@ namespace Umbraco.Tests.Services [Test] public void GetAvailableCompositeContentTypes_No_Results_If_Already_A_Composition() { - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1"); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2"); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3"); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -194,9 +196,9 @@ namespace Umbraco.Tests.Services [Test] public void GetAvailableCompositeContentTypes_Do_Not_Include_Other_Composed_Types() { - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1"); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2"); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3"); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -217,9 +219,9 @@ namespace Umbraco.Tests.Services [Test] public void GetAvailableCompositeContentTypes_Include_Direct_Composed_Types() { - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1"); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2"); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3"); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; @@ -241,10 +243,10 @@ namespace Umbraco.Tests.Services [Test] public void GetAvailableCompositeContentTypes_Include_Indirect_Composed_Types() { - var ct1 = MockedContentTypes.CreateBasicContentType("ct1", "CT1"); - var ct2 = MockedContentTypes.CreateBasicContentType("ct2", "CT2"); - var ct3 = MockedContentTypes.CreateBasicContentType("ct3", "CT3"); - var ct4 = MockedContentTypes.CreateBasicContentType("ct4", "CT4"); + var ct1 = ContentTypeBuilder.CreateBasicContentType("ct1", "CT1"); + var ct2 = ContentTypeBuilder.CreateBasicContentType("ct2", "CT2"); + var ct3 = ContentTypeBuilder.CreateBasicContentType("ct3", "CT3"); + var ct4 = ContentTypeBuilder.CreateBasicContentType("ct4", "CT4"); ct1.Id = 1; ct2.Id = 2; ct3.Id = 3; diff --git a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs similarity index 70% rename from src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs index 84ffa3b696..a164242b2d 100644 --- a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/ShortStringHelper/CmsHelperCasingTests.cs @@ -1,14 +1,22 @@ -using NUnit.Framework; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +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 +38,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/Templates/HtmlImageSourceParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs similarity index 96% rename from src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs index 14e45d976c..43c3f551e1 100644 --- a/src/Umbraco.Tests/Templates/HtmlImageSourceParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlImageSourceParserTests.cs @@ -1,19 +1,17 @@ -using Umbraco.Core.Logging; +using System; +using System.Diagnostics; +using System.Linq; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; -using Umbraco.Web.Templates; -using Umbraco.Web; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Routing; -using Umbraco.Tests.Testing.Objects; -using System.Web; -using System; -using System.Linq; -using Umbraco.Core.Models; using Umbraco.Core; -using System.Diagnostics; -using Umbraco.Tests.TestHelpers; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; using Umbraco.Tests.Common; +using Umbraco.Tests.UnitTests.TestHelpers.Objects; +using Umbraco.Web.Routing; +using Umbraco.Web.Templates; namespace Umbraco.Tests.Templates { @@ -76,9 +74,9 @@ namespace Umbraco.Tests.Templates var umbracoContextFactory = TestUmbracoContextFactory.Create( umbracoContextAccessor: umbracoContextAccessor); - + var webRoutingSettings = new WebRoutingSettings(); var publishedUrlProvider = new UrlProvider(umbracoContextAccessor, - TestHelper.WebRoutingSettings, + 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.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs similarity index 95% rename from src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs index 20677468c6..7660265502 100644 --- a/src/Umbraco.Tests/Templates/HtmlLocalLinkParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/HtmlLocalLinkParserTests.cs @@ -1,15 +1,13 @@ -using Moq; -using NUnit.Framework; -using System; +using System; using System.Linq; -using System.Web; +using Moq; +using NUnit.Framework; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Tests.Common; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing.Objects; -using Umbraco.Web; +using Umbraco.Tests.UnitTests.TestHelpers.Objects; using Umbraco.Web.Routing; using Umbraco.Web.Templates; @@ -72,8 +70,9 @@ namespace Umbraco.Tests.Templates var umbracoContextFactory = TestUmbracoContextFactory.Create( umbracoContextAccessor: umbracoContextAccessor); + var webRoutingSettings = new WebRoutingSettings(); 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.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs similarity index 68% rename from src/Umbraco.Tests/Templates/ViewHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Templates/ViewHelperTests.cs index ca304d5cda..9f6da6c34a 100644 --- a/src/Umbraco.Tests/Templates/ViewHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/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/Web/Controllers/UserEditorAuthorizationHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs similarity index 75% rename from src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs index 0b7aa658ed..2fd0c7b8ea 100644 --- a/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -10,7 +7,8 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Web.Editors; namespace Umbraco.Tests.Web.Controllers @@ -21,8 +19,8 @@ namespace Umbraco.Tests.Web.Controllers [Test] public void Admin_Is_Authorized() { - var currentUser = GetAdminUser(); - var savingUser = MockedUser.GetUserMock(); + var currentUser = CreateAdminUser(); + var savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -35,7 +33,7 @@ namespace Umbraco.Tests.Web.Controllers userService.Object, entityService.Object); - var result = authHelper.IsAuthorized(currentUser, savingUser.Object, new int[0], new int[0], new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new string[0]); Assert.IsTrue(result.Success); } @@ -43,8 +41,8 @@ namespace Umbraco.Tests.Web.Controllers [Test] public void Non_Admin_Cannot_Save_Admin() { - var currentUser = MockedUser.GetUserMock(); - var savingUser = GetAdminUser(); + var currentUser = CreateUser(); + var savingUser = CreateAdminUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -57,7 +55,7 @@ namespace Umbraco.Tests.Web.Controllers userService.Object, entityService.Object); - var result = authHelper.IsAuthorized(currentUser.Object, savingUser, new int[0], new int[0], new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new string[0]); Assert.IsFalse(result.Success); } @@ -65,12 +63,8 @@ namespace Umbraco.Tests.Web.Controllers [Test] public void Cannot_Grant_Group_Membership_Without_Being_A_Member() { - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.Groups).Returns(new[] - { - new ReadOnlyUserGroup(1, "Test", "icon-user", null, null, "test", new string[0], new string[0]) - }); - var savingUser = MockedUser.GetUserMock(); + var currentUser = CreateUser(withGroup: true); + var savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -83,7 +77,7 @@ namespace Umbraco.Tests.Web.Controllers userService.Object, entityService.Object); - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new int[0], new int[0], new[] {"FunGroup"}); + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] {"FunGroup"}); Assert.IsFalse(result.Success); } @@ -91,12 +85,8 @@ namespace Umbraco.Tests.Web.Controllers [Test] public void Can_Grant_Group_Membership_With_Being_A_Member() { - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.Groups).Returns(new[] - { - new ReadOnlyUserGroup(1, "Test", "icon-user", null, null, "test", new string[0], new string[0]) - }); - var savingUser = MockedUser.GetUserMock(); + var currentUser = CreateUser(withGroup: true); + var savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -109,7 +99,7 @@ namespace Umbraco.Tests.Web.Controllers userService.Object, entityService.Object); - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new int[0], new int[0], new[] { "test" }); + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] { "test" }); Assert.IsTrue(result.Success); } @@ -125,10 +115,8 @@ namespace Umbraco.Tests.Web.Controllers {4567, "-1,4567"}, }; - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.StartContentIds).Returns(new[] { 9876 }); - var savingUser = MockedUser.GetUserMock(); - savingUser.Setup(x => x.StartContentIds).Returns(new[] { 1234 }); + var currentUser = CreateUser(startContentIds: new[] { 9876 }); + var savingUser = CreateUser(startContentIds: new[] { 1234 }); var contentService = new Mock(); contentService.Setup(x => x.GetById(It.IsAny())) @@ -149,7 +137,7 @@ namespace Umbraco.Tests.Web.Controllers entityService.Object); //adding 5555 which currentUser has access to since it's a child of 9876 ... adding is still ok even though currentUser doesn't have access to 1234 - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new[] { 1234, 5555 }, new int[0], new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234, 5555 }, new int[0], new string[0]); Assert.IsTrue(result.Success); } @@ -165,10 +153,8 @@ namespace Umbraco.Tests.Web.Controllers {4567, "-1,4567"}, }; - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.StartContentIds).Returns(new[] { 9876 }); - var savingUser = MockedUser.GetUserMock(); - savingUser.Setup(x => x.StartContentIds).Returns(new[] { 1234, 4567 }); + var currentUser = CreateUser(startContentIds: new[] { 9876 }); + var savingUser = CreateUser(startContentIds: new[] { 1234, 4567 }); var contentService = new Mock(); contentService.Setup(x => x.GetById(It.IsAny())) @@ -189,7 +175,7 @@ namespace Umbraco.Tests.Web.Controllers entityService.Object); //removing 4567 start node even though currentUser doesn't have acces to it ... removing is ok - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new[] { 1234 }, new int[0], new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 1234 }, new int[0], new string[0]); Assert.IsTrue(result.Success); } @@ -205,9 +191,8 @@ namespace Umbraco.Tests.Web.Controllers {4567, "-1,4567"}, }; - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.StartContentIds).Returns(new[] { 9876 }); - var savingUser = MockedUser.GetUserMock(); + var currentUser = CreateUser(startContentIds: new[] { 9876 }); + var savingUser = CreateUser(); var contentService = new Mock(); contentService.Setup(x => x.GetById(It.IsAny())) @@ -228,7 +213,7 @@ namespace Umbraco.Tests.Web.Controllers entityService.Object); //adding 1234 but currentUser doesn't have access to it ... nope - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new []{1234}, new int[0], new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new []{1234}, new int[0], new string[0]); Assert.IsFalse(result.Success); } @@ -244,9 +229,8 @@ namespace Umbraco.Tests.Web.Controllers {4567, "-1,4567"}, }; - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.StartContentIds).Returns(new[] { 9876 }); - var savingUser = MockedUser.GetUserMock(); + var currentUser = CreateUser(startContentIds: new[] { 9876 }); + var savingUser = CreateUser(); var contentService = new Mock(); contentService.Setup(x => x.GetById(It.IsAny())) @@ -267,7 +251,7 @@ namespace Umbraco.Tests.Web.Controllers entityService.Object); //adding 5555 which currentUser has access to since it's a child of 9876 ... ok - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new[] { 5555 }, new int[0], new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new[] { 5555 }, new int[0], new string[0]); Assert.IsTrue(result.Success); } @@ -284,9 +268,8 @@ namespace Umbraco.Tests.Web.Controllers }; - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.StartContentIds).Returns(new[] { 9876 }); - var savingUser = MockedUser.GetUserMock(); + var currentUser = CreateUser(startMediaIds: new[] { 9876 }); + var savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -307,7 +290,7 @@ namespace Umbraco.Tests.Web.Controllers entityService.Object); //adding 1234 but currentUser doesn't have access to it ... nope - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new int[0], new[] {1234}, new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] {1234}, new string[0]); Assert.IsFalse(result.Success); } @@ -323,9 +306,8 @@ namespace Umbraco.Tests.Web.Controllers {4567, "-1,4567"}, }; - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.StartMediaIds).Returns(new[] { 9876 }); - var savingUser = MockedUser.GetUserMock(); + var currentUser = CreateUser(startMediaIds: new[] { 9876 }); + var savingUser = CreateUser(); var contentService = new Mock(); var mediaService = new Mock(); @@ -346,7 +328,7 @@ namespace Umbraco.Tests.Web.Controllers entityService.Object); //adding 5555 which currentUser has access to since it's a child of 9876 ... ok - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new int[0], new[] { 5555 }, new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 5555 }, new string[0]); Assert.IsTrue(result.Success); } @@ -362,10 +344,8 @@ namespace Umbraco.Tests.Web.Controllers {4567, "-1,4567"}, }; - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.StartMediaIds).Returns(new[] { 9876 }); - var savingUser = MockedUser.GetUserMock(); - savingUser.Setup(x => x.StartMediaIds).Returns(new[] { 1234 }); + var currentUser = CreateUser(startMediaIds: new[] { 9876 }); + var savingUser = CreateUser(startMediaIds: new[] { 1234 }); var contentService = new Mock(); var mediaService = new Mock(); @@ -386,7 +366,7 @@ namespace Umbraco.Tests.Web.Controllers entityService.Object); //adding 5555 which currentUser has access to since it's a child of 9876 ... adding is still ok even though currentUser doesn't have access to 1234 - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new int[0], new[] { 1234, 5555 }, new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234, 5555 }, new string[0]); Assert.IsTrue(result.Success); } @@ -402,10 +382,8 @@ namespace Umbraco.Tests.Web.Controllers {4567, "-1,4567"}, }; - var currentUser = MockedUser.GetUserMock(); - currentUser.Setup(x => x.StartMediaIds).Returns(new[] { 9876 }); - var savingUser = MockedUser.GetUserMock(); - savingUser.Setup(x => x.StartMediaIds).Returns(new[] { 1234, 4567 }); + var currentUser = CreateUser(startMediaIds: new[] { 9876 }); + var savingUser = CreateUser(startMediaIds: new[] { 1234, 4567 }); var contentService = new Mock(); var mediaService = new Mock(); @@ -426,19 +404,37 @@ namespace Umbraco.Tests.Web.Controllers entityService.Object); //removing 4567 start node even though currentUser doesn't have acces to it ... removing is ok - var result = authHelper.IsAuthorized(currentUser.Object, savingUser.Object, new int[0], new[] { 1234 }, new string[0]); + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new[] { 1234 }, new string[0]); Assert.IsTrue(result.Success); } - private IUser GetAdminUser() + private static IUser CreateUser(bool withGroup = false, int[] startContentIds = null, int[] startMediaIds = null) { - var admin = MockedUser.GetUserMock(); - admin.Setup(x => x.Groups).Returns(new[] + var builder = new UserBuilder() + .WithStartContentIds(startContentIds != null ? startContentIds : new int[0]) + .WithStartMediaIds(startMediaIds != null ? startMediaIds : new int[0]); + if (withGroup) { - new ReadOnlyUserGroup(1, "Admin", "icon-user", null, null, Constants.Security.AdminGroupAlias, new string[0], new string[0]) - }); - return admin.Object; + builder = (UserBuilder)builder + .AddUserGroup() + .WithName("Test") + .WithAlias("test") + .Done(); + } + + return builder.Build(); + } + + private static IUser CreateAdminUser() + { + return new UserBuilder() + .AddUserGroup() + .WithId(1) + .WithName("Admin") + .WithAlias(Constants.Security.AdminGroupAlias) + .Done() + .Build(); } } } diff --git a/src/Umbraco.Tests/UmbracoExamine/UmbracoContentValueSetValidatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs similarity index 100% rename from src/Umbraco.Tests/UmbracoExamine/UmbracoContentValueSetValidatorTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs diff --git a/src/Umbraco.Tests/Web/HealthChecks/HealthCheckResultsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs similarity index 100% rename from src/Umbraco.Tests/Web/HealthChecks/HealthCheckResultsTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs index 017d2c7774..117b9d87cc 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs @@ -1,7 +1,7 @@ using System; using Moq; using NUnit.Framework; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Tests.Common.Builders; @@ -54,7 +54,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models .Build(); //no id assigned - Assert.Throws(() => entity.EnsureValidPath(Mock.Of(), umbracoEntity => new EntitySlim(), umbracoEntity => { })); + Assert.Throws(() => entity.EnsureValidPath(Mock.Of>(), umbracoEntity => new EntitySlim(), umbracoEntity => { })); } [Test] @@ -66,7 +66,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models .Build(); //no parent found - Assert.Throws(() => entity.EnsureValidPath(Mock.Of(), umbracoEntity => null, umbracoEntity => { })); + Assert.Throws(() => entity.EnsureValidPath(Mock.Of>(), umbracoEntity => null, umbracoEntity => { })); } [Test] @@ -76,7 +76,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models .WithId(1234) .Build(); - entity.EnsureValidPath(Mock.Of(), umbracoEntity => null, umbracoEntity => { }); + entity.EnsureValidPath(Mock.Of>(), umbracoEntity => null, umbracoEntity => { }); //works because it's under the root Assert.AreEqual("-1,1234", entity.Path); @@ -90,7 +90,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models .WithParentId(888) .Build(); - entity.EnsureValidPath(Mock.Of(), umbracoEntity => umbracoEntity.ParentId == 888 ? new EntitySlim { Id = 888, Path = "-1,888" } : null, umbracoEntity => { }); + entity.EnsureValidPath(Mock.Of>(), umbracoEntity => umbracoEntity.ParentId == 888 ? new EntitySlim { Id = 888, Path = "-1,888" } : null, umbracoEntity => { }); //works because the parent was found Assert.AreEqual("-1,888,1234", entity.Path); @@ -140,7 +140,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models }; //this will recursively fix all paths - entity.EnsureValidPath(Mock.Of(), getParent, umbracoEntity => { }); + entity.EnsureValidPath(Mock.Of>(), getParent, umbracoEntity => { }); Assert.AreEqual("-1,999", parentA.Path); Assert.AreEqual("-1,999,888", parentB.Path); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs index 5f965af386..b96d937c72 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models { @@ -21,6 +22,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models public void Can_Deep_Clone() { var item = _builder + .WithId(1) .WithParentObjectType(Guid.NewGuid()) .WithChildObjectType(Guid.NewGuid()) .Build(); diff --git a/src/Umbraco.Tests/Services/AmbiguousEventTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/AmbiguousEventTests.cs similarity index 97% rename from src/Umbraco.Tests/Services/AmbiguousEventTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/AmbiguousEventTests.cs index e137da1188..6eebf5d237 100644 --- a/src/Umbraco.Tests/Services/AmbiguousEventTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/AmbiguousEventTests.cs @@ -5,7 +5,7 @@ using NUnit.Framework; using Umbraco.Core.Events; using Umbraco.Core.Services.Implement; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Services { [TestFixture] public class AmbiguousEventTests @@ -75,4 +75,4 @@ namespace Umbraco.Tests.Services } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests/Services/LocalizedTextServiceTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs similarity index 92% rename from src/Umbraco.Tests/Services/LocalizedTextServiceTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs index 2217028c64..d413481475 100644 --- a/src/Umbraco.Tests/Services/LocalizedTextServiceTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/LocalizedTextServiceTests.cs @@ -2,13 +2,10 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Xml.Linq; -using Moq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; -using Umbraco.Core.Logging; -using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; namespace Umbraco.Tests.Services @@ -16,6 +13,7 @@ namespace Umbraco.Tests.Services [TestFixture] public class LocalizedTextServiceTests { + private static ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; [Test] public void Using_Dictionary_Gets_All_Stored_Values() { @@ -42,7 +40,7 @@ namespace Umbraco.Tests.Services }, } } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.GetAllStoredValues(culture); @@ -74,7 +72,7 @@ namespace Umbraco.Tests.Services new XElement("key", new XAttribute("alias", "blah1"), "blahValue1"), new XElement("key", new XAttribute("alias", "blah2"), "blahValue2"))))) } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.GetAllStoredValues(culture); @@ -105,7 +103,7 @@ namespace Umbraco.Tests.Services new XElement("key", new XAttribute("alias", "testKey1"), "testValue1"), new XElement("key", new XAttribute("alias", "testKey1"), "testValue1"))))) } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.GetAllStoredValues(culture); @@ -131,7 +129,7 @@ namespace Umbraco.Tests.Services } } } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("testArea/testKey", culture); @@ -156,7 +154,7 @@ namespace Umbraco.Tests.Services } } } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("testKey", culture); @@ -181,7 +179,7 @@ namespace Umbraco.Tests.Services } } } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("testArea/doNotFind", culture); @@ -207,7 +205,7 @@ namespace Umbraco.Tests.Services } } } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("doNotFind", culture); @@ -232,7 +230,7 @@ namespace Umbraco.Tests.Services } } } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("testKey", culture, new Dictionary { { "0", "world" }, { "1", "great" }, { "2", "planet" } }); @@ -253,7 +251,7 @@ namespace Umbraco.Tests.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("testArea/testKey", culture); @@ -273,7 +271,7 @@ namespace Umbraco.Tests.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("testKey", culture); @@ -293,7 +291,7 @@ namespace Umbraco.Tests.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("testArea/doNotFind", culture); @@ -314,7 +312,7 @@ namespace Umbraco.Tests.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("doNotFind", culture); @@ -334,7 +332,7 @@ namespace Umbraco.Tests.Services new XElement("key", new XAttribute("alias", "testKey"), "Hello %0%, you are such a %1% %2%")))) } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); var result = txtService.Localize("testKey", culture, new Dictionary { { "0", "world" }, { "1", "great" }, { "2", "planet" } }); @@ -360,7 +358,7 @@ namespace Umbraco.Tests.Services } } } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); Assert.AreEqual("[testKey]", txtService.Localize("testArea/testKey", CultureInfo.GetCultureInfo("en-AU"))); } @@ -378,7 +376,7 @@ namespace Umbraco.Tests.Services new XElement("key", new XAttribute("alias", "testKey"), "testValue")))) } - }, Mock.Of()); + }, _loggerFactory.CreateLogger()); Assert.AreEqual("[testKey]", txtService.Localize("testArea/testKey", CultureInfo.GetCultureInfo("en-AU"))); } diff --git a/src/Umbraco.Tests/Services/PropertyValidationServiceTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs similarity index 98% rename from src/Umbraco.Tests/Services/PropertyValidationServiceTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs index 7b1dbc216d..8a7bad3d8c 100644 --- a/src/Umbraco.Tests/Services/PropertyValidationServiceTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/PropertyValidationServiceTests.cs @@ -7,14 +7,15 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.Testing; using Umbraco.Web.PropertyEditors; namespace Umbraco.Tests.Services { [TestFixture] - public class PropertyValidationServiceTests : UmbracoTestBase + public class PropertyValidationServiceTests { + private IShortStringHelper ShortStringHelper => new DefaultShortStringHelper(new DefaultShortStringHelperConfig()); + private void MockObjects(out PropertyValidationService validationService, out IDataType dt) { var textService = new Mock(); diff --git a/src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs similarity index 78% rename from src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs index 6065570b13..80c8b057ab 100644 --- a/src/Umbraco.Tests/ModelsBuilder/BuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Moq; using NUnit.Framework; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded; using Umbraco.ModelsBuilder.Embedded.Building; -namespace Umbraco.Tests.ModelsBuilder +namespace Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded { [TestFixture] public class BuilderTests @@ -42,7 +41,8 @@ namespace Umbraco.Tests.ModelsBuilder { }; - var builder = new TextBuilder(Mock.Of(), types); + var modelsBuilderConfig = new ModelsBuilderSettings(); + var builder = new TextBuilder(modelsBuilderConfig, types); var btypes = builder.TypeModels; var sb = new StringBuilder(); @@ -61,13 +61,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 +79,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 +152,8 @@ namespace Umbraco.Web.PublishedModels " } }; - var builder = new TextBuilder(Mock.Of(), types); + var modelsBuilderConfig = new ModelsBuilderSettings(); + var builder = new TextBuilder(modelsBuilderConfig, types); var btypes = builder.TypeModels; builder.ModelsNamespace = "Umbraco.Web.PublishedModels"; @@ -176,13 +179,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 +197,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""); } } "; @@ -245,7 +250,7 @@ namespace Umbraco.Web.PublishedModels { Alias = "prop2", ClrName = "Prop2", - ModelClrType = typeof(global::System.Text.StringBuilder), + ModelClrType = typeof(StringBuilder), }); type1.Properties.Add(new PropertyModel { @@ -259,7 +264,8 @@ namespace Umbraco.Web.PublishedModels { }; - var builder = new TextBuilder(Mock.Of(), types); + var modelsBuilderConfig = new ModelsBuilderSettings(); + var builder = new TextBuilder(modelsBuilderConfig, types); builder.ModelsNamespace = "Umbraco.ModelsBuilder.Models"; // forces conflict with Umbraco.ModelsBuilder.Umbraco var btypes = builder.TypeModels; @@ -277,8 +283,8 @@ namespace Umbraco.Web.PublishedModels [TestCase("int", typeof(int))] [TestCase("global::System.Collections.Generic.IEnumerable", typeof(IEnumerable))] - [TestCase("global::Umbraco.Tests.ModelsBuilder.BuilderTestsClass1", typeof(BuilderTestsClass1))] - [TestCase("global::Umbraco.Tests.ModelsBuilder.BuilderTests.Class1", typeof(Class1))] + [TestCase("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.BuilderTestsClass1", typeof(BuilderTestsClass1))] + [TestCase("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.BuilderTests.Class1", typeof(Class1))] public void WriteClrType(string expected, Type input) { // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true @@ -293,15 +299,15 @@ namespace Umbraco.Web.PublishedModels [TestCase("int", typeof(int))] [TestCase("global::System.Collections.Generic.IEnumerable", typeof(IEnumerable))] - [TestCase("global::Umbraco.Tests.ModelsBuilder.BuilderTestsClass1", typeof(BuilderTestsClass1))] - [TestCase("global::Umbraco.Tests.ModelsBuilder.BuilderTests.Class1", typeof(Class1))] + [TestCase("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.BuilderTestsClass1", typeof(BuilderTestsClass1))] + [TestCase("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.BuilderTests.Class1", typeof(Class1))] public void WriteClrTypeUsing(string expected, Type input) { // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things var builder = new TextBuilder(); - builder.Using.Add("Umbraco.Tests.ModelsBuilder"); + builder.Using.Add("Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder"); builder.ModelsNamespaceForTests = "ModelsNamespace"; var sb = new StringBuilder(); builder.WriteClrType(sb, input); @@ -313,7 +319,7 @@ namespace Umbraco.Web.PublishedModels { var builder = new TextBuilder(); builder.Using.Add("System.Text"); - builder.ModelsNamespaceForTests = "Umbraco.Tests.ModelsBuilder.Models"; + builder.ModelsNamespaceForTests = "Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Models"; var sb = new StringBuilder(); builder.WriteClrType(sb, typeof(StringBuilder)); @@ -327,7 +333,7 @@ namespace Umbraco.Web.PublishedModels public void WriteClrTypeAnother_WithoutUsing() { var builder = new TextBuilder(); - builder.ModelsNamespaceForTests = "Umbraco.Tests.ModelsBuilder.Models"; + builder.ModelsNamespaceForTests = "Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Models"; var sb = new StringBuilder(); builder.WriteClrType(sb, typeof(StringBuilder)); Assert.AreEqual("global::System.Text.StringBuilder", sb.ToString()); @@ -338,7 +344,7 @@ namespace Umbraco.Web.PublishedModels { var builder = new TextBuilder(); builder.Using.Add("System.Text"); - builder.Using.Add("Umbraco.Tests.ModelsBuilder"); + builder.Using.Add("Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded"); builder.ModelsNamespaceForTests = "SomeRandomNamespace"; var sb = new StringBuilder(); builder.WriteClrType(sb, typeof(global::System.Text.ASCIIEncoding)); @@ -354,7 +360,7 @@ namespace Umbraco.Web.PublishedModels { var builder = new TextBuilder(); builder.Using.Add("System.Text"); - builder.Using.Add("Umbraco.Tests.ModelsBuilder"); + builder.Using.Add("Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded"); builder.ModelsNamespaceForTests = "SomeBorkedNamespace"; var sb = new StringBuilder(); builder.WriteClrType(sb, typeof(global::System.Text.ASCIIEncoding)); @@ -370,7 +376,7 @@ namespace Umbraco.Web.PublishedModels { var builder = new TextBuilder(); builder.Using.Add("System.Text"); - builder.Using.Add("Umbraco.Tests.ModelsBuilder"); + builder.Using.Add("Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded"); builder.ModelsNamespaceForTests = "SomeRandomNamespace"; var sb = new StringBuilder(); builder.WriteClrType(sb, typeof(ASCIIEncoding)); @@ -378,7 +384,7 @@ namespace Umbraco.Web.PublishedModels // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::Umbraco.Tests.ModelsBuilder.ASCIIEncoding", sb.ToString()); + Assert.AreEqual("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.ASCIIEncoding", sb.ToString()); } [Test] @@ -386,15 +392,15 @@ namespace Umbraco.Web.PublishedModels { var builder = new TextBuilder(); builder.Using.Add("System.Text"); - builder.Using.Add("Umbraco.Tests.ModelsBuilder"); - builder.ModelsNamespaceForTests = "Umbraco.Tests.ModelsBuilder.Models"; + builder.Using.Add("Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded"); + builder.ModelsNamespaceForTests = "Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Models"; var sb = new StringBuilder(); builder.WriteClrType(sb, typeof(ASCIIEncoding)); // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::Umbraco.Tests.ModelsBuilder.ASCIIEncoding", sb.ToString()); + Assert.AreEqual("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.ASCIIEncoding", sb.ToString()); } [Test] @@ -402,7 +408,7 @@ namespace Umbraco.Web.PublishedModels { var builder = new TextBuilder(); builder.Using.Add("System.Text"); - builder.Using.Add("Umbraco.Tests.ModelsBuilder"); + builder.Using.Add("Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded"); builder.ModelsNamespaceForTests = "SomeRandomNamespace"; var sb = new StringBuilder(); builder.WriteClrType(sb, typeof(ASCIIEncoding.Nested)); @@ -410,20 +416,20 @@ namespace Umbraco.Web.PublishedModels // note - these assertions differ from the original tests in MB because in the embedded version, the result of Builder.IsAmbiguousSymbol is always true // which means global:: syntax will be applied to most things - Assert.AreEqual("global::Umbraco.Tests.ModelsBuilder.ASCIIEncoding.Nested", sb.ToString()); + Assert.AreEqual("global::Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded.ASCIIEncoding.Nested", sb.ToString()); } public class Class1 { } } -// make it public to be ambiguous (see above) + // make it public to be ambiguous (see above) public class ASCIIEncoding { // can we handle nested types? public class Nested { } } - class BuilderTestsClass1 {} + class BuilderTestsClass1 { } public class System { } } diff --git a/src/Umbraco.Tests/ModelsBuilder/StringExtensions.cs b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/StringExtensions.cs similarity index 71% rename from src/Umbraco.Tests/ModelsBuilder/StringExtensions.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/StringExtensions.cs index 361d104911..2afcd4f471 100644 --- a/src/Umbraco.Tests/ModelsBuilder/StringExtensions.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/StringExtensions.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Tests.ModelsBuilder +namespace Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded { public static class StringExtensions { diff --git a/src/Umbraco.Tests/ModelsBuilder/UmbracoApplicationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/UmbracoApplicationTests.cs similarity index 97% rename from src/Umbraco.Tests/ModelsBuilder/UmbracoApplicationTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/UmbracoApplicationTests.cs index 4d2ae0e6c6..25d1d9f1f9 100644 --- a/src/Umbraco.Tests/ModelsBuilder/UmbracoApplicationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/UmbracoApplicationTests.cs @@ -4,7 +4,7 @@ using NUnit.Framework; using Umbraco.ModelsBuilder.Embedded; using Umbraco.ModelsBuilder.Embedded.Building; -namespace Umbraco.Tests.ModelsBuilder +namespace Umbraco.Tests.UnitTests.Umbraco.ModelsBuilder.Embedded { [TestFixture] public class UmbracoApplicationTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/LanguageBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/LanguageBuilderTests.cs index b4dfaef6e3..1efd9ddc01 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/LanguageBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/LanguageBuilderTests.cs @@ -15,6 +15,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders var builder = new LanguageBuilder(); var expected = CultureInfo.GetCultureInfo("en-GB"); + // Act var language = builder .WithCultureInfo(expected.Name) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserGroupBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserGroupBuilderTests.cs index 2cd2887878..0cfa0649ff 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserGroupBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/UserGroupBuilderTests.cs @@ -1,4 +1,4 @@ -using System; +using System.Linq; using NUnit.Framework; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -41,7 +41,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders Assert.AreEqual(testName, userGroup.Name); Assert.AreEqual(testUserCount, userGroup.UserCount); Assert.AreEqual(testIcon, userGroup.Icon); - Assert.AreEqual(testPermissions, string.Join(string.Empty, userGroup.Permissions)); + Assert.AreEqual(testPermissions.Length, userGroup.Permissions.Count()); Assert.AreEqual(testStartContentId, userGroup.StartContentId); Assert.AreEqual(testStartMediaId, userGroup.StartMediaId); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj index 2cbf1549dd..938eff3096 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,11 @@ - + - + + + + diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/ContentControllerUnitTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/ContentControllerUnitTests.cs index 56f52215a2..2f76db452a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/ContentControllerUnitTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/ContentControllerUnitTests.cs @@ -1,27 +1,23 @@ -using System.Collections.Generic; -using Moq; +using Moq; using NUnit.Framework; 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.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; namespace Umbraco.Tests.Web.Controllers { [TestFixture] public class ContentControllerUnitTests { - [Test] public void Access_Allowed_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(id: 9); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); var content = contentMock.Object; @@ -44,9 +40,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Content_Found() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - var user = userMock.Object; + var user = CreateUser(id: 9); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); var content = contentMock.Object; @@ -72,10 +66,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - userMock.Setup(u => u.StartContentIds).Returns(new[] { 9876 }); - var user = userMock.Object; + var user = CreateUser(id: 9, startContentId: 9876); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); var content = contentMock.Object; @@ -103,9 +94,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_By_Permission() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - var user = userMock.Object; + var user = CreateUser(id: 9); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); var content = contentMock.Object; @@ -134,10 +123,7 @@ namespace Umbraco.Tests.Web.Controllers public void Access_Allowed_By_Permission() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(id: 9); var contentMock = new Mock(); contentMock.Setup(c => c.Path).Returns("-1,1234,5678"); var content = contentMock.Object; @@ -166,10 +152,7 @@ namespace Umbraco.Tests.Web.Controllers public void Access_To_Root_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(); var contentServiceMock = new Mock(); var contentService = contentServiceMock.Object; var userServiceMock = new Mock(); @@ -188,10 +171,7 @@ namespace Umbraco.Tests.Web.Controllers public void Access_To_Recycle_Bin_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(); var contentServiceMock = new Mock(); var contentService = contentServiceMock.Object; var userServiceMock = new Mock(); @@ -210,10 +190,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_To_Recycle_Bin_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.StartContentIds).Returns(new[] { 1234 }); - var user = userMock.Object; + var user = CreateUser(startContentId: 1234); var contentServiceMock = new Mock(); var contentService = contentServiceMock.Object; var userServiceMock = new Mock(); @@ -234,10 +211,8 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_To_Root_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.StartContentIds).Returns(new[] { 1234 }); - var user = userMock.Object; + var user = CreateUser(startContentId: 1234); + var contentServiceMock = new Mock(); var contentService = contentServiceMock.Object; var userServiceMock = new Mock(); @@ -258,10 +233,7 @@ namespace Umbraco.Tests.Web.Controllers public void Access_To_Root_By_Permission() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(); var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection @@ -276,7 +248,6 @@ namespace Umbraco.Tests.Web.Controllers var entityServiceMock = new Mock(); var entityService = entityServiceMock.Object; - //act var result = ContentPermissionsHelper.CheckPermissions(-1, user, userService, contentService, entityService, out var foundContent, new[] { 'A' }); @@ -288,9 +259,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_To_Root_By_Permission() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - var user = userMock.Object; + var user = CreateUser(withUserGroup: false); var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection @@ -316,10 +285,7 @@ namespace Umbraco.Tests.Web.Controllers public void Access_To_Recycle_Bin_By_Permission() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(); var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection @@ -346,9 +312,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_To_Recycle_Bin_By_Permission() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - var user = userMock.Object; + var user = CreateUser(withUserGroup: false); var userServiceMock = new Mock(); var permissions = new EntityPermissionCollection @@ -369,6 +333,24 @@ namespace Umbraco.Tests.Web.Controllers //assert Assert.AreEqual(ContentPermissionsHelper.ContentAccess.Denied, result); } + + private IUser CreateUser(int id = 0, int? startContentId = null, bool withUserGroup = true) + { + var builder = new UserBuilder() + .WithId(id) + .WithStartContentIds(startContentId.HasValue ? new[] { startContentId.Value } : new int[0]); + if (withUserGroup) + { + builder = builder + .AddUserGroup() + .WithId(1) + .WithName("admin") + .WithAlias("admin") + .Done(); + } + + return builder.Build(); + } } //NOTE: The below self hosted stuff does work so need to get some tests written. Some are not possible atm because diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/MediaControllerUnitTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/MediaControllerUnitTests.cs index aef08cec5a..91305e463c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/MediaControllerUnitTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Controllers/MediaControllerUnitTests.cs @@ -5,7 +5,8 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; -using Umbraco.Tests.Common.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.Common.Exceptions; @@ -18,10 +19,7 @@ namespace Umbraco.Tests.Web.Controllers public void Access_Allowed_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(id: 9); var mediaMock = new Mock(); mediaMock.Setup(m => m.Path).Returns("-1,1234,5678"); var media = mediaMock.Object; @@ -42,9 +40,7 @@ namespace Umbraco.Tests.Web.Controllers public void Throws_Exception_When_No_Media_Found() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - var user = userMock.Object; + var user = CreateUser(id: 9); var mediaMock = new Mock(); mediaMock.Setup(m => m.Path).Returns("-1,1234,5678"); var media = mediaMock.Object; @@ -62,10 +58,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - userMock.Setup(u => u.StartMediaIds).Returns(new[] { 9876 }); - var user = userMock.Object; + var user = CreateUser(id: 9, startMediaId: 9876); var mediaMock = new Mock(); mediaMock.Setup(m => m.Path).Returns("-1,1234,5678"); var media = mediaMock.Object; @@ -88,10 +81,7 @@ namespace Umbraco.Tests.Web.Controllers public void Access_To_Root_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(); var mediaServiceMock = new Mock(); var mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); @@ -108,10 +98,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_To_Root_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.StartMediaIds).Returns(new[] { 1234 }); - var user = userMock.Object; + var user = CreateUser(startMediaId: 1234); var mediaServiceMock = new Mock(); var mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); @@ -130,10 +117,7 @@ namespace Umbraco.Tests.Web.Controllers public void Access_To_Recycle_Bin_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.Groups).Returns(new[] { new ReadOnlyUserGroup(1, "admin", "", -1, -1, "admin", new string[0], new List()) }); - var user = userMock.Object; + var user = CreateUser(); var mediaServiceMock = new Mock(); var mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); @@ -150,10 +134,7 @@ namespace Umbraco.Tests.Web.Controllers public void No_Access_To_Recycle_Bin_By_Path() { //arrange - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(0); - userMock.Setup(u => u.StartMediaIds).Returns(new[] { 1234 }); - var user = userMock.Object; + var user = CreateUser(startMediaId: 1234); var mediaServiceMock = new Mock(); var mediaService = mediaServiceMock.Object; var entityServiceMock = new Mock(); @@ -167,5 +148,18 @@ namespace Umbraco.Tests.Web.Controllers //assert Assert.IsFalse(result); } + + private IUser CreateUser(int id = 0, int? startMediaId = null) + { + return new UserBuilder() + .WithId(id) + .WithStartMediaIds(startMediaId.HasValue ? new[] { startMediaId.Value } : new int[0]) + .AddUserGroup() + .WithId(1) + .WithName("admin") + .WithAlias("admin") + .Done() + .Build(); + } } } 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..5c186c890c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttributeTests.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using System.Net.Http.Headers; using Microsoft.AspNetCore.Mvc; using Moq; using NUnit.Framework; @@ -8,12 +7,13 @@ 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.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Web.Actions; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Security; namespace Umbraco.Tests.Web.Controllers { @@ -30,7 +30,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 +48,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 +66,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, Mock.Of(), Mock.Of(), - Mock.Of() ); + Mock.Of() ); var actual = att.GetValueFromResponse(new ObjectResult(container)); @@ -77,10 +77,7 @@ namespace Umbraco.Tests.Web.Controllers [Test] public void Filter_On_Start_Node() { - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - userMock.Setup(u => u.StartContentIds).Returns(new[] { 5 }); - var user = userMock.Object; + var user = CreateUser(id: 9, startContentId: 5); var userServiceMock = new Mock(); var userService = userServiceMock.Object; var entityServiceMock = new Mock(); @@ -94,7 +91,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, userService, entityService, - Mock.Of() ); + Mock.Of() ); var path = ""; for (var i = 0; i < 10; i++) @@ -123,10 +120,7 @@ namespace Umbraco.Tests.Web.Controllers } var ids = list.Select(x => (int)x.Id).ToArray(); - var userMock = MockedUser.GetUserMock(); - userMock.Setup(u => u.Id).Returns(9); - userMock.Setup(u => u.StartContentIds).Returns(new int[0]); - var user = userMock.Object; + var user = CreateUser(id: 9, startContentId: 0); var userServiceMock = new Mock(); //we're only assigning 3 nodes browse permissions so that is what we expect as a result @@ -145,7 +139,7 @@ namespace Umbraco.Tests.Web.Controllers ActionBrowse.ActionLetter, userService, Mock.Of(), - Mock.Of() ); + Mock.Of() ); att.FilterBasedOnPermissions(list, user); Assert.AreEqual(3, list.Count); @@ -154,6 +148,14 @@ namespace Umbraco.Tests.Web.Controllers Assert.AreEqual(3, list.ElementAt(2).Id); } + private IUser CreateUser(int id = 0, int? startContentId = null) + { + return new UserBuilder() + .WithId(id) + .WithStartContentIds(startContentId.HasValue ? new[] { startContentId.Value } : new int[0]) + .Build(); + } + private class MyTestClass { public IEnumerable MyList { get; set; } diff --git a/src/Umbraco.Tests/Web/AngularIntegration/ContentModelSerializationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ContentModelSerializationTests.cs similarity index 100% rename from src/Umbraco.Tests/Web/AngularIntegration/ContentModelSerializationTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ContentModelSerializationTests.cs diff --git a/src/Umbraco.Tests/Web/AngularIntegration/JsInitializationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/JsInitializationTests.cs similarity index 94% rename from src/Umbraco.Tests/Web/AngularIntegration/JsInitializationTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/JsInitializationTests.cs index 90355429c4..f081d0f203 100644 --- a/src/Umbraco.Tests/Web/AngularIntegration/JsInitializationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/JsInitializationTests.cs @@ -1,5 +1,4 @@ -using System.Linq; -using NUnit.Framework; +using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.WebAssets; diff --git a/src/Umbraco.Tests/Web/AngularIntegration/ServerVariablesParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ServerVariablesParserTests.cs similarity index 99% rename from src/Umbraco.Tests/Web/AngularIntegration/ServerVariablesParserTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ServerVariablesParserTests.cs index 74ec6e0034..b0eba4c382 100644 --- a/src/Umbraco.Tests/Web/AngularIntegration/ServerVariablesParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/AngularIntegration/ServerVariablesParserTests.cs @@ -8,8 +8,6 @@ namespace Umbraco.Tests.Web.AngularIntegration [TestFixture] public class ServerVariablesParserTests { - - [Test] public void Parse() { 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/ImageCropperTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ImageCropperTest.cs index 77d7aead5e..cf91550fe5 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ImageCropperTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ImageCropperTest.cs @@ -9,6 +9,7 @@ using Umbraco.Web.Models; using System.Text; using Umbraco.Core.Media; using Umbraco.Extensions; +using System.Collections.Generic; namespace Umbraco.Tests.PropertyEditors { @@ -311,6 +312,8 @@ namespace Umbraco.Tests.PropertyEditors internal class TestImageUrlGenerator : IImageUrlGenerator { + public IEnumerable SupportedImageFileTypes => new[] { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" }; + public string GetImageUrl(ImageUrlGenerationOptions options) { var imageProcessorUrl = new StringBuilder(options.ImageUrl ?? string.Empty); diff --git a/src/Umbraco.Tests/Macros/MacroParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs similarity index 99% rename from src/Umbraco.Tests/Macros/MacroParserTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs index 898ae4b20e..1d9e9012e0 100644 --- a/src/Umbraco.Tests/Macros/MacroParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using Umbraco.Core.Macros; using Umbraco.Web.Macros; namespace Umbraco.Tests.Macros 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..a3a9e79e20 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/BackOfficeAreaRoutesTests.cs @@ -1,10 +1,11 @@ -using Microsoft.AspNetCore.Mvc; +using System.Linq; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; -using System.Linq; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Controllers; @@ -56,6 +57,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing Assert.AreEqual(1, endpoints.DataSources.Count); var route = endpoints.DataSources.First(); Assert.AreEqual(4, route.Endpoints.Count); + AssertMinimalBackOfficeRoutes(route); var endpoint3 = (RouteEndpoint)route.Endpoints[2]; @@ -94,8 +96,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing private BackOfficeAreaRoutes GetBackOfficeAreaRoutes(RuntimeLevel level) { + var globalSettings = new GlobalSettings(); 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.Common/Routing/PreviewRoutesTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs new file mode 100644 index 0000000000..1d85ca554f --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/PreviewRoutesTests.cs @@ -0,0 +1,70 @@ +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Hosting; +using Umbraco.Extensions; +using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.Routing; +using Umbraco.Web.BackOffice.SignalR; +using Umbraco.Web.Common.Attributes; +using Umbraco.Web.Common.Controllers; +using Umbraco.Web.WebApi; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing +{ + + [TestFixture] + public class PreviewRoutesTests + { + [TestCase(RuntimeLevel.Install)] + [TestCase(RuntimeLevel.BootFailed)] + [TestCase(RuntimeLevel.Unknown)] + [TestCase(RuntimeLevel.Boot)] + [TestCase(RuntimeLevel.Upgrade)] + public void RuntimeState_No_Routes(RuntimeLevel level) + { + var routes = GetRoutes(level); + var endpoints = new TestRouteBuilder(); + routes.CreateRoutes(endpoints); + + Assert.AreEqual(0, endpoints.DataSources.Count); + } + + + [Test] + public void RuntimeState_Run() + { + var routes = GetRoutes(RuntimeLevel.Run); + var endpoints = new TestRouteBuilder(); + routes.CreateRoutes(endpoints); + + Assert.AreEqual(1, endpoints.DataSources.Count); + var route = endpoints.DataSources.First(); + Assert.AreEqual(2, route.Endpoints.Count); + + var endpoint0 = (RouteEndpoint) route.Endpoints[0]; + Assert.AreEqual($"{routes.GetPreviewHubRoute()}/negotiate", endpoint0.RoutePattern.RawText); + var endpoint1 = (RouteEndpoint) route.Endpoints[1]; + Assert.AreEqual($"{routes.GetPreviewHubRoute()}", endpoint1.RoutePattern.RawText); + + + } + private PreviewRoutes GetRoutes(RuntimeLevel level) + { + var globalSettings = new GlobalSettings(); + var routes = new PreviewRoutes( + Options.Create(globalSettings), + Mock.Of(x => + x.ToAbsolute(It.IsAny()) == "/umbraco" && x.ApplicationVirtualPath == string.Empty), + Mock.Of(x => x.Level == level)); + + return routes; + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs index 6d28e8a71e..de21bc5129 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Routing/TestRouteBuilder.cs @@ -4,6 +4,12 @@ using Microsoft.Extensions.DependencyInjection; using Moq; using System; using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting.Internal; +using Microsoft.Extensions.Logging; namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing { @@ -16,6 +22,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing var services = new ServiceCollection(); services.AddLogging(); services.AddMvc(); + services.AddSingleton(x => new ApplicationLifetime(x.GetRequiredService>())); + services.AddSignalR(); _serviceProvider = services.BuildServiceProvider(); } @@ -25,7 +33,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Routing public IApplicationBuilder CreateApplicationBuilder() { - return Mock.Of(); + var mock = new Mock(); + mock.Setup(x => x.Build()).Returns(httpContext => Task.CompletedTask); + return mock.Object; } + } } diff --git a/src/Umbraco.Tests/IO/IoHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs similarity index 61% rename from src/Umbraco.Tests/IO/IoHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs index 6e876c4705..1d6e619640 100644 --- a/src/Umbraco.Tests/IO/IoHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/AspNetCoreHostingEnvironmentTests.cs @@ -1,29 +1,34 @@ using System; +using AutoFixture.NUnit3; +using Moq; using NUnit.Framework; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.UnitTests.AutoFixture; +using Umbraco.Web.Common.AspNetCore; namespace Umbraco.Tests.IO { [TestFixture] - public class IoHelperTests + public class AspNetCoreHostingEnvironmentTests { - private IIOHelper _ioHelper => TestHelper.IOHelper; - [TestCase("~/Scripts", "/Scripts", null)] - [TestCase("/Scripts", "/Scripts", null)] - [TestCase("../Scripts", "/Scripts", typeof(ArgumentException))] - public void IOHelper_ResolveUrl(string input, string expected, Type expectedExceptionType) + [InlineAutoMoqData("~/Scripts", "/Scripts", null)] + [InlineAutoMoqData("/Scripts", "/Scripts", null)] + [InlineAutoMoqData("../Scripts", "/Scripts", typeof(InvalidOperationException))] + public void IOHelper_ResolveUrl(string input, string expected, Type expectedExceptionType, AspNetCoreHostingEnvironment sut) { if (expectedExceptionType != null) { - Assert.Throws(expectedExceptionType, () =>_ioHelper.ResolveUrl(input)); + Assert.Throws(expectedExceptionType, () =>sut.ToAbsolute(input)); } else { - var result = _ioHelper.ResolveUrl(input); + + var result = sut.ToAbsolute(input); Assert.AreEqual(expected, result); } } 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..ee2d5f3eab 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/SurfaceControllerTests.cs @@ -1,16 +1,17 @@ -using System; -using System.Threading.Tasks; +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.Configuration.Models; 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; using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.PublishedCache; @@ -38,21 +39,23 @@ namespace Umbraco.Tests.Integration { var httpContextAccessor = Mock.Of(); var hostingEnvironment = Mock.Of(); - var globalSettings = new GlobalSettingsBuilder().Build(); + var backofficeSecurityAccessor = Mock.Of(); + Mock.Get(backofficeSecurityAccessor).Setup(x => x.BackofficeSecurity).Returns(Mock.Of()); + var globalSettings = new GlobalSettings(); 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; @@ -69,23 +72,24 @@ namespace Umbraco.Tests.Integration [Test] public void Umbraco_Context_Not_Null() { - var globalSettings = new GlobalSettingsBuilder().Build(); + var globalSettings = new GlobalSettings(); 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,25 +108,26 @@ 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(); - var globalSettings = new GlobalSettingsBuilder().Build(); + var globalSettings = new GlobalSettings(); var umbracoContextFactory = new UmbracoContextFactory( _umbracoContextAccessor, 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; @@ -143,23 +148,24 @@ namespace Umbraco.Tests.Integration [Test] public void Mock_Current_Page() { - var globalSettings = new GlobalSettingsBuilder().Build(); + var globalSettings = new GlobalSettings(); 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; @@ -197,7 +203,7 @@ namespace Umbraco.Tests.Integration private readonly IPublishedContentQuery _publishedContentQuery; public TestSurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IPublishedContentQuery publishedContentQuery, IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, null, ServiceContext.CreatePartial(), AppCaches.Disabled, null, null, publishedUrlProvider) + : base(umbracoContextAccessor, null, ServiceContext.CreatePartial(), AppCaches.Disabled, null, publishedUrlProvider) { _publishedContentQuery = publishedContentQuery; } 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..75e4d1cfd2 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 GlobalSettings(); 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/Configurations/GlobalSettingsTests.cs b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs deleted file mode 100644 index 56237f562c..0000000000 --- a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Moq; -using NUnit.Framework; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web.Hosting; - -namespace Umbraco.Tests.Configurations -{ - - [TestFixture] - public class GlobalSettingsTests : BaseWebTest - { - [TestCase("~/umbraco", "/", "umbraco")] - [TestCase("~/umbraco", "/MyVirtualDir", "umbraco")] - [TestCase("~/customPath", "/MyVirtualDir/", "custompath")] - [TestCase("~/some-wacky/nestedPath", "/MyVirtualDir", "some-wacky-nestedpath")] - [TestCase("~/some-wacky/nestedPath", "/MyVirtualDir/NestedVDir/", "some-wacky-nestedpath")] - public void Umbraco_Mvc_Area(string path, string rootPath, string outcome) - { - - var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); - var mockHostingSettings = Mock.Get(SettingsForTests.GenerateMockHostingSettings()); - mockHostingSettings.Setup(x => x.ApplicationVirtualPath).Returns(rootPath); - - 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)); - } - } -} diff --git a/src/Umbraco.Tests/IO/FileSystemsTests.cs b/src/Umbraco.Tests/IO/FileSystemsTests.cs index c1d3fbb331..d35f950e75 100644 --- a/src/Umbraco.Tests/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests/IO/FileSystemsTests.cs @@ -1,20 +1,20 @@ using System; using System.IO; using System.Text; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Composing.CompositionExtensions; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.IO.MediaPathSchemes; using Umbraco.Core.Logging; using Umbraco.Core.Services; -using Umbraco.Tests.Components; using Umbraco.Tests.TestHelpers; -using Umbraco.Core.Composing.CompositionExtensions; -using Current = Umbraco.Web.Composing.Current; using FileSystems = Umbraco.Core.IO.FileSystems; namespace Umbraco.Tests.IO @@ -30,29 +30,25 @@ 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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); - composition.Register(_ => Mock.Of()); composition.Register(_ => Mock.Of()); - composition.Register(_ => Mock.Of()); + composition.Register(NullLoggerFactory.Instance); + composition.Register(typeof(ILogger<>), typeof(Logger<>)); 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 GlobalSettings(); + composition.Register(x => Microsoft.Extensions.Options.Options.Create(globalSettings)); + composition.ComposeFileSystems(); - composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); - _factory = composition.CreateFactory(); - Current.Reset(); - Current.Factory = _factory; - // make sure we start clean // because some tests will create corrupt or weird filesystems FileSystems.Reset(); @@ -64,7 +60,6 @@ namespace Umbraco.Tests.IO // stay clean (see note in Setup) FileSystems.Reset(); - Current.Reset(); _register.DisposeIfDisposable(); } @@ -119,7 +114,7 @@ namespace Umbraco.Tests.IO fs.DeleteMediaFiles(new[] { virtPath }); Assert.IsFalse(File.Exists(physPath)); - var scheme = Current.Factory.GetInstance(); + var scheme = _factory.GetInstance(); if (scheme is UniqueMediaPathScheme) { // ~/media/1234 is *not* gone diff --git a/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs b/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs index f1e705c9cb..bd26bbcc66 100644 --- a/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs +++ b/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs @@ -2,10 +2,10 @@ using System.IO; using System.Text; using System.Threading; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Tests.TestHelpers; @@ -16,7 +16,7 @@ namespace Umbraco.Tests.IO public class PhysicalFileSystemTests : AbstractFileSystemTests { public PhysicalFileSystemTests() - : base(new PhysicalFileSystem(TestHelper.IOHelper, TestHelper.GetHostingEnvironment(), Mock.Of(), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests"), "/Media/")) + : base(new PhysicalFileSystem(TestHelper.IOHelper, TestHelper.GetHostingEnvironment(), Mock.Of>(), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests"), "/Media/")) { } [SetUp] diff --git a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs index 07a04479a4..39052b7894 100644 --- a/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs +++ b/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs @@ -1,16 +1,18 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Scoping; using Umbraco.Tests.TestHelpers; +using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; namespace Umbraco.Tests.IO { @@ -22,11 +24,15 @@ namespace Umbraco.Tests.IO // SetUp and TearDown run before/after each test // SetUp does not start before the previous TearDown returns + private readonly ILogger _logger = Mock.Of>(); + private readonly IHostingEnvironment _hostingEnvironment = TestHelper.GetHostingEnvironment(); + private readonly IIOHelper _ioHelper = TestHelper.IOHelper; + [SetUp] public void SetUp() { SafeCallContext.Clear(); - ClearFiles(TestHelper.IOHelper); + ClearFiles(_ioHelper); FileSystems.ResetShadowId(); } @@ -38,10 +44,10 @@ namespace Umbraco.Tests.IO FileSystems.ResetShadowId(); } - private static void ClearFiles(IIOHelper ioHelper) + private static void ClearFiles(IIOHelper _ioHelper) { - TestHelper.DeleteDirectory(ioHelper.MapPath("FileSysTests")); - TestHelper.DeleteDirectory(ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs")); + TestHelper.DeleteDirectory(_ioHelper.MapPath("FileSysTests")); + TestHelper.DeleteDirectory(_ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs")); } private static string NormPath(string path) @@ -52,17 +58,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowDeleteDirectory() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/d1"); @@ -90,17 +92,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowDeleteDirectoryInDir() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub"); @@ -143,17 +141,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowDeleteFile() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); File.WriteAllText(path + "/ShadowTests/f1.txt", "foo"); @@ -186,18 +180,14 @@ namespace Umbraco.Tests.IO [Test] public void ShadowDeleteFileInDir() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub"); @@ -246,17 +236,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowCantCreateFile() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Assert.Throws(() => @@ -269,17 +255,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowCreateFile() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper,hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper,_hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); @@ -312,17 +294,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowCreateFileInDir() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) @@ -356,17 +334,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowAbort() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) @@ -382,17 +356,13 @@ namespace Umbraco.Tests.IO [Test] public void ShadowComplete() { - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub/sub"); @@ -422,21 +392,19 @@ namespace Umbraco.Tests.IO [Test] public void ShadowScopeComplete() { - var logger = Mock.Of(); - var ioHelper = TestHelper.IOHelper; - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); - var shadowfs = ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); + var loggerFactory = NullLoggerFactory.Instance; + var path = _ioHelper.MapPath("FileSysTests"); + var shadowfs = _ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); Directory.CreateDirectory(shadowfs); var scopedFileSystems = false; - var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); + 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 GlobalSettings()); + var fileSystems = new FileSystems(container, Mock.Of>(), loggerFactory, _ioHelper, globalSettings, _hostingEnvironment) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem(phy); var sw = (ShadowWrapper) fs.InnerFileSystem; @@ -447,7 +415,7 @@ namespace Umbraco.Tests.IO string id; // explicit shadow without scope does not work - sw.Shadow(id = ShadowWrapper.CreateShadowId(ioHelper)); + sw.Shadow(id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); @@ -458,7 +426,7 @@ namespace Umbraco.Tests.IO // shadow with scope but no complete does not complete scopedFileSystems = true; // pretend we have a scope - var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f3.txt", ms); @@ -480,7 +448,7 @@ namespace Umbraco.Tests.IO // shadow with scope and complete does complete scopedFileSystems = true; // pretend we have a scope - scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f4.txt", ms); @@ -496,7 +464,7 @@ namespace Umbraco.Tests.IO // test scope for "another thread" scopedFileSystems = true; // pretend we have a scope - scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f5.txt", ms); @@ -519,20 +487,17 @@ namespace Umbraco.Tests.IO [Test] public void ShadowScopeCompleteWithFileConflict() { - var logger = Mock.Of(); - var ioHelper = TestHelper.IOHelper; - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); - var shadowfs = ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); + var path = _ioHelper.MapPath("FileSysTests"); + var shadowfs = _ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); var scopedFileSystems = false; - var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); + 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 GlobalSettings()); + var fileSystems = new FileSystems(container, Mock.Of>(), NullLoggerFactory.Instance, _ioHelper, globalSettings, _hostingEnvironment) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem( phy); var sw = (ShadowWrapper) fs.InnerFileSystem; @@ -543,7 +508,7 @@ namespace Umbraco.Tests.IO string id; scopedFileSystems = true; // pretend we have a scope - var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); @@ -574,20 +539,17 @@ namespace Umbraco.Tests.IO [Test] public void ShadowScopeCompleteWithDirectoryConflict() { - var logger = Mock.Of(); - var ioHelper = TestHelper.IOHelper; - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); - var shadowfs = ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); + var path = _ioHelper.MapPath("FileSysTests"); + var shadowfs = _ioHelper.MapPath(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs"); Directory.CreateDirectory(path); var scopedFileSystems = false; - var phy = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path, "ignore"); + 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 GlobalSettings()); + var fileSystems = new FileSystems(container, Mock.Of>(), NullLoggerFactory.Instance, _ioHelper, globalSettings, _hostingEnvironment) { IsScoped = () => scopedFileSystems }; var fs = fileSystems.GetFileSystem( phy); var sw = (ShadowWrapper)fs.InnerFileSystem; @@ -598,7 +560,7 @@ namespace Umbraco.Tests.IO string id; scopedFileSystems = true; // pretend we have a scope - var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(ioHelper)); + var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(_ioHelper)); Assert.IsTrue(Directory.Exists(shadowfs + "/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); @@ -646,9 +608,7 @@ namespace Umbraco.Tests.IO [Test] public void GetFilesReturnsChildrenOnly() { - var ioHelper = TestHelper.IOHelper; - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); File.WriteAllText(path + "/f1.txt", "foo"); Directory.CreateDirectory(path + "/test"); @@ -670,9 +630,7 @@ namespace Umbraco.Tests.IO [Test] public void DeleteDirectoryAndFiles() { - var ioHelper = TestHelper.IOHelper; - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); File.WriteAllText(path + "/f1.txt", "foo"); Directory.CreateDirectory(path + "/test"); @@ -693,17 +651,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFiles() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -729,17 +683,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFilesUsingEmptyFilter() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -768,17 +718,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFilesUsingNullFilter() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -804,17 +750,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFilesUsingWildcardFilter() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -843,17 +785,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFilesUsingSingleCharacterFilter() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -894,17 +832,13 @@ namespace Umbraco.Tests.IO public void ShadowGetFullPath() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -932,17 +866,13 @@ namespace Umbraco.Tests.IO public void ShadowGetRelativePath() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "ignore"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "ignore"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "ignore"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act @@ -975,17 +905,13 @@ namespace Umbraco.Tests.IO public void ShadowGetUrl() { // Arrange - var ioHelper = TestHelper.IOHelper; - var logger = Mock.Of(); - var hostingEnvironment = TestHelper.GetHostingEnvironment(); - - var path = ioHelper.MapPath("FileSysTests"); + var path = _ioHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); - var fs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowTests/", "rootUrl"); - var sfs = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, path + "/ShadowSystem/", "rootUrl"); + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowTests/", "rootUrl"); + var sfs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, path + "/ShadowSystem/", "rootUrl"); var ss = new ShadowFileSystem(fs, sfs); // Act diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs index 04c02f34d2..c472778f9f 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Xml.XPath; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Composing; using Umbraco.Web.Models; @@ -108,7 +108,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache else { // this is a property that does not correspond to anything, ignore and log - Current.Logger.Warn("Dropping property '{PropertyKey}' because it does not belong to the content type.", i.Key); + Current.Logger.LogWarning("Dropping property '{PropertyKey}' because it does not belong to the content type.", i.Key); } } } diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs index c058c9ac48..7f8793b098 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs @@ -2,9 +2,9 @@ using System.IO; using System.Linq; using System.Xml; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Composing; @@ -41,7 +41,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache } catch (Exception ex) { - Current.Logger.Error(ex, "Could not load preview set {PreviewSet} for user {UserId}.", _previewSet, _userId); + Current.Logger.LogError(ex, "Could not load preview set {PreviewSet} for user {UserId}.", _previewSet, _userId); ClearPreviewSet(); @@ -147,7 +147,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache } catch (Exception ex) { - Current.Logger.Error(ex, "Couldn't delete preview set {FileName} for user {UserId}", file.Name, userId); + Current.Logger.LogError(ex, "Couldn't delete preview set {FileName} for user {UserId}", file.Name, userId); } } 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/PublishedMediaCache.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs index 8221a391b0..02510d8e88 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs @@ -5,12 +5,12 @@ using System.IO; using System.Linq; using System.Threading; using System.Xml.XPath; +using Microsoft.Extensions.Logging; using Examine; using Examine.Search; using Lucene.Net.Store; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -134,13 +134,13 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache //See this thread: http://examine.cdodeplex.com/discussions/264341 //Catch the exception here for the time being, and just fallback to GetMedia // TODO: Need to fix examine in LB scenarios! - Current.Logger.Error(ex, "Could not load data from Examine index for media"); + Current.Logger.LogError(ex, "Could not load data from Examine index for media"); } else if (ex is AlreadyClosedException) { //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db. - Current.Logger.Error(ex, "Could not load data from Examine index for media, the app domain is most likely in a shutdown state"); + Current.Logger.LogError(ex, "Could not load data from Examine index for media, the app domain is most likely in a shutdown state"); } else throw; } @@ -302,13 +302,13 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache //See this thread: http://examine.cdodeplex.com/discussions/264341 //Catch the exception here for the time being, and just fallback to GetMedia // TODO: Need to fix examine in LB scenarios! - Current.Logger.Error(ex, "Could not load data from Examine index for media"); + Current.Logger.LogError(ex, "Could not load data from Examine index for media"); } else if (ex is AlreadyClosedException) { //If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot //be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db. - Current.Logger.Error(ex, "Could not load data from Examine index for media, the app domain is most likely in a shutdown state"); + Current.Logger.LogError(ex, "Could not load data from Examine index for media, the app domain is most likely in a shutdown state"); } else throw; } @@ -326,7 +326,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache var miss = Interlocked.CompareExchange(ref _examineIndexMiss, 0, 0); // volatile read if (miss < ExamineIndexMissMax && Interlocked.Increment(ref _examineIndexMiss) == ExamineIndexMissMax) - Current.Logger.Warn("Failed ({ExamineIndexMissMax} times) to retrieve medias from Examine index and had to load" + Current.Logger.LogWarning("Failed ({ExamineIndexMissMax} times) to retrieve medias from Examine index and had to load" + " them from DB. This may indicate that the Examine index is corrupted.", ExamineIndexMissMax); return ConvertFromIMedia(media); @@ -344,7 +344,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache : ConvertFromXPathNavigator(media.Current); } - Current.Logger.Warn("Could not retrieve media {MediaId} from Examine index or from legacy library.GetMedia method", id); + Current.Logger.LogWarning("Could not retrieve media {MediaId} from Examine index or from legacy library.GetMedia method", id); return null; } diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs index bf7cbe40c4..2bc89e0842 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlPublishedSnapshotService.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; 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; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.PublishedContent; @@ -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; @@ -55,8 +56,8 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache IUmbracoContextAccessor umbracoContextAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, - ILogger logger, - IGlobalSettings globalSettings, + ILoggerFactory loggerFactory, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper, @@ -69,7 +70,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor, documentRepository, mediaRepository, memberRepository, defaultCultureAccessor, - logger, globalSettings, hostingEnvironment, hostingLifetime, shortStringHelper, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents) + loggerFactory, globalSettings, hostingEnvironment, hostingLifetime, shortStringHelper, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents) { _umbracoContextAccessor = umbracoContextAccessor; } @@ -83,8 +84,8 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache IUmbracoContextAccessor umbracoContextAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, - ILogger logger, - IGlobalSettings globalSettings, + ILoggerFactory loggerFactory, + GlobalSettings globalSettings, IHostingEnvironment hostingEnvironment, IApplicationShutdownRegistry hostingLifetime, IShortStringHelper shortStringHelper, @@ -98,7 +99,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _routesCache = new RoutesCache(); _publishedContentTypeFactory = publishedContentTypeFactory; _contentTypeCache = contentTypeCache - ?? new PublishedContentTypeCache(serviceContext.ContentTypeService, serviceContext.MediaTypeService, serviceContext.MemberTypeService, publishedContentTypeFactory, logger); + ?? new PublishedContentTypeCache(serviceContext.ContentTypeService, serviceContext.MediaTypeService, serviceContext.MemberTypeService, publishedContentTypeFactory, loggerFactory.CreateLogger()); _xmlStore = new XmlStore(serviceContext.ContentTypeService, serviceContext.ContentService, scopeProvider, _routesCache, _contentTypeCache, publishedSnapshotAccessor, mainDom, testing, enableRepositoryEvents, diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs index dadf8b6824..41705c7774 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs @@ -5,12 +5,12 @@ using System.IO; using System.Linq; using System.Text; using System.Xml; +using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Repositories; @@ -138,7 +138,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache { if (SyncToXmlFile == false) return; - var logger = Current.Logger; + var loggerFactory = Current.LoggerFactory; // there's always be one task keeping a ref to the runner // so it's safe to just create it as a local var here @@ -147,10 +147,10 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache LongRunning = true, KeepAlive = true, Hosted = false // main domain will take care of stopping the runner (see below) - }, logger, _hostingLifetime); + }, loggerFactory.CreateLogger>(), _hostingLifetime); // create (and add to runner) - _persisterTask = new XmlStoreFilePersister(runner, this, logger); + _persisterTask = new XmlStoreFilePersister(runner, this, loggerFactory.CreateLogger()); var registered = mainDom.Register( null, @@ -286,8 +286,8 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache throw new Exception("Cannot run with both ContinouslyUpdateXmlDiskCache and XmlContentCheckForDiskChanges being true."); if (XmlIsImmutable == false) - //Current.Logger.Warn("Running with CloneXmlContent being false is a bad idea."); - Current.Logger.Warn("CloneXmlContent is false - ignored, we always clone."); + //Current.Logger.LogWarning("Running with CloneXmlContent being false is a bad idea."); + Current.Logger.LogWarning("CloneXmlContent is false - ignored, we always clone."); // note: if SyncFromXmlFile then we should also disable / warn that local edits are going to cause issues... } @@ -415,7 +415,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache } catch (Exception ex) { - Current.Logger.Error(ex, "Failed to build a DTD for the Xml cache."); + Current.Logger.LogError(ex, "Failed to build a DTD for the Xml cache."); } dtd.AppendLine("]>"); @@ -426,7 +426,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache // assumes xml lock (file is always locked) private void LoadXmlLocked(SafeXmlReaderWriter safeXml, out bool registerXmlChange) { - Current.Logger.Debug("Loading Xml..."); + Current.Logger.LogDebug("Loading Xml..."); // try to get it from the file if (XmlFileEnabled && (safeXml.Xml = LoadXmlFromFile()) != null) @@ -674,7 +674,7 @@ AND (umbracoNode.id=@id)"; // (no need to test _released) internal void SaveXmlToFile() { - Current.Logger.Info("Save Xml to file..."); + Current.Logger.LogInformation("Save Xml to file..."); try { @@ -698,14 +698,14 @@ AND (umbracoNode.id=@id)"; fs.Write(bytes, 0, bytes.Length); } - Current.Logger.Info("Saved Xml to file."); + Current.Logger.LogInformation("Saved Xml to file."); } catch (Exception ex) { // if something goes wrong remove the file DeleteXmlFile(); - Current.Logger.Error(ex, "Failed to save Xml to file '{FileName}'.", _xmlFileName); + Current.Logger.LogError(ex, "Failed to save Xml to file '{FileName}'.", _xmlFileName); } } @@ -714,7 +714,7 @@ AND (umbracoNode.id=@id)"; // (no need to test _released) internal async Task SaveXmlToFileAsync() { - Current.Logger.Info("Save Xml to file..."); + Current.Logger.LogInformation("Save Xml to file..."); try { @@ -738,14 +738,14 @@ AND (umbracoNode.id=@id)"; await fs.WriteAsync(bytes, 0, bytes.Length); } - Current.Logger.Info("Saved Xml to file."); + Current.Logger.LogInformation("Saved Xml to file."); } catch (Exception ex) { // if something goes wrong remove the file DeleteXmlFile(); - Current.Logger.Error(ex, "Failed to save Xml to file '{FileName}'.", _xmlFileName); + Current.Logger.LogError(ex, "Failed to save Xml to file '{FileName}'.", _xmlFileName); } } @@ -782,7 +782,7 @@ AND (umbracoNode.id=@id)"; // do NOT try to load if we are not the main domain anymore if (_released) return null; - Current.Logger.Info("Load Xml from file..."); + Current.Logger.LogInformation("Load Xml from file..."); try { @@ -792,17 +792,17 @@ AND (umbracoNode.id=@id)"; xml.Load(fs); } _lastFileRead = DateTime.UtcNow; - Current.Logger.Info("Loaded Xml from file."); + Current.Logger.LogInformation("Loaded Xml from file."); return xml; } catch (FileNotFoundException) { - Current.Logger.Warn("Failed to load Xml, file does not exist."); + Current.Logger.LogWarning("Failed to load Xml, file does not exist."); return null; } catch (Exception ex) { - Current.Logger.Error(ex, "Failed to load Xml from file '{FileName}'.", _xmlFileName); + Current.Logger.LogError(ex, "Failed to load Xml from file '{FileName}'.", _xmlFileName); try { DeleteXmlFile(); @@ -834,7 +834,7 @@ AND (umbracoNode.id=@id)"; _nextFileCheck = now.AddSeconds(1); // check every 1s if (XmlFileLastWriteTime <= _lastFileRead) return; - Current.Logger.Debug("Xml file change detected, reloading."); + Current.Logger.LogDebug("Xml file change detected, reloading."); // time to read @@ -1042,7 +1042,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; { foreach (var payload in payloads) { - Current.Logger.Debug("Notified {ChangeTypes} for content {ContentId}", payload.ChangeTypes, payload.Id); + Current.Logger.LogDebug("Notified {ChangeTypes} for content {ContentId}", payload.ChangeTypes, payload.Id); if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll)) { @@ -1075,7 +1075,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; if (content == null || content.Published == false || content.Trashed) { // no published version - Current.Logger.Debug("Notified, content {ContentId} has no published version.", payload.Id); + Current.Logger.LogDebug("Notified, content {ContentId} has no published version.", payload.Id); if (current != null) { @@ -1114,7 +1114,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; if (dtos.MoveNext() == false) { // gone fishing, remove (possible race condition) - Current.Logger.Debug("Notified, content {ContentId} gone fishing.", payload.Id); + Current.Logger.LogDebug("Notified, content {ContentId} gone fishing.", payload.Id); if (current != null) { @@ -1228,7 +1228,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; .ToArray(); foreach (var payload in payloads) - Current.Logger.Debug("Notified {ChangeTypes} for content type {ContentTypeId}", payload.ChangeTypes, payload.Id); + Current.Logger.LogDebug("Notified {ChangeTypes} for content type {ContentTypeId}", payload.ChangeTypes, payload.Id); if (ids.Length > 0) // must have refreshes, not only removes RefreshContentTypes(ids); @@ -1247,7 +1247,7 @@ ORDER BY umbracoNode.level, umbracoNode.sortOrder"; _contentTypeCache.ClearDataType(payload.Id); foreach (var payload in payloads) - Current.Logger.Debug("Notified {RemovedStatus} for data type {payload.Id}", + Current.Logger.LogDebug("Notified {RemovedStatus} for data type {payload.Id}", payload.Removed ? "Removed" : "Refreshed", payload.Id); diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs index 56c09b18ac..52f639f829 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs @@ -1,7 +1,7 @@ using System; using System.Threading; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Web.Scheduling; namespace Umbraco.Tests.LegacyXmlPublishedCache @@ -18,7 +18,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache internal class XmlStoreFilePersister : LatchedBackgroundTaskBase { private readonly IBackgroundTaskRunner _runner; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly XmlStore _store; private readonly object _locko = new object(); private bool _released; @@ -39,12 +39,12 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache public override bool RunsOnShutdown => _timer != null; // initialize the first instance, which is inactive (not touched yet) - public XmlStoreFilePersister(IBackgroundTaskRunner runner, XmlStore store, ILogger logger) + public XmlStoreFilePersister(IBackgroundTaskRunner runner, XmlStore store, ILogger logger) : this(runner, store, logger, false) { } // initialize further instances, which are active (touched) - private XmlStoreFilePersister(IBackgroundTaskRunner runner, XmlStore store, ILogger logger, bool touched) + private XmlStoreFilePersister(IBackgroundTaskRunner runner, XmlStore store, ILogger logger, bool touched) { _runner = runner; _store = store; @@ -61,7 +61,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache if (touched == false) return; - _logger.Debug("Created, save in {WaitMilliseconds}ms.", WaitMilliseconds); + _logger.LogDebug("Created, save in {WaitMilliseconds}ms.", WaitMilliseconds); _initialTouch = DateTime.Now; _timer = new Timer(_ => TimerRelease()); _timer.Change(WaitMilliseconds, 0); @@ -83,22 +83,22 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache { if (_released) // our timer has triggered OR the runner is shutting down { - _logger.Debug("Touched, was released..."); + _logger.LogDebug("Touched, was released..."); // release: has run or is running, too late, return a new task (adds itself to runner) if (_runner == null) { - _logger.Debug("Runner is down, run now."); + _logger.LogDebug("Runner is down, run now."); runNow = true; } else { - _logger.Debug("Create new..."); + _logger.LogDebug("Create new..."); ret = new XmlStoreFilePersister(_runner, _store, _logger, true); if (ret._runner == null) { // could not enlist with the runner, runner is completed, must run now - _logger.Debug("Runner is down, run now."); + _logger.LogDebug("Runner is down, run now."); runNow = true; } } @@ -106,7 +106,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache else if (_timer == null) // we don't have a timer yet { - _logger.Debug("Touched, was idle, start and save in {WaitMilliseconds}ms.", WaitMilliseconds); + _logger.LogDebug("Touched, was idle, start and save in {WaitMilliseconds}ms.", WaitMilliseconds); _initialTouch = DateTime.Now; _timer = new Timer(_ => TimerRelease()); _timer.Change(WaitMilliseconds, 0); @@ -119,12 +119,12 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache if (DateTime.Now - _initialTouch < TimeSpan.FromMilliseconds(MaxWaitMilliseconds)) { - _logger.Debug("Touched, was waiting, can delay, save in {WaitMilliseconds}ms.", WaitMilliseconds); + _logger.LogDebug("Touched, was waiting, can delay, save in {WaitMilliseconds}ms.", WaitMilliseconds); _timer.Change(WaitMilliseconds, 0); } else { - _logger.Debug("Touched, was waiting, cannot delay."); + _logger.LogDebug("Touched, was waiting, cannot delay."); } } } @@ -135,7 +135,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache if (runNow) //Run(); - _logger.Warn("Cannot write now because we are going down, changes may be lost."); + _logger.LogWarning("Cannot write now because we are going down, changes may be lost."); return ret; // this, by default, unless we created a new one } @@ -144,7 +144,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache { lock (_locko) { - _logger.Debug("Timer: release."); + _logger.LogDebug("Timer: release."); _released = true; Release(); @@ -157,7 +157,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache { lock (_locko) { - _logger.Debug("Run now (sync)."); + _logger.LogDebug("Run now (sync)."); // not really needed but safer (it's only us invoking Run, but the method is public...) _released = true; } diff --git a/src/Umbraco.Tests/Logging/LogviewerTests.cs b/src/Umbraco.Tests/Logging/LogviewerTests.cs index 0a193b4446..04d0150f75 100644 --- a/src/Umbraco.Tests/Logging/LogviewerTests.cs +++ b/src/Umbraco.Tests/Logging/LogviewerTests.cs @@ -4,8 +4,8 @@ using Serilog; using System; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Logging.Viewer; using Umbraco.Tests.TestHelpers; @@ -55,7 +55,7 @@ namespace Umbraco.Tests.Logging File.Copy(exampleLogfilePath, _newLogfilePath, true); File.Copy(exampleSearchfilePath, _newSearchfilePath, true); - var logger = Mock.Of(); + var logger = Mock.Of>(); var logViewerConfig = new LogViewerConfig(hostingEnv); _logViewer = new SerilogJsonLogViewer(logger, logViewerConfig, loggingConfiguration, Log.Logger); } diff --git a/src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs b/src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs deleted file mode 100644 index 1dc261714c..0000000000 --- a/src/Umbraco.Tests/Membership/MembershipProviderBaseTests.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Collections.Specialized; -using System.Configuration.Provider; -using System.Security.Cryptography; -using System.Web.Security; -using Moq; -using NUnit.Framework; -using Umbraco.Core.Security; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Web.Composing; -using Umbraco.Web.Security; - -namespace Umbraco.Tests.Membership -{ - [TestFixture] - [UmbracoTest(WithApplication = true)] - public class MembershipProviderBaseTests : UmbracoTestBase - { - [Test] - public void ChangePasswordQuestionAndAnswer_Without_RequiresQuestionAndAnswer() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) { CallBase = true }; - providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(false); - var provider = providerMock.Object; - - Assert.Throws(() => provider.ChangePasswordQuestionAndAnswer("test", "test", "test", "test")); - } - - [Test] - public void CreateUser_Not_Whitespace() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) {CallBase = true}; - var provider = providerMock.Object; - - MembershipCreateStatus status; - var result = provider.CreateUser("", "", "test@test.com", "", "", true, "", out status); - - Assert.IsNull(result); - Assert.AreEqual(MembershipCreateStatus.InvalidUserName, status); - } - - [Test] - public void CreateUser_Invalid_Question() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) { CallBase = true }; - providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true); - var provider = providerMock.Object; - - MembershipCreateStatus status; - var result = provider.CreateUser("test", "test", "test@test.com", "", "", true, "", out status); - - Assert.IsNull(result); - Assert.AreEqual(MembershipCreateStatus.InvalidQuestion, status); - } - - [Test] - public void CreateUser_Invalid_Answer() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) { CallBase = true }; - providerMock.Setup(@base => @base.RequiresQuestionAndAnswer).Returns(true); - var provider = providerMock.Object; - - MembershipCreateStatus status; - var result = provider.CreateUser("test", "test", "test@test.com", "test", "", true, "", out status); - - Assert.IsNull(result); - Assert.AreEqual(MembershipCreateStatus.InvalidAnswer, status); - } - - [Test] - public void GetPassword_Without_EnablePasswordRetrieval() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) { CallBase = true }; - providerMock.Setup(@base => @base.EnablePasswordRetrieval).Returns(false); - var provider = providerMock.Object; - - Assert.Throws(() => provider.GetPassword("test", "test")); - } - - [Test] - public void GetPassword_With_Hashed() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) { CallBase = true }; - providerMock.Setup(@base => @base.EnablePasswordRetrieval).Returns(true); - providerMock.Setup(@base => @base.PasswordFormat).Returns(MembershipPasswordFormat.Hashed); - var provider = providerMock.Object; - - Assert.Throws(() => provider.GetPassword("test", "test")); - } - - // FIXME: in v7 this test relies on ApplicationContext.Current being null, which makes little - // sense, not going to port the weird code in MembershipProviderBase.ResetPassword, so - // what shall we do? - [Test] - [Ignore("makes no sense?")] - public void ResetPassword_Without_EnablePasswordReset() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) { CallBase = true }; - providerMock.Setup(@base => @base.EnablePasswordReset).Returns(false); - var provider = providerMock.Object; - - Assert.Throws(() => provider.ResetPassword("test", "test")); - } - - [Test] - public void Sets_Defaults() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) { CallBase = true }; - var provider = providerMock.Object; - provider.Initialize("test", new NameValueCollection()); - - Assert.AreEqual("test", provider.Name); - Assert.AreEqual(MembershipProviderBase.GetDefaultAppName(TestHelper.GetHostingEnvironment()), provider.ApplicationName); - Assert.AreEqual(false, provider.EnablePasswordRetrieval); - Assert.AreEqual(true, provider.EnablePasswordReset); - Assert.AreEqual(false, provider.RequiresQuestionAndAnswer); - Assert.AreEqual(true, provider.RequiresUniqueEmail); - Assert.AreEqual(5, provider.MaxInvalidPasswordAttempts); - Assert.AreEqual(10, provider.PasswordAttemptWindow); - Assert.AreEqual(provider.DefaultMinPasswordLength, provider.MinRequiredPasswordLength); - Assert.AreEqual(provider.DefaultMinNonAlphanumericChars, provider.MinRequiredNonAlphanumericCharacters); - Assert.AreEqual(null, provider.PasswordStrengthRegularExpression); - Assert.AreEqual(provider.DefaultUseLegacyEncoding, provider.UseLegacyEncoding); - Assert.AreEqual(MembershipPasswordFormat.Hashed, provider.PasswordFormat); - } - - [Test] - public void Throws_Exception_With_Hashed_Password_And_Password_Retrieval() - { - var providerMock = new Mock(TestHelper.GetHostingEnvironment()) { CallBase = true }; - var provider = providerMock.Object; - - Assert.Throws(() => provider.Initialize("test", new NameValueCollection() - { - {"enablePasswordRetrieval", "true"}, - {"passwordFormat", "Hashed"} - })); - } - - [TestCase("hello", 0, "", 5, true)] - [TestCase("hello", 0, "", 4, true)] - [TestCase("hello", 0, "", 6, false)] - [TestCase("hello", 1, "", 5, false)] - [TestCase("hello!", 1, "", 0, true)] - [TestCase("hello!", 2, "", 0, false)] - [TestCase("hello!!", 2, "", 0, true)] - //8 characters or more in length, at least 1 lowercase letter,at least 1 character that is not a lower letter. - [TestCase("hello", 0, "(?=.{8,})[a-z]+[^a-z]+|[^a-z]+[a-z]+", 0, false)] - [TestCase("helloooo", 0, "(?=.{8,})[a-z]+[^a-z]+|[^a-z]+[a-z]+", 0, false)] - [TestCase("helloooO", 0, "(?=.{8,})[a-z]+[^a-z]+|[^a-z]+[a-z]+", 0, true)] - [TestCase("HELLOOOO", 0, "(?=.{8,})[a-z]+[^a-z]+|[^a-z]+[a-z]+", 0, false)] - [TestCase("HELLOOOo", 0, "(?=.{8,})[a-z]+[^a-z]+|[^a-z]+[a-z]+", 0, true)] - public void Valid_Password(string password, int minRequiredNonAlphanumericChars, string strengthRegex, int minLength, bool pass) - { - var result = MembershipProviderBase.IsPasswordValid(password, minRequiredNonAlphanumericChars, strengthRegex, minLength); - Assert.AreEqual(pass, result.Success); - } - - - - - - } -} diff --git a/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs b/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs deleted file mode 100644 index 4f2cb22b4a..0000000000 --- a/src/Umbraco.Tests/Membership/UmbracoServiceMembershipProviderTests.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System.Collections.Specialized; -using System.Threading; -using System.Web.Security; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Tests.Testing; -using Umbraco.Web.Security.Providers; - -namespace Umbraco.Tests.Membership -{ - [TestFixture] - [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.None, WithApplication = true)] - public class UmbracoServiceMembershipProviderTests : UmbracoTestBase - { - [Test] - public void Sets_Default_Member_Type_From_Service_On_Init() - { - var memberTypeServiceMock = new Mock(); - memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Blah"); - var provider = new MembersMembershipProvider(Mock.Of(), memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver()); - provider.Initialize("test", new NameValueCollection()); - - Assert.AreEqual("Blah", provider.DefaultMemberTypeAlias); - } - - [Test] - public void Sets_Default_Member_Type_From_Config_On_Init() - { - var memberTypeServiceMock = new Mock(); - memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Blah"); - var provider = new MembersMembershipProvider(Mock.Of(), memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver()); - provider.Initialize("test", new NameValueCollection { { "defaultMemberTypeAlias", "Hello" } }); - - Assert.AreEqual("Hello", provider.DefaultMemberTypeAlias); - } - - [Test] - public void Create_User_Already_Exists() - { - var memberTypeServiceMock = new Mock(); - memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Member"); - var membershipServiceMock = new Mock(); - membershipServiceMock.Setup(service => service.Exists("test")).Returns(true); - - var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver()); - provider.Initialize("test", new NameValueCollection()); - - MembershipCreateStatus status; - var user = provider.CreateUser("test", "test", "testtest$1", "test@test.com", "test", "test", true, "test", out status); - - Assert.IsNull(user); - } - - [Test] - public void Create_User_Requires_Unique_Email() - { - var memberTypeServiceMock = new Mock(); - memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Member"); - var membershipServiceMock = new Mock(); - membershipServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => new Member("test", MockedContentTypes.CreateSimpleMemberType())); - - var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver()); - provider.Initialize("test", new NameValueCollection { { "requiresUniqueEmail", "true" } }); - - MembershipCreateStatus status; - var user = provider.CreateUser("test", "test", "testtest$1", "test@test.com", "test", "test", true, "test", out status); - - Assert.IsNull(user); - } - - [Test] - public void Password_Hashed_With_Salt() - { - IMember createdMember = null; - var memberType = MockedContentTypes.CreateSimpleMemberType(); - foreach (var p in ConventionsHelper.GetStandardPropertyTypeStubs(TestHelper.ShortStringHelper)) - { - memberType.AddPropertyType(p.Value); - } - var memberTypeServiceMock = new Mock(); - memberTypeServiceMock.Setup(x => x.GetDefault()).Returns("Member"); - var membershipServiceMock = new Mock(); - membershipServiceMock.Setup(service => service.Exists("test")).Returns(false); - membershipServiceMock.Setup(service => service.GetByEmail("test@test.com")).Returns(() => null); - membershipServiceMock.Setup( - service => service.CreateWithIdentity(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((string u, string e, string p, string m, bool isApproved) => - { - createdMember = new Member("test", e, u, p, memberType, isApproved); - }) - .Returns(() => createdMember); - - var provider = new MembersMembershipProvider(membershipServiceMock.Object, memberTypeServiceMock.Object, TestHelper.GetUmbracoVersion(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver()); - provider.Initialize("test", new NameValueCollection { { "passwordFormat", "Hashed" }, { "hashAlgorithmType", Constants.Security.AspNetUmbraco8PasswordHashAlgorithmName } }); - - - MembershipCreateStatus status; - provider.CreateUser("test", "test", "testtest$1", "test@test.com", "test", "test", true, "test", out status); - - Assert.AreNotEqual("test", createdMember.RawPasswordValue); - - string salt; - var storedPassword = provider.PasswordSecurity.ParseStoredHashPassword(createdMember.RawPasswordValue, out salt); - var hashedPassword = provider.PasswordSecurity.HashPassword("testtest$1", salt); - Assert.AreEqual(hashedPassword, storedPassword); - } - - } -} diff --git a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs index 966c4109c6..474528a8ec 100644 --- a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs @@ -1,14 +1,17 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Install; 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; @@ -18,11 +21,11 @@ namespace Umbraco.Tests.Migrations [UmbracoTest(Database = UmbracoTestOptions.Database.NewEmptyPerTest)] public class AdvancedMigrationTests : TestWithDatabaseBase { + private ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; + [Test] public void CreateTableOfTDto() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -40,9 +43,9 @@ namespace Umbraco.Tests.Migrations .From(string.Empty) .To("done")); - upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), _loggerFactory.CreateLogger(), _loggerFactory); - var helper = new DatabaseSchemaCreator(scope.Database, logger, UmbracoVersion, TestObjects.GetGlobalSettings()); + var helper = new DatabaseSchemaCreator(scope.Database, LoggerFactory.CreateLogger(), LoggerFactory, UmbracoVersion); var exists = helper.TableExists("umbracoUser"); Assert.IsTrue(exists); @@ -53,8 +56,6 @@ namespace Umbraco.Tests.Migrations [Test] public void DeleteKeysAndIndexesOfTDto() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -79,7 +80,7 @@ namespace Umbraco.Tests.Migrations .To("a") .To("done")); - upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), _loggerFactory.CreateLogger(), _loggerFactory); scope.Complete(); } } @@ -87,8 +88,6 @@ namespace Umbraco.Tests.Migrations [Test] public void CreateKeysAndIndexesOfTDto() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -116,7 +115,7 @@ namespace Umbraco.Tests.Migrations .To("b") .To("done")); - upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), _loggerFactory.CreateLogger(), _loggerFactory); scope.Complete(); } } @@ -124,8 +123,6 @@ namespace Umbraco.Tests.Migrations [Test] public void CreateKeysAndIndexes() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -153,7 +150,7 @@ namespace Umbraco.Tests.Migrations .To("b") .To("done")); - upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), _loggerFactory.CreateLogger(), _loggerFactory); scope.Complete(); } } @@ -161,8 +158,6 @@ namespace Umbraco.Tests.Migrations [Test] public void CreateColumn() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -187,7 +182,7 @@ namespace Umbraco.Tests.Migrations .To("a") .To("done")); - upgrader.Execute(ScopeProvider, builder, Mock.Of(), logger); + upgrader.Execute(ScopeProvider, builder, Mock.Of(), _loggerFactory.CreateLogger(), _loggerFactory); scope.Complete(); } } diff --git a/src/Umbraco.Tests/Migrations/AlterMigrationTests.cs b/src/Umbraco.Tests/Migrations/AlterMigrationTests.cs index 8cbd5c5764..2d8dd7d18e 100644 --- a/src/Umbraco.Tests/Migrations/AlterMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/AlterMigrationTests.cs @@ -2,11 +2,11 @@ using System.Diagnostics; using System.Data.Common; using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NPoco; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; @@ -20,19 +20,19 @@ namespace Umbraco.Tests.Migrations [TestFixture] public class AlterMigrationTests { - private ILogger _logger; + private ILogger _logger; private ISqlSyntaxProvider _sqlSyntax; private IUmbracoDatabase _database; [SetUp] public void Setup() { - _logger = Mock.Of(); + _logger = Mock.Of>(); _sqlSyntax = new SqlCeSyntaxProvider(); var dbProviderFactory = DbProviderFactories.GetFactory(Constants.DbProviderNames.SqlServer); var sqlContext = new SqlContext(_sqlSyntax, DatabaseType.SqlServer2008, Mock.Of()); - _database = new UmbracoDatabase("cstr", sqlContext, dbProviderFactory, _logger, TestHelper.BulkSqlInsertProvider); + _database = new UmbracoDatabase("cstr", sqlContext, dbProviderFactory, Mock.Of>(), TestHelper.BulkSqlInsertProvider); } [Test] diff --git a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs index a9785697f4..0a8c6cfb3f 100644 --- a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs @@ -1,18 +1,19 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NPoco; using NUnit.Framework; using Umbraco.Core; -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; @@ -24,7 +25,7 @@ namespace Umbraco.Tests.Migrations [Test] public void CanExecute() { - var logger = Mock.Of(); + var loggerFactory = NullLoggerFactory.Instance; var database = new TestDatabase(); var scope = Mock.Of(); @@ -66,7 +67,7 @@ namespace Umbraco.Tests.Migrations var sourceState = kvs.GetValue("Umbraco.Tests.MigrationPlan") ?? string.Empty; // execute plan - state = plan.Execute(s, sourceState, migrationBuilder, logger); + state = plan.Execute(s, sourceState, migrationBuilder, loggerFactory.CreateLogger(), loggerFactory); // save new state kvs.SetValue("Umbraco.Tests.MigrationPlan", sourceState, state); @@ -139,7 +140,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/Migrations/MigrationTests.cs b/src/Umbraco.Tests/Migrations/MigrationTests.cs index bfadd45b0d..46d9b04b1b 100644 --- a/src/Umbraco.Tests/Migrations/MigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Semver; @@ -10,7 +11,6 @@ using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; using Umbraco.Core.Scoping; using Umbraco.Core.Services; -using ILogger = Umbraco.Core.Logging.ILogger; namespace Umbraco.Tests.Migrations { @@ -46,7 +46,7 @@ namespace Umbraco.Tests.Migrations throw new NotImplementedException(); } - + public IScopeContext Context { get; set; } public ISqlContext SqlContext { get; set; } @@ -63,7 +63,7 @@ namespace Umbraco.Tests.Migrations [Test] public void RunGoodMigration() { - var migrationContext = new MigrationContext(Mock.Of(), Mock.Of()); + var migrationContext = new MigrationContext(Mock.Of(), Mock.Of>()); IMigration migration = new GoodMigration(migrationContext); migration.Migrate(); } @@ -71,7 +71,7 @@ namespace Umbraco.Tests.Migrations [Test] public void DetectBadMigration1() { - var migrationContext = new MigrationContext(Mock.Of(), Mock.Of()); + var migrationContext = new MigrationContext(Mock.Of(), Mock.Of>()); IMigration migration = new BadMigration1(migrationContext); Assert.Throws(() => migration.Migrate()); } @@ -79,7 +79,7 @@ namespace Umbraco.Tests.Migrations [Test] public void DetectBadMigration2() { - var migrationContext = new MigrationContext(Mock.Of(), Mock.Of()); + var migrationContext = new MigrationContext(Mock.Of(), Mock.Of>()); IMigration migration = new BadMigration2(migrationContext); Assert.Throws(() => migration.Migrate()); } diff --git a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs index d9dcbc1d34..ba265b3fd2 100644 --- a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs @@ -1,8 +1,9 @@ using System; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Logging; using Moq; using NPoco; using NUnit.Framework; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; @@ -17,11 +18,10 @@ namespace Umbraco.Tests.Migrations [TestFixture] public class PostMigrationTests { + private static ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; [Test] public void ExecutesPlanPostMigration() { - var logger = Mock.Of(); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -54,7 +54,7 @@ namespace Umbraco.Tests.Migrations TestPostMigration.MigrateCount = 0; var upgrader = new Upgrader(plan); - upgrader.Execute(scopeProvider, builder, Mock.Of(), logger); + upgrader.Execute(scopeProvider, builder, Mock.Of(), _loggerFactory.CreateLogger(), _loggerFactory); Assert.AreEqual(1, TestPostMigration.MigrateCount); } @@ -62,8 +62,6 @@ namespace Umbraco.Tests.Migrations [Test] public void MigrationCanAddPostMigration() { - var logger = Mock.Of(); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -97,10 +95,10 @@ namespace Umbraco.Tests.Migrations TestMigration.MigrateCount = 0; TestPostMigration.MigrateCount = 0; - new MigrationContext(database, logger); + new MigrationContext(database, _loggerFactory.CreateLogger()); var upgrader = new Upgrader(plan); - upgrader.Execute(scopeProvider, builder, Mock.Of(), logger); + upgrader.Execute(scopeProvider, builder, Mock.Of(), _loggerFactory.CreateLogger(), _loggerFactory); Assert.AreEqual(1, TestMigration.MigrateCount); Assert.AreEqual(1, TestPostMigration.MigrateCount); diff --git a/src/Umbraco.Tests/Models/ContentExtensionsTests.cs b/src/Umbraco.Tests/Models/ContentExtensionsTests.cs index bab3a540be..ae59e377d0 100644 --- a/src/Umbraco.Tests/Models/ContentExtensionsTests.cs +++ b/src/Umbraco.Tests/Models/ContentExtensionsTests.cs @@ -1,11 +1,11 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -25,14 +25,12 @@ namespace Umbraco.Tests.Models { base.Compose(); - Composition.Register(_ => Mock.Of()); 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" }; + var editor = new TextboxPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), IOHelper, ShortStringHelper, LocalizedTextService) { Alias = "test" }; Composition.Register(_ => new DataEditorCollection(new[] { editor })); Composition.Register(); var dataType = Mock.Of(); diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index 31e928159b..8fb3f60cc8 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -4,14 +4,13 @@ using System.Diagnostics; using System.Globalization; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using Newtonsoft.Json; using Umbraco.Core; using NUnit.Framework; using Umbraco.Core.Cache; -using Umbraco.Core.Composing; using Umbraco.Core.Composing.CompositionExtensions; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -22,7 +21,6 @@ using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; using Umbraco.Web.PropertyEditors; -using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Models { @@ -35,14 +33,12 @@ namespace Umbraco.Tests.Models { base.Compose(); - Composition.Register(_ => Mock.Of()); 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" }; + var editor = new TextboxPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), IOHelper, ShortStringHelper, LocalizedTextService) { Alias = "test" }; Composition.Register(_ => new DataEditorCollection(new [] { editor })); Composition.Register(); var dataType = Mock.Of(); @@ -237,7 +233,7 @@ namespace Umbraco.Tests.Models private static IProfilingLogger GetTestProfilingLogger() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); + var logger = NullLoggerFactory.Instance.CreateLogger("ProfilingLogger"); var profiler = new TestProfiler(); return new ProfilingLogger(logger, profiler); } diff --git a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs b/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs index a5b059cd23..a44d240ea9 100644 --- a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs +++ b/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs @@ -1,24 +1,5 @@ -using System; -using System.Globalization; -using Moq; -using Newtonsoft.Json; -using NUnit.Framework; -using Newtonsoft.Json.Linq; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; +using NUnit.Framework; using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.PropertyEditors.ValueConverters; -using Umbraco.Core.Services; -using Umbraco.Tests.Components; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web; -using Umbraco.Web.PropertyEditors; -using System.Text; using Umbraco.Infrastructure.Media; using Umbraco.Web.Models; diff --git a/src/Umbraco.Tests/Models/MediaXmlTest.cs b/src/Umbraco.Tests/Models/MediaXmlTest.cs index 632f433c5b..646dc7f2a0 100644 --- a/src/Umbraco.Tests/Models/MediaXmlTest.cs +++ b/src/Umbraco.Tests/Models/MediaXmlTest.cs @@ -1,14 +1,15 @@ using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Core.Strings; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -29,12 +30,12 @@ namespace Umbraco.Tests.Models // reference, so static ctor runs, so event handlers register // and then, this will reset the width, height... because the file does not exist, of course ;-( - var logger = Mock.Of(); + var loggerFactory = NullLoggerFactory.Instance; var scheme = Mock.Of(); - var config = Mock.Of(); + var contentSettings = new ContentSettings(); - var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, logger, ShortStringHelper); - var ignored = new FileUploadPropertyEditor(Mock.Of(), mediaFileSystem, config, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper); + var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, loggerFactory.CreateLogger(), ShortStringHelper); + var ignored = new FileUploadPropertyEditor(loggerFactory, mediaFileSystem, Microsoft.Extensions.Options.Options.Create(contentSettings), DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties); 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..df63461f4d 100644 --- a/src/Umbraco.Tests/Models/VariationTests.cs +++ b/src/Umbraco.Tests/Models/VariationTests.cs @@ -1,15 +1,15 @@ using System; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; -using ILogger = Umbraco.Core.Logging.ILogger; +using Umbraco.Tests.TestHelpers.Entities; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Models @@ -23,9 +23,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 +30,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 +37,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(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) { Alias = "editor", ExplicitValueEditor = MockedValueEditors.CreateDataValueEditor("view") } }); var propertyEditors = new PropertyEditorCollection(dataEditors); @@ -65,7 +58,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/PackageDataInstallationTests.cs b/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs index d089c4aaa2..6aaab9a698 100644 --- a/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs +++ b/src/Umbraco.Tests/Packaging/PackageDataInstallationTests.cs @@ -2,22 +2,23 @@ using System.Linq; using System.Threading; using System.Xml.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; +using Umbraco.Core.Composing.CompositionExtensions; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +using Umbraco.Core.Strings; using Umbraco.Tests.Services; using Umbraco.Tests.Services.Importing; using Umbraco.Tests.Testing; -using Umbraco.Core.Composing.CompositionExtensions; -using Umbraco.Core.Strings; namespace Umbraco.Tests.Packaging { @@ -31,8 +32,8 @@ namespace Umbraco.Tests.Packaging [DataEditor("7e062c13-7c41-4ad9-b389-41d88aeef87c", "Editor1", "editor1")] public class Editor1 : DataEditor { - public Editor1(ILogger logger) - : base(logger, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) + public Editor1(ILoggerFactory loggerFactory) + : base(loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) { } } @@ -41,8 +42,8 @@ namespace Umbraco.Tests.Packaging [DataEditor("d15e1281-e456-4b24-aa86-1dda3e4299d5", "Editor2", "editor2")] public class Editor2 : DataEditor { - public Editor2(ILogger logger) - : base(logger, Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of()) + public Editor2(ILoggerFactory loggerFactory) + : base(loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of()) { } } @@ -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 GlobalSettings(); + 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..4dfc3503aa 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -2,14 +2,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; -using Umbraco.Core.Models; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; @@ -46,18 +45,21 @@ 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 GlobalSettings())); private PackageDataInstallation PackageDataInstallation => new PackageDataInstallation( - Logger, ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, + NullLoggerFactory.Instance.CreateLogger(), NullLoggerFactory.Instance, ServiceContext.FileService, ServiceContext.MacroService, ServiceContext.LocalizationService, ServiceContext.DataTypeService, ServiceContext.EntityService, ServiceContext.ContentTypeService, ServiceContext.ContentService, Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), - Factory.GetInstance(), - Factory.GetInstance() - ); + Microsoft.Extensions.Options.Options.Create(new GlobalSettings()), + Factory.GetInstance()); private IPackageInstallation PackageInstallation => new PackageInstallation( PackageDataInstallation, @@ -122,7 +124,7 @@ namespace Umbraco.Tests.Packaging public void Can_Read_Compiled_Package_Warnings() { //copy a file to the same path that the package will install so we can detect file conflicts - + var filePath = Path.Combine(_testBaseFolder.FullName, "bin", "Auros.DocumentTypePicker.dll"); Directory.CreateDirectory(Path.GetDirectoryName(filePath)); File.WriteAllText(filePath, "test"); diff --git a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs index ba9bd19db5..a69eaf849f 100644 --- a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs +++ b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs @@ -3,20 +3,21 @@ using System.Configuration; using System.Data.SqlServerCe; using System.IO; using System.Threading; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NPoco; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Migrations.Install; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; -using Umbraco.Core.Services; using Umbraco.Persistance.SqlCe; using Umbraco.Tests.TestHelpers; -using Umbraco.Web.Security; namespace Umbraco.Tests.Persistence { @@ -25,7 +26,8 @@ namespace Umbraco.Tests.Persistence public class DatabaseContextTests { private IUmbracoDatabaseFactory _databaseFactory; - private ILogger _logger; + private ILogger _logger; + private ILoggerFactory _loggerFactory; private SqlCeSyntaxProvider _sqlCeSyntaxProvider; private ISqlSyntaxProvider[] _sqlSyntaxProviders; private IUmbracoVersion _umbracoVersion; @@ -36,11 +38,12 @@ namespace Umbraco.Tests.Persistence // create the database factory and database context _sqlCeSyntaxProvider = new SqlCeSyntaxProvider(); _sqlSyntaxProviders = new[] { (ISqlSyntaxProvider) _sqlCeSyntaxProvider }; - _logger = Mock.Of(); + _logger = Mock.Of>(); + _loggerFactory = NullLoggerFactory.Instance; _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 GlobalSettings(); + var connectionStrings = new ConnectionStrings(); + _databaseFactory = new UmbracoDatabaseFactory(_logger, _loggerFactory, Options.Create(globalSettings), Options.Create(connectionStrings), new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); } [TearDown] @@ -73,7 +76,7 @@ namespace Umbraco.Tests.Persistence } // re-create the database factory and database context with proper connection string - _databaseFactory = new UmbracoDatabaseFactory(_logger, connString, Constants.DbProviderNames.SqlCe, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); + _databaseFactory = new UmbracoDatabaseFactory(_logger, NullLoggerFactory.Instance, connString, Constants.DbProviderNames.SqlCe, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); // test get database type (requires an actual database) using (var database = _databaseFactory.CreateDatabase()) @@ -94,7 +97,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, _loggerFactory.CreateLogger(), _loggerFactory, _umbracoVersion); schemaHelper.InitializeDatabaseSchema(); transaction.Complete(); } diff --git a/src/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs b/src/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs index bab0617ec6..fd3b525039 100644 --- a/src/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs +++ b/src/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs @@ -1,9 +1,10 @@ using System; using System.Data.SqlClient; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; @@ -20,7 +21,7 @@ namespace Umbraco.Tests.Persistence.FaultHandling { const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=x;password=umbraco"; const string providerName = Constants.DbProviderNames.SqlServer; - var factory = new UmbracoDatabaseFactory(Mock.Of(), connectionString, providerName, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); + var factory = new UmbracoDatabaseFactory(Mock.Of>(), NullLoggerFactory.Instance, connectionString, providerName, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); using (var database = factory.CreateDatabase()) { @@ -34,7 +35,7 @@ namespace Umbraco.Tests.Persistence.FaultHandling { const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=umbraco;password=umbraco"; const string providerName = Constants.DbProviderNames.SqlServer; - var factory = new UmbracoDatabaseFactory(Mock.Of(), connectionString, providerName, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); + var factory = new UmbracoDatabaseFactory(Mock.Of>(), NullLoggerFactory.Instance, connectionString, providerName, new Lazy(() => Mock.Of()), TestHelper.DbProviderFactoryCreator); using (var database = factory.CreateDatabase()) { diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoBulkInsertTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoBulkInsertTests.cs index 6c4a23fa00..5a0e4b6ed2 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoBulkInsertTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoBulkInsertTests.cs @@ -3,8 +3,9 @@ using System.Collections.Generic; using System.Data; using System.Linq; using System.Text.RegularExpressions; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Tests.TestHelpers; @@ -18,7 +19,7 @@ namespace Umbraco.Tests.Persistence.NPocoTests [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class NPocoBulkInsertTests : TestWithDatabaseBase { - + [NUnit.Framework.Ignore("Ignored because you need to configure your own SQL Server to test thsi with")] [Test] @@ -27,7 +28,7 @@ namespace Umbraco.Tests.Persistence.NPocoTests // create the db // prob not what we want, this is not a real database, but hey, the test is ignored anyways // we'll fix this when we have proper testing infrastructure - var dbSqlServer = TestObjects.GetUmbracoSqlServerDatabase(new DebugDiagnosticsLogger(new MessageTemplates())); + var dbSqlServer = TestObjects.GetUmbracoSqlServerDatabase(new NullLogger()); //drop the table dbSqlServer.Execute("DROP TABLE [umbracoServer]"); diff --git a/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs b/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs index 656e34846a..3da803505f 100644 --- a/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Tests.TestHelpers; using System.Linq; +using Microsoft.Extensions.Logging.Abstractions; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -26,7 +27,7 @@ namespace Umbraco.Tests.Persistence.Querying [Test] public void Equals_Claus_With_Two_Entity_Values() { - var dataType = new DataType(new VoidEditor(Mock.Of(), Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) + var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 12345 }; diff --git a/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs index 91d129aeeb..e09587fa8c 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DomainRepositoryTest.cs @@ -2,13 +2,16 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Configuration.UmbracoSettings; 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,25 +24,27 @@ 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 GlobalSettings()); + 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 templateRepository = new TemplateRepository(accessor, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); + var tagRepository = new TagRepository(accessor, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - languageRepository = new LanguageRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); - contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(accessor, Core.Cache.AppCaches.Disabled, Logger); + languageRepository = new LanguageRepository(accessor, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), globalSettings); + contentTypeRepository = new ContentTypeRepository(accessor, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var relationTypeRepository = new RelationTypeRepository(accessor, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(accessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - documentRepository = new DocumentRepository(accessor, Core.Cache.AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); - var domainRepository = new DomainRepository(accessor, Core.Cache.AppCaches.Disabled, Logger); + documentRepository = new DocumentRepository(accessor, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); + var domainRepository = new DomainRepository(accessor, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger()); return domainRepository; } private int CreateTestData(string isoName, out ContentType ct) { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -48,7 +53,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 GlobalSettings(); + var lang = new Language(globalSettings, isoName); langRepo.Save(lang); ct = MockedContentTypes.CreateBasicContentType("test", "Test"); @@ -66,7 +72,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -100,7 +106,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -132,7 +138,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -159,7 +165,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -190,7 +196,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId1 = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -203,7 +209,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 GlobalSettings(); + var lang2 = new Language(globalSettings, "es"); langRepo.Save(lang2); var content2 = new Content("test", -1, ct) { CreatorId = 0, WriterId = 0 }; documentRepo.Save(content2); @@ -237,7 +244,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -267,7 +274,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -297,7 +304,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -327,7 +334,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -359,7 +366,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -393,7 +400,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; @@ -442,7 +449,7 @@ namespace Umbraco.Tests.Persistence.Repositories ContentType ct; var contentId = CreateTestData("en-AU", out ct); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { DocumentRepository documentRepo; diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs index 83572180af..d5efa77606 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaRepositoryTest.cs @@ -1,21 +1,23 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Persistence.Repositories.Implement; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Scoping; +using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Persistence.Repositories.Implement; -using Umbraco.Core.Scoping; using Umbraco.Tests.Testing; -using Umbraco.Core.Services; -using Umbraco.Core; -using Umbraco.Core.PropertyEditors; namespace Umbraco.Tests.Persistence.Repositories { @@ -34,19 +36,19 @@ namespace Umbraco.Tests.Persistence.Repositories { appCaches = appCaches ?? AppCaches; var scopeAccessor = (IScopeAccessor) provider; - - var templateRepository = new TemplateRepository(scopeAccessor, appCaches, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); + var globalSettings = new GlobalSettings(); + var templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(scopeAccessor, appCaches, Logger, TestObjects.GetGlobalSettings()); - mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, Logger, commonRepository, languageRepository, ShortStringHelper); - var tagRepository = new TagRepository(scopeAccessor, appCaches, Logger); - var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, Logger); + var languageRepository = new LanguageRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); + mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger()); + var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(scopeAccessor); - var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var mediaUrlGenerators = new MediaUrlGeneratorCollection(Enumerable.Empty()); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new MediaRepository(scopeAccessor, appCaches, Logger, mediaTypeRepository, tagRepository, Mock.Of(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService); + var repository = new MediaRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), LoggerFactory, mediaTypeRepository, tagRepository, Mock.Of(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService); return repository; } @@ -60,7 +62,7 @@ namespace Umbraco.Tests.Persistence.Repositories new DictionaryAppCache(), new IsolatedCaches(t => new ObjectCacheAppCache())); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider, out mediaTypeRepository, appCaches: realCache); @@ -102,7 +104,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void SaveMedia() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -129,7 +131,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void SaveMediaMultiple() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -158,7 +160,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetMediaIsNotDirty() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -177,7 +179,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void UpdateMedia() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -200,7 +202,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void DeleteMedia() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -223,7 +225,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetMedia() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -250,7 +252,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void QueryMedia() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -270,7 +272,7 @@ namespace Umbraco.Tests.Persistence.Repositories { // Arrange var folderMediaType = ServiceContext.MediaTypeService.Get(1031); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider, out MediaTypeRepository mediaTypeRepository); @@ -301,7 +303,7 @@ namespace Umbraco.Tests.Persistence.Repositories // Arrange var folderMediaType = ServiceContext.MediaTypeService.Get(1031); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider, out MediaTypeRepository mediaTypeRepository); @@ -327,7 +329,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetPagedResultsByQuery_FirstPage() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider, out MediaTypeRepository mediaTypeRepository); @@ -348,7 +350,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetPagedResultsByQuery_SecondPage() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -370,7 +372,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetPagedResultsByQuery_SinglePage() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -392,7 +394,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetPagedResultsByQuery_DescendingOrder() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -414,7 +416,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetPagedResultsByQuery_AlternateOrder() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -435,7 +437,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetPagedResultsByQuery_FilterMatchingSome() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -458,7 +460,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetPagedResultsByQuery_FilterMatchingAll() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider, out _); @@ -480,7 +482,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetAllMediaByIds() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -500,7 +502,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void GetAllMedia() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -530,7 +532,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void ExistMedia() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; @@ -552,7 +554,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void CountMedia() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MediaTypeRepository mediaTypeRepository; diff --git a/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs index 6ffbdaca10..b9b64bdd5d 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MediaTypeRepositoryTest.cs @@ -1,8 +1,10 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; 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; @@ -21,22 +23,23 @@ namespace Umbraco.Tests.Persistence.Repositories private MediaTypeRepository CreateRepository(IScopeProvider provider) { var cacheHelper = AppCaches.Disabled; - var templateRepository = new TemplateRepository((IScopeAccessor)provider, cacheHelper, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); + var globalSettings = new GlobalSettings(); + var templateRepository = new TemplateRepository((IScopeAccessor)provider, cacheHelper, LoggerFactory.CreateLogger(), TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches, Logger, TestObjects.GetGlobalSettings()); - return new MediaTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); + var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); + return new MediaTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); } private EntityContainerRepository CreateContainerRepository(IScopeProvider provider) { - return new EntityContainerRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger, Constants.ObjectTypes.MediaTypeContainer); + return new EntityContainerRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), Constants.ObjectTypes.MediaTypeContainer); } [Test] public void Can_Move() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var containerRepository = CreateContainerRepository(provider); @@ -83,7 +86,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Create_Container() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var containerRepository = CreateContainerRepository(provider); @@ -101,7 +104,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Delete_Container() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var containerRepository = CreateContainerRepository(provider); @@ -123,7 +126,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Create_Container_Containing_Media_Types() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var containerRepository = CreateContainerRepository(provider); @@ -145,7 +148,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Delete_Container_Containing_Media_Types() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var containerRepository = CreateContainerRepository(provider); @@ -177,7 +180,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Add_On_MediaTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -205,7 +208,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Update_On_MediaTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -243,7 +246,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Delete_On_MediaTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -268,7 +271,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Get_On_MediaTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -287,7 +290,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Get_By_Guid_On_MediaTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -308,7 +311,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetAll_On_MediaTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -330,7 +333,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetAll_By_Guid_On_MediaTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -356,7 +359,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Exists_On_MediaTypeRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -373,7 +376,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Update_MediaType_With_PropertyType_Removed() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -401,7 +404,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_PropertyTypes_On_Video_MediaType() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -423,7 +426,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Verify_PropertyTypes_On_File_MediaType() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index b8c823f59e..04bf37c8d8 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -1,14 +1,13 @@ using System; using System.Diagnostics; using System.Linq; -using System.Xml.Linq; +using Microsoft.Extensions.Logging; using Moq; using NPoco; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; @@ -30,25 +29,26 @@ namespace Umbraco.Tests.Persistence.Repositories private MemberRepository CreateRepository(IScopeProvider provider, out MemberTypeRepository memberTypeRepository, out MemberGroupRepository memberGroupRepository) { var accessor = (IScopeAccessor) provider; + var globalSettings = new GlobalSettings(); var templateRepository = Mock.Of(); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); - 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); - var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); + memberTypeRepository = new MemberTypeRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + memberGroupRepository = new MemberGroupRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); + var tagRepo = new TagRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); + var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(accessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new MemberRepository(accessor, AppCaches.Disabled, Logger, memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of(), relationRepository, relationTypeRepository, PasswordHasher, propertyEditors, dataValueReferences, DataTypeService); + var repository = new MemberRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of(), relationRepository, relationTypeRepository, PasswordHasher, propertyEditors, dataValueReferences, DataTypeService); return repository; } [Test] public void GetMember() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -67,7 +67,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetMembers() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -90,7 +90,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void GetAllMembers() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -116,7 +116,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void QueryMember() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -139,7 +139,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void SaveMember() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -164,7 +164,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void MemberHasBuiltinProperties() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -196,7 +196,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void SavingPreservesPassword() { IMember sut; - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -226,7 +226,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void SavingUpdatesNameAndEmail() { IMember sut; - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -256,7 +256,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void QueryMember_WithSubQuery() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); var query = provider.SqlContext.Query().Where(x => ((Member) x).LongStringPropertyValue.Contains("1095") && @@ -276,7 +276,7 @@ namespace Umbraco.Tests.Persistence.Repositories private IMember CreateTestMember(IMemberType memberType = null, string name = null, string email = null, string password = null, string username = null, Guid? key = null) { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -300,7 +300,7 @@ namespace Umbraco.Tests.Persistence.Repositories private IMemberType CreateTestMemberType(string alias = null) { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { MemberTypeRepository memberTypeRepository; @@ -316,7 +316,7 @@ namespace Umbraco.Tests.Persistence.Repositories private Sql GetBaseQuery(bool isCount) { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); if (isCount) { var sqlCount = provider.SqlContext.Sql() @@ -356,7 +356,7 @@ namespace Umbraco.Tests.Persistence.Repositories private Sql GetSubquery() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); var sql = provider.SqlContext.Sql(); sql.Select("umbracoNode.id") .From() diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs index b8c60f97fe..0a89c2dbe7 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs @@ -1,10 +1,11 @@ using System; using System.Linq; using Moq; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Repositories; @@ -23,15 +24,16 @@ namespace Umbraco.Tests.Persistence.Repositories private MemberTypeRepository CreateRepository(IScopeProvider provider) { var templateRepository = Mock.Of(); + var globalSettings = new GlobalSettings(); var commonRepository = new ContentTypeCommonRepository((IScopeAccessor)provider, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository((IScopeAccessor)provider, AppCaches.Disabled, Mock.Of(), TestObjects.GetGlobalSettings()); - return new MemberTypeRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of(), commonRepository, languageRepository, ShortStringHelper); + 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); } [Test] public void Can_Persist_Member_Type() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -57,7 +59,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Persist_Member_Type_Same_Property_Keys() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -83,7 +85,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Cannot_Persist_Member_Type_Without_Alias() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -99,7 +101,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_All_Member_Types() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -124,7 +126,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_All_Member_Types_By_Guid_Ids() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -149,7 +151,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Member_Types_By_Guid_Id() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -176,7 +178,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_All_Members_When_No_Properties_Assigned() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -203,7 +205,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Member_Type_By_Id() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -219,7 +221,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Member_Type_By_Guid_Id() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -238,7 +240,7 @@ namespace Umbraco.Tests.Persistence.Repositories { var stubs = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (provider.CreateScope()) { var repository = CreateRepository(provider); @@ -283,7 +285,7 @@ namespace Umbraco.Tests.Persistence.Repositories { var stubs = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (provider.CreateScope()) { var repository = CreateRepository(provider); @@ -314,7 +316,7 @@ namespace Umbraco.Tests.Persistence.Repositories { var stubs = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (provider.CreateScope()) { var repository = CreateRepository(provider); @@ -348,7 +350,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Built_In_Member_Type_Properties_Are_Not_Reused_For_Different_Member_Types() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); @@ -370,7 +372,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Delete_MemberType() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = CreateRepository(provider); diff --git a/src/Umbraco.Tests/Persistence/Repositories/PartialViewRepositoryTests.cs b/src/Umbraco.Tests/Persistence/Repositories/PartialViewRepositoryTests.cs index f7744303e3..3c1a003a15 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/PartialViewRepositoryTests.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/PartialViewRepositoryTests.cs @@ -1,4 +1,5 @@ using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -23,7 +24,7 @@ namespace Umbraco.Tests.Persistence.Repositories { base.SetUp(); - _fileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, Constants.SystemDirectories.MvcViews + "/Partials/"); + _fileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, LoggerFactory.CreateLogger(), Constants.SystemDirectories.MvcViews + "/Partials/"); } protected override void Compose() @@ -41,7 +42,7 @@ namespace Umbraco.Tests.Persistence.Repositories var fileSystems = Mock.Of(); Mock.Get(fileSystems).Setup(x => x.PartialViewsFileSystem).Returns(_fileSystem); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { var repository = new PartialViewRepository(fileSystems, IOHelper); diff --git a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs index 4ba2c3eab6..d2f606c973 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/PublicAccessRepositoryTest.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using Moq; +using Microsoft.Extensions.Logging; using NUnit.Framework; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Repositories.Implement; @@ -25,10 +25,10 @@ namespace Umbraco.Tests.Persistence.Repositories { var content = CreateTestData(3).ToArray(); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, LoggerFactory.CreateLogger()); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -54,11 +54,11 @@ namespace Umbraco.Tests.Persistence.Repositories { var content = CreateTestData(3).ToArray(); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { scope.Database.AsUmbracoDatabase().EnableSqlTrace = true; - var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, LoggerFactory.CreateLogger()); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -94,11 +94,11 @@ namespace Umbraco.Tests.Persistence.Repositories { var content = CreateTestData(3).ToArray(); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { scope.Database.AsUmbracoDatabase().EnableSqlTrace = true; - var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, LoggerFactory.CreateLogger()); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -140,10 +140,10 @@ namespace Umbraco.Tests.Persistence.Repositories { var content = CreateTestData(3).ToArray(); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, LoggerFactory.CreateLogger()); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -178,10 +178,10 @@ namespace Umbraco.Tests.Persistence.Repositories { var content = CreateTestData(3).ToArray(); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, LoggerFactory.CreateLogger()); var entry = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -206,10 +206,10 @@ namespace Umbraco.Tests.Persistence.Repositories { var content = CreateTestData(30).ToArray(); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, LoggerFactory.CreateLogger()); var allEntries = new List(); for (int i = 0; i < 10; i++) @@ -270,10 +270,10 @@ namespace Umbraco.Tests.Persistence.Repositories { var content = CreateTestData(3).ToArray(); - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { - var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, Logger); + var repo = new PublicAccessRepository((IScopeAccessor) provider, AppCaches, LoggerFactory.CreateLogger()); var entry1 = new PublicAccessEntry(content[0], content[1], content[2], new[] { @@ -306,23 +306,24 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, AppCaches, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); - var tagRepository = new TagRepository(accessor, AppCaches, Logger); + var globalSettings = new GlobalSettings(); + var templateRepository = new TemplateRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); + var tagRepository = new TagRepository(accessor, AppCaches, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, TestObjects.GetGlobalSettings()); - contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches, Logger); + var languageRepository = new LanguageRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); + contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(accessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); + var repository = new DocumentRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); return repository; } private IEnumerable CreateTestData(int count) { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { ContentTypeRepository ctRepo; diff --git a/src/Umbraco.Tests/Persistence/Repositories/ScriptRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ScriptRepositoryTest.cs index 7922af99b0..0a9632b9ad 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ScriptRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ScriptRepositoryTest.cs @@ -2,17 +2,20 @@ using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Logging; using Moq; 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 +33,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, LoggerFactory.CreateLogger(), new GlobalSettings().UmbracoScriptsPath); Mock.Get(_fileSystems).Setup(x => x.ScriptsFileSystem).Returns(_fileSystem); using (var stream = CreateStream("Umbraco.Sys.registerNamespace(\"Umbraco.Utils\");")) { @@ -40,7 +43,8 @@ namespace Umbraco.Tests.Persistence.Repositories private IScriptRepository CreateRepository() { - return new ScriptRepository(_fileSystems, IOHelper, TestObjects.GetGlobalSettings()); + var globalSettings = new GlobalSettings(); + return new ScriptRepository(_fileSystems, IOHelper, Microsoft.Extensions.Options.Options.Create(globalSettings)); } protected override void Compose() @@ -54,7 +58,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Instantiate_Repository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { // Act @@ -69,7 +73,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Add_On_ScriptRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); @@ -88,7 +92,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Update_On_ScriptRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); @@ -114,7 +118,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Delete_On_ScriptRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); @@ -134,7 +138,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Get_On_ScriptRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); @@ -153,7 +157,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetAll_On_ScriptRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); @@ -181,7 +185,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_GetAll_With_Params_On_ScriptRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); @@ -209,7 +213,7 @@ namespace Umbraco.Tests.Persistence.Repositories public void Can_Perform_Exists_On_ScriptRepository() { // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); @@ -228,7 +232,7 @@ namespace Umbraco.Tests.Persistence.Repositories const string content = "/// "; // Arrange - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); @@ -261,7 +265,7 @@ namespace Umbraco.Tests.Persistence.Repositories { // unless noted otherwise, no changes / 7.2.8 - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var repository = CreateRepository(); diff --git a/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs index f4558dca2d..2ba2e7679e 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/StylesheetRepositoryTest.cs @@ -3,15 +3,18 @@ using System.Data; using System.IO; using System.Linq; using System.Text; +using Microsoft.Extensions.Logging; using Moq; 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 +32,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, LoggerFactory.CreateLogger(), 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 +40,8 @@ namespace Umbraco.Tests.Persistence.Repositories private IStylesheetRepository CreateRepository() { - return new StylesheetRepository(_fileSystems, IOHelper, TestObjects.GetGlobalSettings()); + var globalSettings = new GlobalSettings(); + 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..5037541fae 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/TagRepositoryTest.cs @@ -1,10 +1,10 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.IO; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; @@ -23,7 +23,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Add_On_Repository() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var repository = CreateRepository(provider); @@ -43,7 +43,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Perform_Multiple_Adds_On_Repository() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var repository = CreateRepository(provider); @@ -73,7 +73,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Create_Tag_Relations() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -103,7 +103,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Append_Tag_Relations() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -142,7 +142,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Replace_Tag_Relations() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -184,7 +184,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Merge_Tag_Relations() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -224,7 +224,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Clear_Tag_Relations() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -260,7 +260,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Remove_Specific_Tags_From_Property() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -304,7 +304,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tags_For_Content_By_Id() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -348,7 +348,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tags_For_Content_By_Key() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -393,7 +393,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_All() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -428,7 +428,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_All_With_Ids() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -468,7 +468,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tags_For_Content_For_Group() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -512,7 +512,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tags_For_Property_By_Id() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -556,7 +556,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tags_For_Property_By_Key() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -600,7 +600,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tags_For_Property_For_Group() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -645,7 +645,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tags_For_Entity_Type() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -702,7 +702,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tags_For_Entity_Type_For_Group() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -754,7 +754,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Cascade_Deletes_Tag_Relations() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -790,7 +790,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tagged_Entities_For_Tag_Group() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -870,7 +870,7 @@ namespace Umbraco.Tests.Persistence.Repositories [Test] public void Can_Get_Tagged_Entities_For_Tag() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (ScopeProvider.CreateScope()) { var contentRepository = CreateDocumentRepository(provider, out var contentTypeRepository); @@ -949,41 +949,43 @@ namespace Umbraco.Tests.Persistence.Repositories private TagRepository CreateRepository(IScopeProvider provider) { - return new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, Logger); + return new TagRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger()); } private DocumentRepository CreateDocumentRepository(IScopeProvider provider, out ContentTypeRepository contentTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); - var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger); + var globalSettings = new GlobalSettings(); + var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); + var tagRepository = new TagRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches.Disabled, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); - contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); + contentTypeRepository = new ContentTypeRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(accessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new DocumentRepository(accessor, AppCaches.Disabled, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); + var repository = new DocumentRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); return repository; } private MediaRepository CreateMediaRepository(IScopeProvider provider, out MediaTypeRepository mediaTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); - var tagRepository = new TagRepository(accessor, AppCaches.Disabled, Logger); + var globalSettings = new GlobalSettings(); + var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); + var tagRepository = new TagRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches.Disabled, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetGlobalSettings()); - mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches.Disabled, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); + var languageRepository = new LanguageRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); + mediaTypeRepository = new MediaTypeRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(accessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var mediaUrlGenerators = new MediaUrlGeneratorCollection(Enumerable.Empty()); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new MediaRepository(accessor, AppCaches.Disabled, Logger, mediaTypeRepository, tagRepository, Mock.Of(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService); + var repository = new MediaRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, mediaTypeRepository, tagRepository, Mock.Of(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService); return repository; } } diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index fc7f4f4555..0cd26442be 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -1,20 +1,26 @@ -using System.Linq; +using System; +using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; 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.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 Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.Persistence.Mappers; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; using MockedUser = Umbraco.Tests.TestHelpers.Entities.MockedUser; namespace Umbraco.Tests.Persistence.Repositories @@ -28,18 +34,19 @@ namespace Umbraco.Tests.Persistence.Repositories private MediaRepository CreateMediaRepository(IScopeProvider provider, out IMediaTypeRepository mediaTypeRepository) { var accessor = (IScopeAccessor) provider; - var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); + var globalSettings = new GlobalSettings(); + var templateRepository = new TemplateRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, TestObjects.GetGlobalSettings()); - 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); + var languageRepository = new LanguageRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), 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, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(accessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var mediaUrlGenerators = new MediaUrlGeneratorCollection(Enumerable.Empty()); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new MediaRepository(accessor, AppCaches, Mock.Of(), mediaTypeRepository, tagRepository, Mock.Of(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService); + var repository = new MediaRepository(accessor, AppCaches, Mock.Of>(), LoggerFactory, mediaTypeRepository, tagRepository, Mock.Of(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService); return repository; } @@ -52,31 +59,131 @@ namespace Umbraco.Tests.Persistence.Repositories private DocumentRepository CreateContentRepository(IScopeProvider provider, out IContentTypeRepository contentTypeRepository, out ITemplateRepository templateRepository) { var accessor = (IScopeAccessor) provider; - templateRepository = new TemplateRepository(accessor, AppCaches, Logger, TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); - var tagRepository = new TagRepository(accessor, AppCaches, Logger); + var globalSettings = new GlobalSettings(); + templateRepository = new TemplateRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), TestObjects.GetFileSystemsMock(), IOHelper, ShortStringHelper); + var tagRepository = new TagRepository(accessor, AppCaches, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(accessor, templateRepository, AppCaches, ShortStringHelper); - var languageRepository = new LanguageRepository(accessor, AppCaches, Logger, TestObjects.GetGlobalSettings()); - contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, Logger, commonRepository, languageRepository, ShortStringHelper); - var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, Logger); + var languageRepository = new LanguageRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); + contentTypeRepository = new ContentTypeRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var relationTypeRepository = new RelationTypeRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(accessor); - var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository); + var relationRepository = new RelationRepository(accessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new DocumentRepository(accessor, AppCaches, Logger, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); + var repository = new DocumentRepository(accessor, AppCaches, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); return repository; } 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 GlobalSettings(); + var repository = new UserRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), Mappers, Microsoft.Extensions.Options.Options.Create(globalSettings), Microsoft.Extensions.Options.Options.Create(new UserPasswordConfigurationSettings()), new JsonNetSerializer()); return repository; } private UserGroupRepository CreateUserGroupRepository(IScopeProvider provider) { var accessor = (IScopeAccessor) provider; - return new UserGroupRepository(accessor, AppCaches.Disabled, Logger, ShortStringHelper); + return new UserGroupRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, ShortStringHelper); + } + + [Test] + public void Validate_Login_Session() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + var user = MockedUser.CreateUser(); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + repository.Save(user); + } + + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + var sessionId = repository.CreateLoginSession(user.Id, "1.2.3.4"); + + // manually update this record to be in the past + scope.Database.Execute(SqlContext.Sql() + .Update(u => u.Set(x => x.LoggedOutUtc, DateTime.UtcNow.AddDays(-100))) + .Where(x => x.SessionId == sessionId)); + + var isValid = repository.ValidateLoginSession(user.Id, sessionId); + Assert.IsFalse(isValid); + + // create a new one + sessionId = repository.CreateLoginSession(user.Id, "1.2.3.4"); + isValid = repository.ValidateLoginSession(user.Id, sessionId); + Assert.IsTrue(isValid); + } + } + + [Test] + public void Can_Perform_Add_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var user = MockedUser.CreateUser(); + + // Act + repository.Save(user); + + + // Assert + Assert.That(user.HasIdentity, Is.True); + } + } + + [Test] + public void Can_Perform_Multiple_Adds_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var user1 = MockedUser.CreateUser("1"); + var use2 = MockedUser.CreateUser("2"); + + // Act + repository.Save(user1); + + repository.Save(use2); + + + // Assert + Assert.That(user1.HasIdentity, Is.True); + Assert.That(use2.HasIdentity, Is.True); + } + } + + [Test] + public void Can_Verify_Fresh_Entity_Is_Not_Dirty() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var user = MockedUser.CreateUser(); + repository.Save(user); + + + // Act + var resolved = repository.Get((int)user.Id); + bool dirty = ((User)resolved).IsDirty(); + + // Assert + Assert.That(dirty, Is.False); + } } [Test] @@ -86,8 +193,8 @@ namespace Umbraco.Tests.Persistence.Repositories var mt = MockedContentTypes.CreateSimpleMediaType("testmedia", "TestMedia"); // Arrange - var provider = TestObjects.GetScopeProvider(Logger); - using (var scope = provider.CreateScope()) + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) { var userRepository = CreateRepository(provider); var contentRepository = CreateContentRepository(provider, out var contentTypeRepo); @@ -141,6 +248,272 @@ namespace Umbraco.Tests.Persistence.Repositories } } + [Test] + public void Can_Perform_Delete_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var user = MockedUser.CreateUser(); + + // Act + repository.Save(user); + + var id = user.Id; + + var repository2 = new UserRepository((IScopeAccessor) provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), + Mock.Of(), + Microsoft.Extensions.Options.Options.Create(new GlobalSettings()), + Microsoft.Extensions.Options.Options.Create(new UserPasswordConfigurationSettings()), + Mock.Of()); + + repository2.Delete(user); + + + var resolved = repository2.Get((int) id); + + // Assert + Assert.That(resolved, Is.Null); + } + } + + [Test] + public void Can_Perform_Get_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + var userGroupRepository = CreateUserGroupRepository(provider); + + var user = CreateAndCommitUserWithGroup(repository, userGroupRepository); + + // Act + var updatedItem = repository.Get(user.Id); + + // FIXME: this test cannot work, user has 2 sections but the way it's created, + // they don't show, so the comparison with updatedItem fails - fix! + + // Assert + AssertPropertyValues(updatedItem, user); + } + } + + [Test] + public void Can_Perform_GetByQuery_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + CreateAndCommitMultipleUsers(repository); + + // Act + var query = scope.SqlContext.Query().Where(x => x.Username == "TestUser1"); + var result = repository.Get(query); + + // Assert + Assert.That(result.Count(), Is.GreaterThanOrEqualTo(1)); + } + } + + [Test] + public void Can_Perform_GetAll_By_Param_Ids_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var users = CreateAndCommitMultipleUsers(repository); + + // Act + var result = repository.GetMany((int) users[0].Id, (int) users[1].Id); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Any(), Is.True); + Assert.That(result.Count(), Is.EqualTo(2)); + } + } + + [Test] + public void Can_Perform_GetAll_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + CreateAndCommitMultipleUsers(repository); + + // Act + var result = repository.GetMany(); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.Any(), Is.True); + Assert.That(result.Count(), Is.GreaterThanOrEqualTo(3)); + } + } + + [Test] + public void Can_Perform_Exists_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var users = CreateAndCommitMultipleUsers(repository); + + // Act + var exists = repository.Exists(users[0].Id); + + // Assert + Assert.That(exists, Is.True); + } + } + + [Test] + public void Can_Perform_Count_On_UserRepository() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var users = CreateAndCommitMultipleUsers(repository); + + // Act + var query = scope.SqlContext.Query().Where(x => x.Username == "TestUser1" || x.Username == "TestUser2"); + var result = repository.Count(query); + + // Assert + Assert.AreEqual(2, result); + } + } + + [Test] + public void Can_Get_Paged_Results_By_Query_And_Filter_And_Groups() + { + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var users = CreateAndCommitMultipleUsers(repository); + var query = provider.SqlContext.Query().Where(x => x.Username == "TestUser1" || x.Username == "TestUser2"); + + try + { + scope.Database.AsUmbracoDatabase().EnableSqlTrace = true; + scope.Database.AsUmbracoDatabase().EnableSqlCount = true; + + // Act + var result = repository.GetPagedResultsByQuery(query, 0, 10, out var totalRecs, user => user.Id, Direction.Ascending, + excludeUserGroups: new[] { Constants.Security.TranslatorGroupAlias }, + filter: provider.SqlContext.Query().Where(x => x.Id > -1)); + + // Assert + Assert.AreEqual(2, totalRecs); + } + finally + { + scope.Database.AsUmbracoDatabase().EnableSqlTrace = false; + scope.Database.AsUmbracoDatabase().EnableSqlCount = false; + } + } + + } + + [Test] + public void Can_Get_Paged_Results_With_Filter_And_Groups() + { + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + + var users = CreateAndCommitMultipleUsers(repository); + + try + { + scope.Database.AsUmbracoDatabase().EnableSqlTrace = true; + scope.Database.AsUmbracoDatabase().EnableSqlCount = true; + + // Act + var result = repository.GetPagedResultsByQuery(null, 0, 10, out var totalRecs, user => user.Id, Direction.Ascending, + includeUserGroups: new[] { Constants.Security.AdminGroupAlias, Constants.Security.SensitiveDataGroupAlias }, + excludeUserGroups: new[] { Constants.Security.TranslatorGroupAlias }, + filter: provider.SqlContext.Query().Where(x => x.Id == -1)); + + // Assert + Assert.AreEqual(1, totalRecs); + } + finally + { + scope.Database.AsUmbracoDatabase().EnableSqlTrace = false; + scope.Database.AsUmbracoDatabase().EnableSqlCount = false; + } + } + } + + [Test] + public void Can_Invalidate_SecurityStamp_On_Username_Change() + { + // Arrange + var provider = TestObjects.GetScopeProvider(LoggerFactory); + using (var scope = provider.CreateScope(autoComplete: true)) + { + var repository = CreateRepository(provider); + var userGroupRepository = CreateUserGroupRepository(provider); + + var user = CreateAndCommitUserWithGroup(repository, userGroupRepository); + var originalSecurityStamp = user.SecurityStamp; + + // Ensure when user generated a security stamp is present + Assert.That(user.SecurityStamp, Is.Not.Null); + Assert.That(user.SecurityStamp, Is.Not.Empty); + + // Update username + user.Username = user.Username + "UPDATED"; + repository.Save(user); + + // Get the user + var updatedUser = repository.Get(user.Id); + + // Ensure the Security Stamp is invalidated & no longer the same + Assert.AreNotEqual(originalSecurityStamp, updatedUser.SecurityStamp); + } + } + + private void AssertPropertyValues(IUser updatedItem, IUser originalUser) + { + Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id)); + Assert.That(updatedItem.Name, Is.EqualTo(originalUser.Name)); + Assert.That(updatedItem.Language, Is.EqualTo(originalUser.Language)); + Assert.That(updatedItem.IsApproved, Is.EqualTo(originalUser.IsApproved)); + Assert.That(updatedItem.RawPasswordValue, Is.EqualTo(originalUser.RawPasswordValue)); + Assert.That(updatedItem.IsLockedOut, Is.EqualTo(originalUser.IsLockedOut)); + Assert.IsTrue(updatedItem.StartContentIds.UnsortedSequenceEqual(originalUser.StartContentIds)); + Assert.IsTrue(updatedItem.StartMediaIds.UnsortedSequenceEqual(originalUser.StartMediaIds)); + Assert.That(updatedItem.Email, Is.EqualTo(originalUser.Email)); + Assert.That(updatedItem.Username, Is.EqualTo(originalUser.Username)); + Assert.That(updatedItem.AllowedSections.Count(), Is.EqualTo(originalUser.AllowedSections.Count())); + foreach (var allowedSection in originalUser.AllowedSections) + Assert.IsTrue(updatedItem.AllowedSections.Contains(allowedSection)); + } private static User CreateAndCommitUserWithGroup(IUserRepository repository, IUserGroupRepository userGroupRepository) { @@ -155,6 +528,16 @@ namespace Umbraco.Tests.Persistence.Repositories return user; } + private IUser[] CreateAndCommitMultipleUsers(IUserRepository repository) + { + var user1 = new UserBuilder().WithoutIdentity().WithSuffix("1").Build(); + var user2 = new UserBuilder().WithoutIdentity().WithSuffix("2").Build(); + var user3 = new UserBuilder().WithoutIdentity().WithSuffix("3").Build(); + repository.Save(user1); + repository.Save(user2); + repository.Save(user3); + return new IUser[] { user1, user2, user3 }; + } } } diff --git a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs index 0648e3bc21..fe4a1581d1 100644 --- a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs +++ b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs @@ -1,10 +1,11 @@ using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; 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, LoggerFactory.CreateLogger(), LoggerFactory, 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..54d6b828be 100644 --- a/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs +++ b/src/Umbraco.Tests/Persistence/SqlCeTableByTableTest.cs @@ -1,11 +1,14 @@ -using Moq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; using NPoco; using NUnit.Framework; using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; 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 +19,15 @@ namespace Umbraco.Tests.Persistence [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class SqlCeTableByTableTest : TestWithDatabaseBase { - public IGlobalSettings GlobalSettings => SettingsForTests.GenerateMockGlobalSettings(); + public GlobalSettings GlobalSettings => new GlobalSettings(); + private static ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; [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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); @@ -36,7 +40,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -50,7 +54,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -65,7 +69,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -79,7 +83,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -94,7 +98,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -108,7 +112,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -124,7 +128,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -140,7 +144,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -154,7 +158,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); @@ -167,7 +171,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -182,7 +186,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -196,7 +200,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -213,7 +217,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -229,7 +233,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -243,7 +247,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); @@ -256,7 +260,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); @@ -269,7 +273,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); @@ -282,7 +286,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -298,7 +302,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -315,7 +319,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -330,7 +334,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -347,7 +351,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -365,7 +369,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -382,7 +386,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -397,7 +401,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -412,7 +416,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); @@ -425,7 +429,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); @@ -438,7 +442,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -459,7 +463,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); @@ -472,7 +476,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -486,7 +490,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -500,7 +504,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); @@ -515,7 +519,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, _loggerFactory.CreateLogger(), _loggerFactory, UmbracoVersion); helper.CreateTable(); helper.CreateTable(); diff --git a/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs b/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs index 1d87bb35e7..a43e912ddf 100644 --- a/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs +++ b/src/Umbraco.Tests/Persistence/SyntaxProvider/SqlCeSyntaxProviderTests.cs @@ -1,10 +1,10 @@ using System; using System.Diagnostics; +using Microsoft.Extensions.Logging; using Moq; using NPoco; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Expressions.Common.Expressions; using Umbraco.Core.Migrations.Expressions.Create.Index; @@ -99,7 +99,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine, [Test] public void CreateIndexBuilder_SqlServer_NonClustered_CreatesNonClusteredIndex() { - var logger = Mock.Of(); + var logger = Mock.Of>(); var sqlSyntax = new SqlServerSyntaxProvider(); var db = new TestDatabase(DatabaseType.SqlServer2005, sqlSyntax); var context = new MigrationContext(db, logger); @@ -120,7 +120,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine, [Test] public void CreateIndexBuilder_SqlServer_Unique_CreatesUniqueNonClusteredIndex() { - var logger = Mock.Of(); + var logger = Mock.Of>(); var sqlSyntax = new SqlServerSyntaxProvider(); var db = new TestDatabase(DatabaseType.SqlServer2005, sqlSyntax); var context = new MigrationContext(db, logger); @@ -141,7 +141,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine, [Test] public void CreateIndexBuilder_SqlServer_Unique_CreatesUniqueNonClusteredIndex_Multi_Columnn() { - var logger = Mock.Of(); + var logger = Mock.Of>(); var sqlSyntax = new SqlServerSyntaxProvider(); var db = new TestDatabase(DatabaseType.SqlServer2005, sqlSyntax); var context = new MigrationContext(db, logger); @@ -162,7 +162,7 @@ WHERE (([umbracoNode].[nodeObjectType] = @0))) x)".Replace(Environment.NewLine, [Test] public void CreateIndexBuilder_SqlServer_Clustered_CreatesClusteredIndex() { - var logger = Mock.Of(); + var logger = Mock.Of>(); var sqlSyntax = new SqlServerSyntaxProvider(); var db = new TestDatabase(DatabaseType.SqlServer2005, sqlSyntax); var context = new MigrationContext(db, logger); diff --git a/src/Umbraco.Tests/Persistence/UnitOfWorkTests.cs b/src/Umbraco.Tests/Persistence/UnitOfWorkTests.cs index 02ad6b3971..68c11e221d 100644 --- a/src/Umbraco.Tests/Persistence/UnitOfWorkTests.cs +++ b/src/Umbraco.Tests/Persistence/UnitOfWorkTests.cs @@ -13,7 +13,7 @@ namespace Umbraco.Tests.Persistence [Test] public void ReadLockNonExisting() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); Assert.Throws(() => { using (var scope = provider.CreateScope()) @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Persistence [Test] public void ReadLockExisting() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { scope.ReadLock(Constants.Locks.Servers); @@ -38,7 +38,7 @@ namespace Umbraco.Tests.Persistence [Test] public void WriteLockNonExisting() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); Assert.Throws(() => { using (var scope = provider.CreateScope()) @@ -52,7 +52,7 @@ namespace Umbraco.Tests.Persistence [Test] public void WriteLockExisting() { - var provider = TestObjects.GetScopeProvider(Logger); + var provider = TestObjects.GetScopeProvider(LoggerFactory); using (var scope = provider.CreateScope()) { scope.WriteLock(Constants.Locks.Servers); diff --git a/src/Umbraco.Tests/Properties/AssemblyInfo.cs b/src/Umbraco.Tests/Properties/AssemblyInfo.cs index 610ff433ee..ec1ddca2f8 100644 --- a/src/Umbraco.Tests/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Tests/Properties/AssemblyInfo.cs @@ -34,3 +34,8 @@ using System.Runtime.InteropServices; // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] + +// Internals must be visible to DynamicProxyGenAssembly2 +// in order to mock loggers loggers with types from the assembly +// I.E. Mock.Of>() +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/src/Umbraco.Tests/Published/ConvertersTests.cs b/src/Umbraco.Tests/Published/ConvertersTests.cs index 3ecae51ea8..3ddefd9fa5 100644 --- a/src/Umbraco.Tests/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests/Published/ConvertersTests.cs @@ -1,179 +1,29 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; 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; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; 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 +32,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(), Mock.Of(), Mock.Of(), AppCaches.NoCache); composition.WithCollectionBuilder() .Append() @@ -192,7 +42,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 +58,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(NullLoggerFactory.Instance, dataTypeServiceMock.Object, + Mock.Of(), Mock.Of(), Mock.Of())) + { Id = 1 }; + var dataType2 = new DataType(new VoidEditor("2", NullLoggerFactory.Instance, 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 +114,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..8fb072674a 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] @@ -53,36 +36,8 @@ namespace Umbraco.Tests.Published // there's an "*" there because the arrays are not true SZArray - but that changes when we map Assert.AreEqual("{alias1}[*]", ModelType.For("alias1").MakeArrayType().FullName); // note the inner assembly qualified name - 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); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[{alias1}[*], Umbraco.Core, Version=0.5.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..72f7d0e46c 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs @@ -2,16 +2,16 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Legacy; +using Umbraco.Core.Configuration.Models; 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 +22,6 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; using Umbraco.Tests.Common; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; @@ -60,12 +59,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); @@ -73,7 +67,7 @@ namespace Umbraco.Tests.PublishedContent Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); // create data types, property types and content types - var dataType = new DataType(new VoidEditor("Editor", Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 3 }; + var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 3 }; var dataTypes = new[] { @@ -145,8 +139,9 @@ namespace Umbraco.Tests.PublishedContent _source = new TestDataSource(kits()); var typeFinder = TestHelper.GetTypeFinder(); - var settings = Mock.Of(); + var globalSettings = new GlobalSettings(); + var nuCacheSettings = new NuCacheSettings(); // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; @@ -158,20 +153,21 @@ namespace Umbraco.Tests.PublishedContent _snapshotAccessor, _variationAccesor, Mock.Of(), + NullLoggerFactory.Instance, scopeProvider.Object, Mock.Of(), Mock.Of(), 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..6b97f4d1ed 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -2,14 +2,14 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Legacy; +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,7 +20,6 @@ using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; using Umbraco.Tests.Common; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing.Objects; using Umbraco.Web; @@ -53,12 +52,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); @@ -123,7 +116,7 @@ namespace Umbraco.Tests.PublishedContent Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); // create data types, property types and content types - var dataType = new DataType(new VoidEditor("Editor", Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 3 }; + var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 3 }; var dataTypes = new[] { @@ -186,7 +179,9 @@ namespace Umbraco.Tests.PublishedContent _variationAccesor = new TestVariationContextAccessor(); var typeFinder = TestHelper.GetTypeFinder(); - var settings = Mock.Of(); + + var globalSettings = new GlobalSettings(); + var nuCacheSettings = new NuCacheSettings(); // at last, create the complete NuCache snapshot service! var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; @@ -198,20 +193,21 @@ namespace Umbraco.Tests.PublishedContent new TestPublishedSnapshotAccessor(), _variationAccesor, Mock.Of(), + NullLoggerFactory.Instance, scopeProvider, Mock.Of(), Mock.Of(), 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/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index 2d05a8eda1..9010ed1a6a 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Web.Composing; @@ -127,7 +128,7 @@ namespace Umbraco.Tests.PublishedContent private IPublishedContent GetContent(bool createChildren, int indexVals) { 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(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var contentTypeAlias = createChildren ? "Parent" : "Child"; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs index 8c1024351b..d02a49385d 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentLanguageVariantTests.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.Linq; using Moq; using NUnit.Framework; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; @@ -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 GlobalSettings(); 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..92e17ec9cd 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -2,6 +2,8 @@ using System.IO; using System.Linq; using System.Web.Routing; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; @@ -43,14 +45,14 @@ 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) + protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger , IHostingEnvironment hostingEnvironment) { - var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment); + var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment); - return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false, + return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, profilingLogger , false, // this is so the model factory looks into the test assembly baseLoader.AssembliesToScan .Union(new[] {typeof(PublishedContentMoreTests).Assembly}) @@ -74,7 +76,7 @@ namespace Umbraco.Tests.PublishedContent var umbracoContext = new UmbracoContext( httpContextAccessor, publishedSnapshotService.Object, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), @@ -94,7 +96,7 @@ namespace Umbraco.Tests.PublishedContent private SolidPublishedSnapshot CreatePublishedSnapshot() { 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(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var caches = new SolidPublishedSnapshot(); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index dc23b29c69..058cda093e 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; @@ -44,14 +46,14 @@ namespace Umbraco.Tests.PublishedContent var converters = Factory.GetInstance(); var umbracoContextAccessor = Mock.Of(); var publishedUrlProvider = Mock.Of(); - var logger = Mock.Of(); + var loggerFactory = NullLoggerFactory.Instance; var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); - var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, IOHelper, Mock.Of(), Mock.Of(), Mock.Of(), ShortStringHelper, publishedUrlProvider); + var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), IOHelper, Mock.Of(), Mock.Of(), Mock.Of(), ShortStringHelper, publishedUrlProvider); var localLinkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); var dataTypeService = new TestObjects.TestDataTypeService( new DataType(new RichTextPropertyEditor( - Mock.Of(), + loggerFactory, Mock.Of(), Mock.Of(), Mock.Of(), diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 81b9318c57..982be79a33 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; @@ -42,28 +44,28 @@ 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(); - var logger = Mock.Of(); + var loggerFactory = NullLoggerFactory.Instance; var mediaService = Mock.Of(); var mediaFileService = Mock.Of(); var contentTypeBaseServiceProvider = Mock.Of(); var umbracoContextAccessor = Mock.Of(); var publishedUrlProvider = Mock.Of(); var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); - var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, IOHelper, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper, publishedUrlProvider); + var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), IOHelper, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper, publishedUrlProvider); var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); var localizationService = Mock.Of(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(logger, Mock.Of(), localizationService, LocalizedTextService, ShortStringHelper)) { Id = 1 }, - new DataType(new TrueFalsePropertyEditor(logger, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1001 }, - new DataType(new RichTextPropertyEditor(logger,umbracoContextAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of())) { Id = 1002 }, - new DataType(new IntegerPropertyEditor(logger, Mock.Of(), localizationService, ShortStringHelper, LocalizedTextService)) { Id = 1003 }, - new DataType(new TextboxPropertyEditor(logger, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1004 }, - new DataType(new MediaPickerPropertyEditor(logger, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1005 }); + new DataType(new VoidEditor(loggerFactory, Mock.Of(), localizationService, LocalizedTextService, ShortStringHelper)) { Id = 1 }, + new DataType(new TrueFalsePropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1001 }, + new DataType(new RichTextPropertyEditor(loggerFactory,umbracoContextAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of())) { Id = 1002 }, + new DataType(new IntegerPropertyEditor(loggerFactory, Mock.Of(), localizationService, ShortStringHelper, LocalizedTextService)) { Id = 1003 }, + new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1004 }, + new DataType(new MediaPickerPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1005 }); Composition.RegisterUnique(f => dataTypeService); } @@ -95,11 +97,11 @@ namespace Umbraco.Tests.PublishedContent } - protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IProfilingLogger logger, IHostingEnvironment hostingEnvironment) + protected override TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger , IHostingEnvironment hostingEnvironment) { - var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment); + var baseLoader = base.CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment); - return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false, + return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, profilingLogger , false, // this is so the model factory looks into the test assembly baseLoader.AssembliesToScan .Union(new[] { typeof(PublishedContentTests).Assembly }) @@ -241,7 +243,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 +251,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..8a47d9b25a 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -1,24 +1,21 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Web.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.Web; 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 +44,7 @@ namespace Umbraco.Tests.PublishedContent { } } - class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache + public class SolidPublishedContentCache : PublishedCacheBase, IPublishedContentCache, IPublishedMediaCache { private readonly Dictionary _content = new Dictionary(); @@ -164,7 +161,7 @@ namespace Umbraco.Tests.PublishedContent } } - internal class SolidPublishedContent : IPublishedContent + public class SolidPublishedContent : IPublishedContent { #region Constructor @@ -264,7 +261,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 +276,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 +353,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(NullLoggerFactory.Instance, 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..9860b5739f --- /dev/null +++ b/src/Umbraco.Tests/Routing/BaseUrlProviderTest.cs @@ -0,0 +1,45 @@ +using System.Linq; +using Moq; +using Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Tests.Common; +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 ContentSettings(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); + + 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 WebRoutingSettings(); + 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/ContentFinderByAliasTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByAliasTests.cs index 09b25a4156..3e3f6163bf 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByAliasTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByAliasTests.cs @@ -2,6 +2,7 @@ using System.Linq; using Moq; using NUnit.Framework; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -50,7 +51,7 @@ namespace Umbraco.Tests.Routing var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); var lookup = - new ContentFinderByUrlAlias(Logger, Mock.Of(), VariationContextAccessor); + new ContentFinderByUrlAlias(LoggerFactory.CreateLogger(), Mock.Of(), VariationContextAccessor); var result = lookup.TryFindContent(frequest); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByAliasWithDomainsTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByAliasWithDomainsTests.cs index 6dca84a85a..9af04cfb18 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByAliasWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByAliasWithDomainsTests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -64,7 +65,7 @@ namespace Umbraco.Tests.Routing if (expectedNode > 0) Assert.AreEqual(expectedCulture, request.Culture.Name); - var finder = new ContentFinderByUrlAlias(Logger, Mock.Of(), VariationContextAccessor); + var finder = new ContentFinderByUrlAlias(LoggerFactory.CreateLogger(), Mock.Of(), VariationContextAccessor); var result = finder.TryFindContent(request); if (expectedNode > 0) diff --git a/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs index d3c820d239..a21b36dcf5 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs @@ -1,5 +1,7 @@ using NUnit.Framework; +using Microsoft.Extensions.Logging; using Umbraco.Core; +using Umbraco.Core.Configuration.Models; using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Routing; @@ -17,7 +19,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 WebRoutingSettings(); + var lookup = new ContentFinderByIdPath(Microsoft.Extensions.Options.Options.Create(webRoutingSettings), LoggerFactory.CreateLogger(), 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..b849b100ea 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByUrlAndTemplateTests.cs @@ -1,13 +1,10 @@ -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; +using NUnit.Framework; +using Microsoft.Extensions.Logging; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Tests.Testing; -using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Routing { @@ -30,15 +27,15 @@ 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 GlobalSettings { HideTopLevelNodeFromPath = false }; 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 WebRoutingSettings(); + var lookup = new ContentFinderByUrlAndTemplate(LoggerFactory.CreateLogger(), 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..7337d3ebd2 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByUrlTests.cs @@ -1,13 +1,11 @@ using System; using System.Globalization; -using Moq; using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Web.Composing; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Web.Routing; +using Microsoft.Extensions.Logging; namespace Umbraco.Tests.Routing { @@ -28,15 +26,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 GlobalSettings { HideTopLevelNodeFromPath = true }; - 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); + var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger()); - 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 +61,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 GlobalSettings { HideTopLevelNodeFromPath = false }; - 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); + var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger()); - Assert.IsFalse(Current.Configs.Global().HideTopLevelNodeFromPath); + Assert.IsFalse(globalSettings.HideTopLevelNodeFromPath); var result = lookup.TryFindContent(frequest); @@ -88,13 +85,12 @@ 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 GlobalSettings { HideTopLevelNodeFromPath = false }; - 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); + var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = lookup.TryFindContent(frequest); @@ -115,14 +111,13 @@ 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 GlobalSettings { HideTopLevelNodeFromPath = false }; - 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/")); - var lookup = new ContentFinderByUrl(Logger); + var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = lookup.TryFindContent(frequest); @@ -144,14 +139,13 @@ 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 GlobalSettings { HideTopLevelNodeFromPath = false }; - 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/æøå")); - var lookup = new ContentFinderByUrl(Logger); + var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = lookup.TryFindContent(frequest); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs index ac2e62b1ef..0acbba1a9b 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByUrlWithDomainsTests.cs @@ -1,9 +1,12 @@ using Moq; using NUnit.Framework; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; @@ -127,17 +130,16 @@ 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 GlobalSettings { HideTopLevelNodeFromPath = true }; - var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettingsMock.Object); + var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); // must lookup domain else lookup by url fails publishedRouter.FindDomain(frequest); - var lookup = new ContentFinderByUrl(Logger); + var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); Assert.AreEqual(expectedId, frequest.PublishedContent.Id); @@ -169,10 +171,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 GlobalSettings { HideTopLevelNodeFromPath = true }; - var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettingsMock.Object); + var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -180,7 +181,7 @@ namespace Umbraco.Tests.Routing publishedRouter.FindDomain(frequest); Assert.AreEqual(expectedCulture, frequest.Culture.Name); - var lookup = new ContentFinderByUrl(Logger); + var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); Assert.AreEqual(expectedId, frequest.PublishedContent.Id); diff --git a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs index a81f345e38..73ca7ba03c 100644 --- a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs +++ b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs @@ -1,11 +1,9 @@ -using Moq; -using NUnit.Framework; +using NUnit.Framework; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; -using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Tests.Routing { @@ -266,10 +264,9 @@ 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 globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -278,7 +275,7 @@ namespace Umbraco.Tests.Routing Assert.AreEqual(expectedCulture, frequest.Culture.Name); - var finder = new ContentFinderByUrl(Logger); + var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = finder.TryFindContent(frequest); Assert.IsTrue(result); @@ -315,10 +312,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 GlobalSettings { HideTopLevelNodeFromPath = false }; - var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings.Object); + var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -326,7 +322,7 @@ namespace Umbraco.Tests.Routing publishedRouter.FindDomain(frequest); // find document - var finder = new ContentFinderByUrl(Logger); + var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = finder.TryFindContent(frequest); // apply wildcard domain @@ -370,9 +366,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 GlobalSettings { HideTopLevelNodeFromPath = false }; + var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings); var publishedRouter = CreatePublishedRouter(Factory); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -382,7 +377,7 @@ namespace Umbraco.Tests.Routing Assert.AreEqual(expectedCulture, frequest.Culture.Name); - var finder = new ContentFinderByUrl(Logger); + var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = finder.TryFindContent(frequest); Assert.IsTrue(result); diff --git a/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs b/src/Umbraco.Tests/Routing/GetContentUrlsTests.cs index 4f11802b43..c865a0c726 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.TestHelpers.Entities; +using Umbraco.Web.Routing; +using Microsoft.Extensions.Logging; 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 GlobalSettings(); + _webRoutingSettings = new WebRoutingSettings(); + _requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + } + 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, @@ -55,12 +64,12 @@ namespace Umbraco.Tests.Routing var umbContext = GetUmbracoContext("http://localhost:8000"); var publishedRouter = CreatePublishedRouter(Factory, - contentFinders: new ContentFinderCollection(new[] { new ContentFinderByUrl(Logger) })); + contentFinders: new ContentFinderCollection(new[] { new ContentFinderByUrl(LoggerFactory.CreateLogger()) })); var urls = content.GetContentUrls(publishedRouter, umbContext, GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService, VariationContextAccessor, - Logger, + LoggerFactory.CreateLogger(), UriUtility, PublishedUrlProvider).ToList(); @@ -78,27 +87,29 @@ 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), + LoggerFactory.CreateLogger(), + 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() ); var publishedRouter = CreatePublishedRouter(Factory, - contentFinders:new ContentFinderCollection(new[]{new ContentFinderByUrl(Logger) })); + contentFinders:new ContentFinderCollection(new[]{new ContentFinderByUrl(LoggerFactory.CreateLogger()) })); var urls = content.GetContentUrls(publishedRouter, umbContext, GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService, VariationContextAccessor, - Logger, + LoggerFactory.CreateLogger(), UriUtility, publishedUrlProvider).ToList(); @@ -123,27 +134,28 @@ 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), + LoggerFactory.CreateLogger(), + 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() ); var publishedRouter = CreatePublishedRouter(Factory, - contentFinders: new ContentFinderCollection(new[] { new ContentFinderByUrl(Logger) })); + contentFinders: new ContentFinderCollection(new[] { new ContentFinderByUrl(LoggerFactory.CreateLogger()) })); var urls = child.GetContentUrls(publishedRouter, umbContext, GetLangService("en-US", "fr-FR"), GetTextService(), ServiceContext.ContentService, VariationContextAccessor, - Logger, + LoggerFactory.CreateLogger(), UriUtility, publishedUrlProvider ).ToList(); diff --git a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs index e55a22065b..84d0ea17f6 100644 --- a/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/MediaUrlProviderTests.cs @@ -1,12 +1,13 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using Newtonsoft.Json; using NUnit.Framework; 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; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; @@ -32,14 +33,14 @@ namespace Umbraco.Tests.Routing { base.SetUp(); - var logger = Mock.Of(); + var loggerFactory = NullLoggerFactory.Instance; var mediaFileSystemMock = Mock.Of(); - var contentSection = Mock.Of(); + var contentSettings = new ContentSettings(); 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(loggerFactory, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, UploadAutoFillProperties), + new ImageCropperPropertyEditor(loggerFactory, mediaFileSystemMock, Microsoft.Extensions.Options.Options.Create(contentSettings), dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService, UploadAutoFillProperties), }); _mediaUrlProvider = new DefaultMediaUrlProvider(propertyEditors, UriUtility); } @@ -149,9 +150,10 @@ namespace Umbraco.Tests.Routing private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext) { + var webRoutingSettings = new WebRoutingSettings(); return new UrlProvider( new TestUmbracoContextAccessor(umbracoContext), - TestHelper.WebRoutingSettings, + Microsoft.Extensions.Options.Options.Create(webRoutingSettings), new UrlProviderCollection(Enumerable.Empty()), new MediaUrlProviderCollection(new []{_mediaUrlProvider}), Mock.Of() @@ -189,7 +191,7 @@ namespace Umbraco.Tests.Routing var propertyValueConverters = new PropertyValueConverterCollection(new IPropertyValueConverter[] { new UploadPropertyConverter(), - new ImageCropperValueConverter(), + new ImageCropperValueConverter(Mock.Of>()), }); var publishedModelFactory = Mock.Of(); diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 358a47f09b..2262499347 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -2,31 +2,36 @@ using System.Linq; using System.Web.Mvc; using System.Web.Routing; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; 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.Tests.PublishedContent; -using Umbraco.Tests.Testing; -using Umbraco.Web.Runtime; -using Current = Umbraco.Web.Composing.Current; -using ILogger = Umbraco.Core.Logging.ILogger; +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; namespace Umbraco.Tests.Routing { @@ -49,8 +54,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, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) + : base(globalSettings, connectionStrings,umbracoVersion, ioHelper, NullLoggerFactory.Instance, Mock.Of(), new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, TestHelper.GetTypeFinder(), AppCaches.NoCache) { } @@ -69,7 +74,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 RequestHandlerSettings(); + Composition.RegisterUnique(_ => new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings))); } public override void TearDown() @@ -105,7 +111,7 @@ namespace Umbraco.Tests.Routing frequest.TemplateModel = template; var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); - var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContextAccessor, Mock.Of()), ShortStringHelper); + var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContextAccessor, Mock.Of>()), ShortStringHelper); handler.GetHandlerForRoute(httpContext.Request.RequestContext, frequest); Assert.AreEqual("RenderMvc", routeData.Values["controller"].ToString()); @@ -146,14 +152,15 @@ namespace Umbraco.Tests.Routing var type = new AutoPublishedContentType(Guid.NewGuid(), 22, "CustomDocument", new PublishedPropertyType[] { }); ContentTypesCache.GetPublishedContentTypeByAlias = alias => type; - var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContextAccessor, Mock.Of(), context => + 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(), - Factory.GetInstance()); + Factory.GetInstance(), + Factory.GetInstance()); }), ShortStringHelper); handler.GetHandlerForRoute(httpContext.Request.RequestContext, frequest); @@ -190,8 +197,8 @@ namespace Umbraco.Tests.Routing /// public class CustomDocumentController : RenderMvcController { - public CustomDocumentController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) - : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger) + public CustomDocumentController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory) + : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, loggerFactory) { } diff --git a/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs b/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs index a78459fa39..e3d6477988 100644 --- a/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs +++ b/src/Umbraco.Tests/Routing/RoutableDocumentFilterTests.cs @@ -1,9 +1,9 @@ -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.Core.Configuration.Models; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.TestHelpers; using Umbraco.Web; @@ -51,12 +51,10 @@ 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 GlobalSettings { ReservedPaths = string.Empty, ReservedUrls = string.Empty }; + + 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..34bde09c37 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 Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; +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,9 @@ 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 GlobalSettings { ReservedPaths = GlobalSettings.StaticReservedPaths + "~/umbraco" }; + 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..3ef99f203f --- /dev/null +++ b/src/Umbraco.Tests/Routing/UrlProviderWithHideTopLevelNodeFromPathTests.cs @@ -0,0 +1,58 @@ +using NUnit.Framework; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Configuration.Models; +using Umbraco.Tests.Common; +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 GlobalSettings { HideTopLevelNodeFromPath = HideTopLevelNodeFromPath }; + 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 RequestHandlerSettings { AddTrailingSlash = true }; + + var umbracoContext = GetUmbracoContext("/test", 1111, globalSettings: _globalSettings, snapshotService:PublishedSnapshotService); + var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext); + var urlProvider = new DefaultUrlProvider( + Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + LoggerFactory.CreateLogger(), + 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..79a946f5e3 100644 --- a/src/Umbraco.Tests/Routing/UrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/UrlProviderWithoutHideTopLevelNodeFromPathTests.cs @@ -2,40 +2,38 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using Microsoft.Extensions.Logging; 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.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 GlobalSettings { HideTopLevelNodeFromPath = HideTopLevelNodeFromPath }; } + 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 RequestHandlerSettings { AddTrailingSlash = false }; - 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), + LoggerFactory.CreateLogger(), + 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 RequestHandlerSettings { AddTrailingSlash = true }; - 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), + LoggerFactory.CreateLogger(), + 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 RequestHandlerSettings { AddTrailingSlash = true }; 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), + LoggerFactory.CreateLogger(), + 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 RequestHandlerSettings { AddTrailingSlash = true }; 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), + LoggerFactory.CreateLogger(), + 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 RequestHandlerSettings { AddTrailingSlash = true }; 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), + LoggerFactory.CreateLogger(), + 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 RequestHandlerSettings { AddTrailingSlash = true }; - 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), + LoggerFactory.CreateLogger(), + 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 RequestHandlerSettings(); - var requestHandlerSettings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); - - var urlProvider = new DefaultUrlProvider(requestHandlerSettings, Logger, globalSettings.Object, + var urlProvider = new DefaultUrlProvider(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings), + LoggerFactory.CreateLogger(), + 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..4894e1ad7e 100644 --- a/src/Umbraco.Tests/Routing/UrlRoutesTests.cs +++ b/src/Umbraco.Tests/Routing/UrlRoutesTests.cs @@ -4,7 +4,9 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; +using Umbraco.Tests.Common.Builders; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -196,10 +198,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 GlobalSettings { HideTopLevelNodeFromPath = hide }; - 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 +221,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 GlobalSettings { HideTopLevelNodeFromPath = hide }; - 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 +235,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 GlobalSettings { HideTopLevelNodeFromPath = false }; - 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 +266,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 GlobalSettings { HideTopLevelNodeFromPath = hide }; - 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 +297,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 GlobalSettings { HideTopLevelNodeFromPath = hide }; - 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 +320,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 GlobalSettings { HideTopLevelNodeFromPath = false }; - 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..68c002fea3 100644 --- a/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/UrlsProviderWithDomainsTests.cs @@ -1,16 +1,16 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Tests.Common; using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.Routing; @@ -178,14 +178,14 @@ namespace Umbraco.Tests.Routing [TestCase(10011, "https://domain1.com", false, "/1001-1/")] public void Get_Url_SimpleDomain(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - 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), + LoggerFactory.CreateLogger(), + 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 RequestHandlerSettings { AddTrailingSlash = true }; + var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - 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), + LoggerFactory.CreateLogger(), + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -238,14 +238,14 @@ namespace Umbraco.Tests.Routing [TestCase(1002, "http://domain1.com", false, "/1002/")] public void Get_Url_DeepDomain(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - 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), + LoggerFactory.CreateLogger(), + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -270,14 +270,15 @@ 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 RequestHandlerSettings { AddTrailingSlash = true }; + var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - 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), + LoggerFactory.CreateLogger(), + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -292,14 +293,15 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_DomainsAndCache() { - var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - 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), + LoggerFactory.CreateLogger(), + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -356,14 +358,15 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_Relative_Or_Absolute() { - var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains - - var umbracoContext = GetUmbracoContext("http://domain1.com/test", 1111, globalSettings:globalSettings.Object); + var 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), + LoggerFactory.CreateLogger(), + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -381,14 +384,15 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Url_Alternate() { - var settings = TestHelpers.SettingsForTests.GenerateMockRequestHandlerSettings(); + var requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; - var globalSettings = Mock.Get(Factory.GetInstance()); //this will modify the IGlobalSettings instance stored in the container - globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains - - var umbracoContext = GetUmbracoContext("http://domain1.com/en/test", 1111, globalSettings:globalSettings.Object); + var 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), + LoggerFactory.CreateLogger(), + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -408,9 +412,10 @@ namespace Umbraco.Tests.Routing private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) { + var webRoutingSettings = new WebRoutingSettings(); 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..81fe22a698 100644 --- a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs +++ b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs @@ -2,16 +2,16 @@ using System.Linq; using Moq; using NUnit.Framework; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Tests.TestHelpers; -using Umbraco.Web.Routing; using Umbraco.Core.Services; +using Umbraco.Tests.Common; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Web; -using Umbraco.Tests.Common; +using Umbraco.Web.Routing; namespace Umbraco.Tests.Routing { @@ -33,19 +33,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 requestHandlerSettings = new RequestHandlerSettings { AddTrailingSlash = true }; + var globalSettings = new GlobalSettings { HideTopLevelNodeFromPath = false }; 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), + LoggerFactory.CreateLogger(), + Microsoft.Extensions.Options.Options.Create(globalSettings), new SiteDomainHelper(), umbracoContextAccessor, UriUtility); var publishedUrlProvider = GetPublishedUrlProvider(umbracoContext, urlProvider); @@ -65,7 +66,7 @@ namespace Umbraco.Tests.Routing Assert.IsTrue(frequest.HasDomain); // check that it's been routed - var lookup = new ContentFinderByUrl(Logger); + var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger()); var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); Assert.AreEqual(100111, frequest.PublishedContent.Id); @@ -97,9 +98,10 @@ namespace Umbraco.Tests.Routing private IPublishedUrlProvider GetPublishedUrlProvider(IUmbracoContext umbracoContext, DefaultUrlProvider urlProvider) { + var webRoutingSettings = new WebRoutingSettings(); 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..ea111a1e29 100644 --- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs +++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs @@ -1,28 +1,29 @@ using System; using System.Collections.Generic; -using System.Data; using Examine; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; 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 @@ -70,7 +71,6 @@ namespace Umbraco.Tests.Runtimes Assert.IsTrue(TestComponent.Ctored); Assert.IsNotNull(TestComponent.ProfilingLogger); Assert.IsInstanceOf(TestComponent.ProfilingLogger); - Assert.IsInstanceOf(((ProfilingLogger) TestComponent.ProfilingLogger).Logger); // note: components are NOT disposed after boot @@ -84,48 +84,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(new NullLogger(), + NullLoggerFactory.Instance, + new SecuritySettings(), + new GlobalSettings(), + new ConnectionStrings(), + _ioHelper, _profiler, new AspNetHostingEnvironment(Options.Create(new HostingSettings())), new AspNetBackOfficeInfo(_globalSettings, _ioHelper, new NullLogger(), 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, ILoggerFactory loggerFactory, 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, loggerFactory, 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, ILoggerFactory loggerFactory, IProfiler profiler, IHostingEnvironment hostingEnvironment, IBackOfficeInfo backOfficeInfo) + :base(globalSettings, connectionStrings,umbracoVersion, ioHelper, loggerFactory, 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); @@ -137,6 +128,8 @@ namespace Umbraco.Tests.Runtimes { container.Register(Lifetime.Singleton); container.Register(Lifetime.Singleton); + container.Register(typeof(ILogger<>), typeof(Logger<>), Lifetime.Singleton); + var factory = base.Configure(container); return factory; @@ -170,7 +163,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..e5594a0778 100644 --- a/src/Umbraco.Tests/Runtimes/StandaloneTests.cs +++ b/src/Umbraco.Tests/Runtimes/StandaloneTests.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.Text; using System.Web; using Examine; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -37,6 +38,9 @@ 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; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Tests.Runtimes { @@ -58,36 +62,34 @@ namespace Umbraco.Tests.Runtimes ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus] = ""; // FIXME: we need a better management of settings here (and, true config files?) + var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); // create the very basic and essential things we need - var logger = new ConsoleLogger(new MessageTemplates()); - var profiler = new LogProfiler(logger); - var profilingLogger = new ProfilingLogger(logger, profiler); + var profiler = new LogProfiler(loggerFactory.CreateLogger()); + var profilingLogger = new ProfilingLogger(loggerFactory.CreateLogger("ProfilingLogger"), profiler); var appCaches = AppCaches.Disabled; - var globalSettings = TestHelper.GetConfigs().Global(); - var connectionStrings = TestHelper.GetConfigs().ConnectionStrings(); + var globalSettings = new GlobalSettings(); + var connectionStrings = new ConnectionStrings(); var typeFinder = TestHelper.GetTypeFinder(); - var databaseFactory = new UmbracoDatabaseFactory(logger,globalSettings, connectionStrings, new Lazy(() => factory.GetInstance()), TestHelper.DbProviderFactoryCreator); + var databaseFactory = new UmbracoDatabaseFactory(loggerFactory.CreateLogger(), loggerFactory, 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 typeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), loggerFactory.CreateLogger(), 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, loggerFactory.CreateLogger()); var variationContextAccessor = TestHelper.VariationContextAccessor; - // create the register and the composition var register = TestHelper.GetRegister(); - var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, configs, ioHelper, appCaches); - composition.RegisterEssentials(logger, profiler, profilingLogger, mainDom, appCaches, databaseFactory, typeLoader, runtimeState, typeFinder, ioHelper, umbracoVersion, TestHelper.DbProviderFactoryCreator, hostingEnvironment, backOfficeInfo); + var composition = new Composition(register, typeLoader, profilingLogger, runtimeState, ioHelper, appCaches); + composition.RegisterEssentials(loggerFactory.CreateLogger("Essentials"), loggerFactory, 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, loggerFactory, 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; @@ -95,7 +97,7 @@ namespace Umbraco.Tests.Runtimes var composerTypes = typeLoader.GetTypes() // all of them .Where(x => !x.FullName.StartsWith("Umbraco.Tests.")) // exclude test components .Where(x => x != typeof(WebInitialComposer) && x != typeof(WebFinalComposer)); // exclude web runtime - var composers = new Composers(composition, composerTypes, Enumerable.Empty(), profilingLogger); + var composers = new Composers(composition, composerTypes, Enumerable.Empty(), loggerFactory.CreateLogger(), profilingLogger); composers.Compose(); // must registers stuff that WebRuntimeComponent would register otherwise @@ -118,14 +120,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 ContentSettings(); + var coreDebugSettings = new CoreDebugSettings(); + var nuCacheSettings = new NuCacheSettings(); + var requestHandlerSettings = new RequestHandlerSettings(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); + var webRoutingSettings = new WebRoutingSettings(); + + 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 +180,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, loggerFactory.CreateLogger(), loggerFactory, umbracoVersion); creator.InitializeDatabaseSchema(); scope.Complete(); } @@ -255,30 +272,32 @@ namespace Umbraco.Tests.Runtimes // - assigning the factory to Current.Factory // create the very basic and essential things we need - var logger = new ConsoleLogger(new MessageTemplates()); + var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); var profiler = Mock.Of(); - var profilingLogger = new ProfilingLogger(logger, profiler); + var profilingLogger = new ProfilingLogger(loggerFactory.CreateLogger("ProfilingLogger"), profiler); var appCaches = AppCaches.Disabled; var databaseFactory = Mock.Of(); var typeFinder = TestHelper.GetTypeFinder(); var ioHelper = TestHelper.IOHelper; - var typeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), profilingLogger); + var typeLoader = new TypeLoader(typeFinder, appCaches.RuntimeCache, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), loggerFactory.CreateLogger(), profilingLogger); var runtimeState = Mock.Of(); var hostingEnvironment = Mock.Of(); var backOfficeInfo = TestHelper.GetBackOfficeInfo(); 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); + composition.RegisterEssentials(loggerFactory.CreateLogger("RegisterEssentials"), loggerFactory, 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 GlobalSettings(); + var connectionStrings = new ConnectionStrings(); + + var coreRuntime = new CoreRuntime(globalSettings, connectionStrings, umbracoVersion, ioHelper, loggerFactory, profiler, new AspNetUmbracoBootPermissionChecker(), hostingEnvironment, backOfficeInfo, TestHelper.DbProviderFactoryCreator, TestHelper.MainDom, typeFinder, AppCaches.NoCache); // get the components // all of them? @@ -288,7 +307,7 @@ namespace Umbraco.Tests.Runtimes .Where(x => !x.FullName.StartsWith("Umbraco.Tests")); // single? //var componentTypes = new[] { typeof(CoreRuntimeComponent) }; - var composers = new Composers(composition, composerTypes, Enumerable.Empty(), profilingLogger); + var composers = new Composers(composition, composerTypes, Enumerable.Empty(), loggerFactory.CreateLogger(), profilingLogger); // get components to compose themselves composers.Compose(); diff --git a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs index 2291584f66..f0a9721b08 100644 --- a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs +++ b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs @@ -4,10 +4,10 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Scheduling; @@ -18,20 +18,24 @@ namespace Umbraco.Tests.Scheduling [Category("Slow")] public class BackgroundTaskRunnerTests { - private ILogger _logger; + private ILoggerFactory _loggerFactory; + private ILogger> _backgroundTaskLogger; + private ILogger> _baseTaskLogger; private IApplicationShutdownRegistry _hostingEnvironment; [OneTimeSetUp] public void InitializeFixture() { - _logger = new ConsoleLogger(new MessageTemplates()); + _loggerFactory = LoggerFactory.Create(builder => builder.AddDebug()); + _backgroundTaskLogger = _loggerFactory.CreateLogger>(); + _baseTaskLogger = _loggerFactory.CreateLogger>(); _hostingEnvironment = TestHelper.GetHostingEnvironmentLifetime(); } [Test] public async Task ShutdownWhenRunningWithWait() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var stopped = false; runner.Stopped += (sender, args) => { stopped = true; }; @@ -54,7 +58,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task ShutdownWhenRunningWithoutWait() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var stopped = false; runner.Stopped += (sender, args) => { stopped = true; }; @@ -81,7 +85,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task ShutdownCompletesTheRunner() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { Assert.IsFalse(runner.IsRunning); // because AutoStart is false @@ -104,7 +108,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task ShutdownFlushesTheQueue() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { MyTask t1, t2, t3; @@ -126,7 +130,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task ShutdownForceTruncatesTheQueue() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { MyTask t1, t2, t3; @@ -153,7 +157,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task ShutdownThenForce() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { Assert.IsFalse(runner.IsRunning); // because AutoStart is false @@ -188,7 +192,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task HostingStopNonImmediate() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { MyTask t; @@ -222,7 +226,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task HostingStopImmediate() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { MyTask t; @@ -257,7 +261,7 @@ namespace Umbraco.Tests.Scheduling [Test] public void Create_IsNotRunning() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { Assert.IsFalse(runner.IsRunning); } @@ -271,7 +275,7 @@ namespace Umbraco.Tests.Scheduling { AutoStart = true, KeepAlive = true // else stops! - }, _logger, _hostingEnvironment)) + }, _backgroundTaskLogger, _hostingEnvironment)) { Assert.IsTrue(runner.IsRunning); // because AutoStart is true await runner.StopInternal(false); // keepalive = must be stopped @@ -281,7 +285,7 @@ namespace Umbraco.Tests.Scheduling [Test] public void Create_AutoStartAndKeepAlive_IsRunning() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { AutoStart = true, KeepAlive = true }, _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { AutoStart = true, KeepAlive = true }, _backgroundTaskLogger, _hostingEnvironment)) { Assert.IsTrue(runner.IsRunning); // because AutoStart is true Thread.Sleep(800); // for long @@ -294,7 +298,7 @@ namespace Umbraco.Tests.Scheduling public async Task Dispose_IsRunning() { BackgroundTaskRunner runner; - using (runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { AutoStart = true, KeepAlive = true }, _logger, _hostingEnvironment)) + using (runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { AutoStart = true, KeepAlive = true }, _backgroundTaskLogger, _hostingEnvironment)) { Assert.IsTrue(runner.IsRunning); // dispose will stop it @@ -318,7 +322,7 @@ namespace Umbraco.Tests.Scheduling [Test] public void Startup_KeepAlive_IsRunning() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true }, _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true }, _backgroundTaskLogger, _hostingEnvironment)) { Assert.IsFalse(runner.IsRunning); runner.StartUp(); @@ -330,7 +334,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task Create_AddTask_IsRunning() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _baseTaskLogger, _hostingEnvironment)) { var waitHandle = new ManualResetEvent(false); runner.TaskCompleted += (sender, args) => @@ -348,7 +352,7 @@ namespace Umbraco.Tests.Scheduling [Test] public void Create_KeepAliveAndAddTask_IsRunning() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true }, _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true }, _baseTaskLogger, _hostingEnvironment)) { var waitHandle = new ManualResetEvent(false); runner.TaskCompleted += (sender, args) => @@ -366,7 +370,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task WaitOnRunner_OneTask() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _baseTaskLogger, _hostingEnvironment)) { var task = new MyTask(); Assert.IsTrue(task.Ended == default(DateTime)); @@ -385,7 +389,7 @@ namespace Umbraco.Tests.Scheduling for (var i = 0; i < 10; i++) tasks.Add(new MyTask()); - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = false, LongRunning = true, PreserveRunningTask = true }, _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = false, LongRunning = true, PreserveRunningTask = true }, _baseTaskLogger, _hostingEnvironment)) { tasks.ForEach(runner.Add); @@ -403,7 +407,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task WaitOnTask() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _baseTaskLogger, _hostingEnvironment)) { var task = new MyTask(); var waitHandle = new ManualResetEvent(false); @@ -423,7 +427,7 @@ namespace Umbraco.Tests.Scheduling for (var i = 0; i < 10; i++) tasks.Add(new MyTask(), new ManualResetEvent(false)); - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _baseTaskLogger, _hostingEnvironment)) { runner.TaskCompleted += (sender, task) => tasks[task.Task].Set(); foreach (var t in tasks) runner.Add(t.Key); @@ -452,7 +456,7 @@ namespace Umbraco.Tests.Scheduling IDictionary tasks = getTasks(); BackgroundTaskRunner tManager; - using (tManager = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { LongRunning = true, KeepAlive = true }, _logger, _hostingEnvironment)) + using (tManager = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { LongRunning = true, KeepAlive = true }, _baseTaskLogger, _hostingEnvironment)) { tManager.TaskCompleted += (sender, task) => tasks[task.Task].Set(); @@ -498,7 +502,7 @@ namespace Umbraco.Tests.Scheduling List tasks = getTasks(); - using (var tManager = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { LongRunning = true, PreserveRunningTask = true }, _logger, _hostingEnvironment)) + using (var tManager = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { LongRunning = true, PreserveRunningTask = true }, _baseTaskLogger, _hostingEnvironment)) { tasks.ForEach(tManager.Add); @@ -540,7 +544,7 @@ namespace Umbraco.Tests.Scheduling { var runCount = 0; var waitHandle = new ManualResetEvent(false); - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { runner.TaskCompleted += (sender, args) => { @@ -571,7 +575,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task LatchedTaskRuns() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var task = new MyLatchedTask(200, false); runner.Add(task); @@ -591,7 +595,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task LatchedTaskStops_Runs_On_Shutdown() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var task = new MyLatchedTask(200, true); runner.Add(task); @@ -611,7 +615,7 @@ namespace Umbraco.Tests.Scheduling { var runCount = 0; var waitHandle = new ManualResetEvent(false); - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { runner.TaskCompleted += (sender, args) => { @@ -638,7 +642,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task FailingTaskSync() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var exceptions = new ConcurrentQueue(); runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception); @@ -655,7 +659,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task FailingTaskDisposing() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var exceptions = new ConcurrentQueue(); runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception); @@ -672,7 +676,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task FailingTaskAsync() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var exceptions = new ConcurrentQueue(); runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception); @@ -688,7 +692,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task FailingTaskDisposingAsync() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var exceptions = new ConcurrentQueue(); runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception); @@ -705,7 +709,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task CancelAsyncTask() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var task = new MyAsyncTask(4000); runner.Add(task); @@ -721,7 +725,7 @@ namespace Umbraco.Tests.Scheduling [Test] public async Task CancelLatchedTask() { - using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _logger, _hostingEnvironment)) + using (var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions(), _backgroundTaskLogger, _hostingEnvironment)) { var task = new MyLatchedTask(4000, false); runner.Add(task); @@ -934,7 +938,7 @@ namespace Umbraco.Tests.Scheduling [Test] public void SourceTaskTest() { - var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _logger, TestHelper.GetHostingEnvironmentLifetime()); + var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _backgroundTaskLogger, TestHelper.GetHostingEnvironmentLifetime()); var task = new SourceTask(); runner.Add(task); diff --git a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs index 01169abce2..c2860b57d0 100644 --- a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs +++ b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests2.cs @@ -2,8 +2,9 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; -using Umbraco.Core.Logging; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Scheduling; @@ -13,6 +14,7 @@ namespace Umbraco.Tests.Scheduling [Timeout(60000)] public class BackgroundTaskRunnerTests2 { + private static ILoggerFactory _loggerFactory = NullLoggerFactory.Instance; // this tests was used to debug a background task runner issue that was unearthed by Deploy, // where work items would never complete under certain circumstances, due to threading issues. // (fixed now) @@ -21,8 +23,7 @@ namespace Umbraco.Tests.Scheduling [Timeout(4000)] public async Task ThreadResumeIssue() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironmentLifetime()); + var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _loggerFactory.CreateLogger>(), TestHelper.GetHostingEnvironmentLifetime()); var work = new ThreadResumeIssueWorkItem(); runner.Add(work); @@ -76,8 +77,7 @@ namespace Umbraco.Tests.Scheduling [Ignore("Only runs in the debugger.")] public async Task DebuggerInterferenceIssue() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); - var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger, TestHelper.GetHostingEnvironmentLifetime()); + var runner = new BackgroundTaskRunner(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, _loggerFactory.CreateLogger>(), TestHelper.GetHostingEnvironmentLifetime()); var taskCompleted = false; runner.TaskCompleted += (sender, args) => { diff --git a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs index be609f9a83..ebfb9da8b3 100644 --- a/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeEventDispatcherTests.cs @@ -1,20 +1,22 @@ using System; using System.Linq; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Events; -using Umbraco.Core.Models; using Umbraco.Core.IO; using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Scoping; +using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core.Services; -using Umbraco.Tests.Components; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Scoping @@ -34,28 +36,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(), Mock.Of(), 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 GlobalSettings(); + composition.RegisterUnique(factory => new FileSystems(factory, factory.TryGetInstance>(), 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)] @@ -74,7 +70,7 @@ namespace Umbraco.Tests.Scoping DoThing1 += (sender, args) => { counter1++; if (cancel) args.Cancel = true; }; DoThing2 += (sender, args) => { counter2++; }; - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: passive ? new PassiveEventDispatcher() : null)) { var cancelled = scope.Events.DispatchCancelable(DoThing1, this, new SaveEventArgs("test")); @@ -103,7 +99,7 @@ namespace Umbraco.Tests.Scoping DoThing2 += OnDoThingFail; DoThing3 += OnDoThingFail; - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher())) { scope.Events.Dispatch(DoThing1, this, new SaveEventArgs("test")); @@ -145,7 +141,7 @@ namespace Umbraco.Tests.Scoping var content3 = MockedContent.CreateBasicContent(contentType); content3.Id = 789; - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher())) { @@ -184,7 +180,7 @@ namespace Umbraco.Tests.Scoping var contentService = Mock.Of(); var content = Mock.Of(); - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher())) { scope.Events.Dispatch(Test_Unpublished, contentService, new PublishEventArgs(new [] { content }), "Unpublished"); @@ -218,7 +214,7 @@ namespace Umbraco.Tests.Scoping content3.Id = 123; content3.UpdateDate = now.AddMinutes(3); - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher())) { scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs(content1)); @@ -258,7 +254,7 @@ namespace Umbraco.Tests.Scoping content3.Id = 123; content1.UpdateDate = now.AddMinutes(3); - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher())) { scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs(content1)); @@ -291,7 +287,7 @@ namespace Umbraco.Tests.Scoping content3.Id = 123; content3.UpdateDate = now.AddMinutes(3); - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher())) { scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs(content1)); @@ -315,7 +311,7 @@ namespace Umbraco.Tests.Scoping DoThing2 += OnDoThingFail; DoThing3 += OnDoThingFail; - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance); using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher())) { scope.Events.Dispatch(DoThing1, this, new SaveEventArgs("test")); @@ -341,7 +337,7 @@ namespace Umbraco.Tests.Scoping IScopeContext ambientContext = null; Guid value = Guid.Empty; - var scopeProvider = _testObjects.GetScopeProvider(Mock.Of()) as ScopeProvider; + var scopeProvider = _testObjects.GetScopeProvider(NullLoggerFactory.Instance) as ScopeProvider; DoThing1 += (sender, args) => { counter++; }; DoThing2 += (sender, args) => { counter++; }; diff --git a/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs b/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs index 2e2ebf392c..8c98bc99ff 100644 --- a/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopeFileSystemsTests.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Text; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -9,7 +10,6 @@ using Umbraco.Core.IO; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Core.Composing.CompositionExtensions; -using Umbraco.Core.Logging; using FileSystems = Umbraco.Core.IO.FileSystems; namespace Umbraco.Tests.Scoping @@ -55,7 +55,7 @@ namespace Umbraco.Tests.Scoping [TestCase(false)] public void CreateMediaTest(bool complete) { - var physMediaFileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Mock.Of(), IOHelper.MapPath("media"), "ignore"); + var physMediaFileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Mock.Of>(), IOHelper.MapPath("media"), "ignore"); var mediaFileSystem = Current.MediaFileSystem; Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt")); @@ -88,7 +88,7 @@ namespace Umbraco.Tests.Scoping [Test] public void MultiThread() { - var physMediaFileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Mock.Of(),IOHelper.MapPath("media"), "ignore"); + var physMediaFileSystem = new PhysicalFileSystem(IOHelper, HostingEnvironment, Mock.Of>(),IOHelper.MapPath("media"), "ignore"); var mediaFileSystem = Current.MediaFileSystem; var scopeProvider = ScopeProvider; diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 49bca378c7..68e1c4a2e2 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -1,17 +1,13 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Web.Routing; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; 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; using Umbraco.Core.Persistence.Repositories; @@ -20,16 +16,13 @@ using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Sync; using Umbraco.Tests.Common; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -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 NuCacheSettings(); return new PublishedSnapshotService( options, @@ -98,18 +92,19 @@ namespace Umbraco.Tests.Scoping publishedSnapshotAccessor, Mock.Of(), ProfilingLogger, + NullLoggerFactory.Instance, ScopeProvider, documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, - new DatabaseDataSource(Mock.Of()), - Factory.GetInstance(), + new DatabaseDataSource(Mock.Of>()), + Microsoft.Extensions.Options.Options.Create(globalSettings ?? new GlobalSettings()), 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 +118,7 @@ namespace Umbraco.Tests.Scoping var umbracoContext = new UmbracoContext( httpContextAccessor, service, - Mock.Of(), + Mock.Of(), globalSettings, HostingEnvironment, new TestVariationContextAccessor(), @@ -143,7 +138,7 @@ namespace Umbraco.Tests.Scoping var umbracoContext = GetUmbracoContextNu("http://example.com/", setSingleton: true); // wire cache refresher - _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of()); + _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of>()); _distributedCacheBinder.BindEvents(true); // create document type, document diff --git a/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs b/src/Umbraco.Tests/Scoping/ScopedRepositoryTests.cs index 4c3bb288e4..7bffbbe2ed 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 Microsoft.Extensions.Logging; +using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Web.Composing; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Events; 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 GlobalSettings(); + } + 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 @@ -75,7 +86,7 @@ namespace Umbraco.Tests.Scoping // get user again - else we'd modify the one that's in the cache user = service.GetUserById(user.Id); - _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of()); + _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of>()); _distributedCacheBinder.BindEvents(true); Assert.IsNull(scopeProvider.AmbientScope); @@ -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 @@ -156,7 +167,7 @@ namespace Umbraco.Tests.Scoping Assert.AreEqual(lang.Id, globalCached.Id); Assert.AreEqual("fr-FR", globalCached.IsoCode); - _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of()); + _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of>()); _distributedCacheBinder.BindEvents(true); Assert.IsNull(scopeProvider.AmbientScope); @@ -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"); @@ -248,7 +259,7 @@ namespace Umbraco.Tests.Scoping Assert.AreEqual(item.Id, globalCached.Id); Assert.AreEqual("item-key", globalCached.ItemKey); - _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of()); + _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of>()); _distributedCacheBinder.BindEvents(true); Assert.IsNull(scopeProvider.AmbientScope); diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index 852872fca0..cac420d5e2 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -1,23 +1,24 @@ using System; using System.Collections.Generic; using System.Xml; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Web.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; 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 +45,13 @@ namespace Umbraco.Tests.Scoping protected override void ComposeSettings() { - Composition.Configs.Add(SettingsForTests.GenerateMockContentSettings); - Composition.Configs.Add(SettingsForTests.GenerateMockGlobalSettings); + var contentSettings = new ContentSettings(); + var globalSettings = new GlobalSettings(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); + + 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] @@ -93,7 +99,7 @@ namespace Umbraco.Tests.Scoping var item = new Content("name", -1, contentType); // wire cache refresher - _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of()); + _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of>()); _distributedCacheBinder.BindEvents(true); // check xml in context = "before" @@ -206,7 +212,7 @@ namespace Umbraco.Tests.Scoping ServiceContext.ContentTypeService.Save(contentType); // wire cache refresher - _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of()); + _distributedCacheBinder = new DistributedCacheBinder(new DistributedCache(Current.ServerMessenger, Current.CacheRefreshers), Mock.Of(), Mock.Of>()); _distributedCacheBinder.BindEvents(true); // check xml in context = "before" diff --git a/src/Umbraco.Tests/Security/BackOfficeOwinUserManagerTests.cs b/src/Umbraco.Tests/Security/BackOfficeOwinUserManagerTests.cs deleted file mode 100644 index 8958eabd42..0000000000 --- a/src/Umbraco.Tests/Security/BackOfficeOwinUserManagerTests.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Owin.Security.DataProtection; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.BackOffice; -using Umbraco.Core.Configuration; -using Umbraco.Core.Models.Membership; -using Umbraco.Net; -using Umbraco.Web.Security; - -namespace Umbraco.Tests.Security -{ - public class BackOfficeOwinUserManagerTests - { - [Test] - public async Task CheckPasswordAsync_When_Default_Password_Hasher_Validates_Umbraco7_Hash_Expect_Valid_Password() - { - const string v7Hash = "7Uob6fMTTxDIhWGebYiSxg==P+hgvWlXLbDd4cFLADn811KOaVI/9pg1PNvTuG5NklY="; - const string plaintext = "4XxzH3s3&J"; - - var mockPasswordConfiguration = new Mock(); - 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, - mockIpResolver.Object, - mockUserStore.Object, - null, - mockDataProtectionProvider.Object, - new NullLogger>()); - - var mockGlobalSettings = new Mock(); - mockGlobalSettings.Setup(x => x.DefaultUILanguage).Returns("test"); - - var user = new BackOfficeIdentityUser(mockGlobalSettings.Object, 2, new List()) - { - UserName = "alice", - Name = "Alice", - Email = "alice@umbraco.test", - PasswordHash = v7Hash - }; - - mockUserStore.Setup(x => x.GetPasswordHashAsync(user, It.IsAny())) - .ReturnsAsync(v7Hash); - - var isValidPassword = await userManager.CheckPasswordAsync(user, plaintext); - - Assert.True(isValidPassword); - } - } -} diff --git a/src/Umbraco.Tests/Security/OwinDataProtectorTokenProviderTests.cs b/src/Umbraco.Tests/Security/OwinDataProtectorTokenProviderTests.cs index 7b1ca53104..66965ca632 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 GlobalSettings(); _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/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs index ab9f85aa3c..30d68d92e0 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs @@ -2,15 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; 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; using Umbraco.Core.Persistence; @@ -19,7 +18,6 @@ using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Core.Sync; -using Umbraco.Tests.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; @@ -45,7 +43,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 +57,8 @@ namespace Umbraco.Tests.Services var hostingEnvironment = Mock.Of(); var typeFinder = TestHelper.GetTypeFinder(); - var settings = Mock.Of(); + + var nuCacheSettings = new NuCacheSettings(); return new PublishedSnapshotService( options, @@ -70,18 +69,19 @@ namespace Umbraco.Tests.Services publishedSnapshotAccessor, Mock.Of(), ProfilingLogger, + NullLoggerFactory.Instance, ScopeProvider, documentRepository, mediaRepository, memberRepository, DefaultCultureAccessor, - new DatabaseDataSource(Mock.Of()), - Factory.GetInstance(), + new DatabaseDataSource(Mock.Of>()), + Microsoft.Extensions.Options.Options.Create(globalSettings ?? new GlobalSettings()), 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 +310,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 GlobalSettings(); + + ServiceContext.LocalizationService.Save(new Language(globalSettings, nlCulture)); var includeCultureNames = contentType.Variations.HasFlag(ContentVariation.Culture); @@ -666,9 +668,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 GlobalSettings(); + + 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 +1263,10 @@ namespace Umbraco.Tests.Services private void CreateFrenchAndEnglishLangs() { - var languageEn = new Language(TestObjects.GetGlobalSettings(), "en") { IsDefault = true }; + var globalSettings = new GlobalSettings(); + 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/DataTypeServiceTests.cs b/src/Umbraco.Tests/Services/DataTypeServiceTests.cs deleted file mode 100644 index c047b04430..0000000000 --- a/src/Umbraco.Tests/Services/DataTypeServiceTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using NUnit.Framework; -using Umbraco.Core.Models; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.PropertyEditors; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Services -{ - /// - /// Tests covering the DataTypeService - /// - [TestFixture] - [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class DataTypeServiceTests : TestWithSomeContentBase - { - [Test] - public void DataTypeService_Can_Persist_New_DataTypeDefinition() - { - // Arrange - var dataTypeService = ServiceContext.DataTypeService; - - // Act - IDataType dataType = new DataType(new LabelPropertyEditor(Logger, IOHelper, DataTypeService, LocalizedTextService,LocalizationService, ShortStringHelper)) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; - dataTypeService.Save(dataType); - - // Assert - Assert.That(dataType, Is.Not.Null); - Assert.That(dataType.HasIdentity, Is.True); - - dataType = dataTypeService.GetDataType(dataType.Id); - Assert.That(dataType, Is.Not.Null); - } - - [Test] - public void DataTypeService_Can_Delete_Textfield_DataType_And_Clear_Usages() - { - // Arrange - var dataTypeService = ServiceContext.DataTypeService; - var textfieldId = "Umbraco.Textbox"; - var dataTypeDefinitions = dataTypeService.GetByEditorAlias(textfieldId); - - // Act - var definition = dataTypeDefinitions.First(); - var definitionId = definition.Id; - dataTypeService.Delete(definition); - - var deletedDefinition = dataTypeService.GetDataType(definitionId); - - // Assert - Assert.That(deletedDefinition, Is.Null); - - //Further assertions against the ContentType that contains PropertyTypes based on the TextField - var contentType = ServiceContext.ContentTypeService.Get(NodeDto.NodeIdSeed+1); - Assert.That(contentType.Alias, Is.EqualTo("umbTextpage")); - Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(1)); - } - - [Test] - public void Cannot_Save_DataType_With_Empty_Name() - { - // Arrange - var dataTypeService = ServiceContext.DataTypeService; - - // Act - var dataTypeDefinition = new DataType(new LabelPropertyEditor(Logger, IOHelper, DataTypeService, LocalizedTextService,LocalizationService, ShortStringHelper)) { Name = string.Empty, DatabaseType = ValueStorageType.Ntext }; - - // Act & Assert - Assert.Throws(() => dataTypeService.Save(dataTypeDefinition)); - } - } -} diff --git a/src/Umbraco.Tests/Services/FileServiceTests.cs b/src/Umbraco.Tests/Services/FileServiceTests.cs deleted file mode 100644 index fa27a3ee81..0000000000 --- a/src/Umbraco.Tests/Services/FileServiceTests.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using NUnit.Framework; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Services -{ - [TestFixture] - [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class FileServiceTests : TestWithSomeContentBase - { - [Test] - public void Create_Template_Then_Assign_Child() - { - var child = ServiceContext.FileService.CreateTemplateWithIdentity("Child", "child", "test"); - var parent = ServiceContext.FileService.CreateTemplateWithIdentity("Parent", "parent", "test"); - - child.SetMasterTemplate(parent); - ServiceContext.FileService.SaveTemplate(child); - - child = ServiceContext.FileService.GetTemplate(child.Id); - - Assert.AreEqual(parent.Alias, child.MasterTemplateAlias); - - } - - [Test] - public void Create_Template_With_Child_Then_Unassign() - { - var parent = ServiceContext.FileService.CreateTemplateWithIdentity("Parent", "parent", "test"); - var child = ServiceContext.FileService.CreateTemplateWithIdentity("Child", "child", "test", parent); - - child.SetMasterTemplate(null); - ServiceContext.FileService.SaveTemplate(child); - - child = ServiceContext.FileService.GetTemplate(child.Id); - - Assert.AreEqual(null, child.MasterTemplateAlias); - } - - [Test] - public void Can_Query_Template_Children() - { - var parent = ServiceContext.FileService.CreateTemplateWithIdentity("Parent", "parent", "test"); - var child1 = ServiceContext.FileService.CreateTemplateWithIdentity("Child1", "child1", "test", parent); - var child2 = ServiceContext.FileService.CreateTemplateWithIdentity("Child2", "child2", "test", parent); - - var children = ServiceContext.FileService.GetTemplates(parent.Id).Select(x => x.Id).ToArray(); - - Assert.IsTrue(children.Contains(child1.Id)); - Assert.IsTrue(children.Contains(child2.Id)); - } - - [Test] - public void Create_Template_With_Custom_Alias() - { - var template = ServiceContext.FileService.CreateTemplateWithIdentity("Test template", "customTemplateAlias", "test"); - - ServiceContext.FileService.SaveTemplate(template); - - template = ServiceContext.FileService.GetTemplate(template.Id); - - Assert.AreEqual("Test template", template.Name); - Assert.AreEqual("customTemplateAlias", template.Alias); - } - - } -} diff --git a/src/Umbraco.Tests/Services/Importing/Dictionary-Package.xml b/src/Umbraco.Tests/Services/Importing/Dictionary-Package.xml index 6fa5a3d15f..18ff588d64 100644 --- a/src/Umbraco.Tests/Services/Importing/Dictionary-Package.xml +++ b/src/Umbraco.Tests/Services/Importing/Dictionary-Package.xml @@ -30,7 +30,7 @@ - + - \ No newline at end of file + diff --git a/src/Umbraco.Tests/Services/MemberGroupServiceTests.cs b/src/Umbraco.Tests/Services/MemberGroupServiceTests.cs deleted file mode 100644 index 6199cf5bfb..0000000000 --- a/src/Umbraco.Tests/Services/MemberGroupServiceTests.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Threading; -using NUnit.Framework; -using Umbraco.Core.Models; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Services -{ - [TestFixture] - [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] - public class MemberGroupServiceTests : TestWithSomeContentBase - { - /// - /// Used to list out all ambiguous events that will require dispatching with a name - /// - [Test, Explicit] - public void List_Ambiguous_Events() - { - var service = ServiceContext.MemberGroupService; - Assert.Throws(() => service.Save(new MemberGroup { Name = "" })); - } - } -} diff --git a/src/Umbraco.Tests/Services/MemberServiceTests.cs b/src/Umbraco.Tests/Services/MemberServiceTests.cs deleted file mode 100644 index e7adbdacbf..0000000000 --- a/src/Umbraco.Tests/Services/MemberServiceTests.cs +++ /dev/null @@ -1,1224 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Web.Composing; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Entities; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Tests.Testing; -using Umbraco.Web; -using Umbraco.Web.PublishedCache.NuCache; -using Umbraco.Web.Security.Providers; -using Umbraco.Tests.Common; - -namespace Umbraco.Tests.Services -{ - [TestFixture] - [Category("Slow")] - [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] - public class MemberServiceTests : TestWithSomeContentBase - { - public override void SetUp() - { - base.SetUp(); - } - - [Test] - public void Can_Create_Member_With_Properties() - { - var memberType = ServiceContext.MemberTypeService.Get("member"); - IMember member = new Member("xname", "xemail", "xusername", "xrawpassword", memberType, true); - ServiceContext.MemberService.Save(member); - - member = ServiceContext.MemberService.GetById(member.Id); - Assert.AreEqual("xemail", member.Email); - - var dataTypeService = ServiceContext.DataTypeService; - var contentTypeFactory = new PublishedContentTypeFactory(new NoopPublishedModelFactory(), new PropertyValueConverterCollection(Enumerable.Empty()), dataTypeService); - var pmemberType = new PublishedContentType(memberType, contentTypeFactory); - - var publishedSnapshotAccessor = new TestPublishedSnapshotAccessor(); - var variationContextAccessor = new TestVariationContextAccessor(); - var pmember = PublishedMember.Create(member, pmemberType, false, publishedSnapshotAccessor, variationContextAccessor, Current.PublishedModelFactory); - - // contains the umbracoMember... properties created when installing, on the member type - // contains the other properties, that PublishedContentType adds (BuiltinMemberProperties) - // - // TODO: see TODO in PublishedContentType, this list contains duplicates - - var aliases = new[] - { - Constants.Conventions.Member.Comments, - Constants.Conventions.Member.FailedPasswordAttempts, - Constants.Conventions.Member.IsApproved, - Constants.Conventions.Member.IsLockedOut, - Constants.Conventions.Member.LastLockoutDate, - Constants.Conventions.Member.LastLoginDate, - Constants.Conventions.Member.LastPasswordChangeDate, - nameof(IMember.Email), - nameof(IMember.Username), - nameof(IMember.Comments), - nameof(IMember.IsApproved), - nameof(IMember.IsLockedOut), - nameof(IMember.LastLockoutDate), - nameof(IMember.CreateDate), - nameof(IMember.LastLoginDate), - nameof(IMember.LastPasswordChangeDate) - }; - - var properties = pmember.Properties.ToList(); - - Assert.IsTrue(properties.Select(x => x.Alias).ContainsAll(aliases)); - - var email = properties[aliases.IndexOf(nameof(IMember.Email))]; - Assert.AreEqual("xemail", email.GetSourceValue()); - } - - [Test] - public void Can_Create_Member() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - Assert.AreNotEqual(0, member.Id); - var foundMember = ServiceContext.MemberService.GetById(member.Id); - Assert.IsNotNull(foundMember); - Assert.AreEqual("test@test.com", foundMember.Email); - } - - [Test] - public void Can_Create_Member_With_Long_TLD_In_Email() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.marketing", "pass", "test"); - ServiceContext.MemberService.Save(member); - - Assert.AreNotEqual(0, member.Id); - var foundMember = ServiceContext.MemberService.GetById(member.Id); - Assert.IsNotNull(foundMember); - Assert.AreEqual("test@test.marketing", foundMember.Email); - } - - [Test] - public void Can_Create_Role() - { - ServiceContext.MemberService.AddRole("MyTestRole"); - - var found = ServiceContext.MemberService.GetAllRoles(); - - Assert.AreEqual(1, found.Count()); - Assert.AreEqual("MyTestRole", found.Single()); - } - - [Test] - public void Can_Create_Duplicate_Role() - { - ServiceContext.MemberService.AddRole("MyTestRole"); - ServiceContext.MemberService.AddRole("MyTestRole"); - - var found = ServiceContext.MemberService.GetAllRoles(); - - Assert.AreEqual(1, found.Count()); - Assert.AreEqual("MyTestRole", found.Single()); - } - - [Test] - public void Can_Get_All_Roles() - { - ServiceContext.MemberService.AddRole("MyTestRole1"); - ServiceContext.MemberService.AddRole("MyTestRole2"); - ServiceContext.MemberService.AddRole("MyTestRole3"); - - var found = ServiceContext.MemberService.GetAllRoles(); - - Assert.AreEqual(3, found.Count()); - } - [Test] - public void Can_Get_All_Roles_IDs() - { - ServiceContext.MemberService.AddRole("MyTestRole1"); - ServiceContext.MemberService.AddRole("MyTestRole2"); - ServiceContext.MemberService.AddRole("MyTestRole3"); - - var found = ServiceContext.MemberService.GetAllRolesIds(); - - Assert.AreEqual(3, found.Count()); - } - [Test] - public void Can_Get_All_Roles_By_Member_Id() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - ServiceContext.MemberService.AddRole("MyTestRole1"); - ServiceContext.MemberService.AddRole("MyTestRole2"); - ServiceContext.MemberService.AddRole("MyTestRole3"); - ServiceContext.MemberService.AssignRoles(new[] { member.Id }, new[] { "MyTestRole1", "MyTestRole2" }); - - var memberRoles = ServiceContext.MemberService.GetAllRoles(member.Id); - - Assert.AreEqual(2, memberRoles.Count()); - - } - [Test] - public void Can_Get_All_Roles_Ids_By_Member_Id() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - ServiceContext.MemberService.AddRole("MyTestRole1"); - ServiceContext.MemberService.AddRole("MyTestRole2"); - ServiceContext.MemberService.AddRole("MyTestRole3"); - ServiceContext.MemberService.AssignRoles(new[] { member.Id }, new[] { "MyTestRole1", "MyTestRole2" }); - - var memberRoles = ServiceContext.MemberService.GetAllRolesIds(member.Id); - - Assert.AreEqual(2, memberRoles.Count()); - - } - [Test] - public void Can_Get_All_Roles_By_Member_Username() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - //need to test with '@' symbol in the lookup - IMember member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2@test.com"); - ServiceContext.MemberService.Save(member2); - - ServiceContext.MemberService.AddRole("MyTestRole1"); - ServiceContext.MemberService.AddRole("MyTestRole2"); - ServiceContext.MemberService.AddRole("MyTestRole3"); - ServiceContext.MemberService.AssignRoles(new[] { member.Id, member2.Id }, new[] { "MyTestRole1", "MyTestRole2" }); - - var memberRoles = ServiceContext.MemberService.GetAllRoles("test"); - Assert.AreEqual(2, memberRoles.Count()); - - var memberRoles2 = ServiceContext.MemberService.GetAllRoles("test2@test.com"); - Assert.AreEqual(2, memberRoles2.Count()); - } - - [Test] - public void Can_Delete_Role() - { - ServiceContext.MemberService.AddRole("MyTestRole1"); - - ServiceContext.MemberService.DeleteRole("MyTestRole1", false); - - var memberRoles = ServiceContext.MemberService.GetAllRoles(); - - Assert.AreEqual(0, memberRoles.Count()); - } - - [Test] - public void Throws_When_Deleting_Assigned_Role() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - ServiceContext.MemberService.AddRole("MyTestRole1"); - ServiceContext.MemberService.AssignRoles(new[] { member.Id }, new[] { "MyTestRole1", "MyTestRole2" }); - - Assert.Throws(() => ServiceContext.MemberService.DeleteRole("MyTestRole1", true)); - } - - [Test] - public void Can_Get_Members_In_Role() - { - ServiceContext.MemberService.AddRole("MyTestRole1"); - int roleId; - using (var scope = ScopeProvider.CreateScope()) - { - roleId = scope.Database.ExecuteScalar("SELECT id from umbracoNode where [text] = 'MyTestRole1'"); - scope.Complete(); - } - - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); - ServiceContext.MemberService.Save(member2); - - using (var scope = ScopeProvider.CreateScope()) - { - scope.Database.Insert(new Member2MemberGroupDto { MemberGroup = roleId, Member = member1.Id }); - scope.Database.Insert(new Member2MemberGroupDto { MemberGroup = roleId, Member = member2.Id }); - scope.Complete(); - } - - var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); - Assert.AreEqual(2, membersInRole.Count()); - } - - [Test] - public void Cannot_Save_Member_With_Empty_Name() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, string.Empty, "test@test.com", "pass", "test"); - - // Act & Assert - Assert.Throws(() => ServiceContext.MemberService.Save(member)); - - } - - [TestCase("MyTestRole1", "test1", StringPropertyMatchType.StartsWith, 1)] - [TestCase("MyTestRole1", "test", StringPropertyMatchType.StartsWith, 3)] - [TestCase("MyTestRole1", "test1", StringPropertyMatchType.Exact, 1)] - [TestCase("MyTestRole1", "test", StringPropertyMatchType.Exact, 0)] - [TestCase("MyTestRole1", "st2", StringPropertyMatchType.EndsWith, 1)] - [TestCase("MyTestRole1", "test%", StringPropertyMatchType.Wildcard, 3)] - public void Find_Members_In_Role(string roleName1, string usernameToMatch, StringPropertyMatchType matchType, int resultCount) - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); - ServiceContext.MemberService.Save(member2); - var member3 = MockedMember.CreateSimpleMember(memberType, "test3", "test3@test.com", "pass", "test3"); - ServiceContext.MemberService.Save(member3); - - ServiceContext.MemberService.AssignRoles(new[] { member1.Id, member2.Id, member3.Id }, new[] { roleName1 }); - - var result = ServiceContext.MemberService.FindMembersInRole(roleName1, usernameToMatch, matchType); - Assert.AreEqual(resultCount, result.Count()); - } - - [Test] - public void Associate_Members_To_Roles_With_Member_Id() - { - ServiceContext.MemberService.AddRole("MyTestRole1"); - - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); - ServiceContext.MemberService.Save(member2); - - // temp make sure they exist - Assert.IsNotNull(ServiceContext.MemberService.GetById(member1.Id)); - Assert.IsNotNull(ServiceContext.MemberService.GetById(member2.Id)); - - ServiceContext.MemberService.AssignRoles(new[] { member1.Id, member2.Id }, new[] { "MyTestRole1" }); - - var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); - - Assert.AreEqual(2, membersInRole.Count()); - } - - [Test] - public void Associate_Members_To_Roles_With_Member_Id_Casing() - { - ServiceContext.MemberService.AddRole("MyTestRole1"); - - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); - ServiceContext.MemberService.Save(member2); - - // temp make sure they exist - Assert.IsNotNull(ServiceContext.MemberService.GetById(member1.Id)); - Assert.IsNotNull(ServiceContext.MemberService.GetById(member2.Id)); - - ServiceContext.MemberService.AssignRoles(new[] { member1.Id, member2.Id }, new[] { "mytestrole1" }); - - var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); - - Assert.AreEqual(2, membersInRole.Count()); - } - - [Test] - public void Associate_Members_To_Roles_With_Member_Username() - { - ServiceContext.MemberService.AddRole("MyTestRole1"); - - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); - ServiceContext.MemberService.Save(member2); - - ServiceContext.MemberService.AssignRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole1" }); - - var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); - - Assert.AreEqual(2, membersInRole.Count()); - } - - [Test] - public void Associate_Members_To_Roles_With_Member_Username_Containing_At_Symbols() - { - ServiceContext.MemberService.AddRole("MyTestRole1"); - - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1@test.com"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2@test.com"); - ServiceContext.MemberService.Save(member2); - - ServiceContext.MemberService.AssignRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole1" }); - - var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); - - Assert.AreEqual(2, membersInRole.Count()); - } - - [Test] - public void Associate_Members_To_Roles_With_New_Role() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); - ServiceContext.MemberService.Save(member2); - - //implicitly create the role - ServiceContext.MemberService.AssignRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole1" }); - - var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); - - Assert.AreEqual(2, membersInRole.Count()); - } - - [Test] - public void Remove_Members_From_Roles_With_Member_Id() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); - ServiceContext.MemberService.Save(member2); - - ServiceContext.MemberService.AssignRoles(new[] { member1.Id, member2.Id }, new[] { "MyTestRole1", "MyTestRole2" }); - - ServiceContext.MemberService.DissociateRoles(new[] {member1.Id }, new[] {"MyTestRole1"}); - ServiceContext.MemberService.DissociateRoles(new[] { member1.Id, member2.Id }, new[] { "MyTestRole2" }); - - var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); - Assert.AreEqual(1, membersInRole.Count()); - membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole2"); - Assert.AreEqual(0, membersInRole.Count()); - } - - [Test] - public void Remove_Members_From_Roles_With_Member_Username() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member1 = MockedMember.CreateSimpleMember(memberType, "test1", "test1@test.com", "pass", "test1"); - ServiceContext.MemberService.Save(member1); - var member2 = MockedMember.CreateSimpleMember(memberType, "test2", "test2@test.com", "pass", "test2"); - ServiceContext.MemberService.Save(member2); - - ServiceContext.MemberService.AssignRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole1", "MyTestRole2" }); - - ServiceContext.MemberService.DissociateRoles(new[] { member1.Username }, new[] { "MyTestRole1" }); - ServiceContext.MemberService.DissociateRoles(new[] { member1.Username, member2.Username }, new[] { "MyTestRole2" }); - - var membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole1"); - Assert.AreEqual(1, membersInRole.Count()); - membersInRole = ServiceContext.MemberService.GetMembersInRole("MyTestRole2"); - Assert.AreEqual(0, membersInRole.Count()); - } - - [Test] - public void Can_Delete_member() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - ServiceContext.MemberService.Delete(member); - var deleted = ServiceContext.MemberService.GetById(member.Id); - - // Assert - Assert.That(deleted, Is.Null); - } - - [Test] - public void ContentXml_Created_When_Saved() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - ContentXmlDto xml; - using (var scope = ScopeProvider.CreateScope()) - { - xml = scope.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = member.Id }); - scope.Complete(); - } - Assert.IsNotNull(xml); - } - - [Test] - public void Exists_By_Username() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - IMember member2 = MockedMember.CreateSimpleMember(memberType, "test", "test2@test.com", "pass", "test2@test.com"); - ServiceContext.MemberService.Save(member2); - - Assert.IsTrue(ServiceContext.MemberService.Exists("test")); - Assert.IsFalse(ServiceContext.MemberService.Exists("notFound")); - Assert.IsTrue(ServiceContext.MemberService.Exists("test2@test.com")); - } - - [Test] - public void Exists_By_Id() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - Assert.IsTrue(ServiceContext.MemberService.Exists(member.Id)); - Assert.IsFalse(ServiceContext.MemberService.Exists(9876)); - } - - [Test] - public void Tracks_Dirty_Changes() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - var resolved = ServiceContext.MemberService.GetByEmail(member.Email); - - //NOTE: This will not trigger a property isDirty because this is not based on a 'Property', it is - // just a c# property of the Member object - resolved.Email = "changed@test.com"; - - //NOTE: this WILL trigger a property isDirty because setting this c# property actually sets a value of - // the underlying 'Property' - resolved.FailedPasswordAttempts = 1234; - - var dirtyMember = (ICanBeDirty) resolved; - var dirtyProperties = resolved.Properties.Where(x => x.IsDirty()).ToList(); - Assert.IsTrue(dirtyMember.IsDirty()); - Assert.AreEqual(1, dirtyProperties.Count); - } - - [Test] - public void Get_By_Email() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - Assert.IsNotNull(ServiceContext.MemberService.GetByEmail(member.Email)); - Assert.IsNull(ServiceContext.MemberService.GetByEmail("do@not.find")); - } - - [Test] - public void Get_Member_Name() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "Test Real Name", "test@test.com", "pass", "testUsername"); - ServiceContext.MemberService.Save(member); - - - Assert.AreEqual("Test Real Name", member.Name); - } - - [Test] - public void Get_By_Username() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - Assert.IsNotNull(ServiceContext.MemberService.GetByUsername(member.Username)); - Assert.IsNull(ServiceContext.MemberService.GetByUsername("notFound")); - } - - [Test] - public void Get_By_Object_Id() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); - ServiceContext.MemberService.Save(member); - - Assert.IsNotNull(ServiceContext.MemberService.GetById(member.Id)); - Assert.IsNull(ServiceContext.MemberService.GetById(9876)); - } - - [Test] - public void Get_All_Paged_Members() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - - long totalRecs; - var found = ServiceContext.MemberService.GetAll(0, 2, out totalRecs); - - Assert.AreEqual(2, found.Count()); - Assert.AreEqual(10, totalRecs); - Assert.AreEqual("test0", found.First().Username); - Assert.AreEqual("test1", found.Last().Username); - } - - [Test] - public void Get_All_Paged_Members_With_Filter() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - - long totalRecs; - var found = ServiceContext.MemberService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, true, null, "Member No-"); - - Assert.AreEqual(2, found.Count()); - Assert.AreEqual(10, totalRecs); - Assert.AreEqual("test0", found.First().Username); - Assert.AreEqual("test1", found.Last().Username); - - found = ServiceContext.MemberService.GetAll(0, 2, out totalRecs, "username", Direction.Ascending, true, null, "Member No-5"); - - Assert.AreEqual(1, found.Count()); - Assert.AreEqual(1, totalRecs); - Assert.AreEqual("test5", found.First().Username); - } - - [Test] - public void Find_By_Name_Starts_With() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "Bob", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindMembersByDisplayName("B", 0, 100, out totalRecs, StringPropertyMatchType.StartsWith); - - Assert.AreEqual(1, found.Count()); - } - - [Test] - public void Find_By_Email_Starts_With() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - //don't find this - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello","hello"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindByEmail("tes", 0, 100, out totalRecs, StringPropertyMatchType.StartsWith); - - Assert.AreEqual(10, found.Count()); - } - - [Test] - public void Find_By_Email_Ends_With() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - //include this - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindByEmail("test.com", 0, 100, out totalRecs, StringPropertyMatchType.EndsWith); - - Assert.AreEqual(11, found.Count()); - } - - [Test] - public void Find_By_Email_Contains() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - //include this - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindByEmail("test", 0, 100, out totalRecs, StringPropertyMatchType.Contains); - - Assert.AreEqual(11, found.Count()); - } - - [Test] - public void Find_By_Email_Exact() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - //include this - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindByEmail("hello@test.com", 0, 100, out totalRecs, StringPropertyMatchType.Exact); - - Assert.AreEqual(1, found.Count()); - } - - [Test] - public void Find_By_Login_Starts_With() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - //don't find this - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindByUsername("tes", 0, 100, out totalRecs, StringPropertyMatchType.StartsWith); - - Assert.AreEqual(10, found.Count()); - } - - [Test] - public void Find_By_Login_Ends_With() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - //include this - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindByUsername("llo", 0, 100, out totalRecs, StringPropertyMatchType.EndsWith); - - Assert.AreEqual(1, found.Count()); - } - - [Test] - public void Find_By_Login_Contains() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - //include this - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hellotest"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindByUsername("test", 0, 100, out totalRecs, StringPropertyMatchType.Contains); - - Assert.AreEqual(11, found.Count()); - } - - [Test] - public void Find_By_Login_Exact() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - //include this - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - long totalRecs; - var found = ServiceContext.MemberService.FindByUsername("hello", 0, 100, out totalRecs, StringPropertyMatchType.Exact); - - Assert.AreEqual(1, found.Count()); - } - - [Test] - public void Get_By_Property_String_Value_Exact() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "title", "hello member", StringPropertyMatchType.Exact); - - Assert.AreEqual(1, found.Count()); - } - - [Test] - public void Get_By_Property_String_Value_Contains() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "title", " member", StringPropertyMatchType.Contains); - - Assert.AreEqual(11, found.Count()); - } - - [Test] - public void Get_By_Property_String_Value_Starts_With() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "title", "Member No", StringPropertyMatchType.StartsWith); - - Assert.AreEqual(10, found.Count()); - } - - [Test] - public void Get_By_Property_String_Value_Ends_With() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("title", "title of mine"); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "title", "mine", StringPropertyMatchType.EndsWith); - - Assert.AreEqual(1, found.Count()); - } - - [Test] - public void Get_By_Property_Int_Value_Exact() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "number") - { - Name = "Number", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -51 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("number", i)); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("number", 2); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "number", 2, ValuePropertyMatchType.Exact); - - Assert.AreEqual(2, found.Count()); - } - - [Test] - public void Get_By_Property_Int_Value_Greater_Than() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "number") - { - Name = "Number", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -51 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("number", i)); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("number", 10); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "number", 3, ValuePropertyMatchType.GreaterThan); - - Assert.AreEqual(7, found.Count()); - } - - [Test] - public void Get_By_Property_Int_Value_Greater_Than_Equal_To() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "number") - { - Name = "Number", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -51 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("number", i)); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("number", 10); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "number", 3, ValuePropertyMatchType.GreaterThanOrEqualTo); - - Assert.AreEqual(8, found.Count()); - } - - [Test] - public void Get_By_Property_Int_Value_Less_Than() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.DateTime, ValueStorageType.Date, "number") - { - Name = "Number", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -51 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("number", i)); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("number", 1); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "number", 5, ValuePropertyMatchType.LessThan); - - Assert.AreEqual(6, found.Count()); - } - - [Test] - public void Get_By_Property_Int_Value_Less_Than_Or_Equal() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "number") - { - Name = "Number", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -51 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("number", i)); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("number", 1); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "number", 5, ValuePropertyMatchType.LessThanOrEqualTo); - - Assert.AreEqual(7, found.Count()); - } - - [Test] - public void Get_By_Property_Date_Value_Exact() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") - { - Name = "Date", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -36 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 2, 0)); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "date", new DateTime(2013, 12, 20, 1, 2, 0), ValuePropertyMatchType.Exact); - - Assert.AreEqual(2, found.Count()); - } - - [Test] - public void Get_By_Property_Date_Value_Greater_Than() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") - { - Name = "Date", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -36 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 10, 0)); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "date", new DateTime(2013, 12, 20, 1, 3, 0), ValuePropertyMatchType.GreaterThan); - - Assert.AreEqual(7, found.Count()); - } - - [Test] - public void Get_By_Property_Date_Value_Greater_Than_Equal_To() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") - { - Name = "Date", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -36 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 10, 0)); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "date", new DateTime(2013, 12, 20, 1, 3, 0), ValuePropertyMatchType.GreaterThanOrEqualTo); - - Assert.AreEqual(8, found.Count()); - } - - [Test] - public void Get_By_Property_Date_Value_Less_Than() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") - { - Name = "Date", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -36 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 1, 0)); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "date", new DateTime(2013, 12, 20, 1, 5, 0), ValuePropertyMatchType.LessThan); - - Assert.AreEqual(6, found.Count()); - } - - [Test] - public void Get_By_Property_Date_Value_Less_Than_Or_Equal() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - memberType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Integer, ValueStorageType.Integer, "date") - { - Name = "Date", - //NOTE: This is what really determines the db type - the above definition doesn't really do anything - DataTypeId = -36 - }, "Content"); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.SetValue("date", new DateTime(2013, 12, 20, 1, i, 0))); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue("date", new DateTime(2013, 12, 20, 1, 1, 0)); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetMembersByPropertyValue( - "date", new DateTime(2013, 12, 20, 1, 5, 0), ValuePropertyMatchType.LessThanOrEqualTo); - - Assert.AreEqual(7, found.Count()); - } - - [Test] - public void Count_All_Members() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10); - ServiceContext.MemberService.Save(members); - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetCount(MemberCountType.All); - - Assert.AreEqual(11, found); - } - - [Test] - public void Count_All_Locked_Members() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.IsLockedOut = i % 2 == 0); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue(Constants.Conventions.Member.IsLockedOut, true); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetCount(MemberCountType.LockedOut); - - Assert.AreEqual(6, found); - } - - [Test] - public void Count_All_Approved_Members() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var members = MockedMember.CreateSimpleMember(memberType, 10, (i, member) => member.IsApproved = i % 2 == 0); - ServiceContext.MemberService.Save(members); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - customMember.SetValue(Constants.Conventions.Member.IsApproved, false); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetCount(MemberCountType.Approved); - - Assert.AreEqual(5, found); - } - - [Test] - public void Setting_Property_On_Built_In_Member_Property_When_Property_Doesnt_Exist_On_Type_Is_Ok() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - memberType.RemovePropertyType(Constants.Conventions.Member.Comments); - ServiceContext.MemberTypeService.Save(memberType); - Assert.IsFalse(memberType.PropertyTypes.Any(x => x.Alias == Constants.Conventions.Member.Comments)); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - //this should not throw an exception - customMember.Comments = "hello world"; - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetById(customMember.Id); - - Assert.IsTrue(found.Comments.IsNullOrWhiteSpace()); - } - - /// - /// Because we are forcing some of the built-ins to be Labels which have an underlying db type as nvarchar but we need - /// to ensure that the dates/int get saved to the correct column anyways. - /// - [Test] - public void Setting_DateTime_Property_On_Built_In_Member_Property_Saves_To_Correct_Column() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - var member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "test", "test"); - var date = DateTime.Now; - member.LastLoginDate = DateTime.Now; - ServiceContext.MemberService.Save(member); - - var result = ServiceContext.MemberService.GetById(member.Id); - Assert.AreEqual( - date.TruncateTo(DateTimeExtensions.DateTruncate.Second), - result.LastLoginDate.TruncateTo(DateTimeExtensions.DateTruncate.Second)); - - //now ensure the col is correct - var sql = Current.SqlContext.Sql().Select() - .From() - .InnerJoin().On(dto => dto.PropertyTypeId, dto => dto.Id) - .InnerJoin().On((left, right) => left.VersionId == right.Id) - .Where(dto => dto.NodeId == member.Id) - .Where(dto => dto.Alias == Constants.Conventions.Member.LastLoginDate); - - List colResult; - using (var scope = ScopeProvider.CreateScope()) - { - colResult = scope.Database.Fetch(sql); - scope.Complete(); - } - - Assert.AreEqual(1, colResult.Count); - Assert.IsTrue(colResult.First().DateValue.HasValue); - Assert.IsFalse(colResult.First().IntegerValue.HasValue); - Assert.IsNull(colResult.First().TextValue); - Assert.IsNull(colResult.First().VarcharValue); - } - - [Test] - public void New_Member_Approved_By_Default() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - var found = ServiceContext.MemberService.GetById(customMember.Id); - - Assert.IsTrue(found.IsApproved); - } - - [Test] - public void Ensure_Content_Xml_Created() - { - IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); - ServiceContext.MemberTypeService.Save(memberType); - - var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); - ServiceContext.MemberService.Save(customMember); - - using (var scope = ScopeProvider.CreateScope()) - { - Assert.IsTrue(scope.Database.Exists(customMember.Id)); - } - } - } -} diff --git a/src/Umbraco.Tests/Services/PackagingServiceTests.cs b/src/Umbraco.Tests/Services/PackagingServiceTests.cs deleted file mode 100644 index f6878e9407..0000000000 --- a/src/Umbraco.Tests/Services/PackagingServiceTests.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.IO; -using NUnit.Framework; -using Umbraco.Core.IO; -using Umbraco.Core.Models.Packaging; -using Umbraco.Core.Services.Implement; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Services -{ - [TestFixture] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class PackagingServiceTests : TestWithSomeContentBase - { - - - - - - } -} diff --git a/src/Umbraco.Tests/Services/PerformanceTests.cs b/src/Umbraco.Tests/Services/PerformanceTests.cs index 67de1c91d7..da33685bdd 100644 --- a/src/Umbraco.Tests/Services/PerformanceTests.cs +++ b/src/Umbraco.Tests/Services/PerformanceTests.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; -using NPoco; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using Umbraco.Core; using Umbraco.Web.Composing; @@ -11,7 +11,6 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; @@ -58,9 +57,8 @@ namespace Umbraco.Tests.Services private static IProfilingLogger GetTestProfilingLogger() { - var logger = new DebugDiagnosticsLogger(new MessageTemplates()); var profiler = new TestProfiler(); - return new ProfilingLogger(logger, profiler); + return new ProfilingLogger(new NullLogger(), profiler); } [Test] diff --git a/src/Umbraco.Tests/Services/PublicAccessServiceTests.cs b/src/Umbraco.Tests/Services/PublicAccessServiceTests.cs deleted file mode 100644 index 8434aad332..0000000000 --- a/src/Umbraco.Tests/Services/PublicAccessServiceTests.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using NUnit.Framework; -using Umbraco.Core.Models; -using Umbraco.Core.Services; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Umbraco.Tests.Testing; - -namespace Umbraco.Tests.Services -{ - [TestFixture] - [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class PublicAccessServiceTests : TestWithSomeContentBase - { - [Test] - public void Can_Add_New_Entry() - { - // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah"); - ServiceContext.FileService.SaveTemplate(ct.DefaultTemplate); - contentTypeService.Save(ct); - var c = MockedContent.CreateSimpleContent(ct, "Test", -1); - contentService.Save(c); - var publicAccessService = ServiceContext.PublicAccessService; - - - // Act - var entry = new PublicAccessEntry(c, c, c, new[] - { - new PublicAccessRule() - { - RuleType = "TestType", - RuleValue = "TestVal" - }, - }); - var result = publicAccessService.Save(entry); - - // Assert - Assert.IsTrue(result.Success); - Assert.AreEqual(OperationResultType.Success, result.Result.Result); - Assert.IsTrue(entry.HasIdentity); - Assert.AreNotEqual(entry.Key, Guid.Empty); - Assert.AreEqual(c.Id, entry.LoginNodeId); - Assert.AreEqual(c.Id, entry.NoAccessNodeId); - Assert.AreEqual(c.Id, entry.ProtectedNodeId); - } - - [Test] - public void Can_Add_Rule() - { - // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah"); - ServiceContext.FileService.SaveTemplate(ct.DefaultTemplate); - contentTypeService.Save(ct); - var c = MockedContent.CreateSimpleContent(ct, "Test", -1); - contentService.Save(c); - var publicAccessService = ServiceContext.PublicAccessService; - var entry = new PublicAccessEntry(c, c, c, new[] - { - new PublicAccessRule() - { - RuleType = "TestType", - RuleValue = "TestVal" - }, - }); - publicAccessService.Save(entry); - - // Act - var updated = publicAccessService.AddRule(c, "TestType2", "AnotherVal"); - //re-get - entry = publicAccessService.GetEntryForContent(c); - - // Assert - Assert.IsTrue(updated.Success); - Assert.AreEqual(OperationResultType.Success, updated.Result.Result); - Assert.AreEqual(2, entry.Rules.Count()); - } - - [Test] - public void Can_Add_Multiple_Value_For_Same_Rule_Type() - { - // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah"); - ServiceContext.FileService.SaveTemplate(ct.DefaultTemplate); - contentTypeService.Save(ct); - var c = MockedContent.CreateSimpleContent(ct, "Test", -1); - contentService.Save(c); - var publicAccessService = ServiceContext.PublicAccessService; - var entry = new PublicAccessEntry(c, c, c, new[] - { - new PublicAccessRule() - { - RuleType = "TestType", - RuleValue = "TestVal" - }, - }); - publicAccessService.Save(entry); - - // Act - var updated1 = publicAccessService.AddRule(c, "TestType", "AnotherVal1"); - var updated2 = publicAccessService.AddRule(c, "TestType", "AnotherVal2"); - - //re-get - entry = publicAccessService.GetEntryForContent(c); - - // Assert - Assert.IsTrue(updated1.Success); - Assert.IsTrue(updated2.Success); - Assert.AreEqual(OperationResultType.Success, updated1.Result.Result); - Assert.AreEqual(OperationResultType.Success, updated2.Result.Result); - Assert.AreEqual(3, entry.Rules.Count()); - } - - [Test] - public void Can_Remove_Rule() - { - // Arrange - var contentService = ServiceContext.ContentService; - var contentTypeService = ServiceContext.ContentTypeService; - var ct = MockedContentTypes.CreateSimpleContentType("blah", "Blah"); - ServiceContext.FileService.SaveTemplate(ct.DefaultTemplate); - contentTypeService.Save(ct); - var c = MockedContent.CreateSimpleContent(ct, "Test", -1); - contentService.Save(c); - var publicAccessService = ServiceContext.PublicAccessService; - var entry = new PublicAccessEntry(c, c, c, new[] - { - new PublicAccessRule() - { - RuleType = "TestType", - RuleValue = "TestValue1" - }, - new PublicAccessRule() - { - RuleType = "TestType", - RuleValue = "TestValue2" - }, - }); - publicAccessService.Save(entry); - - // Act - var removed = publicAccessService.RemoveRule(c, "TestType", "TestValue1"); - //re-get - entry = publicAccessService.GetEntryForContent(c); - - // Assert - Assert.IsTrue(removed.Success); - Assert.AreEqual(OperationResultType.Success, removed.Result.Result); - Assert.AreEqual(1, entry.Rules.Count()); - Assert.AreEqual("TestValue2", entry.Rules.ElementAt(0).RuleValue); - } - - } -} 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/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs index 6bc228bf83..3c3e14e2c4 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs @@ -3,15 +3,15 @@ using System.IO; using Moq; using NPoco; using NUnit.Framework; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Core.Persistence.Mappers; -using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence; using Umbraco.Persistance.SqlCe; -using Umbraco.Tests.Components; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.TestHelpers @@ -42,12 +42,14 @@ namespace Umbraco.Tests.TestHelpers var typeFinder = TestHelper.GetTypeFinder(); var typeLoader = new TypeLoader(typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), + Mock.Of>(), 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(), Mock.Of(), TestHelper.IOHelper, AppCaches.NoCache); composition.RegisterUnique(_ => Mock.Of()); + composition.RegisterUnique(_ => NullLoggerFactory.Instance); composition.RegisterUnique(_ => Mock.Of()); composition.RegisterUnique(typeLoader); diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 8926c02182..51836502fb 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -1,10 +1,13 @@ using System; using System.Linq; using System.Threading; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; 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 +16,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; @@ -43,7 +47,7 @@ namespace Umbraco.Tests.TestHelpers // AutoPublishedContentTypes generates properties automatically 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(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var type = new AutoPublishedContentType(Guid.NewGuid(), 0, "anything", new PublishedPropertyType[] { }); @@ -91,17 +95,19 @@ namespace Umbraco.Tests.TestHelpers internal PublishedRouter CreatePublishedRouter(IFactory container = null, ContentFinderCollection contentFinders = null) { - return CreatePublishedRouter(SettingsForTests.GenerateMockWebRoutingSettings(), container ?? Factory, contentFinders); + var webRoutingSettings = new WebRoutingSettings(); + 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(), new ProfilingLogger(Mock.Of(), Mock.Of()), + Mock.Of>(), Mock.Of(), Mock.Of(), container?.GetInstance() ?? Current.Factory.GetInstance(), diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index 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.Common/TestHelpers/Entities/MockedContent.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs similarity index 100% rename from src/Umbraco.Tests.Common/TestHelpers/Entities/MockedContent.cs rename to src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs diff --git a/src/Umbraco.Tests.Common/TestHelpers/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs similarity index 97% rename from src/Umbraco.Tests.Common/TestHelpers/MockedContentTypes.cs rename to src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index a01d6decf5..035788abfc 100644 --- a/src/Umbraco.Tests.Common/TestHelpers/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -184,23 +184,7 @@ namespace Umbraco.Tests.TestHelpers.Entities return contentType; } - public static ContentType CreateSimpleContentType2(string alias, string name, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content") - { - var contentType = CreateSimpleContentType(alias, name, parent, randomizeAliases, propertyGroupName); - var propertyType = new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) - { - Alias = RandomAlias("gen", randomizeAliases), - Name = "Gen", - Description = "", - Mandatory = false, - SortOrder = 1, - DataTypeId = -88 - }; - contentType.AddPropertyType(propertyType); - - return contentType; - } public static ContentType CreateSimpleContentType(string alias, string name, IContentType parent = null, bool randomizeAliases = false, string propertyGroupName = "Content") { diff --git a/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedMedia.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedMedia.cs similarity index 100% rename from src/Umbraco.Tests.Common/TestHelpers/Entities/MockedMedia.cs rename to src/Umbraco.Tests/TestHelpers/Entities/MockedMedia.cs diff --git a/src/Umbraco.Tests.Common/TestHelpers/Entities/MockedMember.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs similarity index 100% rename from src/Umbraco.Tests.Common/TestHelpers/Entities/MockedMember.cs rename to src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs index 531d87f76f..4707c4af38 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedUser.cs @@ -1,6 +1,7 @@ -using Moq; -using System; +using System; using System.Collections.Generic; +using Moq; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.Membership; 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 GlobalSettings(); + 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 GlobalSettings(); 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.Common/TestHelpers/Entities/MockedUserGroup.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedUserGroup.cs similarity index 100% rename from src/Umbraco.Tests.Common/TestHelpers/Entities/MockedUserGroup.cs rename to src/Umbraco.Tests/TestHelpers/Entities/MockedUserGroup.cs 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/Stubs/TestControllerFactory.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs index f5d18e05ba..d0348cf589 100644 --- a/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs +++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs @@ -5,10 +5,10 @@ using System.Reflection; using System.Web.Mvc; using System.Web.Routing; using System.Web.SessionState; +using Microsoft.Extensions.Logging; using Moq; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Logging; using Umbraco.Web; using Current = Umbraco.Web.Composing.Current; @@ -20,16 +20,16 @@ namespace Umbraco.Tests.TestHelpers.Stubs internal class TestControllerFactory : IControllerFactory { private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly Func _factory; - public TestControllerFactory(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger) + public TestControllerFactory(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger) { _umbracoContextAccessor = umbracoContextAccessor; _logger = logger; } - public TestControllerFactory(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, Func factory) + public TestControllerFactory(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, Func factory) { _umbracoContextAccessor = umbracoContextAccessor; _logger = logger; diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs index 9aeb668518..b016b4ebe6 100644 --- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs +++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs @@ -33,6 +33,10 @@ 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 Microsoft.Extensions.Logging; +using Umbraco.Core.Configuration.Models; namespace Umbraco.Tests.TestHelpers { @@ -59,11 +63,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 +80,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 +98,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 GlobalSettings())); /// @@ -117,12 +117,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 +304,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..671af42ef0 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -4,15 +4,14 @@ using System.Data; using System.Data.Common; using System.Linq; using System.Linq.Expressions; +using Microsoft.Extensions.Logging; 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; @@ -46,7 +45,7 @@ namespace Umbraco.Tests.TestHelpers // can create a database - but don't try to use it! if (configured && canConnect) - databaseFactoryMock.Setup(x => x.CreateDatabase()).Returns(GetUmbracoSqlCeDatabase(Mock.Of())); + databaseFactoryMock.Setup(x => x.CreateDatabase()).Returns(GetUmbracoSqlCeDatabase(Mock.Of>())); return databaseFactoryMock.Object; } @@ -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..0b284b8f47 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 Microsoft.Extensions.Logging; 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; @@ -47,7 +45,7 @@ namespace Umbraco.Tests.TestHelpers /// An UmbracoDatabase. /// This is just a void database that has no actual database but pretends to have an open connection /// that can begin a transaction. - public UmbracoDatabase GetUmbracoSqlCeDatabase(ILogger logger) + public UmbracoDatabase GetUmbracoSqlCeDatabase(ILogger logger) { var syntax = new SqlCeSyntaxProvider(); var connection = GetDbConnection(); @@ -62,7 +60,7 @@ namespace Umbraco.Tests.TestHelpers /// An UmbracoDatabase. /// This is just a void database that has no actual database but pretends to have an open connection /// that can begin a transaction. - public UmbracoDatabase GetUmbracoSqlServerDatabase(ILogger logger) + public UmbracoDatabase GetUmbracoSqlServerDatabase(ILogger logger) { var syntax = new SqlServerSyntaxProvider(); // do NOT try to get the server's version! var connection = GetDbConnection(); @@ -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 { @@ -239,28 +80,33 @@ namespace Umbraco.Tests.TestHelpers return container?.TryGetInstance() ?? Mock.Of(); } - public IScopeProvider GetScopeProvider(ILogger logger, ITypeFinder typeFinder = null, FileSystems fileSystems = null, IUmbracoDatabaseFactory databaseFactory = null) + public IScopeProvider GetScopeProvider(ILoggerFactory loggerFactory, ITypeFinder typeFinder = null, FileSystems fileSystems = null, IUmbracoDatabaseFactory databaseFactory = null) { + var globalSettings = new GlobalSettings(); + var connectionString = ConfigurationManager.ConnectionStrings[Constants.System.UmbracoConnectionName].ConnectionString; + var connectionStrings = new ConnectionStrings { UmbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, connectionString) }; + var coreDebugSettings = new CoreDebugSettings(); + if (databaseFactory == null) { // var mappersBuilder = new MapperCollectionBuilder(Current.Container); // FIXME: // mappersBuilder.AddCore(); // var mappers = mappersBuilder.CreateCollection(); var mappers = Current.Factory.GetInstance(); - databaseFactory = new UmbracoDatabaseFactory(logger, - SettingsForTests.DefaultGlobalSettings, - new ConnectionStrings(), - Constants.System.UmbracoConnectionName, + databaseFactory = new UmbracoDatabaseFactory( + loggerFactory.CreateLogger(), + loggerFactory, + 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()); + typeFinder ??= new TypeFinder(loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); + fileSystems ??= new FileSystems(Current.Factory, loggerFactory.CreateLogger(), loggerFactory, 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, loggerFactory.CreateLogger(), loggerFactory, typeFinder, NoAppCache.Instance); } } diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index cfcdacdadf..7d565d70b2 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -1,17 +1,16 @@ 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; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; 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 +32,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 { @@ -91,7 +91,7 @@ namespace Umbraco.Tests.TestHelpers return TestObjects.GetDatabaseFactoryMock(); var lazyMappers = new Lazy(f.GetInstance); - var factory = new UmbracoDatabaseFactory(f.GetInstance(), GetDbConnectionString(), GetDbProviderName(), lazyMappers, TestHelper.DbProviderFactoryCreator); + var factory = new UmbracoDatabaseFactory(f.GetInstance>(), f.GetInstance(), GetDbConnectionString(), GetDbProviderName(), lazyMappers, TestHelper.DbProviderFactoryCreator); factory.ResetForTests(); return factory; }); @@ -152,7 +152,7 @@ namespace Umbraco.Tests.TestHelpers protected virtual string GetDbConnectionString() { - return @"Datasource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;"; + return @"DataSource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;"; } @@ -237,16 +237,16 @@ 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(), Factory.GetInstance(), - Logger); + Factory.GetInstance>()); // testing=true so XmlStore will not use the file nor the database @@ -260,8 +260,8 @@ namespace Umbraco.Tests.TestHelpers Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), DefaultCultureAccessor, - Logger, - Factory.GetInstance(), + Factory.GetInstance(), + globalSettings ?? TestObjects.GetGlobalSettings(), HostingEnvironment, HostingLifetime, ShortStringHelper, @@ -301,7 +301,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, LoggerFactory.CreateLogger(), LoggerFactory, UmbracoVersion); //Create the umbraco database and its base data schemaHelper.InitializeDatabaseSchema(); @@ -344,14 +344,14 @@ namespace Umbraco.Tests.TestHelpers } catch (Exception ex) { - Logger.Error(ex, "Could not remove the old database file"); + LoggerFactory.CreateLogger().LogError(ex, "Could not remove the old database file"); // swallow this exception - that's because a sub class might require further teardown logic onFail?.Invoke(ex); } } - 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 +374,8 @@ namespace Umbraco.Tests.TestHelpers var umbracoContext = new UmbracoContext( httpContextAccessor, service, - Mock.Of(), - globalSettings ?? Factory.GetInstance(), + Mock.Of(), + globalSettings ?? new GlobalSettings(), HostingEnvironment, new TestVariationContextAccessor(), UriUtility, diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index 6f5739eb02..017f7022e7 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -3,12 +3,14 @@ using System.Globalization; using System.Linq; using System.Web; using System.Web.Security; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; 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 +29,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 +87,10 @@ namespace Umbraco.Tests.Testing.TestingTests .Returns(UrlInfo.Url("/hello/world/1234")); var urlProvider = urlProviderMock.Object; + var webRoutingSettings = new WebRoutingSettings(); 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); @@ -101,14 +105,14 @@ namespace Umbraco.Tests.Testing.TestingTests [Test] public void Can_Mock_UmbracoApiController_Dependencies_With_Injected_UmbracoMapper() { - var logger = Mock.Of(); + var profilingLogger = Mock.Of(); var memberService = Mock.Of(); var memberTypeService = Mock.Of(); var membershipProvider = new MembersMembershipProvider(memberService, memberTypeService, Mock.Of(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver()); - var membershipHelper = new MembershipHelper(Mock.Of(), Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, logger, ShortStringHelper, Mock.Of()); + var membershipHelper = new MembershipHelper(Mock.Of(), Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, NullLoggerFactory.Instance, 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, profilingLogger , Mock.Of(), umbracoMapper, Mock.Of()); Assert.Pass(); } @@ -116,7 +120,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..347545068c 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -4,22 +4,32 @@ using System.Globalization; using System.IO; using System.Linq; using System.Reflection; +using System.Web.Http.Validation; using System.Web.Routing; using System.Web.Security; using System.Xml.Linq; using Examine; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; +using Serilog; 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 +37,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.Tests.Components; +using Umbraco.Net; +using Umbraco.Tests.Common; 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.Media; +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; +using ILogger = Microsoft.Extensions.Logging.ILogger; namespace Umbraco.Tests.Testing { @@ -116,7 +121,8 @@ namespace Umbraco.Tests.Testing #region Accessors protected ServiceContext ServiceContext => Factory.GetInstance(); - protected ILogger Logger => Factory.GetInstance(); + protected ILoggerFactory LoggerFactory => Factory.GetInstance(); + protected IJsonSerializer JsonNetSerializer { get; } = new JsonNetSerializer(); protected IIOHelper IOHelper { get; private set; } @@ -128,6 +134,8 @@ namespace Umbraco.Tests.Testing protected ILocalizationService LocalizationService => Factory.GetInstance(); protected ILocalizedTextService LocalizedTextService { get; private set; } protected IShortStringHelper ShortStringHelper => Factory?.GetInstance() ?? TestHelper.ShortStringHelper; + protected IImageUrlGenerator ImageUrlGenerator => Factory.GetInstance(); + protected UploadAutoFillProperties UploadAutoFillProperties => Factory.GetInstance(); protected IUmbracoVersion UmbracoVersion { get; private set; } protected ITypeFinder TypeFinder { get; private set; } @@ -136,7 +144,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(); @@ -148,8 +156,15 @@ namespace Umbraco.Tests.Testing protected UmbracoMapper Mapper => Factory.GetInstance(); protected IHttpContextAccessor HttpContextAccessor => Factory.GetInstance(); - protected IRuntimeState RuntimeState => ComponentTests.MockRuntimeState(RuntimeLevel.Run); + protected IRuntimeState RuntimeState => MockRuntimeState(RuntimeLevel.Run); + private ILoggerFactory _loggerFactory; + protected static IRuntimeState MockRuntimeState(RuntimeLevel level) + { + var runtimeState = Mock.Of(); + Mock.Get(runtimeState).Setup(x => x.Level).Returns(level); + return runtimeState; + } #endregion #region Setup @@ -166,39 +181,44 @@ namespace Umbraco.Tests.Testing // FIXME: align to runtimes & components - don't redo everything here !!!! Yes this is getting painful - var (logger, profiler) = GetLoggers(Options.Logger); - var proflogger = new ProfilingLogger(logger, profiler); + var loggerFactory = GetLoggerFactory(Options.Logger); + _loggerFactory = loggerFactory; + var profiler = new LogProfiler(loggerFactory.CreateLogger()); + var msLogger = loggerFactory.CreateLogger("msLogger"); + var proflogger = new ProfilingLogger(loggerFactory.CreateLogger("ProfilingLogger"), profiler); IOHelper = TestHelper.IOHelper; - TypeFinder = new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); + TypeFinder = new TypeFinder(loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(GetType().Assembly), new VaryingRuntimeHash()); var appCaches = GetAppCaches(); - var globalSettings = TestHelpers.SettingsForTests.DefaultGlobalSettings; - var settings = TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings(); + var globalSettings = new GlobalSettings(); + var settings = new WebRoutingSettings(); - IBackOfficeInfo backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, IOHelper, logger, settings); + IBackOfficeInfo backOfficeInfo = new AspNetBackOfficeInfo(globalSettings, IOHelper, loggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(settings)); IIpResolver ipResolver = new AspNetIpResolver(); - UmbracoVersion = new UmbracoVersion(globalSettings); + UmbracoVersion = new UmbracoVersion(); - LocalizedTextService = new LocalizedTextService(new Dictionary>(), logger); - var typeLoader = GetTypeLoader(IOHelper, TypeFinder, appCaches.RuntimeCache, HostingEnvironment, proflogger, Options.TypeLoader); + LocalizedTextService = new LocalizedTextService(new Dictionary>(), loggerFactory.CreateLogger()); + var typeLoader = GetTypeLoader(IOHelper, TypeFinder, appCaches.RuntimeCache, HostingEnvironment, loggerFactory.CreateLogger(), proflogger, Options.TypeLoader); var register = TestHelper.GetRegister(); - Composition = new Composition(register, typeLoader, proflogger, ComponentTests.MockRuntimeState(RuntimeLevel.Run), TestHelper.GetConfigs(), TestHelper.IOHelper, AppCaches.NoCache); - + Composition = new Composition(register, typeLoader, proflogger, MockRuntimeState(RuntimeLevel.Run), TestHelper.IOHelper, AppCaches.NoCache); + //TestHelper.GetConfigs().RegisterWith(register); + Composition.RegisterUnique(typeof(ILoggerFactory), loggerFactory); + Composition.Register(typeof(ILogger<>), typeof(Logger<>)); + Composition.Register(typeof(ILogger), msLogger); Composition.RegisterUnique(IOHelper); Composition.RegisterUnique(UriUtility); Composition.RegisterUnique(UmbracoVersion); Composition.RegisterUnique(TypeFinder); Composition.RegisterUnique(LocalizedTextService); Composition.RegisterUnique(typeLoader); - Composition.RegisterUnique(logger); - Composition.RegisterUnique(profiler); + Composition.RegisterUnique(profiler); Composition.RegisterUnique(proflogger); Composition.RegisterUnique(appCaches); Composition.RegisterUnique(HostingEnvironment); @@ -213,7 +233,7 @@ namespace Umbraco.Tests.Testing var memberService = Mock.Of(); var memberTypeService = Mock.Of(); var membershipProvider = new MembersMembershipProvider(memberService, memberTypeService, Mock.Of(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver()); - var membershipHelper = new MembershipHelper(Mock.Of(), Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, logger, ShortStringHelper, Mock.Of()); + var membershipHelper = new MembershipHelper(Mock.Of(), Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, loggerFactory, ShortStringHelper, Mock.Of()); Composition.RegisterUnique(membershipHelper); @@ -252,30 +272,26 @@ namespace Umbraco.Tests.Testing #region Compose - protected virtual (ILogger, IProfiler) GetLoggers(UmbracoTestOptions.Logger option) + protected virtual ILoggerFactory GetLoggerFactory(UmbracoTestOptions.Logger option) { - ILogger logger; - IProfiler profiler; + ILoggerFactory factory; switch (option) { case UmbracoTestOptions.Logger.Mock: - logger = Mock.Of(); - profiler = Mock.Of(); + factory = NullLoggerFactory.Instance; break; case UmbracoTestOptions.Logger.Serilog: - logger = new SerilogLogger(new FileInfo(TestHelper.MapPathForTestFiles("~/unit-test.config"))); - profiler = new LogProfiler(logger); + factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddSerilog(); }); break; case UmbracoTestOptions.Logger.Console: - logger = new ConsoleLogger(new MessageTemplates()); - profiler = new LogProfiler(logger); + factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => { builder.AddConsole(); }); break; default: throw new NotSupportedException($"Logger option {option} is not supported."); } - return (logger, profiler); + return factory; } protected virtual AppCaches GetAppCaches() @@ -313,21 +329,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 WebRoutingSettings(); 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())); @@ -340,6 +356,7 @@ namespace Umbraco.Tests.Testing runtimeStateMock.Setup(x => x.Level).Returns(RuntimeLevel.Run); Composition.RegisterUnique(f => runtimeStateMock.Object); Composition.Register(_ => Mock.Of()); + Composition.Register(); // ah... Composition.WithCollectionBuilder(); @@ -369,35 +386,35 @@ namespace Umbraco.Tests.Testing .ComposeCoreMappingProfiles(); } - protected virtual TypeLoader GetTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IHostingEnvironment hostingEnvironment, IProfilingLogger logger, UmbracoTestOptions.TypeLoader option) + protected virtual TypeLoader GetTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IHostingEnvironment hostingEnvironment, ILogger logger, IProfilingLogger profilingLogger , UmbracoTestOptions.TypeLoader option) { switch (option) { case UmbracoTestOptions.TypeLoader.Default: - return _commonTypeLoader ?? (_commonTypeLoader = CreateCommonTypeLoader(typeFinder, runtimeCache, logger, hostingEnvironment)); + return _commonTypeLoader ?? (_commonTypeLoader = CreateCommonTypeLoader(typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment)); case UmbracoTestOptions.TypeLoader.PerFixture: - return _featureTypeLoader ?? (_featureTypeLoader = CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment)); + return _featureTypeLoader ?? (_featureTypeLoader = CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment)); case UmbracoTestOptions.TypeLoader.PerTest: - return CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, hostingEnvironment); + return CreateTypeLoader(ioHelper, typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment); default: throw new ArgumentOutOfRangeException(nameof(option)); } } - protected virtual TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IProfilingLogger logger, IHostingEnvironment hostingEnvironment) + protected virtual TypeLoader CreateTypeLoader(IIOHelper ioHelper, ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger , IHostingEnvironment hostingEnvironment) { - return CreateCommonTypeLoader(typeFinder, runtimeCache, logger, hostingEnvironment); + return CreateCommonTypeLoader(typeFinder, runtimeCache, logger, profilingLogger , hostingEnvironment); } // common to all tests = cannot be overriden - private static TypeLoader CreateCommonTypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, IProfilingLogger logger, IHostingEnvironment hostingEnvironment) + private static TypeLoader CreateCommonTypeLoader(ITypeFinder typeFinder, IAppPolicyCache runtimeCache, ILogger logger, IProfilingLogger profilingLogger , IHostingEnvironment hostingEnvironment) { - return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, false, new[] + return new TypeLoader(typeFinder, runtimeCache, new DirectoryInfo(hostingEnvironment.LocalTempPath), logger, profilingLogger , false, new[] { Assembly.Load("Umbraco.Core"), Assembly.Load("Umbraco.Web"), Assembly.Load("Umbraco.Tests"), - Assembly.Load("Umbraco.Infrastructure") + Assembly.Load("Umbraco.Infrastructure"), }); } @@ -411,16 +428,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 ContentSettings(); + var coreDebugSettings = new CoreDebugSettings(); + var globalSettings = new GlobalSettings(); + var nuCacheSettings = new NuCacheSettings(); + var requestHandlerSettings = new RequestHandlerSettings(); + var userPasswordConfigurationSettings = new UserPasswordConfigurationSettings(); + var webRoutingSettings = new WebRoutingSettings(); - //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) @@ -442,10 +464,9 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(factory => TestObjects.GetFileSystemsMock()); - var logger = Mock.Of(); var scheme = Mock.Of(); - var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, logger, TestHelper.ShortStringHelper); + var mediaFileSystem = new MediaFileSystem(Mock.Of(), scheme, _loggerFactory.CreateLogger(), TestHelper.ShortStringHelper); Composition.RegisterUnique(factory => mediaFileSystem); // no factory (noop) @@ -457,13 +478,13 @@ namespace Umbraco.Tests.Testing Composition.RegisterUnique(_ => new TransientEventMessagesFactory()); - var globalSettings = TestHelper.GetConfigs().Global(); - var connectionStrings = TestHelper.GetConfigs().ConnectionStrings(); + var globalSettings = new GlobalSettings(); + var connectionStrings = new ConnectionStrings(); - Composition.RegisterUnique(f => new UmbracoDatabaseFactory(Logger, + Composition.RegisterUnique(f => new UmbracoDatabaseFactory(_loggerFactory.CreateLogger(), + LoggerFactory, globalSettings, connectionStrings, - Constants.System.UmbracoConnectionName, new Lazy(f.GetInstance), TestHelper.DbProviderFactoryCreator)); @@ -472,7 +493,7 @@ namespace Umbraco.Tests.Testing Composition.WithCollectionBuilder(); // empty Composition.RegisterUnique(factory - => TestObjects.GetScopeProvider(factory.TryGetInstance(), factory.TryGetInstance(), factory.TryGetInstance(), factory.TryGetInstance())); + => TestObjects.GetScopeProvider(_loggerFactory, factory.TryGetInstance(), factory.TryGetInstance(), factory.TryGetInstance())); Composition.RegisterUnique(factory => (IScopeAccessor) factory.GetInstance()); Composition.ComposeServices(); @@ -553,7 +574,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..2e87628612 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -33,6 +33,10 @@ + + true + true + true full @@ -77,14 +81,14 @@ - + 2.0.0-alpha.20200128.15 - 1.8.14 + 1.11.24 - + @@ -95,114 +99,97 @@ - - - - + + + + 3.1.8 + + + + + + - - + + - + - + + + - - - - - - + + + + - - - - - - - + + + + + + - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - + - - - - - @@ -213,7 +200,6 @@ - @@ -222,16 +208,10 @@ - - - - - - @@ -239,30 +219,19 @@ - - - - - - - - - - - @@ -279,8 +248,6 @@ - - @@ -290,33 +257,12 @@ - - - - - - - - - - - - - - - - - - - - - True @@ -341,8 +287,6 @@ - - @@ -359,29 +303,17 @@ - - - - - - - - - - - - True @@ -392,7 +324,6 @@ - @@ -402,7 +333,6 @@ - @@ -414,16 +344,9 @@ - - - - - - - @@ -458,10 +381,6 @@ - - {fbe7c065-dac0-4025-a78b-63b24d3ab00b} - Umbraco.Configuration - {29aa69d9-b597-4395-8d42-43b1263c240a} Umbraco.Core @@ -474,10 +393,6 @@ {3ae7bf57-966b-45a5-910a-954d7c554441} Umbraco.Infrastructure - - {52ac0ba8-a60e-4e36-897b-e8b97a54ed1c} - Umbraco.ModelsBuilder.Embedded - {33085570-9bf2-4065-a9b0-a29d920d13ba} Umbraco.Persistance.SqlCe @@ -542,11 +457,10 @@ - - + - + diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index 0d55fd99d7..9bd448dc38 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -1,13 +1,13 @@ using System.IO; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; using Umbraco.Core.Strings; -using Umbraco.Tests.Components; using Umbraco.Tests.TestHelpers; +using NullLogger = Microsoft.Extensions.Logging.Abstractions.NullLogger; namespace Umbraco.Tests.UmbracoExamine { @@ -17,9 +17,9 @@ namespace Umbraco.Tests.UmbracoExamine [OneTimeSetUp] public void InitializeFixture() { - - var logger = new SerilogLogger(new FileInfo(TestHelper.MapPathForTestFiles("~/unit-test.config"))); - _profilingLogger = new ProfilingLogger(logger, new LogProfiler(logger)); + + // var logger = new SerilogLogger(new FileInfo(TestHelper.MapPathForTestFiles("~/unit-test.config"))); + _profilingLogger = new ProfilingLogger(NullLogger.Instance, new LogProfiler(NullLogger.Instance)); } private IProfilingLogger _profilingLogger; @@ -33,8 +33,8 @@ namespace Umbraco.Tests.UmbracoExamine protected override void Compose() { base.Compose(); - - Composition.RegisterUnique(_ => new DefaultShortStringHelper(SettingsForTests.GenerateMockRequestHandlerSettings())); + var requestHandlerSettings = new RequestHandlerSettings(); + Composition.RegisterUnique(_ => new DefaultShortStringHelper(Microsoft.Extensions.Options.Options.Create(requestHandlerSettings))); } } } diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index b4ff26d760..59ebaa34e8 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -6,6 +6,7 @@ using Examine.LuceneEngine.Providers; using Lucene.Net.Analysis; using Lucene.Net.Analysis.Standard; using Lucene.Net.Store; +using Microsoft.Extensions.Logging; using Moq; using Umbraco.Core; using Umbraco.Core.Hosting; @@ -55,7 +56,7 @@ namespace Umbraco.Tests.UmbracoExamine public static MediaIndexPopulator GetMediaIndexRebuilder(PropertyEditorCollection propertyEditors, IMediaService mediaService) { - var mediaValueSetBuilder = new MediaValueSetBuilder(propertyEditors, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), GetMockUserService(), GetMockLogger(), TestHelper.ShortStringHelper, TestHelper.JsonSerializer); + var mediaValueSetBuilder = new MediaValueSetBuilder(propertyEditors, new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(TestHelper.ShortStringHelper) }), GetMockUserService(), Mock.Of>(), TestHelper.ShortStringHelper, TestHelper.JsonSerializer); var mediaIndexDataSource = new MediaIndexPopulator(null, mediaService, mediaValueSetBuilder); return mediaIndexDataSource; } @@ -156,7 +157,7 @@ namespace Umbraco.Tests.UmbracoExamine return mediaTypeServiceMock.Object; } - public static IProfilingLogger GetMockLogger() + public static IProfilingLogger GetMockProfilingLogger() { return new ProfilingLogger(Mock.Of(), Mock.Of()); } @@ -185,6 +186,8 @@ namespace Umbraco.Tests.UmbracoExamine new UmbracoFieldDefinitionCollection(), analyzer, profilingLogger, + Mock.Of>(), + Mock.Of(), hostingEnvironment, runtimeState, languageService, diff --git a/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs b/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs index 59209f3e7d..a91a305314 100644 --- a/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs @@ -54,7 +54,7 @@ namespace Umbraco.Tests.Web.Controllers public class Plugin1Controller : PluginController { public Plugin1Controller(IUmbracoContextAccessor umbracoContextAccessor) - : base(umbracoContextAccessor, null, null, null, null, null) + : base(umbracoContextAccessor, null, null, null, null) { } } @@ -63,7 +63,7 @@ namespace Umbraco.Tests.Web.Controllers public class Plugin2Controller : PluginController { public Plugin2Controller(IUmbracoContextAccessor umbracoContextAccessor) - : base(umbracoContextAccessor, null, null, null, null, null) + : base(umbracoContextAccessor, null, null, null, null) { } } @@ -72,7 +72,7 @@ namespace Umbraco.Tests.Web.Controllers public class Plugin3Controller : PluginController { public Plugin3Controller(IUmbracoContextAccessor umbracoContextAccessor) - : base(umbracoContextAccessor, null, null, null, null, null) + : base(umbracoContextAccessor, null, null, null, null) { } } @@ -80,7 +80,7 @@ namespace Umbraco.Tests.Web.Controllers public class Plugin4Controller : PluginController { public Plugin4Controller(IUmbracoContextAccessor umbracoContextAccessor) - : base(umbracoContextAccessor, null, null, null, null, null) + : base(umbracoContextAccessor, null, null, null, null) { } } 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..a2bcb4928a 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -2,13 +2,10 @@ using System.Web; using System.Web.Mvc; using System.Web.Routing; -using System.Web.Security; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Dictionary; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using Umbraco.Tests.Common; @@ -17,8 +14,6 @@ using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.Mvc; using Umbraco.Web.PublishedCache; -using Umbraco.Web.Security; -using Umbraco.Web.Security.Providers; using Current = Umbraco.Web.Composing.Current; namespace Umbraco.Tests.Web.Mvc @@ -155,8 +150,8 @@ namespace Umbraco.Tests.Web.Mvc var content = Mock.Of(publishedContent => publishedContent.Id == 12345); - - var publishedRouter = BaseWebTest.CreatePublishedRouter(TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings()); + var webRoutingSettings = new WebRoutingSettings(); + var publishedRouter = BaseWebTest.CreatePublishedRouter(webRoutingSettings); var frequest = publishedRouter.CreateRequest(umbracoContext, new Uri("http://localhost/test")); frequest.PublishedContent = content; @@ -181,7 +176,7 @@ namespace Umbraco.Tests.Web.Mvc private readonly IPublishedContentQuery _publishedContentQuery; public TestSurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IPublishedContentQuery publishedContentQuery) - : base(umbracoContextAccessor, null, ServiceContext.CreatePartial(), AppCaches.Disabled, null, null) + : base(umbracoContextAccessor, null, ServiceContext.CreatePartial(), AppCaches.Disabled, null) { _publishedContentQuery = publishedContentQuery; } diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index 6f1a073eca..c7ab297076 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -1,23 +1,21 @@ using System; using System.Globalization; -using System.Linq; using System.Web.Mvc; using System.Web.Routing; +using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Web.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; -using Umbraco.Core.Strings; +using Umbraco.Tests.Common; using Umbraco.Tests.LegacyXmlPublishedCache; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; -using Umbraco.Tests.Common; using Umbraco.Web; +using Umbraco.Web.Composing; using Umbraco.Web.Models; using Umbraco.Web.Mvc; using Umbraco.Web.Routing; @@ -387,7 +385,8 @@ namespace Umbraco.Tests.Web.Mvc { var umbracoContext = GetUmbracoContext("/dang", 0); - var publishedRouter = BaseWebTest.CreatePublishedRouter(TestHelpers.SettingsForTests.GenerateMockWebRoutingSettings()); + var webRoutingSettings = new WebRoutingSettings(); + var publishedRouter = BaseWebTest.CreatePublishedRouter(webRoutingSettings); var frequest = publishedRouter.CreateRequest(umbracoContext, new Uri("http://localhost/dang")); frequest.Culture = CultureInfo.InvariantCulture; @@ -414,14 +413,14 @@ namespace Umbraco.Tests.Web.Mvc var cache = NoAppCache.Instance; //var provider = new ScopeUnitOfWorkProvider(databaseFactory, new RepositoryFactory(Mock.Of())); - var scopeProvider = TestObjects.GetScopeProvider(Mock.Of()); + var scopeProvider = TestObjects.GetScopeProvider(NullLoggerFactory.Instance); var factory = Mock.Of(); var umbracoContextAccessor = Mock.Of(); _service = new XmlPublishedSnapshotService(svcCtx, factory, scopeProvider, cache, null, null, umbracoContextAccessor, null, null, null, new TestDefaultCultureAccessor(), - Current.Logger, TestObjects.GetGlobalSettings(), + Current.LoggerFactory, TestObjects.GetGlobalSettings(), TestHelper.GetHostingEnvironment(), TestHelper.GetHostingEnvironmentLifetime(), ShortStringHelper, @@ -438,7 +437,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/UmbracoHelperTests.cs b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs index b17943e63e..34beee7499 100644 --- a/src/Umbraco.Tests/Web/UmbracoHelperTests.cs +++ b/src/Umbraco.Tests/Web/UmbracoHelperTests.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Text; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -11,6 +12,7 @@ using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Current = Umbraco.Web.Composing.Current; + namespace Umbraco.Tests.Web { @@ -36,6 +38,7 @@ namespace Umbraco.Tests.Web typeFinder, NoAppCache.Instance, new DirectoryInfo(ioHelper.MapPath("~/App_Data/TEMP")), + Mock.Of>(), new ProfilingLogger(Mock.Of(), Mock.Of()) ) ); 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 06eef1c1bb..a6b350da91 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -1,21 +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 Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.BackOffice; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; 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; @@ -39,54 +39,57 @@ 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 ILogger _logger; + 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; + private readonly LinkGenerator _linkGenerator; // TODO: We need to import the logic from Umbraco.Web.Editors.AuthenticationController // 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, - ILogger logger, + IOptions globalSettings, + IOptions securitySettings, + ILogger logger, IIpResolver ipResolver, - IUserPasswordConfiguration passwordConfiguration, + IOptions passwordConfiguration, IEmailSender emailSender, Core.Hosting.IHostingEnvironment hostingEnvironment, - IRequestAccessor requestAccessor) + 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; + _linkGenerator = linkGenerator; } /// @@ -96,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); } /// @@ -148,7 +151,7 @@ namespace Umbraco.Web.BackOffice.Controllers //NOTE: We are using 30 seconds because that is what is coded into angular to force logout to give some headway in // the timeout process. - _logger.Info( + _logger.LogInformation( "User logged will be logged out due to timeout: {Username}, IP Address: {IPAddress}", backOfficeIdentity.Name, _ipResolver.GetCurrentRequestIpAddress()); @@ -164,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; @@ -186,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 @@ -207,7 +210,7 @@ namespace Umbraco.Web.BackOffice.Controllers [SetAngularAntiForgeryTokens] public ActionResult GetCurrentInvitedUser() { - var user = _webSecurity.CurrentUser; + var user = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser; if (user.IsApproved) { @@ -351,19 +354,19 @@ namespace Umbraco.Web.BackOffice.Controllers var lockedOut = await _userManager.IsLockedOutAsync(identityUser); if (lockedOut) { - _logger.Info("User {UserId} is currently locked out, unlocking and resetting AccessFailedCount", model.UserId); + _logger.LogInformation("User {UserId} is currently locked out, unlocking and resetting AccessFailedCount", model.UserId); //// var user = await UserManager.FindByIdAsync(model.UserId); var unlockResult = await _userManager.SetLockoutEndDateAsync(identityUser, DateTimeOffset.Now); if (unlockResult.Succeeded == false) { - _logger.Warn("Could not unlock for user {UserId} - error {UnlockError}", model.UserId, unlockResult.Errors.First().Description); + _logger.LogWarning("Could not unlock for user {UserId} - error {UnlockError}", model.UserId, unlockResult.Errors.First().Description); } var resetAccessFailedCountResult = await _userManager.ResetAccessFailedCountAsync(identityUser); if (resetAccessFailedCountResult.Succeeded == false) { - _logger.Warn("Could not reset access failed count {UserId} - error {UnlockError}", model.UserId, unlockResult.Errors.First().Description); + _logger.LogWarning("Could not reset access failed count {UserId} - error {UnlockError}", model.UserId, unlockResult.Errors.First().Description); } } @@ -409,7 +412,7 @@ namespace Umbraco.Web.BackOffice.Controllers { HttpContext.SignOutAsync(Core.Constants.Security.BackOfficeAuthenticationType); - _logger.Info("User {UserName} from IP address {RemoteIpAddress} has logged out", User.Identity == null ? "UNKNOWN" : User.Identity.Name, HttpContext.Connection.RemoteIpAddress); + _logger.LogInformation("User {UserName} from IP address {RemoteIpAddress} has logged out", User.Identity == null ? "UNKNOWN" : User.Identity.Name, HttpContext.Connection.RemoteIpAddress); _userManager.RaiseLogoutSuccessEvent(User, int.Parse(User.Identity.GetUserId())); @@ -438,11 +441,10 @@ namespace Umbraco.Web.BackOffice.Controllers private string ConstructCallbackUrl(int userId, string code) { // Get an mvc helper to get the url - var urlHelper = new UrlHelper(ControllerContext); - var action = urlHelper.Action(nameof(BackOfficeController.ValidatePasswordResetCode), ControllerExtensions.GetControllerName(), + var action = _linkGenerator.GetPathByAction(nameof(BackOfficeController.ValidatePasswordResetCode), ControllerExtensions.GetControllerName(), new { - area = _globalSettings.GetUmbracoMvcArea(_hostingEnvironment), + area = Constants.Web.Mvc.BackOfficeArea, u = userId, r = code }); diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs index 7cbeb8e86e..bbb8195aa0 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeAssetsController.cs @@ -2,12 +2,14 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.Extensions.Logging; 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; using Umbraco.Web.Common.Attributes; namespace Umbraco.Web.BackOffice.Controllers @@ -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, ILoggerFactory loggerFactory, IOptions globalSettings) { - _jsLibFileSystem = new PhysicalFileSystem(ioHelper, hostingEnvironment, logger, globalSettings.UmbracoPath + Path.DirectorySeparatorChar + "lib"); + _jsLibFileSystem = new PhysicalFileSystem(ioHelper, hostingEnvironment, loggerFactory.CreateLogger(), 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 1970205ebc..7a8adca44f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -5,15 +5,18 @@ 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 Microsoft.Extensions.Logging; 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; using Umbraco.Extensions; @@ -29,50 +32,50 @@ 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 ILogger _logger; + 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, - ILogger logger) - + 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; } [HttpGet] @@ -80,7 +83,7 @@ namespace Umbraco.Web.BackOffice.Controllers { var viewPath = Path.Combine(_globalSettings.UmbracoPath , Constants.Web.Mvc.BackOfficeArea, nameof(Default) + ".cshtml") .Replace("\\", "/"); // convert to forward slashes since it's a virtual path - + return await RenderDefaultOrProcessExternalLoginAsync( () => View(viewPath), () => View(viewPath)); @@ -92,14 +95,14 @@ 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(); } if (invite == null) { - _logger.Warn("VerifyUser endpoint reached with invalid token: NULL"); + _logger.LogWarning("VerifyUser endpoint reached with invalid token: NULL"); return RedirectToAction(nameof(Default)); } @@ -107,7 +110,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (parts.Length != 2) { - _logger.Warn("VerifyUser endpoint reached with invalid token: {Invite}", invite); + _logger.LogWarning("VerifyUser endpoint reached with invalid token: {Invite}", invite); return RedirectToAction(nameof(Default)); } @@ -116,7 +119,7 @@ namespace Umbraco.Web.BackOffice.Controllers var decoded = token.FromUrlBase64(); if (decoded.IsNullOrWhiteSpace()) { - _logger.Warn("VerifyUser endpoint reached with invalid token: {Invite}", invite); + _logger.LogWarning("VerifyUser endpoint reached with invalid token: {Invite}", invite); return RedirectToAction(nameof(Default)); } @@ -125,7 +128,7 @@ namespace Umbraco.Web.BackOffice.Controllers var identityUser = await _userManager.FindByIdAsync(id); if (identityUser == null) { - _logger.Warn("VerifyUser endpoint reached with non existing user: {UserId}", id); + _logger.LogWarning("VerifyUser endpoint reached with non existing user: {UserId}", id); return RedirectToAction(nameof(Default)); } @@ -133,7 +136,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (result.Succeeded == false) { - _logger.Warn("Could not verify email, Error: {Errors}, Token: {Invite}", result.Errors.ToErrorMessage(), invite); + _logger.LogWarning("Could not verify email, Error: {Errors}, Token: {Invite}", result.Errors.ToErrorMessage(), invite); return new RedirectResult(Url.Action(nameof(Default)) + "#/login/false?invite=3"); } @@ -185,7 +188,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' @@ -250,11 +253,11 @@ namespace Umbraco.Web.BackOffice.Controllers var user = await _userManager.FindByIdAsync(userId.ToString()); if (user != null) { - var result = await _userManager.VerifyUserTokenAsync(user, "ResetPassword", "ResetPassword", resetCode); + var result = await _userManager.VerifyUserTokenAsync(user, "Default", "ResetPassword", resetCode); if (result) { //Add a flag and redirect for it to be displayed - TempData[ViewDataExtensions.TokenPasswordResetCode] = new ValidatePasswordResetCodeModel { UserId = userId, ResetCode = resetCode }; + TempData[ViewDataExtensions.TokenPasswordResetCode] = _jsonSerializer.Serialize(new ValidatePasswordResetCodeModel { UserId = userId, ResetCode = resetCode }); return RedirectToLocal(Url.Action("Default", "BackOffice")); } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs index 34494e1492..9f109d7bbf 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs @@ -1,28 +1,27 @@ -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.Media; using Umbraco.Core.WebAssets; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Profiling; using Umbraco.Web.BackOffice.PropertyEditors; +using Umbraco.Web.BackOffice.Routing; 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,45 +33,51 @@ 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; + private readonly IImageUrlGenerator _imageUrlGenerator; + private readonly PreviewRoutes _previewRoutes; public BackOfficeServerVariables( 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) + IAuthenticationSchemeProvider authenticationSchemeProvider, + IImageUrlGenerator imageUrlGenerator, + PreviewRoutes previewRoutes) { _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; + _imageUrlGenerator = imageUrlGenerator; + _previewRoutes = previewRoutes; } /// @@ -84,7 +89,7 @@ namespace Umbraco.Web.BackOffice.Controllers //this is the filter for the keys that we'll keep based on the full version of the server vars var keepOnlyKeys = new Dictionary { - {"umbracoUrls", new[] {"authenticationApiBaseUrl", "serverVarsJs", "externalLoginsUrl", "currentUserApiBaseUrl"}}, + {"umbracoUrls", new[] {"authenticationApiBaseUrl", "serverVarsJs", "externalLoginsUrl", "currentUserApiBaseUrl", "previewHubUrl"}}, {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage", "canSendRequiredEmail", "usernameIsEmail"}}, {"application", new[] {"applicationPath", "cacheBuster"}}, {"isDebuggingEnabled", new string[] { }}, @@ -356,6 +361,9 @@ namespace Umbraco.Web.BackOffice.Controllers "elementTypeApiBaseUrl", _linkGenerator.GetUmbracoApiServiceBaseUrl( controller => controller.GetAll()) }, + { + "previewHubUrl", _previewRoutes.GetPreviewHubRoute() + }, } }, { @@ -366,7 +374,7 @@ namespace Umbraco.Web.BackOffice.Controllers {"appPluginsPath", _hostingEnvironment.ToAbsolute(Constants.SystemDirectories.AppPlugins).TrimEnd('/')}, { "imageFileTypes", - string.Join(",", _contentSettings.ImageFileTypes) + string.Join(",", _imageUrlGenerator.SupportedImageFileTypes) }, { "disallowedUploadFiles", @@ -513,7 +521,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..96f0689b52 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -7,10 +7,10 @@ using System.Net.Mime; using System.Text; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Umbraco.Core; 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; @@ -39,7 +39,7 @@ using Umbraco.Web.Models.Mapping; using Umbraco.Web.Security; using Umbraco.Web.WebApi.Filters; -namespace Umbraco.Web.Editors +namespace Umbraco.Web.BackOffice.Controllers { /// /// The API controller used for editing content @@ -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; @@ -72,19 +72,20 @@ namespace Umbraco.Web.Editors private readonly IMemberGroupService _memberGroupService; private readonly ISqlContext _sqlContext; private readonly Lazy> _allLangs; + private readonly ILogger _logger; public object Domains { get; private set; } public ContentController( ICultureDictionary cultureDictionary, - ILogger logger, + ILoggerFactory loggerFactory, IShortStringHelper shortStringHelper, IEventMessagesFactory eventMessages, ILocalizedTextService localizedTextService, PropertyEditorCollection propertyEditors, IContentService contentService, IUserService userService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IEntityService entityService, IContentTypeService contentTypeService, UmbracoMapper umbracoMapper, @@ -99,13 +100,13 @@ namespace Umbraco.Web.Editors ActionCollection actionCollection, IMemberGroupService memberGroupService, ISqlContext sqlContext) - : base(cultureDictionary, logger, shortStringHelper, eventMessages, localizedTextService) + : base(cultureDictionary, loggerFactory, shortStringHelper, eventMessages, localizedTextService) { _propertyEditors = propertyEditors; _contentService = contentService; _localizedTextService = localizedTextService; _userService = userService; - _webSecurity = webSecurity; + _backofficeSecurityAccessor = backofficeSecurityAccessor; _entityService = entityService; _contentTypeService = contentTypeService; _umbracoMapper = umbracoMapper; @@ -120,6 +121,7 @@ namespace Umbraco.Web.Editors _actionCollection = actionCollection; _memberGroupService = memberGroupService; _sqlContext = sqlContext; + _logger = loggerFactory.CreateLogger(); _allLangs = new Lazy>(() => _localizationService.GetAllLanguages().ToDictionary(x => x.IsoCode, x => x, StringComparer.InvariantCultureIgnoreCase)); @@ -428,7 +430,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 +599,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 +635,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 +660,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 +762,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 +1206,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 +1223,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 +1258,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 +1267,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 +1295,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 +1340,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 +1348,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 +1503,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 +1555,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 +1565,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 +1589,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,10 +1618,10 @@ 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"); + _logger.LogWarning("Content sorting failed, this was probably caused by an event being cancelled"); // TODO: Now you can cancel sorting, does the event messages bubble up automatically? throw HttpResponseException.CreateValidationErrorResponse("Content sorting failed, this was probably caused by an event being cancelled"); } @@ -1628,7 +1630,7 @@ namespace Umbraco.Web.Editors } catch (Exception ex) { - Logger.Error(ex, "Could not update content sort order"); + _logger.LogError(ex, "Could not update content sort order"); throw; } } @@ -1643,7 +1645,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 +1660,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 +1683,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 +1706,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 +1774,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) @@ -2001,7 +2003,7 @@ namespace Umbraco.Web.Editors if (template == null) { //ModelState.AddModelError("Template", "No template exists with the specified alias: " + contentItem.TemplateAlias); - Logger.Warn("No template exists with the specified alias: {TemplateAlias}", contentSave.TemplateAlias); + _logger.LogWarning("No template exists with the specified alias: {TemplateAlias}", contentSave.TemplateAlias); } else if (template.Id != contentSave.PersistedContent.TemplateId) { @@ -2260,7 +2262,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 +2277,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 +2299,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 +2364,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/ContentControllerBase.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs index 9e9f7e8fbd..d2b751837c 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs @@ -3,13 +3,13 @@ using System.Linq; using System.Net; using System.Net.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Umbraco.Composing; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; -using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; @@ -30,20 +30,22 @@ namespace Umbraco.Web.BackOffice.Controllers public abstract class ContentControllerBase : BackOfficeNotificationsController { protected ICultureDictionary CultureDictionary { get; } - protected ILogger Logger { get; } + protected ILoggerFactory LoggerFactory { get; } protected IShortStringHelper ShortStringHelper { get; } protected IEventMessagesFactory EventMessages { get; } protected ILocalizedTextService LocalizedTextService { get; } + private readonly ILogger _logger; protected ContentControllerBase( ICultureDictionary cultureDictionary, - ILogger logger, + ILoggerFactory loggerFactory, IShortStringHelper shortStringHelper, IEventMessagesFactory eventMessages, ILocalizedTextService localizedTextService) { CultureDictionary = cultureDictionary; - Logger = logger; + LoggerFactory = loggerFactory; + _logger = loggerFactory.CreateLogger(); ShortStringHelper = shortStringHelper; EventMessages = eventMessages; LocalizedTextService = localizedTextService; @@ -78,7 +80,7 @@ namespace Umbraco.Web.BackOffice.Controllers // get the property editor if (propertyDto.PropertyEditor == null) { - Logger.Warn("No property editor found for property {PropertyAlias}", propertyDto.Alias); + _logger.LogWarning("No property editor found for property {PropertyAlias}", propertyDto.Alias); continue; } diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs index 146f2c32b7..6d15333abd 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs @@ -8,6 +8,7 @@ using System.Text; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; +using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Core; @@ -15,7 +16,6 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; using Umbraco.Core.Hosting; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; @@ -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,18 +51,19 @@ 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; private readonly IFileService _fileService; - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IContentService _contentService; private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; private readonly ILocalizationService _LocalizationService; @@ -67,31 +71,31 @@ 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, - ILogger logger, + ILogger logger, + ILoggerFactory loggerFactory, IContentService contentService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, ILocalizationService localizationService, IMacroService macroService, IEntityService entityService, - IHostingEnvironment hostingEnvironment) + IHostingEnvironment hostingEnvironment, + EditorValidatorCollection editorValidatorCollection) : base(cultureDictionary, editorValidatorCollection, contentTypeService, @@ -101,18 +105,19 @@ 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; _fileService = fileService; _logger = logger; + _loggerFactory = loggerFactory; _contentService = contentService; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; _LocalizationService = localizationService; @@ -206,7 +211,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 +310,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 +326,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 @@ -461,7 +466,7 @@ namespace Umbraco.Web.BackOffice.Controllers var tryCreateTemplate = _fileService.CreateTemplateForContentType(contentTypeAlias, contentTypeName); if (tryCreateTemplate == false) { - _logger.Warn("Could not create a template for Content Type: \"{ContentTypeAlias}\", status: {Status}", + _logger.LogWarning("Could not create a template for Content Type: \"{ContentTypeAlias}\", status: {Status}", contentTypeAlias, tryCreateTemplate.Result.Result); } @@ -615,13 +620,13 @@ namespace Umbraco.Web.BackOffice.Controllers return NotFound(); } - var dataInstaller = new PackageDataInstallation(_logger, _fileService, _macroService, _LocalizationService, - _dataTypeService, _entityService, _contentTypeService, _contentService, _propertyEditors, _scopeProvider, _shortStringHelper, _globalSettings, _localizedTextService); + var dataInstaller = new PackageDataInstallation(_loggerFactory.CreateLogger(), _loggerFactory, _fileService, _macroService, _LocalizationService, + _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); @@ -632,7 +637,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (Exception ex) { - _logger.Error(ex, "Error cleaning up temporary udt file in App_Data: {File}", filePath); + _logger.LogError(ex, "Error cleaning up temporary udt file in App_Data: {File}", filePath); } return Ok(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 3bf44f4e9c..8efe13782a 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 Microsoft.Extensions.Logging; 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.Logging; +using Umbraco.Core.IO; 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,41 +37,41 @@ 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 ILogger _logger; + private readonly IBackOfficeUserManager _backOfficeUserManager; + private readonly ILoggerFactory _loggerFactory; private readonly ILocalizedTextService _localizedTextService; private readonly AppCaches _appCaches; private readonly IShortStringHelper _shortStringHelper; public CurrentUserController( IMediaFileSystem mediaFileSystem, - IContentSettings contentSettings, + IOptions contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IUserService userService, UmbracoMapper umbracoMapper, - BackOfficeUserManager backOfficeUserManager, - ILogger logger, + IBackOfficeUserManager backOfficeUserManager, + ILoggerFactory loggerFactory, 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; - _logger = logger; + _loggerFactory = loggerFactory; _localizedTextService = localizedTextService; _appCaches = appCaches; _shortStringHelper = shortStringHelper; @@ -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)); } /// @@ -216,8 +216,8 @@ 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 passwordChanger = new PasswordChanger(_loggerFactory.CreateLogger()); + 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..0d341e9a04 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs @@ -9,8 +9,8 @@ using System; using System.Linq; using System.Text; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Umbraco.Core.Cache; -using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -34,7 +34,7 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly AppCaches _appCaches; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IDashboardService _dashboardService; private readonly IUmbracoVersion _umbracoVersion; private readonly IShortStringHelper _shortStringHelper; @@ -43,12 +43,11 @@ 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, AppCaches appCaches, - ILogger logger, + ILogger logger, IRuntimeState runtimeState, IDashboardService dashboardService, IUmbracoVersion umbracoVersion, @@ -98,7 +97,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (HttpRequestException ex) { - _logger.Error(ex.InnerException ?? ex, "Error getting dashboard content from {Url}", url); + _logger.LogError(ex.InnerException ?? ex, "Error getting dashboard content from {Url}", url); //it's still new JObject() - we return it like this to avoid error codes which triggers UI warnings _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0)); @@ -136,7 +135,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (HttpRequestException ex) { - _logger.Error(ex.InnerException ?? ex, "Error getting dashboard CSS from {Url}", url); + _logger.LogError(ex.InnerException ?? ex, "Error getting dashboard CSS from {Url}", url); //it's still string.Empty - we return it like this to avoid error codes which triggers UI warnings _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0)); @@ -199,7 +198,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (HttpRequestException ex) { - _logger.Error(ex.InnerException ?? ex, "Error getting remote dashboard data from {UrlPrefix}{Url}", urlPrefix, url); + _logger.LogError(ex.InnerException ?? ex, "Error getting remote dashboard data from {UrlPrefix}{Url}", urlPrefix, url); //it's still string.Empty - we return it like this to avoid error codes which triggers UI warnings _appCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0)); 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..dded7dad30 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs @@ -3,11 +3,12 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Umbraco.Core; 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 { @@ -30,26 +33,26 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoTreeAuthorize(Constants.Trees.Dictionary)] public class DictionaryController : BackOfficeNotificationsController { - private readonly ILogger _logger; + 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, + 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); } @@ -124,7 +127,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (Exception ex) { - _logger.Error(GetType(), ex, "Error creating dictionary with {Name} under {ParentId}", key, parentId); + _logger.LogError(ex, "Error creating dictionary with {Name} under {ParentId}", key, parentId); throw HttpResponseException.CreateNotificationValidationErrorResponse("Error creating dictionary item"); } } @@ -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) { @@ -257,7 +260,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (Exception ex) { - _logger.Error(GetType(), ex, "Error saving dictionary with {Name} under {ParentId}", dictionary.Name, dictionary.ParentId); + _logger.LogError(ex, "Error saving dictionary with {Name} under {ParentId}", dictionary.Name, dictionary.ParentId); throw HttpResponseException.CreateNotificationValidationErrorResponse("Something went wrong saving dictionary"); } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 433cf6f345..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)) { @@ -248,6 +249,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// UDI of the entity to fetch URL for /// The culture to fetch the URL for /// The URL or path to the item + [DetermineAmbiguousActionByPassingParameters] public HttpResponseMessage GetUrl(Udi udi, string culture = "*") { var intId = _entityService.GetId(udi); @@ -281,6 +283,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// We are not restricting this with security because there is no sensitive data /// + [DetermineAmbiguousActionByPassingParameters] public HttpResponseMessage GetUrl(int id, UmbracoEntityTypes type, string culture = null) { culture = culture ?? ClientCulture(); @@ -719,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(); } @@ -860,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/ExamineManagementController.cs b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs index a302f7f7cf..72f07c02f3 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs @@ -4,10 +4,10 @@ using System.Linq; using Examine; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.IO; -using Umbraco.Core.Logging; using Umbraco.Examine; using Umbraco.Extensions; using Umbraco.Web.Common.Attributes; @@ -22,14 +22,14 @@ namespace Umbraco.Web.BackOffice.Controllers public class ExamineManagementController : UmbracoAuthorizedJsonController { private readonly IExamineManager _examineManager; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IIOHelper _ioHelper; private readonly IIndexDiagnosticsFactory _indexDiagnosticsFactory; private readonly IAppPolicyCache _runtimeCache; private readonly IndexRebuilder _indexRebuilder; - public ExamineManagementController(IExamineManager examineManager, ILogger logger, IIOHelper ioHelper, IIndexDiagnosticsFactory indexDiagnosticsFactory, + public ExamineManagementController(IExamineManager examineManager, ILogger logger, IIOHelper ioHelper, IIndexDiagnosticsFactory indexDiagnosticsFactory, AppCaches appCaches, IndexRebuilder indexRebuilder) { @@ -136,7 +136,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (!validate.IsSuccessStatusCode()) throw new HttpResponseException(validate); - _logger.Info("Rebuilding index '{IndexName}'", indexName); + _logger.LogInformation("Rebuilding index '{IndexName}'", indexName); //remove it in case there's a handler there already index.IndexOperationComplete -= Indexer_IndexOperationComplete; @@ -162,7 +162,7 @@ namespace Umbraco.Web.BackOffice.Controllers { //ensure it's not listening index.IndexOperationComplete -= Indexer_IndexOperationComplete; - _logger.Error(ex, "An error occurred rebuilding index"); + _logger.LogError(ex, "An error occurred rebuilding index"); var response = new ConflictObjectResult("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {ex}"); HttpContext.SetReasonPhrase("Could Not Rebuild"); @@ -245,14 +245,12 @@ namespace Umbraco.Web.BackOffice.Controllers { var indexer = (IIndex)sender; - _logger.Debug("Logging operation completed for index {IndexName}", indexer.Name); + _logger.LogDebug("Logging operation completed for index {IndexName}", indexer.Name); //ensure it's not listening anymore indexer.IndexOperationComplete -= Indexer_IndexOperationComplete; - _logger - .Info($"Rebuilding index '{indexer.Name}' done."); + _logger.LogInformation($"Rebuilding index '{indexer.Name}' done."); var cacheKey = "temp_indexing_op_" + indexer.Name; _runtimeCache.Clear(cacheKey); diff --git a/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs b/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs index 24ec184519..285915873c 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/HelpController.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.Net.Http; using System.Runtime.Serialization; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Editors; @@ -13,9 +13,9 @@ namespace Umbraco.Web.BackOffice.Controllers [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] public class HelpController : UmbracoAuthorizedJsonController { - private readonly ILogger _logger; + private readonly ILogger _logger; - public HelpController(ILogger logger) + public HelpController(ILogger logger) { _logger = logger; } @@ -40,7 +40,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (HttpRequestException rex) { - _logger.Info(GetType(), $"Check your network connection, exception: {rex.Message}"); + _logger.LogInformation($"Check your network connection, exception: {rex.Message}"); } return new List(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/IconController.cs b/src/Umbraco.Web.BackOffice/Controllers/IconController.cs index bbefa82bd9..a856306118 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/IconController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/IconController.cs @@ -1,29 +1,18 @@ 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.Web.BackOffice.Controllers; +using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Common.Attributes; -using Umbraco.Web.Common.Filters; -namespace Umbraco.Web.Editors +namespace Umbraco.Web.BackOffice.Controllers { [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 +23,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..1f626b1b0f 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ImagesController.cs @@ -2,7 +2,6 @@ using System.IO; using Microsoft.AspNetCore.Mvc; using Umbraco.Core; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Media; using Umbraco.Core.Models; @@ -18,14 +17,13 @@ namespace Umbraco.Web.BackOffice.Controllers public class ImagesController : UmbracoAuthorizedApiController { private readonly IMediaFileSystem _mediaFileSystem; - private readonly IContentSettings _contentSettings; private readonly IImageUrlGenerator _imageUrlGenerator; - public ImagesController(IMediaFileSystem mediaFileSystem, IContentSettings contentSettings, + public ImagesController( + IMediaFileSystem mediaFileSystem, IImageUrlGenerator imageUrlGenerator) { _mediaFileSystem = mediaFileSystem; - _contentSettings = contentSettings; _imageUrlGenerator = imageUrlGenerator; } @@ -58,7 +56,7 @@ namespace Umbraco.Web.BackOffice.Controllers var ext = Path.GetExtension(imagePath); // we need to check if it is an image by extension - if (_contentSettings.IsImageFile(ext) == false) + if (_imageUrlGenerator.IsSupportedImageFormat(ext) == false) return NotFound(); //redirect to ImageProcessor thumbnail with rnd generated from last modified time of original media file @@ -99,9 +97,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 +107,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..9b6878dcbe 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs @@ -5,8 +5,8 @@ using System.IO; using System.Linq; using System.Net.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Umbraco.Core.Hosting; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Strings; using Umbraco.Web.Models.ContentEditing; @@ -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,8 +33,8 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly ParameterEditorCollection _parameterEditorCollection; private readonly IMacroService _macroService; private readonly IShortStringHelper _shortStringHelper; - private readonly IWebSecurity _webSecurity; - private readonly ILogger _logger; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly ILogger _logger; private readonly IHostingEnvironment _hostingEnvironment; private readonly UmbracoMapper _umbracoMapper; @@ -41,8 +42,8 @@ namespace Umbraco.Web.BackOffice.Controllers ParameterEditorCollection parameterEditorCollection, IMacroService macroService, IShortStringHelper shortStringHelper, - IWebSecurity webSecurity, - ILogger logger, + 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,14 +96,14 @@ namespace Umbraco.Web.BackOffice.Controllers MacroSource = string.Empty }; - _macroService.Save(macro, _webSecurity.CurrentUser.Id); + _macroService.Save(macro, _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id); return macro.Id; } catch (Exception exception) { const string errorMessage = "Error creating macro"; - _logger.Error(exception, errorMessage); + _logger.LogError(exception, errorMessage); throw HttpResponseException.CreateNotificationValidationErrorResponse(errorMessage); } } @@ -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(); @@ -226,7 +227,7 @@ namespace Umbraco.Web.BackOffice.Controllers catch (Exception exception) { const string errorMessage = "Error creating macro"; - _logger.Error(exception, errorMessage); + _logger.LogError(exception, errorMessage); throw HttpResponseException.CreateNotificationValidationErrorResponse(errorMessage); } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index ba19f7c2b4..5bf6798170 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -3,35 +3,32 @@ 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.Logging; +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.Mapping; +using Umbraco.Core.Media; +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.Web.ContentApps; -using Umbraco.Web.WebApi.Filters; -using Constants = Umbraco.Core.Constants; -using Umbraco.Core.Mapping; +using Umbraco.Core.Security; +using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Filters; @@ -39,7 +36,10 @@ using Umbraco.Web.BackOffice.ModelBinders; using Umbraco.Web.Common.ActionResults; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; -using Umbraco.Web.Security; +using Umbraco.Web.ContentApps; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.BackOffice.Controllers { @@ -52,28 +52,31 @@ 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; private readonly ISqlContext _sqlContext; private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; private readonly IRelationService _relationService; + private readonly IImageUrlGenerator _imageUrlGenerator; + private readonly ILogger _logger; + public MediaController( ICultureDictionary cultureDictionary, - ILogger logger, + ILoggerFactory loggerFactory, 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, @@ -81,15 +84,16 @@ namespace Umbraco.Web.BackOffice.Controllers IRelationService relationService, PropertyEditorCollection propertyEditors, IMediaFileSystem mediaFileSystem, - IHostingEnvironment hostingEnvironment) - : base(cultureDictionary, logger, shortStringHelper, eventMessages, localizedTextService) + IHostingEnvironment hostingEnvironment, + IImageUrlGenerator imageUrlGenerator) + : base(cultureDictionary, loggerFactory, 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; @@ -99,6 +103,8 @@ namespace Umbraco.Web.BackOffice.Controllers _propertyEditors = propertyEditors; _mediaFileSystem = mediaFileSystem; _hostingEnvironment = hostingEnvironment; + _logger = loggerFactory.CreateLogger(); + _imageUrlGenerator = imageUrlGenerator; } /// @@ -116,7 +122,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 +284,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 +441,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 +451,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 +475,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 +549,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 +595,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")); } @@ -622,14 +628,14 @@ namespace Umbraco.Web.BackOffice.Controllers // Save Media with new sort order and update content xml in db accordingly if (mediaService.Sort(sortedMedia) == false) { - Logger.Warn("Media sorting failed, this was probably caused by an event being cancelled"); + _logger.LogWarning("Media sorting failed, this was probably caused by an event being cancelled"); throw HttpResponseException.CreateValidationErrorResponse("Media sorting failed, this was probably caused by an event being cancelled"); } return Ok(); } catch (Exception ex) { - Logger.Error(ex, "Could not update media sort order"); + _logger.LogError(ex, "Could not update media sort order"); throw; } } @@ -646,7 +652,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 +748,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (contentTypeAlias == Constants.Conventions.MediaTypes.AutoSelect) { - if (_contentSettings.ImageFileTypes.Contains(ext)) + if (_imageUrlGenerator.SupportedImageFileTypes.Contains(ext)) { mediaType = Constants.Conventions.MediaTypes.Image; } @@ -754,7 +760,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 +769,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 +862,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..fd4d5c96cc 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.Logging; +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,27 +54,27 @@ 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( ICultureDictionary cultureDictionary, - ILogger logger, + ILoggerFactory loggerFactory, 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) + : base(cultureDictionary, loggerFactory, 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; } @@ -305,18 +305,22 @@ namespace Umbraco.Web.BackOffice.Controllers private IMember CreateMemberData(MemberSave contentItem) { - var memberType = _memberTypeService.Get(contentItem.ContentTypeAlias); - if (memberType == null) - 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, - RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword), - Comments = contentItem.Comments, - IsApproved = contentItem.IsApproved - }; + throw new NotImplementedException("Members have not been migrated to netcore"); - return member; + // TODO: all member password processing and creation needs to be done with a new aspnet identity MemberUserManager that hasn't been created yet. + + //var memberType = _memberTypeService.Get(contentItem.ContentTypeAlias); + //if (memberType == null) + // throw new InvalidOperationException($"No member type found with alias {contentItem.ContentTypeAlias}"); + //var member = new Member(contentItem.Name, contentItem.Email, contentItem.Username, memberType, true) + //{ + // CreatorId = _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.Id, + // RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword), + // Comments = contentItem.Comments, + // IsApproved = contentItem.IsApproved + //}; + + //return member; } /// @@ -328,13 +332,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 @@ -372,8 +376,10 @@ namespace Umbraco.Web.BackOffice.Controllers if (contentItem.Password == null) return; + throw new NotImplementedException("Members have not been migrated to netcore"); + // TODO: all member password processing and creation needs to be done with a new aspnet identity MemberUserManager that hasn't been created yet. // set the password - contentItem.PersistedContent.RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword); + //contentItem.PersistedContent.RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword); } private static void UpdateName(MemberSave memberSave) @@ -458,7 +464,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..69188e1636 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs @@ -16,14 +16,16 @@ 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; using Umbraco.Web.Common.Exceptions; +using Umbraco.Web.Editors; using Umbraco.Web.Routing; using Umbraco.Web.Security; -namespace Umbraco.Web.Editors +namespace Umbraco.Web.BackOffice.Controllers { /// /// An API controller used for dealing with member types @@ -33,7 +35,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 +48,7 @@ namespace Umbraco.Web.Editors IMemberTypeService memberTypeService, UmbracoMapper umbracoMapper, ILocalizedTextService localizedTextService, - IWebSecurity webSecurity, + IBackofficeSecurityAccessor backofficeSecurityAccessor, IShortStringHelper shortStringHelper) : base(cultureDictionary, editorValidatorCollection, @@ -57,7 +59,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 +143,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 +203,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..4959ffe2aa 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs @@ -5,14 +5,15 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Semver; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Hosting; -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; @@ -37,8 +38,8 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IUmbracoApplicationLifetime _umbracoApplicationLifetime; private readonly IRuntimeMinifier _runtimeMinifier; private readonly IPackagingService _packagingService; - private readonly ILogger _logger; - private readonly IWebSecurity _webSecurity; + private readonly ILogger _logger; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILocalizedTextService _localizedTextService; public PackageInstallController( @@ -47,8 +48,8 @@ namespace Umbraco.Web.BackOffice.Controllers IUmbracoApplicationLifetime umbracoApplicationLifetime, IRuntimeMinifier runtimeMinifier, IPackagingService packagingService, - ILogger logger, - IWebSecurity webSecurity, + ILogger logger, + 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,19 +88,19 @@ 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) { - _logger.Error(ex, "Failed to uninstall."); + _logger.LogError(ex, "Failed to uninstall."); throw; } @@ -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..898cf123a5 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs @@ -2,7 +2,7 @@ using System.Xml; using System.Security; using Microsoft.AspNetCore.Mvc; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Web.Models.ContentEditing; using Umbraco.Core; @@ -12,32 +12,40 @@ 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 { [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] public class RedirectUrlManagementController : UmbracoAuthorizedApiController { - private readonly ILogger _logger; - private readonly IWebRoutingSettings _webRoutingSettings; - private readonly IWebSecurity _webSecurity; + private readonly ILogger _logger; + 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); + _logger.LogDebug(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..1ab5bd9bfa 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/RelationTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/RelationTypeController.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Net; using System.Net.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -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 { @@ -26,13 +25,13 @@ namespace Umbraco.Web.BackOffice.Controllers [UmbracoTreeAuthorize(Constants.Trees.RelationTypes)] public class RelationTypeController : BackOfficeNotificationsController { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly UmbracoMapper _umbracoMapper; private readonly IRelationService _relationService; private readonly IShortStringHelper _shortStringHelper; public RelationTypeController( - ILogger logger, + ILogger logger, UmbracoMapper umbracoMapper, IRelationService relationService, IShortStringHelper shortStringHelper) @@ -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 /// @@ -157,7 +154,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (Exception ex) { - _logger.Error(GetType(), ex, "Error creating relation type with {Name}", relationType.Name); + _logger.LogError(ex, "Error creating relation type with {Name}", relationType.Name); throw HttpResponseException.CreateNotificationValidationErrorResponse("Error creating relation type."); } } @@ -188,7 +185,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (Exception ex) { - _logger.Error(GetType(), ex, "Error saving relation type with {Id}", relationType.Id); + _logger.LogError(ex, "Error saving relation type with {Id}", relationType.Id); throw HttpResponseException.CreateNotificationValidationErrorResponse("Something went wrong when saving the relation type"); } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs b/src/Umbraco.Web.BackOffice/Controllers/SectionController.cs index 5239994e04..982dab6dec 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; @@ -13,7 +15,7 @@ using Umbraco.Web.Security; using Umbraco.Web.Services; using Umbraco.Web.Trees; -namespace Umbraco.Web.Editors +namespace Umbraco.Web.BackOffice.Controllers { /// /// The API controller used for using the list of sections @@ -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..4bae8970bc 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs @@ -6,10 +6,13 @@ 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.Media; using Umbraco.Core.Strings; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.ActionsResults; @@ -28,20 +31,22 @@ 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; + private readonly IImageUrlGenerator _imageUrlGenerator; public TinyMceController( IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper, - IContentSettings contentSettings, - IIOHelper ioHelper - ) + IOptions contentSettings, + IIOHelper ioHelper, + IImageUrlGenerator imageUrlGenerator) { _hostingEnvironment = hostingEnvironment; _shortStringHelper = shortStringHelper; - _contentSettings = contentSettings; + _contentSettings = contentSettings.Value; _ioHelper = ioHelper; + _imageUrlGenerator = imageUrlGenerator; } [HttpPost] @@ -76,7 +81,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 || _imageUrlGenerator.SupportedImageFileTypes.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..c232401b78 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/UmbracoAuthorizedApiController.cs @@ -1,4 +1,5 @@ -using Umbraco.Web.BackOffice.Filters; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.Filters; @@ -14,13 +15,12 @@ namespace Umbraco.Web.BackOffice.Controllers /// before their timeout expires. /// [IsBackOffice] - //[UmbracoUserTimeoutFilter] //TODO reintroduce + [UmbracoUserTimeoutFilter] [UmbracoAuthorize] [DisableBrowserCache] [UmbracoWebApiRequireHttps] - //[CheckIfUserTicketDataIsStale] //TODO reintroduce - //[UnhandedExceptionLoggerConfiguration] //TODO reintroduce - //[EnableDetailedErrors] //TODO reintroduce + [CheckIfUserTicketDataIsStale] + [MiddlewareFilter(typeof(UnhandledExceptionLoggerFilter))] 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..d45951a3df 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 Microsoft.Extensions.Logging; 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 ILogger _logger; + private readonly GlobalSettings _globalSettings; + private readonly IBackOfficeUserManager _backOfficeUserManager; + private readonly ILoggerFactory _loggerFactory; 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, - ILogger logger, + IOptions globalSettings, + IBackOfficeUserManager backOfficeUserManager, + ILoggerFactory loggerFactory, 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,9 +116,9 @@ namespace Umbraco.Web.BackOffice.Controllers _entityService = entityService; _mediaService = mediaService; _contentService = contentService; - _globalSettings = globalSettings; + _globalSettings = globalSettings.Value; _backOfficeUserManager = backOfficeUserManager; - _logger = logger; + _loggerFactory = loggerFactory; _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); @@ -657,8 +661,8 @@ namespace Umbraco.Web.BackOffice.Controllers throw new HttpResponseException(HttpStatusCode.NotFound); } - var passwordChanger = new PasswordChanger(_logger); - var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(_webSecurity.CurrentUser, found, changingPasswordModel, _backOfficeUserManager); + var passwordChanger = new PasswordChanger(_loggerFactory.CreateLogger()); + 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..471aed51e1 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) { @@ -20,6 +20,7 @@ namespace Umbraco.Extensions app.UseRequestLocalization(); app.UseUmbracoRequestLogging(); app.UseUmbracoBackOffice(); + app.UseUmbracoPreview(); app.UseUmbracoInstaller(); return app; @@ -44,15 +45,20 @@ 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; } + public static IApplicationBuilder UseUmbracoPreview(this IApplicationBuilder app) + { + app.UseEndpoints(endpoints => + { + var previewRoutes = app.ApplicationServices.GetRequiredService(); + previewRoutes.CreateRoutes(endpoints); + }); + + return app; + } } } diff --git a/src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeServiceCollectionExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs similarity index 61% rename from src/Umbraco.Web.BackOffice/Extensions/UmbracoBackOfficeServiceCollectionExtensions.cs rename to src/Umbraco.Web.BackOffice/Extensions/BackOfficeServiceCollectionExtensions.cs index fc3efab5e0..71fa97b9cb 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 /// @@ -85,6 +45,11 @@ namespace Umbraco.Extensions services.ConfigureOptions(); } + public static void AddUmbracoPreview(this IServiceCollection services) + { + services.AddSignalR(); + } + /// /// Adds the services required for using Umbraco back office Identity /// @@ -98,14 +63,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 +86,7 @@ namespace Umbraco.Extensions services.TryAddScoped, PasswordValidator>(); services.TryAddScoped>( services => new BackOfficePasswordHasher( - new LegacyPasswordSecurity(services.GetRequiredService()), + new LegacyPasswordSecurity(), 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/HtmlHelperBackOfficeExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs index ad51b1b543..68025fc7ab 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs @@ -116,8 +116,7 @@ namespace Umbraco.Extensions sb.AppendLine(); sb.AppendLine(@"var errors = [];"); - var errors = val as IEnumerable; - if (errors != null) + if (val is IEnumerable errors) { foreach (var error in errors) { @@ -125,13 +124,10 @@ namespace Umbraco.Extensions } } - var resetCodeModel = val as ValidatePasswordResetCodeModel; - - sb.AppendLine(@"app.value(""resetPasswordCodeInfo"", {"); sb.AppendLine(@"errors: errors,"); sb.Append(@"resetCodeModel: "); - sb.AppendLine(JsonConvert.SerializeObject(resetCodeModel)); + sb.AppendLine(val?.ToString() ?? "null"); sb.AppendLine(@"});"); return html.Raw(sb.ToString()); 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..a1a671527a --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Extensions/UmbracoBuilderExtensions.cs @@ -0,0 +1,32 @@ +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() + .WithPreview() + .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()); + + public static IUmbracoBuilder WithPreview(this IUmbracoBuilder builder) + => builder.AddWith(nameof(WithPreview), () => builder.Services.AddUmbracoPreview()); + } +} 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..812e4e0a73 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentModelValidator.cs @@ -6,7 +6,7 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -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 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)); } } @@ -52,11 +52,11 @@ namespace Umbraco.Web.BackOffice.Filters private readonly ILocalizedTextService _textService; protected ContentModelValidator( - ILogger logger, - IWebSecurity webSecurity, + ILogger logger, + IBackofficeSecurity backofficeSecurity, ILocalizedTextService textService, IPropertyValidationService propertyValidationService) - : base(logger, webSecurity, propertyValidationService) + : base(logger, backofficeSecurity, propertyValidationService) { _textService = textService ?? throw new ArgumentNullException(nameof(textService)); } @@ -144,7 +144,7 @@ namespace Umbraco.Web.BackOffice.Filters { var message = $"Could not find property editor \"{p.DataType.EditorAlias}\" for property with id {p.Id}."; - Logger.Warn(message); + Logger.LogWarning(message); continue; } diff --git a/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs b/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs index 493b2e04ea..bf28b2ff63 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentSaveModelValidator.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; @@ -12,11 +12,11 @@ namespace Umbraco.Web.BackOffice.Filters internal class ContentSaveModelValidator : ContentModelValidator { public ContentSaveModelValidator( - ILogger logger, - IWebSecurity webSecurity, + ILogger logger, + 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..c2717f7335 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs @@ -4,8 +4,8 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Security; using Umbraco.Core.Services; @@ -32,23 +32,23 @@ namespace Umbraco.Web.BackOffice.Filters private readonly IContentService _contentService; private readonly IEntityService _entityService; private readonly IPropertyValidationService _propertyValidationService; - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly ILocalizedTextService _textService; private readonly IUserService _userService; - private readonly IWebSecurity _webSecurity; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public ContentSaveValidationFilter( - ILogger logger, - IWebSecurity webSecurity, + ILoggerFactory loggerFactory, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IContentService contentService, IUserService userService, IEntityService entityService, IPropertyValidationService propertyValidationService) { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + _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(_loggerFactory.CreateLogger(), _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/FileUploadCleanupFilterAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/FileUploadCleanupFilterAttribute.cs index 0646f94121..d008b2d536 100644 --- a/src/Umbraco.Web.BackOffice/Filters/FileUploadCleanupFilterAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/FileUploadCleanupFilterAttribute.cs @@ -5,8 +5,8 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.WebApi.Filters @@ -36,10 +36,10 @@ namespace Umbraco.Web.WebApi.Filters private class FileUploadCleanupFilter : IAsyncActionFilter { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly bool _incomingModel; - public FileUploadCleanupFilter(ILogger logger, bool incomingModel) + public FileUploadCleanupFilter(ILogger logger, bool incomingModel) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _incomingModel = incomingModel; @@ -75,7 +75,7 @@ namespace Umbraco.Web.WebApi.Filters } catch (Exception ex) { - _logger.Error(ex, + _logger.LogError(ex, "Could not delete temp file {FileName}", f.TempFilePath); } } @@ -86,20 +86,20 @@ namespace Umbraco.Web.WebApi.Filters { if (context == null) { - _logger.Warn("The context is null!!??"); + _logger.LogWarning("The context is null!!??"); return Task.CompletedTask; } if (context.Result == null) { - _logger.Warn( + _logger.LogWarning( "The context.Result is null!!??"); return Task.CompletedTask; } if(!(context.Result is ObjectResult objectResult)) { - _logger.Warn( + _logger.LogWarning( "Could not acquire context.Result as ObjectResult"); return Task.CompletedTask; } @@ -120,7 +120,7 @@ namespace Umbraco.Web.WebApi.Filters tempFolders.Add(dir); } - _logger.Debug( + _logger.LogDebug( "Removing temp file {FileName}", f.TempFilePath); try @@ -129,7 +129,7 @@ namespace Umbraco.Web.WebApi.Filters } catch (Exception ex) { - _logger.Error(ex, + _logger.LogError(ex, "Could not delete temp file {FileName}", f.TempFilePath); } @@ -138,20 +138,20 @@ namespace Umbraco.Web.WebApi.Filters } else { - _logger.Warn( + _logger.LogWarning( "The f.TempFilePath is null or whitespace!!??"); } } } else { - _logger.Warn( + _logger.LogWarning( "The uploadedFiles.UploadedFiles is null!!??"); } } else { - _logger.Warn( + _logger.LogWarning( "The actionExecutedContext.Request.Content.Value is not IHaveUploadedFiles, it is {ObjectType}", objectResult.Value.GetType()); } 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..d30cf7c7ea 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MediaItemSaveValidationAttribute.cs @@ -1,9 +1,10 @@ using System; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; 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; @@ -26,21 +27,21 @@ namespace Umbraco.Web.BackOffice.Filters private readonly IPropertyValidationService _propertyValidationService; - private readonly ILogger _logger; private readonly IMediaService _mediaService; private readonly ILocalizedTextService _textService; - private readonly IWebSecurity _webSecurity; + private readonly ILoggerFactory _loggerFactory; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; public MediaItemSaveValidationFilter( - ILogger logger, - IWebSecurity webSecurity, + ILoggerFactory loggerFactory, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IMediaService mediaService, IEntityService entityService, IPropertyValidationService propertyValidationService) { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + _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(_loggerFactory.CreateLogger(), _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..e906226809 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MediaSaveModelValidator.cs @@ -1,4 +1,4 @@ -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; @@ -12,11 +12,11 @@ namespace Umbraco.Web.BackOffice.Filters internal class MediaSaveModelValidator : ContentModelValidator> { public MediaSaveModelValidator( - ILogger logger, - IWebSecurity webSecurity, + ILogger logger, + 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..7b3fa00835 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MemberSaveModelValidator.cs @@ -4,8 +4,8 @@ using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -25,14 +25,14 @@ namespace Umbraco.Web.BackOffice.Filters private readonly IShortStringHelper _shortStringHelper; public MemberSaveModelValidator( - ILogger logger, - IWebSecurity webSecurity, + ILogger logger, + 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..1bbe4a80b7 100644 --- a/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/MemberSaveValidationAttribute.cs @@ -1,7 +1,8 @@ using System; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Models.ContentEditing; @@ -21,8 +22,8 @@ namespace Umbraco.Web.BackOffice.Filters private sealed class MemberSaveValidationFilter : IActionFilter { - private readonly ILogger _logger; - private readonly IWebSecurity _webSecurity; + private readonly ILoggerFactory _loggerFactory; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; private readonly ILocalizedTextService _textService; private readonly IMemberTypeService _memberTypeService; private readonly IMemberService _memberService; @@ -30,16 +31,16 @@ namespace Umbraco.Web.BackOffice.Filters private readonly IPropertyValidationService _propertyValidationService; public MemberSaveValidationFilter( - ILogger logger, - IWebSecurity webSecurity, + ILoggerFactory loggerFactory, + IBackofficeSecurityAccessor backofficeSecurityAccessor, ILocalizedTextService textService, IMemberTypeService memberTypeService, IMemberService memberService, IShortStringHelper shortStringHelper, IPropertyValidationService propertyValidationService) { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity)); + _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); + _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(_loggerFactory.CreateLogger(), _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/UnhandledExceptionLoggerFilter.cs b/src/Umbraco.Web.BackOffice/Filters/UnhandledExceptionLoggerFilter.cs new file mode 100644 index 0000000000..ebea90249c --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Filters/UnhandledExceptionLoggerFilter.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Builder; + + +namespace Umbraco.Web.BackOffice.Filters +{ + /// + /// Applies the UnhandledExceptionLoggerMiddleware to a specific controller + /// when used with this attribute [MiddlewareFilter(typeof(UnhandledExceptionLoggerFilter))] + /// The middleware will run in the filter pipeline, at the same stage as resource filters + /// + public class UnhandledExceptionLoggerFilter + { + public void Configure(IApplicationBuilder applicationBuilder) + { + applicationBuilder.UseMiddleware(); + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Filters/UnhandledExceptionLoggerMiddleware.cs b/src/Umbraco.Web.BackOffice/Filters/UnhandledExceptionLoggerMiddleware.cs new file mode 100644 index 0000000000..db6162afa8 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Filters/UnhandledExceptionLoggerMiddleware.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.Logging; +using Umbraco.Core; + +namespace Umbraco.Web.BackOffice.Filters +{ + /// + /// Logs any unhandled exception. + /// + public class UnhandledExceptionLoggerMiddleware : IMiddleware + { + private readonly ILogger _logger; + + public UnhandledExceptionLoggerMiddleware(ILogger logger) + { + _logger = logger; + } + + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute); + // If it's a client side request just call next and don't try to log anything + if (requestUri.IsClientSideRequest()) + { + await next(context); + } + else + { + // Call the next middleware, and catch any errors that occurs in the rest of the pipeline + try + { + await next(context); + } + catch (Exception e) + { + _logger.LogError(e, "Unhandled controller exception occurred for request '{RequestUrl}'", requestUri.AbsoluteUri); + // Throw the error again, just in case it gets handled + throw; + } + } + } + } +} 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/Filters/ValidateAngularAntiForgeryTokenAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/ValidateAngularAntiForgeryTokenAttribute.cs index acafacff47..556a84e0dc 100644 --- a/src/Umbraco.Web.BackOffice/Filters/ValidateAngularAntiForgeryTokenAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/ValidateAngularAntiForgeryTokenAttribute.cs @@ -6,8 +6,8 @@ using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Extensions; using Umbraco.Web.BackOffice.Security; @@ -29,11 +29,11 @@ namespace Umbraco.Web.BackOffice.Filters private class ValidateAngularAntiForgeryTokenFilter : IAsyncActionFilter { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IBackOfficeAntiforgery _antiforgery; private readonly ICookieManager _cookieManager; - public ValidateAngularAntiForgeryTokenFilter(ILogger logger, IBackOfficeAntiforgery antiforgery, ICookieManager cookieManager) + public ValidateAngularAntiForgeryTokenFilter(ILogger logger, IBackOfficeAntiforgery antiforgery, ICookieManager cookieManager) { _logger = logger; _antiforgery = antiforgery; @@ -104,7 +104,7 @@ namespace Umbraco.Web.BackOffice.Filters } catch (AntiforgeryValidationException ex) { - _logger.Error(ex, "Could not validate XSRF token"); + _logger.LogError(ex, "Could not validate XSRF token"); return false; } } diff --git a/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs b/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs index 6b8eada506..99535d3d30 100644 --- a/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs +++ b/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs @@ -3,11 +3,13 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; using Umbraco.Core; -using Umbraco.Core.Logging; 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; +using Microsoft.Extensions.Logging; namespace Umbraco.Web.BackOffice.Controllers { @@ -20,14 +22,14 @@ namespace Umbraco.Web.BackOffice.Controllers { private readonly HealthCheckCollection _checks; private readonly IList _disabledCheckIds; - private readonly ILogger _logger; + 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(); @@ -71,7 +73,7 @@ namespace Umbraco.Web.BackOffice.Controllers } catch (Exception ex) { - _logger.Error(ex, "Exception in health check: {HealthCheckName}", check.Name); + _logger.LogError(ex, "Exception in health check: {HealthCheckName}", check.Name); throw; } } diff --git a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs index af8862bdec..8124a91377 100644 --- a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs +++ b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Dictionary; -using Umbraco.Core.Logging; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -30,7 +30,7 @@ namespace Umbraco.Web.Models.Mapping private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IPublishedRouter _publishedRouter; private readonly ILocalizationService _localizationService; - private readonly ILogger _logger; + private readonly ILoggerFactory _loggerFactory; private readonly IUserService _userService; private readonly IEntityService _entityService; private readonly IVariationContextAccessor _variationContextAccessor; @@ -43,7 +43,7 @@ namespace Umbraco.Web.Models.Mapping public ContentMapDefinition(CommonMapper commonMapper, CommonTreeNodeMapper commonTreeNodeMapper, ICultureDictionary cultureDictionary, ILocalizedTextService localizedTextService, IContentService contentService, IContentTypeService contentTypeService, - IFileService fileService, IUmbracoContextAccessor umbracoContextAccessor, IPublishedRouter publishedRouter, ILocalizationService localizationService, ILogger logger, + IFileService fileService, IUmbracoContextAccessor umbracoContextAccessor, IPublishedRouter publishedRouter, ILocalizationService localizationService, ILoggerFactory loggerFactory, IUserService userService, IVariationContextAccessor variationContextAccessor, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, UriUtility uriUtility, IPublishedUrlProvider publishedUrlProvider, IEntityService entityService) { _commonMapper = commonMapper; @@ -56,7 +56,7 @@ namespace Umbraco.Web.Models.Mapping _umbracoContextAccessor = umbracoContextAccessor; _publishedRouter = publishedRouter; _localizationService = localizationService; - _logger = logger; + _loggerFactory = loggerFactory; _userService = userService; _entityService = entityService; _variationContextAccessor = variationContextAccessor; @@ -188,7 +188,7 @@ namespace Umbraco.Web.Models.Mapping var urls = umbracoContext == null ? new[] { UrlInfo.Message("Cannot generate urls without a current Umbraco Context") } - : source.GetContentUrls(_publishedRouter, umbracoContext, _localizationService, _localizedTextService, _contentService, _variationContextAccessor, _logger, _uriUtility, _publishedUrlProvider).ToArray(); + : source.GetContentUrls(_publishedRouter, umbracoContext, _localizationService, _localizedTextService, _contentService, _variationContextAccessor, _loggerFactory.CreateLogger(), _uriUtility, _publishedUrlProvider).ToArray(); return urls; } 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/PropertyEditors/RteEmbedController.cs b/src/Umbraco.Web.BackOffice/PropertyEditors/RteEmbedController.cs index 5ce8e09280..164864410c 100644 --- a/src/Umbraco.Web.BackOffice/PropertyEditors/RteEmbedController.cs +++ b/src/Umbraco.Web.BackOffice/PropertyEditors/RteEmbedController.cs @@ -1,6 +1,6 @@ using System; using System.Text.RegularExpressions; -using Umbraco.Core.Logging; +using Microsoft.Extensions.Logging; using Umbraco.Web.BackOffice.Controllers; using Umbraco.Core.Media; using Umbraco.Web.Common.Attributes; @@ -16,9 +16,9 @@ namespace Umbraco.Web.BackOffice.PropertyEditors public class RteEmbedController : UmbracoAuthorizedJsonController { private readonly EmbedProvidersCollection _embedCollection; - private readonly ILogger _logger; + private readonly ILogger _logger; - public RteEmbedController(EmbedProvidersCollection embedCollection, ILogger logger) + public RteEmbedController(EmbedProvidersCollection embedCollection, ILogger logger) { _embedCollection = embedCollection ?? throw new ArgumentNullException(nameof(embedCollection)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -63,7 +63,7 @@ namespace Umbraco.Web.BackOffice.PropertyEditors } catch(Exception ex) { - _logger.Error(ex, "Error embedding url {Url} - width: {Width} height: {Height}", url, width, height); + _logger.LogError(ex, "Error embedding url {Url} - width: {Width} height: {Height}", url, width, height); result.OEmbedStatus = OEmbedStatus.Error; } diff --git a/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/BackOfficeAreaRoutes.cs index ec0a75fe11..7922b6a46d 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; @@ -49,7 +51,6 @@ namespace Umbraco.Web.BackOffice.Routing MapMinimalBackOffice(endpoints); endpoints.MapUmbracoRoute(_umbracoPathSegment, Constants.Web.Mvc.BackOfficeArea, null); AutoRouteBackOfficeControllers(endpoints); - break; case RuntimeLevel.BootFailed: case RuntimeLevel.Unknown: diff --git a/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs b/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs new file mode 100644 index 0000000000..210b0ffddb --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Routing/PreviewRoutes.cs @@ -0,0 +1,57 @@ +using Microsoft.AspNetCore.Builder; +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.SignalR; +using Umbraco.Web.Common.Routing; + +namespace Umbraco.Web.BackOffice.Routing +{ + /// + /// Creates routes for the preview hub + /// + public class PreviewRoutes : IAreaRoutes + { + private readonly IRuntimeState _runtimeState; + private readonly string _umbracoPathSegment; + + public PreviewRoutes( + IOptions globalSettings, + IHostingEnvironment hostingEnvironment, + IRuntimeState runtimeState) + { + _runtimeState = runtimeState; + _umbracoPathSegment = globalSettings.Value.GetUmbracoMvcArea(hostingEnvironment); + } + + public void CreateRoutes(IEndpointRouteBuilder endpoints) + { + switch (_runtimeState.Level) + { + case RuntimeLevel.Install: + break; + case RuntimeLevel.Upgrade: + break; + case RuntimeLevel.Run: + endpoints.MapHub(GetPreviewHubRoute()); + break; + case RuntimeLevel.BootFailed: + case RuntimeLevel.Unknown: + case RuntimeLevel.Boot: + break; + } + } + + /// + /// Returns the path to the signalR hub used for preview + /// + /// Path to signalR hub + public string GetPreviewHubRoute() + { + return $"/{_umbracoPathSegment}/{nameof(PreviewHub)}"; + } + } +} diff --git a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs index 600602f5b5..005a0db36e 100644 --- a/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs +++ b/src/Umbraco.Web.BackOffice/Runtime/BackOfficeComposer.cs @@ -1,13 +1,16 @@ using System.Linq; +using Microsoft.Extensions.Logging; using Umbraco.Core; 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.Filters; 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; @@ -20,9 +23,8 @@ namespace Umbraco.Web.BackOffice.Runtime { public void Compose(Composition composition) { - - composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(); composition.Register(Lifetime.Request); composition.Register(Lifetime.Request); @@ -43,8 +45,11 @@ namespace Umbraco.Web.BackOffice.Runtime new PhysicalFileSystem( factory.GetInstance(), factory.GetInstance(), - factory.GetInstance(), + factory.GetInstance>(), "~/")); + + composition.RegisterUnique(); + 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/BackOfficePasswordHasher.cs b/src/Umbraco.Web.BackOffice/Security/BackOfficePasswordHasher.cs index df3bc2935b..6c61e7bb35 100644 --- a/src/Umbraco.Web.BackOffice/Security/BackOfficePasswordHasher.cs +++ b/src/Umbraco.Web.BackOffice/Security/BackOfficePasswordHasher.cs @@ -11,72 +11,73 @@ namespace Umbraco.Web.BackOffice.Security /// /// A password hasher for back office users /// + /// + /// This allows us to verify passwords in old formats and roll forward to the latest format + /// public class BackOfficePasswordHasher : PasswordHasher { - private readonly LegacyPasswordSecurity _passwordSecurity; + private readonly LegacyPasswordSecurity _legacyPasswordSecurity; private readonly IJsonSerializer _jsonSerializer; + private readonly PasswordHasher _aspnetV2PasswordHasher = new PasswordHasher(new V2PasswordHasherOptions()); public BackOfficePasswordHasher(LegacyPasswordSecurity passwordSecurity, IJsonSerializer jsonSerializer) { - _passwordSecurity = passwordSecurity; + _legacyPasswordSecurity = passwordSecurity; _jsonSerializer = jsonSerializer; } public override string HashPassword(BackOfficeIdentityUser user, string password) + { + // Always use the latest/current hash algorithm when hashing new passwords for storage. + // NOTE: This is only overridden to show that we can since we may need to adjust this in the future + // if new/different formats are required. + return base.HashPassword(user, password); + } + + /// + /// Verifies a user's hashed password + /// + /// + /// + /// + /// + /// + /// This will check the user's current hashed password format stored with their user row and use that to verify the hash. This could be any hashes + /// from the very old v4, to the older v6-v8, to the older aspnet identity and finally to the most recent + /// + public override PasswordVerificationResult VerifyHashedPassword(BackOfficeIdentityUser user, string hashedPassword, string providedPassword) { if (!user.PasswordConfig.IsNullOrWhiteSpace()) { // check if the (legacy) password security supports this hash algorith and if so then use it var deserialized = _jsonSerializer.Deserialize(user.PasswordConfig); - if (_passwordSecurity.SupportHashAlgorithm(deserialized.HashAlgorithm)) - return _passwordSecurity.HashPasswordForStorage(password); + if (_legacyPasswordSecurity.SupportHashAlgorithm(deserialized.HashAlgorithm)) + { + var result = _legacyPasswordSecurity.VerifyPassword(deserialized.HashAlgorithm, providedPassword, hashedPassword); + return result + ? PasswordVerificationResult.SuccessRehashNeeded + : PasswordVerificationResult.Failed; + } - // We will explicitly detect names here since this allows us to future proof these checks. + // We will explicitly detect names here // The default is PBKDF2.ASPNETCORE.V3: // PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations. // The underlying class only lets us change 2 things which is the version: options.CompatibilityMode and the iteration count // The PBKDF2.ASPNETCORE.V2 settings are: // PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations. - switch (deserialized.HashAlgorithm) - { - case Constants.Security.AspNetCoreV3PasswordHashAlgorithmName: - return base.HashPassword(user, password); - case Constants.Security.AspNetCoreV2PasswordHashAlgorithmName: - var v2Hasher = new PasswordHasher(new V2PasswordHasherOptions()); - return v2Hasher.HashPassword(user, password); - } - } - - // else keep the default - return base.HashPassword(user, password); - } - - public override PasswordVerificationResult VerifyHashedPassword(BackOfficeIdentityUser user, string hashedPassword, string providedPassword) - { - if (!user.PasswordConfig.IsNullOrWhiteSpace()) - { - // check if the (legacy) password security supports this hash algorith and if so then use it - var deserialized = _jsonSerializer.Deserialize(user.PasswordConfig); - if (_passwordSecurity.SupportHashAlgorithm(deserialized.HashAlgorithm)) - { - var result = _passwordSecurity.VerifyPassword(providedPassword, hashedPassword); - return result - ? PasswordVerificationResult.Success - : PasswordVerificationResult.Failed; - } - switch (deserialized.HashAlgorithm) { case Constants.Security.AspNetCoreV3PasswordHashAlgorithmName: return base.VerifyHashedPassword(user, hashedPassword, providedPassword); case Constants.Security.AspNetCoreV2PasswordHashAlgorithmName: - var v2Hasher = new PasswordHasher(new V2PasswordHasherOptions()); - return v2Hasher.VerifyHashedPassword(user, hashedPassword, providedPassword); + var legacyResult = _aspnetV2PasswordHasher.VerifyHashedPassword(user, hashedPassword, providedPassword); + if (legacyResult == PasswordVerificationResult.Success) return PasswordVerificationResult.SuccessRehashNeeded; + return legacyResult; } } - // else go the default + // else go the default (v3) return base.VerifyHashedPassword(user, hashedPassword, providedPassword); } 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..1a4298cd6b 100644 --- a/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs +++ b/src/Umbraco.Web.BackOffice/Security/PasswordChanger.cs @@ -1,9 +1,9 @@ using System; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.BackOffice; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Extensions; using Umbraco.Web.Models; @@ -13,9 +13,9 @@ namespace Umbraco.Web.BackOffice.Security { internal class PasswordChanger { - private readonly ILogger _logger; + private readonly ILogger _logger; - public PasswordChanger(ILogger logger) + public PasswordChanger(ILogger logger) { _logger = logger; } @@ -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)); @@ -72,7 +72,7 @@ namespace Umbraco.Web.BackOffice.Security if (resetResult.Succeeded == false) { var errors = resetResult.Errors.ToErrorMessage(); - _logger.Warn("Could not reset user password {PasswordErrors}", errors); + _logger.LogWarning("Could not reset user password {PasswordErrors}", errors); return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult(errors, new[] { "value" }) }); } @@ -92,7 +92,7 @@ namespace Umbraco.Web.BackOffice.Security { //no, fail with error messages for "password" var errors = changeResult.Errors.ToErrorMessage(); - _logger.Warn("Could not change user password {PasswordErrors}", errors); + _logger.LogWarning("Could not change user password {PasswordErrors}", errors); return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult(errors, new[] { "password" }) }); } return Attempt.Succeed(new PasswordChangedModel()); 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..07a52b4446 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Services/IconService.cs @@ -0,0 +1,98 @@ +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; + +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(Constants.SvgSanitizer.Attributes); + sanitizer.AllowedCssProperties.UnionWith(Constants.SvgSanitizer.Attributes); + sanitizer.AllowedTags.UnionWith(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; + } + } + } +} diff --git a/src/Umbraco.Web/SignalR/IPreviewHub.cs b/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs similarity index 57% rename from src/Umbraco.Web/SignalR/IPreviewHub.cs rename to src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs index 2eb722c40d..96a28e5c0d 100644 --- a/src/Umbraco.Web/SignalR/IPreviewHub.cs +++ b/src/Umbraco.Web.BackOffice/SignalR/IPreviewHub.cs @@ -1,11 +1,14 @@ -namespace Umbraco.Web.SignalR +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; + +namespace Umbraco.Web.BackOffice.SignalR { public interface IPreviewHub { // define methods implemented by client // ReSharper disable InconsistentNaming - void refreshed(int id); + Task refreshed(int id); // ReSharper restore InconsistentNaming } diff --git a/src/Umbraco.Web.BackOffice/SignalR/PreviewHub.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHub.cs new file mode 100644 index 0000000000..794e38b678 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHub.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.SignalR; +using System.Threading.Tasks; + +namespace Umbraco.Web.BackOffice.SignalR +{ + public class PreviewHub : Hub + { } +} diff --git a/src/Umbraco.Web/SignalR/PreviewHubComponent.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs similarity index 73% rename from src/Umbraco.Web/SignalR/PreviewHubComponent.cs rename to src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs index 1d8a10118b..d1f00e9911 100644 --- a/src/Umbraco.Web/SignalR/PreviewHubComponent.cs +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComponent.cs @@ -1,19 +1,20 @@ using System; -using Microsoft.AspNet.SignalR; +using System.Configuration; +using Microsoft.AspNetCore.SignalR; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Sync; using Umbraco.Web.Cache; -namespace Umbraco.Web.SignalR +namespace Umbraco.Web.BackOffice.SignalR { public class PreviewHubComponent : IComponent { - private readonly Lazy> _hubContext; + private readonly Lazy> _hubContext; // using a lazy arg here means that we won't create the hub until necessary // and therefore we won't have too bad an impact on boot time - public PreviewHubComponent(Lazy> hubContext) + public PreviewHubComponent(Lazy> hubContext) { _hubContext = hubContext; } @@ -32,7 +33,7 @@ namespace Umbraco.Web.SignalR ContentCacheRefresher.CacheUpdated -= HandleCacheUpdated; } - private void HandleCacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) + private async void HandleCacheUpdated(ContentCacheRefresher sender, CacheRefresherEventArgs args) { if (args.MessageType != MessageType.RefreshByPayload) return; var payloads = (ContentCacheRefresher.JsonPayload[])args.MessageObject; @@ -40,7 +41,7 @@ namespace Umbraco.Web.SignalR foreach (var payload in payloads) { var id = payload.Id; // keep it simple for now, ignore ChangeTypes - hubContextInstance.Clients.All.refreshed(id); + await hubContextInstance.Clients.All.refreshed(id); } } } diff --git a/src/Umbraco.Web/SignalR/PreviewHubComposer.cs b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs similarity index 66% rename from src/Umbraco.Web/SignalR/PreviewHubComposer.cs rename to src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs index cef1e166c2..6660d918c0 100644 --- a/src/Umbraco.Web/SignalR/PreviewHubComposer.cs +++ b/src/Umbraco.Web.BackOffice/SignalR/PreviewHubComposer.cs @@ -1,6 +1,6 @@ -using Microsoft.AspNet.SignalR; -using Umbraco.Core; +using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Web.BackOffice.SignalR; namespace Umbraco.Web.SignalR { @@ -10,8 +10,6 @@ namespace Umbraco.Web.SignalR public override void Compose(Composition composition) { base.Compose(composition); - - composition.RegisterUnique(_ => GlobalHost.ConnectionManager.GetHubContext()); } } } diff --git a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs index c9bcf01fad..6f7eec68f8 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; @@ -27,25 +30,29 @@ namespace Umbraco.Web.Trees /// Used to return tree root nodes ///
[AngularJsonOnlyConfiguration] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] public class ApplicationTreeController : UmbracoAuthorizedApiController { private readonly ITreeService _treeService; 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/ContentBlueprintTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs index 5b7ffd2e05..607efbf2f9 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs @@ -23,7 +23,7 @@ namespace Umbraco.Web.Trees /// [UmbracoApplicationAuthorize(Constants.Applications.Content)] [Tree(Constants.Applications.Settings, Constants.Trees.ContentBlueprints, SortOrder = 12, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class ContentBlueprintTreeController : TreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs index 0cc73af315..1685b329dd 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -12,7 +13,7 @@ using Umbraco.Web.Models.Trees; 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 { @@ -33,46 +36,45 @@ namespace Umbraco.Web.Trees Constants.Applications.Packages, Constants.Applications.Members)] [Tree(Constants.Applications.Content, Constants.Trees.Content)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] [SearchableTree("searchResultFormatter", "configureContentResult", 10)] public class ContentTreeController : ContentTreeControllerBase, ISearchableTree { 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, - ILogger logger, + 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..227bfd5746 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs @@ -3,9 +3,9 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Services; -using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Web.Models.Trees; using Umbraco.Core.Models.Entities; @@ -25,8 +25,8 @@ namespace Umbraco.Web.Trees public abstract class ContentTreeControllerBase : TreeController, ITreeNodeController { private readonly IEntityService _entityService; - private readonly IWebSecurity _webSecurity; - private readonly ILogger _logger; + private readonly IBackofficeSecurityAccessor _backofficeSecurityAccessor; + private readonly ILogger _logger; private readonly ActionCollection _actionCollection; private readonly IUserService _userService; private readonly IDataTypeService _dataTypeService; @@ -38,8 +38,8 @@ namespace Umbraco.Web.Trees UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, IMenuItemCollectionFactory menuItemCollectionFactory, IEntityService entityService, - IWebSecurity webSecurity, - ILogger logger, + IBackofficeSecurityAccessor backofficeSecurityAccessor, + ILogger logger, ActionCollection actionCollection, IUserService userService, IDataTypeService dataTypeService @@ -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.LogWarning("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/ContentTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs index 2ee5ef0b3f..82e4d70e8c 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs @@ -18,7 +18,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.DocumentTypes)] [Tree(Constants.Applications.Settings, Constants.Trees.DocumentTypes, SortOrder = 0, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class ContentTypeTreeController : TreeController, ISearchableTree { diff --git a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs index c68908c3dc..7cffe230c7 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.DataTypes)] [Tree(Constants.Applications.Settings, Constants.Trees.DataTypes, SortOrder = 3, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class DataTypeTreeController : TreeController, ISearchableTree { diff --git a/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs index d92ca0e6c7..657772e622 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.Trees // We are allowed to see the dictionary tree, if we are allowed to manage templates, such that se can use the // dictionary items in templates, even when we dont have authorization to manage the dictionary items )] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] [Tree(Constants.Applications.Translation, Constants.Trees.Dictionary, TreeGroup = Constants.Trees.Groups.Settings)] public class DictionaryTreeController : TreeController diff --git a/src/Umbraco.Web.BackOffice/Trees/LanguageTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/LanguageTreeController.cs index d34c26b07d..a3c0354ca9 100644 --- a/src/Umbraco.Web.BackOffice/Trees/LanguageTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/LanguageTreeController.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Languages)] [Tree(Constants.Applications.Settings, Constants.Trees.Languages, SortOrder = 11, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class LanguageTreeController : TreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/LogViewerTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/LogViewerTreeController.cs index e9fe918c52..4de3670fcd 100644 --- a/src/Umbraco.Web.BackOffice/Trees/LogViewerTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/LogViewerTreeController.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.LogViewer)] [Tree(Constants.Applications.Settings, Constants.Trees.LogViewer, SortOrder= 9, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class LogViewerTreeController : TreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs index c3d15996d5..690b1888c5 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs @@ -13,7 +13,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Macros)] [Tree(Constants.Applications.Settings, Constants.Trees.Macros, TreeTitle = "Macros", SortOrder = 4, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class MacrosTreeController : TreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs index 46ef45e85d..10edcd46c7 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -11,7 +12,7 @@ using Umbraco.Web.Actions; 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; @@ -31,7 +32,7 @@ namespace Umbraco.Web.Trees Constants.Applications.Packages, Constants.Applications.Members)] [Tree(Constants.Applications.Media, Constants.Trees.Media)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] [SearchableTree("searchResultFormatter", "configureMediaResult", 20)] public class MediaTreeController : ContentTreeControllerBase, ISearchableTree, ITreeNodeController @@ -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, - ILogger logger, + 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/MediaTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs index 27f4f8f77e..52a66d63ce 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs @@ -18,7 +18,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.MediaTypes)] [Tree(Constants.Applications.Settings, Constants.Trees.MediaTypes, SortOrder = 1, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class MediaTypeTreeController : TreeController, ISearchableTree { diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs index 06bd355b7d..22925e27e2 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs @@ -13,7 +13,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.MemberGroups)] [Tree(Constants.Applications.Members, Constants.Trees.MemberGroups, SortOrder = 1)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class MemberGroupTreeController : MemberTypeAndGroupTreeControllerBase { diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTreeController.cs index 967e4f22fc..e6d18f3b72 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; @@ -28,7 +29,7 @@ namespace Umbraco.Web.Trees Constants.Applications.Media, Constants.Applications.Members)] [Tree(Constants.Applications.Members, Constants.Trees.Members, SortOrder = 0)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] [SearchableTree("searchResultFormatter", "configureMemberResult")] public class MemberTreeController : TreeController, ISearchableTree, ITreeNodeController @@ -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/Trees/MemberTypeAndGroupTreeControllerBase.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTypeAndGroupTreeControllerBase.cs index 882ef6def3..a82d08eeac 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTypeAndGroupTreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTypeAndGroupTreeControllerBase.cs @@ -10,7 +10,7 @@ using Umbraco.Web.WebApi; namespace Umbraco.Web.Trees { - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public abstract class MemberTypeAndGroupTreeControllerBase : TreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs index b2d4a172fb..ae8a883fda 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberTypeTreeController.cs @@ -17,7 +17,7 @@ namespace Umbraco.Web.Trees [CoreTree] [UmbracoTreeAuthorize(Constants.Trees.MemberTypes)] [Tree(Constants.Applications.Settings, Constants.Trees.MemberTypes, SortOrder = 2, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] public class MemberTypeTreeController : MemberTypeAndGroupTreeControllerBase, ISearchableTree { private readonly UmbracoTreeSearcher _treeSearcher; diff --git a/src/Umbraco.Web.BackOffice/Trees/PackagesTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/PackagesTreeController.cs index f58b822f1c..634c093f46 100644 --- a/src/Umbraco.Web.BackOffice/Trees/PackagesTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/PackagesTreeController.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Packages)] [Tree(Constants.Applications.Packages, Constants.Trees.Packages, SortOrder = 0, IsSingleNodeTree = true)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class PackagesTreeController : TreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/PartialViewMacrosTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/PartialViewMacrosTreeController.cs index 612b59ca4a..7fa4580372 100644 --- a/src/Umbraco.Web.BackOffice/Trees/PartialViewMacrosTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/PartialViewMacrosTreeController.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web.Trees /// [Tree(Constants.Applications.Settings, Constants.Trees.PartialViewMacros, SortOrder = 8, TreeGroup = Constants.Trees.Groups.Templating)] [UmbracoTreeAuthorize(Constants.Trees.PartialViewMacros)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class PartialViewMacrosTreeController : PartialViewsTreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs index afe720fde9..761475612f 100644 --- a/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/PartialViewsTreeController.cs @@ -17,7 +17,7 @@ namespace Umbraco.Web.Trees /// [Tree(Core.Constants.Applications.Settings, Core.Constants.Trees.PartialViews, SortOrder = 7, TreeGroup = Core.Constants.Trees.Groups.Templating)] [UmbracoTreeAuthorize(Constants.Trees.PartialViews)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class PartialViewsTreeController : FileSystemTreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs index 46c6f004c6..a4fffc5760 100644 --- a/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.RelationTypes)] [Tree(Constants.Applications.Settings, Constants.Trees.RelationTypes, SortOrder = 5, TreeGroup = Constants.Trees.Groups.Settings)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class RelationTypeTreeController : TreeController { diff --git a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs index fca6d7beb7..109b5c93c9 100644 --- a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs @@ -21,7 +21,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Templates)] [Tree(Constants.Applications.Settings, Constants.Trees.Templates, SortOrder = 6, TreeGroup = Constants.Trees.Groups.Templating)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class TemplatesTreeController : TreeController, ISearchableTree { diff --git a/src/Umbraco.Web.BackOffice/Trees/UserTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/UserTreeController.cs index de7cb6c33c..9019b71d1b 100644 --- a/src/Umbraco.Web.BackOffice/Trees/UserTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/UserTreeController.cs @@ -18,7 +18,7 @@ namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Users)] [Tree(Constants.Applications.Users, Constants.Trees.Users, SortOrder = 0, IsSingleNodeTree = true)] - [PluginController("UmbracoTrees")] + [PluginController(Constants.Web.Mvc.BackOfficeTreeArea)] [CoreTree] public class UserTreeController : TreeController { 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/ApplicationModels/BackOfficeApplicationModelProvider.cs b/src/Umbraco.Web.Common/ApplicationModels/BackOfficeApplicationModelProvider.cs index d7c9833c6f..0ad6c4ec1a 100644 --- a/src/Umbraco.Web.Common/ApplicationModels/BackOfficeApplicationModelProvider.cs +++ b/src/Umbraco.Web.Common/ApplicationModels/BackOfficeApplicationModelProvider.cs @@ -14,7 +14,7 @@ namespace Umbraco.Web.Common.ApplicationModels public BackOfficeApplicationModelProvider(IModelMetadataProvider modelMetadataProvider) { ActionModelConventions = new List() - { + { new BackOfficeIdentityCultureConvention() }; } @@ -52,7 +52,9 @@ namespace Umbraco.Web.Common.ApplicationModels { var pluginControllerAttribute = controller.Attributes.OfType().FirstOrDefault(); return pluginControllerAttribute != null - && pluginControllerAttribute.AreaName == Core.Constants.Web.Mvc.BackOfficeArea; + && (pluginControllerAttribute.AreaName == Core.Constants.Web.Mvc.BackOfficeArea + || pluginControllerAttribute.AreaName == Core.Constants.Web.Mvc.BackOfficeApiArea + || pluginControllerAttribute.AreaName == Core.Constants.Web.Mvc.BackOfficeTreeArea); } } } 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..ad168114e0 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: @@ -102,7 +100,7 @@ namespace Umbraco.Web.Common.AspNetCore if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute)) return virtualPath; - var fullPath = ApplicationVirtualPath.EnsureEndsWith('/') + virtualPath.TrimStart("~/"); + var fullPath = ApplicationVirtualPath.EnsureEndsWith('/') + virtualPath.TrimStart("~/").TrimStart("/"); return fullPath; } 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..5b4876baca --- /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, builder.Config, 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/Controllers/PluginController.cs b/src/Umbraco.Web.Common/Controllers/PluginController.cs index f78fa1a7e4..d5b033c26e 100644 --- a/src/Umbraco.Web.Common/Controllers/PluginController.cs +++ b/src/Umbraco.Web.Common/Controllers/PluginController.cs @@ -49,11 +49,6 @@ namespace Umbraco.Web.Common.Controllers /// public AppCaches AppCaches { get; } - /// - /// Gets or sets the logger. - /// - public ILogger Logger { get; } - /// /// Gets or sets the profiling logger. /// @@ -64,13 +59,12 @@ namespace Umbraco.Web.Common.Controllers /// internal PluginControllerMetadata Metadata => GetMetadata(GetType()); - protected PluginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger) + protected PluginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger) { UmbracoContextAccessor = umbracoContextAccessor; DatabaseFactory = databaseFactory; Services = services; AppCaches = appCaches; - Logger = logger; ProfilingLogger = profilingLogger; } 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/ImageCropperTemplateExtensions.cs b/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateExtensions.cs index ddcd8e7abe..77c07e85b2 100644 --- a/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ImageCropperTemplateExtensions.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using Umbraco.Composing; using Umbraco.Core; using Umbraco.Core.PropertyEditors.ValueConverters; +using Microsoft.Extensions.Logging; namespace Umbraco.Extensions { @@ -27,7 +28,7 @@ namespace Umbraco.Extensions } catch (Exception ex) { - Current.Logger.Error(typeof(ImageCropperTemplateExtensions), ex, "Could not parse the json string: {Json}", json); + Current.Logger.LogError(ex, "Could not parse the json string: {Json}", json); } } diff --git a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs index 31ff07b964..f2babdb07c 100644 --- a/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/LinkGeneratorExtensions.cs @@ -54,7 +54,9 @@ namespace Umbraco.Extensions /// public static string GetInstallerApiUrl(this LinkGenerator linkGenerator) { - return linkGenerator.GetPathByAction(nameof(InstallController.Index), ControllerExtensions.GetControllerName(), new { area = Constants.Web.Mvc.InstallArea }).EnsureEndsWith('/'); + return linkGenerator.GetPathByAction(nameof(InstallApiController.GetSetup), + ControllerExtensions.GetControllerName(), + new { area = Constants.Web.Mvc.InstallArea }).TrimEnd(nameof(InstallApiController.GetSetup)); } /// diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index d18275ca7f..adae78bd74 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -1,25 +1,25 @@ 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.Composing; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Configuration.Models.Validation; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Logging.Serilog; @@ -27,13 +27,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 = Microsoft.Extensions.Logging.ILogger; namespace Umbraco.Extensions { - - public static class UmbracoCoreServiceCollectionExtensions { /// @@ -95,6 +96,29 @@ 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, + IConfiguration configuration, + out IFactory factory) + => services.AddUmbracoCore(webHostEnvironment, umbContainer, entryAssembly, appCaches, loggingConfiguration, configuration, GetCoreRuntime, out factory); + /// /// Adds the Umbraco Configuration requirements /// @@ -105,11 +129,32 @@ namespace Umbraco.Extensions { if (configuration == null) throw new ArgumentNullException(nameof(configuration)); - var configsFactory = new AspNetCoreConfigsFactory(configuration); + services.AddSingleton, ContentSettingsValidator>(); + services.AddSingleton, GlobalSettingsValidator>(); + services.AddSingleton, RequestHandlerSettingsValidator>(); - var configs = configsFactory.Create(); - - services.AddSingleton(configs); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigActiveDirectory)); + services.Configure(configuration.GetSection("ConnectionStrings"), o => o.BindNonPublicProperties = true); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigContent)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigCoreDebug)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigExceptionFilter)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigGlobal)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigHealthChecks)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigHosting)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigImaging)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigExamine)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigKeepAlive)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigLogging)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigMemberPassword)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigModelsBuilder), o => o.BindNonPublicProperties = true); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigNuCache)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigRequestHandler)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigRuntime)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigSecurity)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigTours)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigTypeFinder)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigUserPassword)); + services.Configure(configuration.GetSection(Constants.Configuration.ConfigWebRouting)); return services; } @@ -119,10 +164,11 @@ namespace Umbraco.Extensions /// /// /// + /// /// - public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment) + public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration configuration) { - return services.AddUmbracoCore(webHostEnvironment, out _); + return services.AddUmbracoCore(webHostEnvironment, configuration, out _); } /// @@ -130,9 +176,10 @@ namespace Umbraco.Extensions /// /// /// + /// /// /// - public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, out IFactory factory) + public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment, IConfiguration configuration, out IFactory factory) { if (!UmbracoServiceProviderFactory.IsActive) throw new InvalidOperationException("Ensure to add UseUmbraco() in your Program.cs after ConfigureWebHostDefaults to enable Umbraco's service provider factory"); @@ -140,19 +187,25 @@ namespace Umbraco.Extensions var umbContainer = UmbracoServiceProviderFactory.UmbracoContainer; var loggingConfig = new LoggingConfiguration( - Path.Combine(webHostEnvironment.ContentRootPath, "App_Data", "Logs"), - Path.Combine(webHostEnvironment.ContentRootPath, "config", "serilog.config"), - Path.Combine(webHostEnvironment.ContentRootPath, "config", "serilog.user.config")); + Path.Combine(webHostEnvironment.ContentRootPath, "umbraco", "logs")); IHttpContextAccessor httpContextAccessor = new HttpContextAccessor(); services.AddSingleton(httpContextAccessor); + services.AddSingleton(loggingConfig); + 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, + configuration, + GetCoreRuntime, out factory); return services; @@ -168,6 +221,7 @@ namespace Umbraco.Extensions /// /// /// + /// Delegate to create an /// /// public static IServiceCollection AddUmbracoCore( @@ -175,8 +229,11 @@ namespace Umbraco.Extensions IWebHostEnvironment webHostEnvironment, IRegister umbContainer, Assembly entryAssembly, - IRequestCache requestCache, + AppCaches appCaches, ILoggingConfiguration loggingConfiguration, + IConfiguration configuration, + //TODO: Yep that's extremely ugly + Func getRuntime, out IFactory factory) { if (services is null) throw new ArgumentNullException(nameof(services)); @@ -203,67 +260,80 @@ 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); + configuration, 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 loggerFactory = services.BuildServiceProvider().GetService(); - var coreRuntime = GetCoreRuntime( - configs, + var umbracoVersion = new UmbracoVersion(); + var typeFinder = CreateTypeFinder(loggerFactory, profiler, webHostEnvironment, entryAssembly, typeFinderSettings); + + var coreRuntime = getRuntime( + globalSettings.CurrentValue, + connectionStrings.Value, umbracoVersion, ioHelper, - logger, + loggerFactory, profiler, hostingEnvironment, backOfficeInfo, typeFinder, - requestCache, + appCaches, dbProviderFactoryCreator); factory = coreRuntime.Configure(container); + + services.Configure(hostingSettings => + { + hostingSettings.Debug = false; + }); + + return services; } - private static ITypeFinder CreateTypeFinder(Core.Logging.ILogger logger, IProfiler profiler, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, ITypeFinderSettings typeFinderSettings) + private static ITypeFinder CreateTypeFinder(ILoggerFactory loggerFactory, IProfiler profiler, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, IOptionsMonitor typeFinderSettings) { var runtimeHashPaths = new RuntimeHashPaths(); runtimeHashPaths.AddFolder(new DirectoryInfo(Path.Combine(webHostEnvironment.ContentRootPath, "bin"))); - var runtimeHash = new RuntimeHash(new ProfilingLogger(logger, profiler), runtimeHashPaths); - return new TypeFinder(logger, new DefaultUmbracoAssemblyProvider(entryAssembly), runtimeHash, new TypeFinderConfig(typeFinderSettings)); + var runtimeHash = new RuntimeHash(new ProfilingLogger(loggerFactory.CreateLogger("RuntimeHash"), profiler), runtimeHashPaths); + return new TypeFinder(loggerFactory.CreateLogger(), new DefaultUmbracoAssemblyProvider(entryAssembly), runtimeHash, new TypeFinderConfig(typeFinderSettings)); } 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, ILoggerFactory loggerFactory, + 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) - : new MainDomSemaphoreLock(logger, hostingEnvironment); + ? (IMainDomLock)new SqlMainDomLock(loggerFactory.CreateLogger(), loggerFactory, globalSettings, connectionStrings, dbProviderFactoryCreator, hostingEnvironment) + : new MainDomSemaphoreLock(loggerFactory.CreateLogger(), hostingEnvironment); - var mainDom = new MainDom(logger, mainDomLock); + var mainDom = new MainDom(loggerFactory.CreateLogger(), mainDomLock); var coreRuntime = new CoreRuntime( - configs, + globalSettings, + connectionStrings, umbracoVersion, ioHelper, - logger, + loggerFactory, profiler, new AspNetCoreBootPermissionsChecker(), hostingEnvironment, @@ -271,32 +341,29 @@ 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, + IConfiguration configuration, out IIOHelper ioHelper, out Core.Hosting.IHostingEnvironment hostingEnvironment, 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); - logger = AddLogger(services, hostingEnvironment, loggingConfiguration); - + ioHelper = new IOHelper(hostingEnvironment); + AddLogger(services, hostingEnvironment, loggingConfiguration, configuration); backOfficeInfo = new AspNetCoreBackOfficeInfo(globalSettings); profiler = GetWebProfiler(hostingEnvironment); @@ -307,10 +374,18 @@ namespace Umbraco.Extensions /// Create and configure the logger /// /// - private static Core.Logging.ILogger AddLogger(IServiceCollection services, Core.Hosting.IHostingEnvironment hostingEnvironment, ILoggingConfiguration loggingConfiguration) + private static void AddLogger( + IServiceCollection services, + Core.Hosting.IHostingEnvironment hostingEnvironment, + ILoggingConfiguration loggingConfiguration, + IConfiguration configuration) { // Create a serilog logger - var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration); + var logger = SerilogLogger.CreateWithDefaultConfiguration(hostingEnvironment, loggingConfiguration, configuration); + + // This is nessasary to pick up all the loggins to MS ILogger. + Log.Logger = logger.SerilogLog; + // Wire up all the bits that serilog needs. We need to use our own code since the Serilog ext methods don't cater to our needs since // we don't want to use the global serilog `Log` object and we don't have our own ILogger implementation before the HostBuilder runs which @@ -318,7 +393,10 @@ namespace Umbraco.Extensions // I have created a PR to make this nicer https://github.com/serilog/serilog-extensions-hosting/pull/19 but we'll need to wait for that. // Also see : https://github.com/serilog/serilog-extensions-hosting/blob/dev/src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs - services.AddSingleton(services => new SerilogLoggerFactory(logger.SerilogLog, false)); + services.AddLogging(configure => + { + configure.AddSerilog(logger.SerilogLog, false); + }); // This won't (and shouldn't) take ownership of the logger. services.AddSingleton(logger.SerilogLog); @@ -331,8 +409,6 @@ namespace Umbraco.Extensions // Consumed by user code services.AddSingleton(diagnosticContext); - - return logger; } private static IProfiler GetWebProfiler(Umbraco.Core.Hosting.IHostingEnvironment hostingEnvironment) diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs index a795edf6cf..e37b6f81fd 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs @@ -1,5 +1,6 @@ using System.Buffers; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.Infrastructure; @@ -19,6 +20,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 +42,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,29 +54,31 @@ namespace Umbraco.Extensions /// /// /// - public static IServiceCollection AddUmbracoImageSharp(this IServiceCollection services, IImagingSettings imagingSettings) + public static IServiceCollection AddUmbracoImageSharp(this IServiceCollection services, ImagingSettings imagingSettings) { - services.AddImageSharpCore( - options => + + services.AddImageSharp(options => { options.Configuration = SixLabors.ImageSharp.Configuration.Default; - options.MaxBrowserCacheDays = imagingSettings.MaxBrowserCacheDays; - options.MaxCacheDays = imagingSettings.MaxCacheDays; - options.CachedNameLength = imagingSettings.CachedNameLength; - options.OnParseCommands = context => + options.BrowserMaxAge = imagingSettings.Cache.BrowserMaxAge; + options.CacheMaxAge = imagingSettings.Cache.CacheMaxAge; + options.CachedNameLength = imagingSettings.Cache.CachedNameLength; + options.OnParseCommandsAsync = 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); + + return Task.CompletedTask; }; - options.OnBeforeSave = _ => { }; - options.OnProcessed = _ => { }; - options.OnPrepareResponse = _ => { }; + options.OnBeforeSaveAsync = _ => Task.CompletedTask; + options.OnProcessedAsync = _ => Task.CompletedTask; + options.OnPrepareResponseAsync = _ => Task.CompletedTask; }) .SetRequestParser() .SetMemoryAllocator(provider => ArrayPoolMemoryAllocator.CreateWithMinimalPooling()) .Configure(options => { - options.CacheFolder = imagingSettings.CacheFolder; + options.CacheFolder = imagingSettings.Cache.CacheFolder; }) .SetCache() .SetCacheHash() @@ -128,13 +131,13 @@ namespace Umbraco.Extensions // TODO: we can inject params with DI here public UmbracoMvcConfigureOptions() - { + { } // TODO: we can configure global mvc options here if we need to public void Configure(MvcOptions options) - { - + { + } } diff --git a/src/Umbraco.Web.Common/Filters/BackOfficeCultureFilter.cs b/src/Umbraco.Web.Common/Filters/BackOfficeCultureFilter.cs index 99109fe230..8a241e6a9d 100644 --- a/src/Umbraco.Web.Common/Filters/BackOfficeCultureFilter.cs +++ b/src/Umbraco.Web.Common/Filters/BackOfficeCultureFilter.cs @@ -12,6 +12,7 @@ namespace Umbraco.Web.Common.Filters { public void OnActionExecuted(ActionExecutedContext context) { + } public void OnActionExecuting(ActionExecutingContext context) 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/Filters/UmbracoUserTimeoutFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/UmbracoUserTimeoutFilterAttribute.cs new file mode 100644 index 0000000000..2c11b06839 --- /dev/null +++ b/src/Umbraco.Web.Common/Filters/UmbracoUserTimeoutFilterAttribute.cs @@ -0,0 +1,36 @@ +using System.Globalization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Umbraco.Extensions; + +namespace Umbraco.Web.Common.Filters +{ + /// + /// This will check if the user making the request is authenticated and if there's an auth ticket tied to the user + /// we will add a custom header to the response indicating how many seconds are remaining for the + /// user's session. This allows us to keep track of a user's session effectively in the back office. + /// + public class UmbracoUserTimeoutFilterAttribute : TypeFilterAttribute + { + public UmbracoUserTimeoutFilterAttribute() : base(typeof(UmbracoUserTimeoutFilter)) + { + } + + private class UmbracoUserTimeoutFilter : IActionFilter + { + public void OnActionExecuted(ActionExecutedContext context) + { + //this can occur if an error has already occurred. + if (context.HttpContext.Response is null) return; + + var remainingSeconds = context.HttpContext.User.GetRemainingAuthSeconds(); + context.HttpContext.Response.Headers.Add("X-Umb-User-Seconds", remainingSeconds.ToString(CultureInfo.InvariantCulture)); + } + + public void OnActionExecuting(ActionExecutingContext context) + { + // Noop + } + } + } +} diff --git a/src/Umbraco.Web.Common/Install/InstallApiController.cs b/src/Umbraco.Web.Common/Install/InstallApiController.cs index edc73ef293..8c32796ad8 100644 --- a/src/Umbraco.Web.Common/Install/InstallApiController.cs +++ b/src/Umbraco.Web.Common/Install/InstallApiController.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Logging; @@ -30,23 +31,21 @@ 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 ILogger _logger; private readonly IProfilingLogger _proflog; - public InstallApiController(DatabaseBuilder databaseBuilder, IProfilingLogger proflog, + public InstallApiController(DatabaseBuilder databaseBuilder, IProfilingLogger proflog, ILogger logger, 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; + _logger = logger; } @@ -90,14 +89,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(); } @@ -155,7 +146,7 @@ namespace Umbraco.Web.Common.Install } catch (Exception ex) { - _logger.Error(ex, "An error occurred during installation step {Step}", + _logger.LogError(ex, "An error occurred during installation step {Step}", step.Name); if (ex is TargetInvocationException && ex.InnerException != null) @@ -268,7 +259,7 @@ namespace Umbraco.Web.Common.Install } catch (Exception ex) { - _logger.Error(ex, "Checking if step requires execution ({Step}) failed.", + _logger.LogError(ex, "Checking if step requires execution ({Step}) failed.", step.Name); throw; } @@ -299,7 +290,7 @@ namespace Umbraco.Web.Common.Install } catch (Exception ex) { - _logger.Error(ex, "Installation step {Step} failed.", step.Name); + _logger.LogError(ex, "Installation step {Step} failed.", step.Name); throw; } } diff --git a/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs index 80a21d6724..6ccebc9b25 100644 --- a/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs +++ b/src/Umbraco.Web.Common/Install/InstallAuthorizeAttribute.cs @@ -2,8 +2,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Logging; namespace Umbraco.Web.Common.Install { @@ -24,7 +24,7 @@ namespace Umbraco.Web.Common.Install var serviceProvider = authorizationFilterContext.HttpContext.RequestServices; var runtimeState = serviceProvider.GetService(); var umbracoContext = serviceProvider.GetService(); - var logger = serviceProvider.GetService(); + var logger = serviceProvider.GetService>(); if (!IsAllowed(runtimeState, umbracoContext, logger)) { @@ -33,7 +33,7 @@ namespace Umbraco.Web.Common.Install } - private static bool IsAllowed(IRuntimeState runtimeState, IUmbracoContext umbracoContext, ILogger logger) + private static bool IsAllowed(IRuntimeState runtimeState, IUmbracoContext umbracoContext, ILogger logger) { try { @@ -45,7 +45,7 @@ namespace Umbraco.Web.Common.Install } catch (Exception ex) { - logger.Error(ex, "An error occurred determining authorization"); + logger.LogError(ex, "An error occurred determining authorization"); return false; } } diff --git a/src/Umbraco.Web.Common/Install/InstallController.cs b/src/Umbraco.Web.Common/Install/InstallController.cs index dbd0def5e9..e908b4f128 100644 --- a/src/Umbraco.Web.Common/Install/InstallController.cs +++ b/src/Umbraco.Web.Common/Install/InstallController.cs @@ -2,16 +2,19 @@ using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Logging; using System.Threading.Tasks; 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,31 +26,31 @@ 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; + private readonly ILogger _logger; private readonly LinkGenerator _linkGenerator; 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, + 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) { @@ -113,12 +116,12 @@ namespace Umbraco.Web.Common.Install private static bool _reported; private static RuntimeLevel _reportedLevel; - private static void ReportRuntime(ILogger logger, RuntimeLevel level, string message) + private static void ReportRuntime(ILogger logger, RuntimeLevel level, string message) { if (_reported && _reportedLevel == level) return; _reported = true; _reportedLevel = level; - logger.Warn(typeof(UmbracoInstallApplicationBuilderExtensions), message); + logger.LogWarning(message); } } } diff --git a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs index 8685c0b8b1..c0d2fdbdd4 100644 --- a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs +++ b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs @@ -4,9 +4,11 @@ using System.IO; using System.Linq; using System.Text; using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; 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; @@ -20,9 +22,10 @@ namespace Umbraco.Web.Macros { public class MacroRenderer : IMacroRenderer { - private readonly IProfilingLogger _plogger; + private readonly IProfilingLogger _profilingLogger; + private readonly ILogger _logger; 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 +36,11 @@ namespace Umbraco.Web.Macros private readonly IRequestAccessor _requestAccessor; private readonly IHttpContextAccessor _httpContextAccessor; - public MacroRenderer( - IProfilingLogger plogger, + IProfilingLogger profilingLogger , + ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, - IContentSettings contentSettings, + IOptions contentSettings, ILocalizedTextService textService, AppCaches appCaches, IMacroService macroService, @@ -48,9 +51,10 @@ namespace Umbraco.Web.Macros IRequestAccessor requestAccessor, IHttpContextAccessor httpContextAccessor) { - _plogger = plogger ?? throw new ArgumentNullException(nameof(plogger)); + _profilingLogger = profilingLogger ?? throw new ArgumentNullException(nameof(profilingLogger )); + _logger = logger; _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)); @@ -111,7 +115,7 @@ namespace Umbraco.Web.Macros if (macroContent == null) return null; - _plogger.Debug("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier); + _logger.LogDebug("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier); // ensure that the source has not changed // note: does not handle dependencies, and never has @@ -120,13 +124,13 @@ namespace Umbraco.Web.Macros { if (macroSource.Exists == false) { - _plogger.Debug("Macro source does not exist anymore, ignore cache."); + _logger.LogDebug("Macro source does not exist anymore, ignore cache."); return null; } if (macroContent.Date < macroSource.LastWriteTime) { - _plogger.Debug("Macro source has changed, ignore cache."); + _logger.LogDebug("Macro source has changed, ignore cache."); return null; } } @@ -160,7 +164,7 @@ namespace Umbraco.Web.Macros new TimeSpan(0, 0, model.CacheDuration) ); - _plogger.Debug("Macro content saved to cache '{MacroCacheId}'", model.CacheIdentifier); + _logger.LogDebug("Macro content saved to cache '{MacroCacheId}'", model.CacheIdentifier); } // gets the macro source file name @@ -219,7 +223,7 @@ namespace Umbraco.Web.Macros if (content == null) throw new ArgumentNullException(nameof(content)); var macroInfo = $"Render Macro: {macro.Name}, cache: {macro.CacheDuration}"; - using (_plogger.DebugDuration(macroInfo, "Rendered Macro.")) + using (_profilingLogger.DebugDuration(macroInfo, "Rendered Macro.")) { // parse macro parameters ie replace the special [#key], [$key], etc. syntaxes foreach (var prop in macro.Properties) @@ -265,7 +269,7 @@ namespace Umbraco.Web.Macros /// private Attempt ExecuteMacroWithErrorWrapper(MacroModel macro, string msgIn, string msgOut, Func getMacroContent, Func msgErr) { - using (_plogger.DebugDuration(msgIn, msgOut)) + using (_profilingLogger.DebugDuration(msgIn, msgOut)) { return ExecuteProfileMacroWithErrorWrapper(macro, msgIn, getMacroContent, msgErr); } @@ -282,7 +286,7 @@ namespace Umbraco.Web.Macros } catch (Exception e) { - _plogger.Warn(e, "Failed {MsgIn}", msgIn); + _logger.LogWarning(e, "Failed {MsgIn}", msgIn); var macroErrorEventArgs = new MacroErrorEventArgs { @@ -290,7 +294,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..3544465dfe 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -2,12 +2,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.Logging; using Umbraco.Web.Common.Lifetime; using Umbraco.Core; using Umbraco.Core.Logging; using System.Threading; using Umbraco.Core.Cache; using System.Collections.Generic; +using Umbraco.Core.Security; namespace Umbraco.Web.Common.Middleware { @@ -20,21 +22,24 @@ namespace Umbraco.Web.Common.Middleware /// public class UmbracoRequestMiddleware : IMiddleware { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IUmbracoRequestLifetimeManager _umbracoRequestLifetimeManager; private readonly IUmbracoContextFactory _umbracoContextFactory; private readonly IRequestCache _requestCache; + private readonly IBackofficeSecurityFactory _backofficeSecurityFactory; public UmbracoRequestMiddleware( - ILogger logger, + 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,15 +52,16 @@ 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); + _logger.LogTrace("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, requestUri); } try @@ -65,7 +71,7 @@ namespace Umbraco.Web.Common.Middleware catch (Exception ex) { // try catch so we don't kill everything in all requests - _logger.Error(ex); + _logger.LogError(ex.Message); } finally { @@ -84,7 +90,7 @@ namespace Umbraco.Web.Common.Middleware if (umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest) { LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); - _logger.Verbose("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, requestUri, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds); + _logger.LogTrace("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, requestUri, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds); } try @@ -104,7 +110,7 @@ namespace Umbraco.Web.Common.Middleware /// /// /// - private static void DisposeRequestCacheItems(ILogger logger, IRequestCache requestCache, Uri requestUri) + private static void DisposeRequestCacheItems(ILogger logger, IRequestCache requestCache, Uri requestUri) { // do not process if client-side request if (requestUri.IsClientSideRequest()) @@ -128,7 +134,7 @@ namespace Umbraco.Web.Common.Middleware } catch (Exception ex) { - logger.Error("Could not dispose item with key " + k, ex); + logger.LogError("Could not dispose item with key " + k, ex); } try { @@ -136,7 +142,7 @@ namespace Umbraco.Web.Common.Middleware } catch (Exception ex) { - logger.Error("Could not dispose item key " + k, ex); + logger.LogError("Could not dispose item key " + k, ex); } } } diff --git a/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs index bc5cce9df1..0c10b7d95a 100644 --- a/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs +++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs @@ -1,4 +1,7 @@ -using System; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Umbraco.Core.Composing; using Umbraco.Core.Logging; using Umbraco.Net; @@ -13,8 +16,9 @@ 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, + public WebProfilerComponent(IProfiler profiler, ILogger logger, IUmbracoRequestLifetime umbracoRequestLifetime, IUmbracoApplicationLifetime umbracoApplicationLifetime) { _umbracoRequestLifetime = umbracoRequestLifetime; @@ -28,7 +32,7 @@ namespace Umbraco.Web.Common.Profiler // if VoidProfiler was registered, let it be known if (profiler is VoidProfiler) - logger.Info( + logger.LogInformation( "Profiler is VoidProfiler, not profiling (must run debug mode to profile)."); _profile = false; } @@ -44,13 +48,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/PublishedModels/DummyClassSoThatPublishedModelsNamespaceExists.cs b/src/Umbraco.Web.Common/PublishedModels/DummyClassSoThatPublishedModelsNamespaceExists.cs similarity index 100% rename from src/Umbraco.Web/PublishedModels/DummyClassSoThatPublishedModelsNamespaceExists.cs rename to src/Umbraco.Web.Common/PublishedModels/DummyClassSoThatPublishedModelsNamespaceExists.cs diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index 959c4c27a2..0d91892445 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; @@ -37,7 +39,7 @@ namespace Umbraco.Web.Common.Runtime [ComposeAfter(typeof(CoreInitialComposer))] public class AspNetCoreComposer : ComponentComposer, IComposer { - public new void Compose(Composition composition) + public override void Compose(Composition composition) { base.Compose(composition); @@ -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()); } } } 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 89% rename from src/Umbraco.Web.Common/Security/WebSecurity.cs rename to src/Umbraco.Web.Common/Security/BackofficeSecurity.cs index c67d5a9b4f..c16071b68a 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; } @@ -65,7 +66,7 @@ namespace Umbraco.Web.Common.Security /// public Attempt GetUserId() { - var identity = _httpContextAccessor.GetRequiredHttpContext().GetCurrentIdentity(); + var identity = _httpContextAccessor.HttpContext?.GetCurrentIdentity(); return identity == null ? Attempt.Fail() : Attempt.Succeed(identity.Id); } @@ -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 46e9c44f43..122f76b76c 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -15,17 +15,17 @@ - - - + + + - - + + @@ -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..f50a2e2ba8 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, @@ -93,7 +96,6 @@ namespace Umbraco.Web if (currentUmbracoContext != null) return new UmbracoContextReference(currentUmbracoContext, false, _umbracoContextAccessor); - var umbracoContext = CreateUmbracoContext(); _umbracoContextAccessor.UmbracoContext = umbracoContext; diff --git a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js index fb03cbd1b1..179faeb843 100644 --- a/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js +++ b/src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js @@ -212,16 +212,18 @@ function dependencies() { }, { "name": "signalr", - "src": ["./node_modules/signalr/jquery.signalR.js"], - "base": "./node_modules/signalr" + "src": [ + "./node_modules/@microsoft/signalr/dist/browser/signalr.min.js", + ], + "base": "./node_modules/@microsoft/signalr/dist/browser" }, { "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", @@ -279,7 +281,7 @@ function dependencies() { var assetsTask = gulp.src(config.sources.globs.assets, { allowEmpty: true }); assetsTask = assetsTask.pipe(imagemin([ imagemin.gifsicle({interlaced: true}), - imagemin.jpegtran({progressive: true}), + imagemin.mozjpeg({progressive: true}), imagemin.optipng({optimizationLevel: 5}), imagemin.svgo({ plugins: [ diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 100774f385..eae04dc289 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -10,6 +10,7 @@ "watch": "gulp watch" }, "dependencies": { + "@microsoft/signalr": "^3.1.8", "ace-builds": "1.4.2", "angular": "1.8.0", "angular-animate": "1.7.5", @@ -38,10 +39,9 @@ "lazyload-js": "1.0.0", "moment": "2.22.2", "ng-file-upload": "12.2.13", - "nouislider": "14.6.0", + "nouislider": "14.6.2", "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", @@ -61,7 +61,7 @@ "gulp-cli": "^2.3.0", "gulp-concat": "2.6.1", "gulp-eslint": "6.0.0", - "gulp-imagemin": "6.1.1", + "gulp-imagemin": "7.1.0", "gulp-less": "4.0.1", "gulp-notify": "^3.0.0", "gulp-postcss": "8.0.0", @@ -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..f26763bd14 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); @@ -261,7 +252,7 @@ function iconHelper($http, $q, $sce, $timeout, umbRequestHelper) { /** LEGACY - Return a list of icons from icon fonts, optionally filter them */ /** It fetches them directly from the active stylesheets in the browser */ - getLegacyIcons: function(){ + getIcons: function(){ var deferred = $q.defer(); $timeout(function(){ if(collectedIcons){ @@ -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..e5ce8d572c 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"; @@ -205,6 +205,7 @@ // Property Editors @import "../views/components/blockcard/umb-block-card-grid.less"; @import "../views/components/blockcard/umb-block-card.less"; +@import "../views/components/umb-property-info-button/umb-property-info-button.less"; @import "../views/propertyeditors/blocklist/umb-block-list-property-editor.less"; @import "../views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.less"; @import "../views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.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/buttons/umb-button-ellipsis.less b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less index 54302ba869..7104e6478f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button-ellipsis.less @@ -4,10 +4,10 @@ margin: 0 auto; cursor: pointer; border-radius: @baseBorderRadius; - color: black; + color: @ui-action-discreet-type; position: relative; opacity: 0.8; - transition: opacity .3s ease-out; + transition: opacity 120ms, color 120ms; &--absolute { position: absolute; @@ -23,6 +23,10 @@ justify-content: center; } + &:hover { + color: @ui-action-discreet-type-hover; + } + .umb-button-ellipsis--tab, .umb-tour-is-visible .umb-tree &, &:hover, @@ -47,6 +51,7 @@ &__icon { color: inherit; flex-basis: 100%; + font-size: 12px; .umb-button-ellipsis--tab & { margin: 0 0 7px; 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-root.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less index a3529d5504..ba33883b08 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree-root.less @@ -1,5 +1,7 @@ -.umb-tree-root { +.umb-tree-root { + border: 2px solid transparent; + &-link { display: flex; align-items: center; 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..bf8e7fdb70 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 @@ -95,8 +95,6 @@ body.touch .umb-tree { position: relative; width: auto; height: auto; - margin: 0 5px 0 auto; - padding: 7px 5px; overflow: visible; clip: auto; } @@ -185,11 +183,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; + margin: 0 10px 0 auto; cursor: pointer; border-radius: @baseBorderRadius; + transition: background-color 120ms; + + .umb-button-ellipsis { + padding: 3px 5px; + } i { height: 5px !important; @@ -205,7 +207,7 @@ body.touch .umb-tree { } &:hover { - background: rgba(255, 255, 255, .5); + background-color: rgba(255, 255, 255, .8); i { background: @ui-active-type-hover; 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-icon.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-icon.less index e3b0550d15..e08174e378 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-icon.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-icon.less @@ -1,4 +1,27 @@ .umb-icon { + display: inline-block; + width: 1em; + height: 1em; + + svg { + width: 100%; + height: 100%; + fill: currentColor; + } + + &.large{ + width: 32px; + height: 32px; + } + &.medium{ + width: 24px; + height: 24px; + } + &.small{ + width: 14px; + height: 14px; + } + &:before, &:after { content: none !important; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-iconpicker.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-iconpicker.less index e23325a7d2..5062aae660 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-iconpicker.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-iconpicker.less @@ -58,7 +58,6 @@ } .umb-iconpicker-item i { - font-family: inherit; font-size: 30px; } 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..d05139a06f 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; @@ -233,3 +234,7 @@ .umb-media-grid__list-view .umb-table-cell.umb-table__name .item-name { white-space:normal; } +.umb-media-grid__list-view .umb-table-cell.umb-table__name ins { + text-decoration: none; + margin-top: 3px; +} 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/helveticons.less b/src/Umbraco.Web.UI.Client/src/less/helveticons.less index a51f4e9f6f..cded6b8269 100644 --- a/src/Umbraco.Web.UI.Client/src/less/helveticons.less +++ b/src/Umbraco.Web.UI.Client/src/less/helveticons.less @@ -8,36 +8,9 @@ font-style: normal; } -span[class^="icon-"], -span[class*=" icon-"] { - display: inline-block; - width: 1em; - height: 1em; - *margin-right: .3em; - - svg { - width: 100%; - height: 100%; - fill: currentColor; - } - - &.large{ - width: 32px; - height: 32px; - } - &.medium{ - width: 24px; - height: 24px; - } - &.small{ - width: 14px; - height: 14px; - } -} [class^="icon-"], -[class*=" icon-"], -button.icon-trash { +[class*=" icon-"]{ font-family: 'icomoon'; speak: none; font-style: normal; @@ -52,8 +25,7 @@ button.icon-trash { } [class^="icon-"]:before, -[class*=" icon-"]:before, -button.icon-trash { +[class*=" icon-"]:before { text-decoration: inherit; display: inline-block; speak: none; @@ -69,1838 +41,1834 @@ i.small{ font-size: 14px; } -i.icon-zoom-out:before { +.icon-zoom-out:before { content: "\e000"; } -i.icon-truck:before { +.icon-truck:before { content: "\e001"; } -i.icon-zoom-in:before { +.icon-zoom-in:before { content: "\e002"; } -i.icon-zip:before { +.icon-zip:before { content: "\e003"; } -i.icon-axis-rotation:before { +.icon-axis-rotation:before { content: "\e004"; } -i.icon-yen-bag:before { +.icon-yen-bag:before { content: "\e005"; } -i.icon-axis-rotation-2:before { +.icon-axis-rotation-2:before { content: "\e006"; } -i.icon-axis-rotation-3:before { +.icon-axis-rotation-3:before { content: "\e007"; } -i.icon-wrench:before { +.icon-wrench:before { content: "\e008"; } -i.icon-wine-glass:before { +.icon-wine-glass:before { content: "\e009"; } -i.icon-wrong:before { +.icon-wrong:before { content: "\e00a"; } -i.icon-windows:before { +.icon-windows:before { content: "\e00b"; } -i.icon-window-sizes:before { +.icon-window-sizes:before { content: "\e00c"; } -i.icon-window-popin:before { +.icon-window-popin:before { content: "\e00d"; } -i.icon-wifi:before { +.icon-wifi:before { content: "\e00e"; } -i.icon-width:before { +.icon-width:before { content: "\e00f"; } -i.icon-weight:before { +.icon-weight:before { content: "\e010"; } -i.icon-war:before { +.icon-war:before { content: "\e011"; } -i.icon-wand:before { +.icon-wand:before { content: "\e012"; } -i.icon-wallet:before { +.icon-wallet:before { content: "\e013"; } -i.icon-wall-plug:before { +.icon-wall-plug:before { content: "\e014"; } -i.icon-voice:before { +.icon-voice:before { content: "\e016"; } -i.icon-video:before { +.icon-video:before { content: "\e017"; } -i.icon-vcard:before { +.icon-vcard:before { content: "\e018"; } -i.icon-utilities:before { +.icon-utilities:before { content: "\e019"; } -i.icon-users:before { +.icon-users:before { content: "\e01a"; } -i.icon-users-alt:before { +.icon-users-alt:before { content: "\e01b"; } -i.icon-user:before { +.icon-user:before { content: "\e01c"; } -i.icon-user-glasses:before { +.icon-user-glasses:before { content: "\e01d"; } -i.icon-user-females:before { +.icon-user-females:before { content: "\e01e"; } -i.icon-user-females-alt:before { +.icon-user-females-alt:before { content: "\e01f"; } -i.icon-user-female:before { +.icon-user-female:before { content: "\e020"; } -i.icon-usb:before { +.icon-usb:before { content: "\e021"; } -i.icon-usb-connector:before { +.icon-usb-connector:before { content: "\e022"; } -i.icon-unlocked:before { +.icon-unlocked:before { content: "\e023"; } -i.icon-universal:before { +.icon-universal:before { content: "\e024"; } -i.icon-undo:before { +.icon-undo:before { content: "\e025"; } -i.icon-umbrella:before { +.icon-umbrella:before { content: "\e026"; } -i.icon-umb-deploy:before { +.icon-umb-deploy:before { content: "\e027"; } -i.icon-umb-contour:before, .traycontour:before { +.icon-umb-contour:before, .traycontour:before { content: "\e028"; } -i.icon-umb-settings:before, .traysettings:before { +.icon-umb-settings:before, .traysettings:before { content: "\e029"; } -i.icon-umb-users:before, .trayuser:before, .trayusers:before{ +.icon-umb-users:before, .trayuser:before, .trayusers:before{ content: "\e02a"; } -i.icon-umb-media:before, .traymedia:before { +.icon-umb-media:before, .traymedia:before { content: "\e02b"; } -i.icon-umb-content:before, .traycontent:before{ +.icon-umb-content:before, .traycontent:before{ content: "\e02c"; } -i.icon-umb-developer:before, .traydeveloper:before { +.icon-umb-developer:before, .traydeveloper:before { content: "\e02d"; } -i.icon-umb-members:before, .traymember:before { +.icon-umb-members:before, .traymember:before { content: "\e015"; } -i.icon-umb-translation:before, .traytranslation:before { +.icon-umb-translation:before, .traytranslation:before { content: "\e1fd"; } -i.icon-tv:before { +.icon-tv:before { content: "\e02e"; } -i.icon-tv-old:before { +.icon-tv-old:before { content: "\e02f"; } -i.icon-trophy:before { +.icon-trophy:before { content: "\e030"; } -i.icon-tree:before { +.icon-tree:before { content: "\e031"; } -i.icon-trash:before, -button.icon-trash:before { +.icon-trash:before { content: "\e032"; } -i.icon-trash-alt:before, -button.icon-trash-alt:before { +.icon-trash-alt:before { content: "\e033"; } -i.icon-trash-alt-2:before, -button.icon-trash-alt-2:before { +.icon-trash-alt-2:before { content: "\e034"; } -i.icon-train:before { +.icon-train:before { content: "\e035"; } -i.icon-trafic:before, -i.icon-traffic:before { +.icon-trafic:before, +.icon-traffic:before { content: "\e036"; } -i.icon-traffic-alt:before { +.icon-traffic-alt:before { content: "\e037"; } -i.icon-top:before { +.icon-top:before { content: "\e038"; } -i.icon-tools:before { +.icon-tools:before { content: "\e039"; } -i.icon-timer:before { +.icon-timer:before { content: "\e03a"; } -i.icon-time:before { +.icon-time:before { content: "\e03b"; } -i.icon-t-shirt:before { +.icon-t-shirt:before { content: "\e03c"; } -i.icon-tab-key:before { +.icon-tab-key:before { content: "\e03d"; } -i.icon-tab:before { +.icon-tab:before { content: "\e03e"; } -i.icon-tactics:before { +.icon-tactics:before { content: "\e03f"; } -i.icon-tag:before { +.icon-tag:before { content: "\e040"; } -i.icon-tags:before { +.icon-tags:before { content: "\e041"; } -i.icon-takeaway-cup:before { +.icon-takeaway-cup:before { content: "\e042"; } -i.icon-target:before { +.icon-target:before { content: "\e043"; } -i.icon-temperature-alt:before, -i.icon-temperatrure-alt:before { +.icon-temperature-alt:before, +.icon-temperatrure-alt:before { content: "\e044"; } -i.icon-temperature:before { +.icon-temperature:before { content: "\e045"; } -i.icon-terminal:before { +.icon-terminal:before { content: "\e046"; } -i.icon-theater:before { +.icon-theater:before { content: "\e047"; } -i.icon-thief:before, -i.icon-theif:before { +.icon-thief:before, +.icon-theif:before { content: "\e048"; } -i.icon-thought-bubble:before { +.icon-thought-bubble:before { content: "\e049"; } -i.icon-thumb-down:before { +.icon-thumb-down:before { content: "\e04a"; } -i.icon-thumb-up:before { +.icon-thumb-up:before { content: "\e04b"; } -i.icon-thumbnail-list:before { +.icon-thumbnail-list:before { content: "\e04c"; } -i.icon-thumbnails-small:before { +.icon-thumbnails-small:before { content: "\e04d"; } -i.icon-thumbnails:before { +.icon-thumbnails:before { content: "\e04e"; } -i.icon-ticket:before { +.icon-ticket:before { content: "\e04f"; } -i.icon-sync:before { +.icon-sync:before { content: "\e050"; } -i.icon-sweatshirt:before { +.icon-sweatshirt:before { content: "\e051"; } -i.icon-sunny:before { +.icon-sunny:before { content: "\e052"; } -i.icon-stream:before { +.icon-stream:before { content: "\e053"; } -i.icon-store:before { +.icon-store:before { content: "\e054"; } -i.icon-stop:before { +.icon-stop:before { content: "\e055"; } -i.icon-stop-hand:before { +.icon-stop-hand:before { content: "\e056"; } -i.icon-stop-alt:before { +.icon-stop-alt:before { content: "\e057"; } -i.icon-stamp:before { +.icon-stamp:before { content: "\e058"; } -i.icon-stacked-disks:before { +.icon-stacked-disks:before { content: "\e059"; } -i.icon-ssd:before { +.icon-ssd:before { content: "\e05a"; } -i.icon-squiggly-line:before { +.icon-squiggly-line:before { content: "\e05b"; } -i.icon-sprout:before { +.icon-sprout:before { content: "\e05c"; } -i.icon-split:before { +.icon-split:before { content: "\e05d"; } -i.icon-split-alt:before { +.icon-split-alt:before { content: "\e05e"; } -i.icon-speed-gauge:before { +.icon-speed-gauge:before { content: "\e05f"; } -i.icon-speaker:before { +.icon-speaker:before { content: "\e060"; } -i.icon-sound:before { +.icon-sound:before { content: "\e061"; } -i.icon-spades:before { +.icon-spades:before { content: "\e062"; } -i.icon-sound-waves:before { +.icon-sound-waves:before { content: "\e063"; } -i.icon-shipping-box:before { +.icon-shipping-box:before { content: "\e064"; } -i.icon-shipping:before { +.icon-shipping:before { content: "\e065"; } -i.icon-shoe:before { +.icon-shoe:before { content: "\e066"; } -i.icon-shopping-basket-alt-2:before { +.icon-shopping-basket-alt-2:before { content: "\e067"; } -i.icon-shopping-basket:before { +.icon-shopping-basket:before { content: "\e068"; } -i.icon-shopping-basket-alt:before { +.icon-shopping-basket-alt:before { content: "\e069"; } -i.icon-shorts:before { +.icon-shorts:before { content: "\e06a"; } -i.icon-shuffle:before { +.icon-shuffle:before { content: "\e06b"; } -i.icon-science:before, -i.icon-sience:before { +.icon-science:before, +.icon-sience:before { content: "\e06c"; } -i.icon-simcard:before { +.icon-simcard:before { content: "\e06d"; } -i.icon-single-note:before { +.icon-single-note:before { content: "\e06e"; } -i.icon-sitemap:before { +.icon-sitemap:before { content: "\e06f"; } -i.icon-sleep:before { +.icon-sleep:before { content: "\e070"; } -i.icon-slideshow:before { +.icon-slideshow:before { content: "\e071"; } -i.icon-smiley-inverted:before { +.icon-smiley-inverted:before { content: "\e072"; } -i.icon-smiley:before { +.icon-smiley:before { content: "\e073"; } -i.icon-snow:before { +.icon-snow:before { content: "\e074"; } -i.icon-sound-low:before { +.icon-sound-low:before { content: "\e075"; } -i.icon-sound-medium:before { +.icon-sound-medium:before { content: "\e076"; } -i.icon-sound-off:before { +.icon-sound-off:before { content: "\e077"; } -i.icon-shift:before { +.icon-shift:before { content: "\e078"; } -i.icon-shield:before { +.icon-shield:before { content: "\e079"; } -i.icon-sharing-iphone:before { +.icon-sharing-iphone:before { content: "\e07a"; } -i.icon-share:before { +.icon-share:before { content: "\e07b"; } -i.icon-share-alt:before { +.icon-share-alt:before { content: "\e07c"; } -i.icon-share-alt-2:before { +.icon-share-alt-2:before { content: "\e07d"; } -i.icon-settings:before, -button.icon-settings:before { +.icon-settings:before { content: "\e07e"; } -i.icon-settings-alt:before { +.icon-settings-alt:before { content: "\e07f"; } -i.icon-settings-alt-2:before { +.icon-settings-alt-2:before { content: "\e080"; } -i.icon-server:before { +.icon-server:before { content: "\e081"; } -i.icon-server-alt:before { +.icon-server-alt:before { content: "\e082"; } -i.icon-sensor:before { +.icon-sensor:before { content: "\e083"; } -i.icon-security-camera:before { +.icon-security-camera:before { content: "\e084"; } -i.icon-search:before { +.icon-search:before { content: "\e085"; } -i.icon-scull:before { +.icon-scull:before { content: "\e086"; } -i.icon-script:before { +.icon-script:before { content: "\e087"; } -i.icon-script-alt:before { +.icon-script-alt:before { content: "\e088"; } -i.icon-screensharing:before { +.icon-screensharing:before { content: "\e089"; } -i.icon-school:before { +.icon-school:before { content: "\e08a"; } -i.icon-scan:before { +.icon-scan:before { content: "\e08b"; } -i.icon-refresh:before { +.icon-refresh:before { content: "\e08c"; } -i.icon-remote:before { +.icon-remote:before { content: "\e08d"; } -i.icon-remove:before { +.icon-remove:before { content: "\e08e"; } -i.icon-repeat-one:before { +.icon-repeat-one:before { content: "\e08f"; } -i.icon-repeat:before { +.icon-repeat:before { content: "\e090"; } -i.icon-resize:before { +.icon-resize:before { content: "\e091"; } -i.icon-reply-arrow:before { +.icon-reply-arrow:before { content: "\e092"; } -i.icon-return-to-top:before { +.icon-return-to-top:before { content: "\e093"; } -i.icon-right-double-arrow:before { +.icon-right-double-arrow:before { content: "\e094"; } -i.icon-road:before { +.icon-road:before { content: "\e095"; } -i.icon-roadsign:before { +.icon-roadsign:before { content: "\e096"; } -i.icon-rocket:before { +.icon-rocket:before { content: "\e097"; } -i.icon-rss:before { +.icon-rss:before { content: "\e098"; } -i.icon-ruler-alt:before { +.icon-ruler-alt:before { content: "\e099"; } -i.icon-ruler:before { +.icon-ruler:before { content: "\e09a"; } -i.icon-sandbox-toys:before { +.icon-sandbox-toys:before { content: "\e09b"; } -i.icon-satellite-dish:before { +.icon-satellite-dish:before { content: "\e09c"; } -i.icon-save:before { +.icon-save:before { content: "\e09d"; } -i.icon-safedial:before { +.icon-safedial:before { content: "\e09e"; } -i.icon-safe:before { +.icon-safe:before { content: "\e09f"; } -i.icon-redo:before { +.icon-redo:before { content: "\e0a0"; } -i.icon-printer-alt:before { +.icon-printer-alt:before { content: "\e0a1"; } -i.icon-planet:before { +.icon-planet:before { content: "\e0a2"; } -i.icon-paste-in:before { +.icon-paste-in:before { content: "\e0a3"; } -i.icon-os-x:before { +.icon-os-x:before { content: "\e0a4"; } -i.icon-navigation-left:before { +.icon-navigation-left:before { content: "\e0a5"; } -i.icon-message:before { +.icon-message:before { content: "\e0a6"; } -i.icon-lock:before { +.icon-lock:before { content: "\e0a7"; } -i.icon-layers-alt:before { +.icon-layers-alt:before { content: "\e0a8"; } -i.icon-record:before { +.icon-record:before { content: "\e0a9"; } -i.icon-print:before { +.icon-print:before { content: "\e0aa"; } -i.icon-plane:before { +.icon-plane:before { content: "\e0ab"; } -i.icon-partly-cloudy:before { +.icon-partly-cloudy:before { content: "\e0ac"; } -i.icon-ordered-list:before { +.icon-ordered-list:before { content: "\e0ad"; } -i.icon-navigation-last:before { +.icon-navigation-last:before { content: "\e0ae"; } -i.icon-message-unopened:before { +.icon-message-unopened:before { content: "\e0af"; } -i.icon-location-nearby:before { +.icon-location-nearby:before { content: "\e0b0"; } -i.icon-laptop:before { +.icon-laptop:before { content: "\e0b1"; } -i.icon-reception:before { +.icon-reception:before { content: "\e0b2"; } -i.icon-price-yen:before { +.icon-price-yen:before { content: "\e0b3"; } -i.icon-piracy:before { +.icon-piracy:before { content: "\e0b4"; } -i.icon-parental-control:before { +.icon-parental-control:before { content: "\e0b5"; } -i.icon-operator:before { +.icon-operator:before { content: "\e0b6"; } -i.icon-navigation-horizontal:before { +.icon-navigation-horizontal:before { content: "\e0b7"; } -i.icon-message-open:before { +.icon-message-open:before { content: "\e0b8"; } -i.icon-lab:before { +.icon-lab:before { content: "\e0b9"; } -i.icon-location-near-me:before { +.icon-location-near-me:before { content: "\e0ba"; } -i.icon-receipt-yen:before { +.icon-receipt-yen:before { content: "\e0bb"; } -i.icon-price-pound:before { +.icon-price-pound:before { content: "\e0bc"; } -i.icon-pin-location:before { +.icon-pin-location:before { content: "\e0bd"; } -i.icon-parachute-drop:before { +.icon-parachute-drop:before { content: "\e0be"; } -i.icon-old-phone:before { +.icon-old-phone:before { content: "\e0bf"; } -i.icon-merge:before { +.icon-merge:before { content: "\e0c0"; } -i.icon-navigation-first:before { +.icon-navigation-first:before { content: "\e0c1"; } -i.icon-locate:before { +.icon-locate:before { content: "\e0c2"; } -i.icon-keyhole:before { +.icon-keyhole:before { content: "\e0c3"; } -i.icon-receipt-pound:before { +.icon-receipt-pound:before { content: "\e0c4"; } -i.icon-price-euro:before { +.icon-price-euro:before { content: "\e0c5"; } -i.icon-piggy-bank:before { +.icon-piggy-bank:before { content: "\e0c6"; } -i.icon-paper-plane:before { +.icon-paper-plane:before { content: "\e0c7"; } -i.icon-old-key:before { +.icon-old-key:before { content: "\e0c8"; } -i.icon-navigation-down:before { +.icon-navigation-down:before { content: "\e0c9"; } -i.icon-megaphone:before { +.icon-megaphone:before { content: "\e0ca"; } -i.icon-loading:before { +.icon-loading:before { content: "\e0cb"; } -i.icon-keychain:before { +.icon-keychain:before { content: "\e0cc"; } -i.icon-receipt-euro:before { +.icon-receipt-euro:before { content: "\e0cd"; } -i.icon-price-dollar:before { +.icon-price-dollar:before { content: "\e0ce"; } -i.icon-pie-chart:before { +.icon-pie-chart:before { content: "\e0cf"; } -i.icon-paper-plane-alt:before { +.icon-paper-plane-alt:before { content: "\e0d0"; } -i.icon-notepad:before { +.icon-notepad:before { content: "\e0d1"; } -i.icon-navigation-bottom:before { +.icon-navigation-bottom:before { content: "\e0d2"; } -i.icon-meeting:before { +.icon-meeting:before { content: "\e0d3"; } -i.icon-keyboard:before { +.icon-keyboard:before { content: "\e0d4"; } -i.icon-load:before { +.icon-load:before { content: "\e0d5"; } -i.icon-receipt-dollar:before { +.icon-receipt-dollar:before { content: "\e0d6"; } -i.icon-previous:before { +.icon-previous:before { content: "\e0d7"; } -i.icon-pictures:before { +.icon-pictures:before { content: "\e0d8"; } -i.icon-notepad-alt:before { +.icon-notepad-alt:before { content: "\e0d9"; } -i.icon-paper-bag:before { +.icon-paper-bag:before { content: "\e0da"; } -i.icon-badge:before { +.icon-badge:before { content: "\e0db"; } -i.icon-medicine:before { +.icon-medicine:before { content: "\e0dc"; } -i.icon-list:before { +.icon-list:before { content: "\e0dd"; } -i.icon-key:before { +.icon-key:before { content: "\e0de"; } -i.icon-receipt-alt:before { +.icon-receipt-alt:before { content: "\e0df"; } -i.icon-previous-media:before { +.icon-previous-media:before { content: "\e0e0"; } -i.icon-pictures-alt:before { +.icon-pictures-alt:before { content: "\e0e1"; } -i.icon-pants:before { +.icon-pants:before { content: "\e0e2"; } -i.icon-nodes:before { +.icon-nodes:before { content: "\e0e3"; } -i.icon-music:before { +.icon-music:before { content: "\e0e4"; } -i.icon-readonly:before { +.icon-readonly:before { content: "\e0e5"; } -i.icon-presentation:before { +.icon-presentation:before { content: "\e0e6"; } -i.icon-pictures-alt-2:before { +.icon-pictures-alt-2:before { content: "\e0e7"; } -i.icon-panel-close:before, -i.icon-pannel-close:before { +.icon-panel-close:before, +.icon-pannel-close:before { content: "\e0e8"; } -i.icon-next:before { +.icon-next:before { content: "\e0e9"; } -i.icon-multiple-windows:before { +.icon-multiple-windows:before { content: "\e0ea"; } -i.icon-medical-emergency:before { +.icon-medical-emergency:before { content: "\e0eb"; } -i.icon-medal:before { +.icon-medal:before { content: "\e0ec"; } -i.icon-link:before { +.icon-link:before { content: "\e0ed"; } -i.icon-linux-tux:before { +.icon-linux-tux:before { content: "\e0ee"; } -i.icon-junk:before { +.icon-junk:before { content: "\e0ef"; } -i.icon-item-arrangement:before { +.icon-item-arrangement:before { content: "\e0f0"; } -i.icon-iphone:before { +.icon-iphone:before { content: "\e0f1"; } -i.icon-lightning:before { +.icon-lightning:before { content: "\e0f2"; } -i.icon-map:before { +.icon-map:before { content: "\e0f3"; } -i.icon-multiple-credit-cards:before { +.icon-multiple-credit-cards:before { content: "\e0f4"; } -i.icon-next-media:before { +.icon-next-media:before { content: "\e0f5"; } -i.icon-panel-show:before { +.icon-panel-show:before { content: "\e0f6"; } -i.icon-picture:before { +.icon-picture:before { content: "\e0f7"; } -i.icon-power:before { +.icon-power:before { content: "\e0f8"; } -i.icon-re-post:before { +.icon-re-post:before { content: "\e0f9"; } -i.icon-rate:before { +.icon-rate:before { content: "\e0fa"; } -i.icon-rain:before { +.icon-rain:before { content: "\e0fb"; } -i.icon-radio:before { +.icon-radio:before { content: "\e0fc"; } -i.icon-radio-receiver:before { +.icon-radio-receiver:before { content: "\e0fd"; } -i.icon-radio-alt:before { +.icon-radio-alt:before { content: "\e0fe"; } -i.icon-quote:before { +.icon-quote:before { content: "\e0ff"; } -i.icon-qr-code:before { +.icon-qr-code:before { content: "\e100"; } -i.icon-pushpin:before { +.icon-pushpin:before { content: "\e101"; } -i.icon-pulse:before { +.icon-pulse:before { content: "\e102"; } -i.icon-projector:before { +.icon-projector:before { content: "\e103"; } -i.icon-play:before { +.icon-play:before { content: "\e104"; } -i.icon-playing-cards:before { +.icon-playing-cards:before { content: "\e105"; } -i.icon-playlist:before { +.icon-playlist:before { content: "\e106"; } -i.icon-plugin:before { +.icon-plugin:before { content: "\e107"; } -i.icon-podcast:before { +.icon-podcast:before { content: "\e108"; } -i.icon-poker-chip:before { +.icon-poker-chip:before { content: "\e109"; } -i.icon-poll:before { +.icon-poll:before { content: "\e10a"; } -i.icon-post-it:before { +.icon-post-it:before { content: "\e10b"; } -i.icon-pound-bag:before { +.icon-pound-bag:before { content: "\e10c"; } -i.icon-power-outlet:before { +.icon-power-outlet:before { content: "\e10d"; } -i.icon-photo-album:before { +.icon-photo-album:before { content: "\e10e"; } -i.icon-phone:before { +.icon-phone:before { content: "\e10f"; } -i.icon-phone-ring:before { +.icon-phone-ring:before { content: "\e110"; } -i.icon-people:before { +.icon-people:before { content: "\e111"; } -i.icon-people-female:before { +.icon-people-female:before { content: "\e112"; } -i.icon-people-alt:before { +.icon-people-alt:before { content: "\e113"; } -i.icon-people-alt-2:before { +.icon-people-alt-2:before { content: "\e114"; } -i.icon-pc:before { +.icon-pc:before { content: "\e115"; } -i.icon-pause:before { +.icon-pause:before { content: "\e116"; } -i.icon-path:before { +.icon-path:before { content: "\e117"; } -i.icon-out:before { +.icon-out:before { content: "\e118"; } -i.icon-outbox:before { +.icon-outbox:before { content: "\e119"; } -i.icon-outdent:before { +.icon-outdent:before { content: "\e11a"; } -i.icon-page-add:before { +.icon-page-add:before { content: "\e11b"; } -i.icon-page-down:before { +.icon-page-down:before { content: "\e11c"; } -i.icon-page-remove:before { +.icon-page-remove:before { content: "\e11d"; } -i.icon-page-restricted:before { +.icon-page-restricted:before { content: "\e11e"; } -i.icon-page-up:before { +.icon-page-up:before { content: "\e11f"; } -i.icon-paint-roller:before { +.icon-paint-roller:before { content: "\e120"; } -i.icon-palette:before { +.icon-palette:before { content: "\e121"; } -i.icon-newspaper:before { +.icon-newspaper:before { content: "\e122"; } -i.icon-newspaper-alt:before { +.icon-newspaper-alt:before { content: "\e123"; } -i.icon-network-alt:before { +.icon-network-alt:before { content: "\e124"; } -i.icon-navigational-arrow:before { +.icon-navigational-arrow:before { content: "\e125"; } -i.icon-navigation:before { +.icon-navigation:before { content: "\e126"; } -i.icon-navigation-vertical:before { +.icon-navigation-vertical:before { content: "\e127"; } -i.icon-navigation-up:before { +.icon-navigation-up:before { content: "\e128"; } -i.icon-navigation-top:before { +.icon-navigation-top:before { content: "\e129"; } -i.icon-navigation-road:before { +.icon-navigation-road:before { content: "\e12a"; } -i.icon-navigation-right:before { +.icon-navigation-right:before { content: "\e12b"; } -i.icon-microscope:before { +.icon-microscope:before { content: "\e12c"; } -i.icon-mindmap:before { +.icon-mindmap:before { content: "\e12d"; } -i.icon-molecular-network:before { +.icon-molecular-network:before { content: "\e12e"; } -i.icon-molecular:before { +.icon-molecular:before { content: "\e12f"; } -i.icon-mountain:before { +.icon-mountain:before { content: "\e130"; } -i.icon-mouse-cursor:before { +.icon-mouse-cursor:before { content: "\e131"; } -i.icon-mouse:before { +.icon-mouse:before { content: "\e132"; } -i.icon-movie-alt:before { +.icon-movie-alt:before { content: "\e133"; } -i.icon-map-marker:before { +.icon-map-marker:before { content: "\e134"; } -i.icon-movie:before { +.icon-movie:before { content: "\e135"; } -i.icon-map-location:before { +.icon-map-location:before { content: "\e136"; } -i.icon-map-alt:before { +.icon-map-alt:before { content: "\e137"; } -i.icon-male-symbol:before { +.icon-male-symbol:before { content: "\e138"; } -i.icon-male-and-female:before { +.icon-male-and-female:before { content: "\e139"; } -i.icon-mailbox:before { +.icon-mailbox:before { content: "\e13a"; } -i.icon-magnet:before { +.icon-magnet:before { content: "\e13b"; } -i.icon-loupe:before { +.icon-loupe:before { content: "\e13c"; } -i.icon-mobile:before { +.icon-mobile:before { content: "\e13d"; } -i.icon-logout:before { +.icon-logout:before { content: "\e13e"; } -i.icon-log-out:before { +.icon-log-out:before { content: "\e13f"; } -i.icon-layers:before { +.icon-layers:before { content: "\e140"; } -i.icon-left-double-arrow:before { +.icon-left-double-arrow:before { content: "\e141"; } -i.icon-layout:before { +.icon-layout:before { content: "\e142"; } -i.icon-legal:before { +.icon-legal:before { content: "\e143"; } -i.icon-lense:before { +.icon-lense:before { content: "\e144"; } -i.icon-library:before { +.icon-library:before { content: "\e145"; } -i.icon-light-down:before { +.icon-light-down:before { content: "\e146"; } -i.icon-light-up:before { +.icon-light-up:before { content: "\e147"; } -i.icon-lightbulb-active:before { +.icon-lightbulb-active:before { content: "\e148"; } -i.icon-lightbulb:before { +.icon-lightbulb:before { content: "\e149"; } -i.icon-ipad:before { +.icon-ipad:before { content: "\e14a"; } -i.icon-invoice:before { +.icon-invoice:before { content: "\e14b"; } -i.icon-info:before { +.icon-info:before { content: "\e14c"; } -i.icon-infinity:before { +.icon-infinity:before { content: "\e14d"; } -i.icon-indent:before { +.icon-indent:before { content: "\e14e"; } -i.icon-inbox:before { +.icon-inbox:before { content: "\e14f"; } -i.icon-inbox-full:before { +.icon-inbox-full:before { content: "\e150"; } -i.icon-inactive-line:before { +.icon-inactive-line:before { content: "\e151"; } -i.icon-imac:before { +.icon-imac:before { content: "\e152"; } -i.icon-hourglass:before { +.icon-hourglass:before { content: "\e153"; } -i.icon-home:before { +.icon-home:before { content: "\e154"; } -i.icon-grid:before { +.icon-grid:before { content: "\e155"; } -i.icon-food:before { +.icon-food:before { content: "\e156"; } -i.icon-favorite:before { +.icon-favorite:before { content: "\e157"; } -i.icon-door-open-alt:before { +.icon-door-open-alt:before { content: "\e158"; } -i.icon-diagnostics:before { +.icon-diagnostics:before { content: "\e159"; } -i.icon-contrast:before { +.icon-contrast:before { content: "\e15a"; } -i.icon-coins-dollar-alt:before { +.icon-coins-dollar-alt:before { content: "\e15b"; } -i.icon-circle-dotted-active:before { +.icon-circle-dotted-active:before { content: "\e15c"; } -i.icon-cinema:before { +.icon-cinema:before { content: "\e15d"; } -i.icon-chip:before { +.icon-chip:before { content: "\e15e"; } -i.icon-chip-alt:before { +.icon-chip-alt:before { content: "\e15f"; } -i.icon-chess:before { +.icon-chess:before { content: "\e160"; } -i.icon-checkbox:before { +.icon-checkbox:before { content: "\e161"; } -i.icon-checkbox-empty:before { +.icon-checkbox-empty:before { content: "\e162"; } -i.icon-checkbox-dotted:before { +.icon-checkbox-dotted:before { content: "\e163"; } -i.icon-checkbox-dotted-active:before { +.icon-checkbox-dotted-active:before { content: "\e164"; } -i.icon-check:before { +.icon-check:before { content: "\e165"; } -i.icon-chat:before { +.icon-chat:before { content: "\e166"; } -i.icon-chat-active:before { +.icon-chat-active:before { content: "\e167"; } -i.icon-chart:before { +.icon-chart:before { content: "\e168"; } -i.icon-chart-curve:before { +.icon-chart-curve:before { content: "\e169"; } -i.icon-certificate:before { +.icon-certificate:before { content: "\e16a"; } -i.icon-categories:before { +.icon-categories:before { content: "\e16b"; } -i.icon-cash-register:before { +.icon-cash-register:before { content: "\e16c"; } -i.icon-car:before { +.icon-car:before { content: "\e16d"; } -i.icon-caps-lock:before { +.icon-caps-lock:before { content: "\e16e"; } -i.icon-candy:before { +.icon-candy:before { content: "\e16f"; } -i.icon-circle-dotted:before { +.icon-circle-dotted:before { content: "\e170"; } -i.icon-circuits:before { +.icon-circuits:before { content: "\e171"; } -i.icon-circus:before { +.icon-circus:before { content: "\e172"; } -i.icon-client:before { +.icon-client:before { content: "\e173"; } -i.icon-clothes-hanger:before { +.icon-clothes-hanger:before { content: "\e174"; } -i.icon-cloud-drive:before { +.icon-cloud-drive:before { content: "\e175"; } -i.icon-cloud-upload:before { +.icon-cloud-upload:before { content: "\e176"; } -i.icon-cloud:before { +.icon-cloud:before { content: "\e177"; } -i.icon-cloudy:before { +.icon-cloudy:before { content: "\e178"; } -i.icon-clubs:before { +.icon-clubs:before { content: "\e179"; } -i.icon-cocktail:before { +.icon-cocktail:before { content: "\e17a"; } -i.icon-code:before { +.icon-code:before { content: "\e17b"; } -i.icon-coffee:before { +.icon-coffee:before { content: "\e17c"; } -i.icon-coin-dollar:before { +.icon-coin-dollar:before { content: "\e17d"; } -i.icon-coin-pound:before { +.icon-coin-pound:before { content: "\e17e"; } -i.icon-coin-yen:before { +.icon-coin-yen:before { content: "\e17f"; } -i.icon-coin:before { +.icon-coin:before { content: "\e180"; } -i.icon-coins-alt:before { +.icon-coins-alt:before { content: "\e181"; } -i.icon-console:before { +.icon-console:before { content: "\e182"; } -i.icon-connection:before { +.icon-connection:before { content: "\e183"; } -i.icon-compress:before { +.icon-compress:before { content: "\e184"; } -i.icon-company:before { +.icon-company:before { content: "\e185"; } -i.icon-command:before { +.icon-command:before { content: "\e186"; } -i.icon-coin-euro:before { +.icon-coin-euro:before { content: "\e187"; } -i.icon-combination-lock:before { +.icon-combination-lock:before { content: "\e188"; } -i.icon-combination-lock-open:before { +.icon-combination-lock-open:before { content: "\e189"; } -i.icon-comb:before { +.icon-comb:before { content: "\e18a"; } -i.icon-columns:before { +.icon-columns:before { content: "\e18b"; } -i.icon-colorpicker:before { +.icon-colorpicker:before { content: "\e18c"; } -i.icon-color-bucket:before { +.icon-color-bucket:before { content: "\e18d"; } -i.icon-coins:before { +.icon-coins:before { content: "\e18e"; } -i.icon-coins-yen:before { +.icon-coins-yen:before { content: "\e18f"; } -i.icon-coins-yen-alt:before { +.icon-coins-yen-alt:before { content: "\e190"; } -i.icon-coins-pound:before { +.icon-coins-pound:before { content: "\e191"; } -i.icon-coins-pound-alt:before { +.icon-coins-pound-alt:before { content: "\e192"; } -i.icon-coins-euro:before { +.icon-coins-euro:before { content: "\e193"; } -i.icon-coins-euro-alt:before { +.icon-coins-euro-alt:before { content: "\e194"; } -i.icon-coins-dollar:before { +.icon-coins-dollar:before { content: "\e195"; } -i.icon-conversation-alt:before { +.icon-conversation-alt:before { content: "\e196"; } -i.icon-conversation:before { +.icon-conversation:before { content: "\e197"; } -i.icon-coverflow:before { +.icon-coverflow:before { content: "\e198"; } -i.icon-credit-card-alt:before { +.icon-credit-card-alt:before { content: "\e199"; } -i.icon-credit-card:before { +.icon-credit-card:before { content: "\e19a"; } -i.icon-crop:before { +.icon-crop:before { content: "\e19b"; } -i.icon-crosshair:before { +.icon-crosshair:before { content: "\e19c"; } -i.icon-crown-alt:before { +.icon-crown-alt:before { content: "\e19d"; } -i.icon-crown:before { +.icon-crown:before { content: "\e19e"; } -i.icon-cupcake:before { +.icon-cupcake:before { content: "\e19f"; } -i.icon-curve:before { +.icon-curve:before { content: "\e1a0"; } -i.icon-cut:before { +.icon-cut:before { content: "\e1a1"; } -i.icon-dashboard:before { +.icon-dashboard:before { content: "\e1a2"; } -i.icon-defrag:before { +.icon-defrag:before { content: "\e1a3"; } -i.icon-delete:before { +.icon-delete:before { content: "\e1a4"; } -i.icon-delete-key:before { +.icon-delete-key:before { content: "\e1a5"; } -i.icon-departure:before { +.icon-departure:before { content: "\e1a6"; } -i.icon-desk:before { +.icon-desk:before { content: "\e1a7"; } -i.icon-desktop:before { +.icon-desktop:before { content: "\e1a8"; } -i.icon-donate:before { +.icon-donate:before { content: "\e1a9"; } -i.icon-dollar-bag:before { +.icon-dollar-bag:before { content: "\e1aa"; } -i.icon-documents:before { +.icon-documents:before { content: "\e1ab"; } -i.icon-document:before { +.icon-document:before { content: "\e1ac"; } -i.icon-document-dashed-line:before { +.icon-document-dashed-line:before { content: "\e1ad"; } -i.icon-dock-connector:before { +.icon-dock-connector:before { content: "\e1ae"; } -i.icon-dna:before { +.icon-dna:before { content: "\e1af"; } -i.icon-display:before { +.icon-display:before { content: "\e1b0"; } -i.icon-disk-image:before { +.icon-disk-image:before { content: "\e1b1"; } -i.icon-disc:before { +.icon-disc:before { content: "\e1b2"; } -i.icon-directions:before { +.icon-directions:before { content: "\e1b3"; } -i.icon-directions-alt:before { +.icon-directions-alt:before { content: "\e1b4"; } -i.icon-diploma:before { +.icon-diploma:before { content: "\e1b5"; } -i.icon-diploma-alt:before { +.icon-diploma-alt:before { content: "\e1b6"; } -i.icon-dice:before { +.icon-dice:before { content: "\e1b7"; } -i.icon-diamonds:before { +.icon-diamonds:before { content: "\e1b8"; } -i.icon-diamond:before { +.icon-diamond:before { content: "\e1b9"; } -i.icon-diagonal-arrow:before { +.icon-diagonal-arrow:before { content: "\e1ba"; } -i.icon-diagonal-arrow-alt:before { +.icon-diagonal-arrow-alt:before { content: "\e1bb"; } -i.icon-door-open:before { +.icon-door-open:before { content: "\e1bc"; } -i.icon-download-alt:before { +.icon-download-alt:before { content: "\e1bd"; } -i.icon-download:before { +.icon-download:before { content: "\e1be"; } -i.icon-drop:before { +.icon-drop:before { content: "\e1bf"; } -i.icon-eco:before { +.icon-eco:before { content: "\e1c0"; } -i.icon-economy:before { +.icon-economy:before { content: "\e1c1"; } -i.icon-edit:before { +.icon-edit:before { content: "\e1c2"; } -i.icon-eject:before { +.icon-eject:before { content: "\e1c3"; } -i.icon-employee:before { +.icon-employee:before { content: "\e1c4"; } -i.icon-energy-saving-bulb:before { +.icon-energy-saving-bulb:before { content: "\e1c5"; } -i.icon-enter:before { +.icon-enter:before { content: "\e1c6"; } -i.icon-equalizer:before { +.icon-equalizer:before { content: "\e1c7"; } -i.icon-escape:before { +.icon-escape:before { content: "\e1c8"; } -i.icon-ethernet:before { +.icon-ethernet:before { content: "\e1c9"; } -i.icon-euro-bag:before { +.icon-euro-bag:before { content: "\e1ca"; } -i.icon-exit-fullscreen:before { +.icon-exit-fullscreen:before { content: "\e1cb"; } -i.icon-eye:before { +.icon-eye:before { content: "\e1cc"; } -i.icon-facebook-like:before { +.icon-facebook-like:before { content: "\e1cd"; } -i.icon-factory:before { +.icon-factory:before { content: "\e1ce"; } -i.icon-font:before { +.icon-font:before { content: "\e1cf"; } -i.icon-folders:before { +.icon-folders:before { content: "\e1d0"; } -i.icon-folder:before, i.icon-folder-close:before { +.icon-folder:before, .icon-folder-close:before { content: "\e1d1"; } -i.icon-folder-outline:before { +.icon-folder-outline:before { content: "\e1d2"; } -i.icon-folder-open:before { +.icon-folder-open:before { content: "\e1d3"; } -i.icon-flowerpot:before { +.icon-flowerpot:before { content: "\e1d4"; } -i.icon-flashlight:before { +.icon-flashlight:before { content: "\e1d5"; } -i.icon-flash:before { +.icon-flash:before { content: "\e1d6"; } -i.icon-flag:before { +.icon-flag:before { content: "\e1d7"; } -i.icon-flag-alt:before { +.icon-flag-alt:before { content: "\e1d8"; } -i.icon-firewire:before { +.icon-firewire:before { content: "\e1d9"; } -i.icon-firewall:before { +.icon-firewall:before { content: "\e1da"; } -i.icon-fire:before { +.icon-fire:before { content: "\e1db"; } -i.icon-fingerprint:before { +.icon-fingerprint:before { content: "\e1dc"; } -i.icon-filter:before { +.icon-filter:before { content: "\e1dd"; } -i.icon-filter-arrows:before { +.icon-filter-arrows:before { content: "\e1de"; } -i.icon-files:before { +.icon-files:before { content: "\e1df"; } -i.icon-file-cabinet:before { +.icon-file-cabinet:before { content: "\e1e0"; } -i.icon-female-symbol:before { +.icon-female-symbol:before { content: "\e1e1"; } -i.icon-footprints:before { +.icon-footprints:before { content: "\e1e2"; } -i.icon-hammer:before { +.icon-hammer:before { content: "\e1e3"; } -i.icon-hand-active-alt:before { +.icon-hand-active-alt:before { content: "\e1e4"; } -i.icon-forking:before { +.icon-forking:before { content: "\e1e5"; } -i.icon-hand-active:before { +.icon-hand-active:before { content: "\e1e6"; } -i.icon-hand-pointer-alt:before { +.icon-hand-pointer-alt:before { content: "\e1e7"; } -i.icon-hand-pointer:before { +.icon-hand-pointer:before { content: "\e1e8"; } -i.icon-handprint:before { +.icon-handprint:before { content: "\e1e9"; } -i.icon-handshake:before { +.icon-handshake:before { content: "\e1ea"; } -i.icon-handtool:before { +.icon-handtool:before { content: "\e1eb"; } -i.icon-hard-drive:before { +.icon-hard-drive:before { content: "\e1ec"; } -i.icon-help:before { +.icon-help:before { content: "\e1ed"; } -i.icon-graduate:before { +.icon-graduate:before { content: "\e1ee"; } -i.icon-gps:before { +.icon-gps:before { content: "\e1ef"; } -i.icon-help-alt:before { +.icon-help-alt:before { content: "\e1f0"; } -i.icon-height:before { +.icon-height:before { content: "\e1f1"; } -i.icon-globe:before { +.icon-globe:before { content: "\e1f2"; } -i.icon-hearts:before { +.icon-hearts:before { content: "\e1f3"; } -i.icon-globe-inverted-europe-africa:before { +.icon-globe-inverted-europe-africa:before { content: "\e1f4"; } -i.icon-headset:before { +.icon-headset:before { content: "\e1f5"; } -i.icon-globe-inverted-asia:before { +.icon-globe-inverted-asia:before { content: "\e1f6"; } -i.icon-headphones:before { +.icon-headphones:before { content: "\e1f7"; } -i.icon-globe-inverted-america:before { +.icon-globe-inverted-america:before { content: "\e1f8"; } -i.icon-hd:before { +.icon-hd:before { content: "\e1f9"; } -i.icon-globe-europe-africa:before, -i.icon-globe-europe---africa:before { +.icon-globe-europe-africa:before, +.icon-globe-europe---africa:before { content: "\e1fa"; } -i.icon-hat:before { +.icon-hat:before { content: "\e1fb"; } -i.icon-globe-asia:before { +.icon-globe-asia:before { content: "\e1fc"; } -i.icon-globe-alt:before { +.icon-globe-alt:before { content: "\e1fd"; } -i.icon-hard-drive-alt:before { +.icon-hard-drive-alt:before { content: "\e1fe"; } -i.icon-glasses:before { +.icon-glasses:before { content: "\e1ff"; } -i.icon-gift:before { +.icon-gift:before { content: "\e200"; } -i.icon-handtool-alt:before { +.icon-handtool-alt:before { content: "\e201"; } -i.icon-geometry:before { +.icon-geometry:before { content: "\e202"; } -i.icon-game:before { +.icon-game:before { content: "\e203"; } -i.icon-fullscreen:before { +.icon-fullscreen:before { content: "\e204"; } -i.icon-fullscreen-alt:before { +.icon-fullscreen-alt:before { content: "\e205"; } -i.icon-frame:before { +.icon-frame:before { content: "\e206"; } -i.icon-frame-alt:before { +.icon-frame-alt:before { content: "\e207"; } -i.icon-camera-roll:before { +.icon-camera-roll:before { content: "\e208"; } -i.icon-bookmark:before { +.icon-bookmark:before { content: "\e209"; } -i.icon-bill:before { +.icon-bill:before { content: "\e20a"; } -i.icon-baby-stroller:before { +.icon-baby-stroller:before { content: "\e20b"; } -i.icon-alarm-clock:before { +.icon-alarm-clock:before { content: "\e20c"; } -i.icon-addressbook:before, -i.icon-adressbook:before { +.icon-addressbook:before, +.icon-adressbook:before { content: "\e20d"; } -i.icon-add:before { +.icon-add:before { content: "\e20e"; } -i.icon-activity:before { +.icon-activity:before { content: "\e20f"; } -i.icon-untitled:before { +.icon-untitled:before { content: "\e210"; } -i.icon-glasses:before { +.icon-glasses:before { content: "\e211"; } -i.icon-camcorder:before { +.icon-camcorder:before { content: "\e212"; } -i.icon-calendar:before { +.icon-calendar:before { content: "\e213"; } -i.icon-calendar-alt:before { +.icon-calendar-alt:before { content: "\e214"; } -i.icon-calculator:before { +.icon-calculator:before { content: "\e215"; } -i.icon-bus:before { +.icon-bus:before { content: "\e216"; } -i.icon-burn:before { +.icon-burn:before { content: "\e217"; } -i.icon-bulleted-list:before { +.icon-bulleted-list:before { content: "\e218"; } -i.icon-bug:before { +.icon-bug:before { content: "\e219"; } -i.icon-brush:before { +.icon-brush:before { content: "\e21a"; } -i.icon-brush-alt:before { +.icon-brush-alt:before { content: "\e21b"; } -i.icon-brush-alt-2:before { +.icon-brush-alt-2:before { content: "\e21c"; } -i.icon-browser-window:before { +.icon-browser-window:before { content: "\e21d"; } -i.icon-briefcase:before { +.icon-briefcase:before { content: "\e21e"; } -i.icon-brick:before { +.icon-brick:before { content: "\e21f"; } -i.icon-brackets:before { +.icon-brackets:before { content: "\e220"; } -i.icon-box:before { +.icon-box:before { content: "\e221"; } -i.icon-box-open:before { +.icon-box-open:before { content: "\e222"; } -i.icon-box-alt:before { +.icon-box-alt:before { content: "\e223"; } -i.icon-books:before { +.icon-books:before { content: "\e224"; } -i.icon-billboard:before { +.icon-billboard:before { content: "\e225"; } -i.icon-bills-dollar:before { +.icon-bills-dollar:before { content: "\e226"; } -i.icon-bills-euro:before { +.icon-bills-euro:before { content: "\e227"; } -i.icon-bills-pound:before { +.icon-bills-pound:before { content: "\e228"; } -i.icon-bills-yen:before { +.icon-bills-yen:before { content: "\e229"; } -i.icon-bills:before { +.icon-bills:before { content: "\e22a"; } -i.icon-binarycode:before { +.icon-binarycode:before { content: "\e22b"; } -i.icon-binoculars:before { +.icon-binoculars:before { content: "\e22c"; } -i.icon-bird:before { +.icon-bird:before { content: "\e22d"; } -i.icon-birthday-cake:before { +.icon-birthday-cake:before { content: "\e22e"; } -i.icon-blueprint:before { +.icon-blueprint:before { content: "\e22f"; } -i.icon-block:before { +.icon-block:before { content: "\e230"; } -i.icon-bluetooth:before { +.icon-bluetooth:before { content: "\e231"; } -i.icon-boat-shipping:before { +.icon-boat-shipping:before { content: "\e232"; } -i.icon-bomb:before { +.icon-bomb:before { content: "\e233"; } -i.icon-book-alt-2:before { +.icon-book-alt-2:before { content: "\e234"; } -i.icon-bones:before { +.icon-bones:before { content: "\e235"; } -i.icon-book-alt:before { +.icon-book-alt:before { content: "\e236"; } -i.icon-book:before { +.icon-book:before { content: "\e237"; } -i.icon-bill-yen:before { +.icon-bill-yen:before { content: "\e238"; } -i.icon-award:before { +.icon-award:before { content: "\e239"; } -i.icon-bill-pound:before { +.icon-bill-pound:before { content: "\e23a"; } -i.icon-autofill:before { +.icon-autofill:before { content: "\e23b"; } -i.icon-bill-euro:before { +.icon-bill-euro:before { content: "\e23c"; } -i.icon-auction-hammer:before { +.icon-auction-hammer:before { content: "\e23d"; } -i.icon-bill-dollar:before { +.icon-bill-dollar:before { content: "\e23e"; } -i.icon-attachment:before { +.icon-attachment:before { content: "\e23f"; } -i.icon-bell:before { +.icon-bell:before { content: "\e240"; } -i.icon-article:before { +.icon-article:before { content: "\e241"; } -i.icon-bell-off:before { +.icon-bell-off:before { content: "\e242"; } -i.icon-art-easel:before { +.icon-art-easel:before { content: "\e243"; } -i.icon-beer-glass:before { +.icon-beer-glass:before { content: "\e244"; } -i.icon-arrow-up:before { +.icon-arrow-up:before { content: "\e245"; } -i.icon-battery-low:before { +.icon-battery-low:before { content: "\e246"; } -i.icon-arrow-right:before { +.icon-arrow-right:before { content: "\e247"; } -i.icon-battery-full:before { +.icon-battery-full:before { content: "\e248"; } -i.icon-arrow-left:before { +.icon-arrow-left:before { content: "\e249"; } -i.icon-bars:before { +.icon-bars:before { content: "\e24a"; } -i.icon-arrow-down:before { +.icon-arrow-down:before { content: "\e24b"; } -i.icon-barcode:before { +.icon-barcode:before { content: "\e24c"; } -i.icon-arrivals:before { +.icon-arrivals:before { content: "\e24d"; } -i.icon-bar-chart:before { +.icon-bar-chart:before { content: "\e24e"; } -i.icon-application-window:before { +.icon-application-window:before { content: "\e24f"; } -i.icon-band-aid:before { +.icon-band-aid:before { content: "\e250"; } -i.icon-application-window-alt:before { +.icon-application-window-alt:before { content: "\e251"; } -i.icon-ball:before { +.icon-ball:before { content: "\e252"; } -i.icon-application-error:before { +.icon-application-error:before { content: "\e253"; } -i.icon-badge-restricted:before { +.icon-badge-restricted:before { content: "\e254"; } -i.icon-app:before { +.icon-app:before { content: "\e255"; } -i.icon-badge-remove:before { +.icon-badge-remove:before { content: "\e256"; } -i.icon-anchor:before { +.icon-anchor:before { content: "\e257"; } -i.icon-badge-count:before { +.icon-badge-count:before { content: "\e258"; } -i.icon-alt:before { +.icon-alt:before { content: "\e259"; } -i.icon-badge-add:before { +.icon-badge-add:before { content: "\e25a"; } -i.icon-alert:before { +.icon-alert:before { content: "\e25b"; } -i.icon-backspace:before { +.icon-backspace:before { content: "\e25c"; } -i.icon-alert-alt:before { +.icon-alert-alt:before { content: "\e25d"; } -i.icon-section:before { +.icon-section:before { content: "\e24f"; } 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/preview/preview.controller.js b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js index 5d1047de1b..b312c57503 100644 --- a/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/preview/preview.controller.js @@ -11,7 +11,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi var cultures = []; $scope.tabbingActive = false; - // There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution. + // There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution. // For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 function handleFirstTab(evt) { if (evt.keyCode === 9) { @@ -44,9 +44,6 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi } function configureSignalR(iframe) { - // signalr hub - var previewHub = $.connection.previewHub; - // visibility tracking var dirtyContent = false; var visibleContent = true; @@ -61,31 +58,39 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi } }); - if (previewHub && previewHub.client) { - previewHub.client.refreshed = function (message, sender) { - console.log("Notified by SignalR preview hub (" + message + ")."); + // signalr hub + // If connection already exists and is connected just return + // otherwise we'll have multiple connections + if( $.connection && $.connection.connectionState === signalR.HubConnectionState.Connected) return; - if ($scope.pageId != message) { - console.log("Not a notification for us (" + $scope.pageId + ")."); - return; - } + $.connection = new signalR.HubConnectionBuilder() + .withUrl(Umbraco.Sys.ServerVariables.umbracoUrls.previewHubUrl) + .withAutomaticReconnect() + .configureLogging(signalR.LogLevel.Warning) + .build(); - if (!visibleContent) { - console.log("Not visible, will reload."); - dirtyContent = true; - return; - } - - console.log("Reloading."); - var iframeDoc = (iframe.contentWindow || iframe.contentDocument); - iframeDoc.location.reload(); - }; - } + $.connection.on("refreshed", function (message) { + console.log("Notified by SignalR preview hub (" + message + ")."); + if ($scope.pageId != message) { + console.log("Not a notification for us (" + $scope.pageId + ")."); + return; + } + if (!visibleContent) { + console.log("Not visible, will reload."); + dirtyContent = true; + return; + } + console.log("Reloading."); + var iframeDoc = iframe.contentWindow || iframe.contentDocument; + iframeDoc.location.reload(); + }) try { - $.connection.hub.start() - .done(function () { console.log("Connected to SignalR preview hub (ID=" + $.connection.hub.id + ")"); }) - .fail(function () { console.log("Could not connect to SignalR preview hub."); }); + $.connection.start().then(function () { + console.log("Connected to SignalR preview hub (ID=" + $.connection.connectionId + ")"); + }).catch(function () { + console.log("Could not connect to SignalR preview hub."); + }); } catch (e) { console.error("Could not establish signalr connection. Error: " + e); } @@ -95,7 +100,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi if (isInit === "true") { //do not continue, this is the first load of this new window, if this is passed in it means it's been //initialized by the content editor and then the content editor will actually re-load this window without - //this flag. This is a required trick to get around chrome popup mgr. + //this flag. This is a required trick to get around chrome popup mgr. return; } 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 @@ - + { - vm.icons = icons; - vm.loading = false; - iconHelper.getLegacyIcons() - .then(icons => { - if(icons && icons.length > 0) { - vm.icons = icons.concat(vm.icons); - } - }); - }); + iconHelper.getIcons().then(function (icons) { + vm.icons = icons; + vm.loading = false; + }); // set a default color if nothing is passed in vm.color = $scope.model.color ? findColor($scope.model.color) : vm.colors.find(x => x.default); @@ -96,7 +88,7 @@ function IconPickerController($scope, $http, $sce, localizationService, iconHelp } function submit() { - if ($scope.model && $scope.model.submit) { + if ($scope.model && $scope.model.submit) { $scope.model.submit($scope.model); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html index 417e6992bd..dd2ff41efa 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/iconpicker/iconpicker.html @@ -45,10 +45,10 @@
    -
  • -
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html index ea247c77e5..2ce7af8d9d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.html @@ -9,32 +9,32 @@ hide-icon="true" hide-description="true"> - +
-
-
...
-
-
-
-
...
-
- -
-
-
-
...
-
- -
-
-
-
...
-
-
+ + + +
@@ -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 @@
-
+