diff --git a/NuGet.Config b/NuGet.Config index 64425091dc..d6c63173f8 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -8,5 +8,6 @@ + diff --git a/src/Umbraco.Core/CompositionExtensions.cs b/src/Umbraco.Core/CompositionExtensions.cs index 5b9abeeb45..218e2a04e3 100644 --- a/src/Umbraco.Core/CompositionExtensions.cs +++ b/src/Umbraco.Core/CompositionExtensions.cs @@ -1,11 +1,11 @@ using Umbraco.Core.Composing; +using Umbraco.Core.HealthCheck; using Umbraco.Core.Manifest; using Umbraco.Core.PropertyEditors; using Umbraco.Web.Actions; using Umbraco.Web.ContentApps; using Umbraco.Web.Dashboards; using Umbraco.Web.Editors; -using Umbraco.Web.HealthCheck; using Umbraco.Web.Routing; using Umbraco.Web.Sections; using Umbraco.Web.Tour; diff --git a/src/Umbraco.Core/Configuration/HealthChecks/AbstractConfigCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/AbstractConfigCheck.cs deleted file mode 100644 index f3452131f0..0000000000 --- a/src/Umbraco.Core/Configuration/HealthChecks/AbstractConfigCheck.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; -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; -using Umbraco.Core.Services; - -namespace Umbraco.Web.HealthCheck.Checks.Config -{ - public abstract class AbstractConfigCheck : HealthCheck - { - private readonly IHostingEnvironment _hostingEnvironment; - private readonly ConfigurationService _configurationService; - - protected ILocalizedTextService TextService { get; } - protected ILoggerFactory LoggerFactory { get; } - - /// - /// Gets the config file path. - /// - public abstract string FilePath { get; } - - /// - /// Gets XPath statement to the config element to check. - /// - public abstract string XPath { get; } - - /// - /// Gets the values to compare against. - /// - public abstract IEnumerable Values { get; } - - /// - /// Gets the current value - /// - public string CurrentValue { get; set; } - - /// - /// Gets the provided value - /// - public string ProvidedValue { get; set; } - - /// - /// Gets the comparison type for checking the value. - /// - public abstract ValueComparisonType ValueComparisonType { get; } - - /// - /// Gets the flag indicating if the check is considered successful if the config value is missing (defaults to false - an error - if missing) - /// - public virtual bool ValidIfConfigMissing - { - get { return false; } - } - - protected AbstractConfigCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) - { - _hostingEnvironment = hostingEnvironment; - TextService = textService; - LoggerFactory = loggerFactory; - _configurationService = new ConfigurationService(AbsoluteFilePath, XPath, textService, loggerFactory.CreateLogger()); - } - - /// - /// Gets the name of the file. - /// - private string FileName => Path.GetFileName(FilePath); - - /// - /// Gets the absolute file path. - /// - private string AbsoluteFilePath => _hostingEnvironment.MapPathContentRoot(FilePath); - - /// - /// Gets the message for when the check has succeeded. - /// - public virtual string CheckSuccessMessage - { - get - { - return TextService.Localize("healthcheck/checkSuccessMessage", - new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath }); - } - } - - /// - /// Gets the message for when the check has failed. - /// - public virtual string CheckErrorMessage - { - get - { - return ValueComparisonType == ValueComparisonType.ShouldEqual - ? TextService.Localize("healthcheck/checkErrorMessageDifferentExpectedValue", - new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath }) - : TextService.Localize("healthcheck/checkErrorMessageUnexpectedValue", - new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, XPath, AbsoluteFilePath }); - } - } - - /// - /// Gets the rectify success message. - /// - public virtual string RectifySuccessMessage - { - get - { - var recommendedValue = Values.FirstOrDefault(v => v.IsRecommended); - var rectifiedValue = recommendedValue != null - ? recommendedValue.Value - : ProvidedValue; - return TextService.Localize("healthcheck/rectifySuccessMessage", - new[] - { - CurrentValue, - rectifiedValue, - XPath, - AbsoluteFilePath - }); - } - } - - /// - /// Gets a value indicating whether this check can be rectified automatically. - /// - public virtual bool CanRectify => ValueComparisonType == ValueComparisonType.ShouldEqual; - - /// - /// Gets a value indicating whether this check can be rectified automatically if a value is provided. - /// - public virtual bool CanRectifyWithValue => ValueComparisonType == ValueComparisonType.ShouldNotEqual; - - public override IEnumerable GetStatus() - { - var successMessage = string.Format(CheckSuccessMessage, FileName, XPath, Values); - - var configValue = _configurationService.GetConfigurationValue(); - if (configValue.Success == false) - { - if (ValidIfConfigMissing) - { - return new[] { new HealthCheckStatus(successMessage) { ResultType = StatusResultType.Success } }; - } - - var errorMessage = configValue.Result; - return new[] { new HealthCheckStatus(errorMessage) { ResultType = StatusResultType.Error } }; - } - - CurrentValue = configValue.Result; - - // need to update the successMessage with the CurrentValue - successMessage = string.Format(CheckSuccessMessage, FileName, XPath, Values, CurrentValue); - - var valueFound = Values.Any(value => string.Equals(CurrentValue, value.Value, StringComparison.InvariantCultureIgnoreCase)); - if (ValueComparisonType == ValueComparisonType.ShouldEqual && valueFound || ValueComparisonType == ValueComparisonType.ShouldNotEqual && valueFound == false) - { - return new[] { new HealthCheckStatus(successMessage) { ResultType = StatusResultType.Success } }; - } - - // Declare the action for rectifying the config value - var rectifyAction = new HealthCheckAction("rectify", Id) - { - Name = TextService.Localize("healthcheck/rectifyButton"), - ValueRequired = CanRectifyWithValue, - }; - - var resultMessage = string.Format(CheckErrorMessage, FileName, XPath, Values, CurrentValue); - return new[] - { - new HealthCheckStatus(resultMessage) - { - ResultType = StatusResultType.Error, - Actions = CanRectify || CanRectifyWithValue ? new[] { rectifyAction } : new HealthCheckAction[0] - } - }; - } - - /// - /// Rectifies this check. - /// - /// - public virtual HealthCheckStatus Rectify() - { - if (ValueComparisonType == ValueComparisonType.ShouldNotEqual) - throw new InvalidOperationException(TextService.Localize("healthcheck/cannotRectifyShouldNotEqual")); - - var recommendedValue = Values.First(v => v.IsRecommended).Value; - return UpdateConfigurationValue(recommendedValue); - } - - /// - /// Rectifies this check with a provided value. - /// - /// Value provided - /// - public virtual HealthCheckStatus Rectify(string value) - { - if (ValueComparisonType == ValueComparisonType.ShouldEqual) - throw new InvalidOperationException(TextService.Localize("healthcheck/cannotRectifyShouldEqualWithValue")); - - if (string.IsNullOrWhiteSpace(value)) - throw new InvalidOperationException(TextService.Localize("healthcheck/valueToRectifyNotProvided")); - - // Need to track provided value in order to correctly put together the rectify message - ProvidedValue = value; - - return UpdateConfigurationValue(value); - } - - private HealthCheckStatus UpdateConfigurationValue(string value) - { - var updateConfigFile = _configurationService.UpdateConfigFile(value); - - if (updateConfigFile.Success == false) - { - var message = updateConfigFile.Result; - return new HealthCheckStatus(message) { ResultType = StatusResultType.Error }; - } - - var resultMessage = string.Format(RectifySuccessMessage, FileName, XPath, Values); - return new HealthCheckStatus(resultMessage) { ResultType = StatusResultType.Success }; - } - - public override HealthCheckStatus ExecuteAction(HealthCheckAction action) - { - return string.IsNullOrEmpty(action.ProvidedValue) - ? Rectify() - : Rectify(action.ProvidedValue); - } - } -} diff --git a/src/Umbraco.Core/Configuration/HealthChecks/CompilationDebugCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/CompilationDebugCheck.cs index b400093a34..a7b99ea205 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/CompilationDebugCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/CompilationDebugCheck.cs @@ -1,33 +1,41 @@ using System.Collections.Generic; using Microsoft.Extensions.Logging; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.HealthCheck; +using Umbraco.Core.HealthCheck.Checks; using Umbraco.Core.Services; -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.Configuration.HealthChecks { [HealthCheck("61214FF3-FC57-4B31-B5CF-1D095C977D6D", "Debug Compilation Mode", Description = "Leaving debug compilation mode enabled can severely slow down a website and take up more memory on the server.", Group = "Live Environment")] - public class CompilationDebugCheck : AbstractConfigCheck + public class CompilationDebugCheck : AbstractSettingsCheck { - public CompilationDebugCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) - : base(textService, hostingEnvironment, loggerFactory) - { } + private readonly IOptionsMonitor _hostingSettings; - public override string FilePath => "~/Web.config"; + public CompilationDebugCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory, IOptionsMonitor hostingSettings) + : base(textService, loggerFactory) + { + _hostingSettings = hostingSettings; + } - public override string XPath => "/configuration/system.web/compilation/@debug"; + public override string ItemPath => Constants.Configuration.ConfigHostingDebug; public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual; - public override bool ValidIfConfigMissing => true; - public override IEnumerable Values => new List { - new AcceptableConfiguration { IsRecommended = true, Value = bool.FalseString.ToLower() } + new AcceptableConfiguration + { + IsRecommended = true, + Value = bool.FalseString.ToLower() + } }; + public override string CurrentValue => _hostingSettings.CurrentValue.Debug.ToString(); + public override string CheckSuccessMessage => TextService.Localize("healthcheck/compilationDebugCheckSuccessMessage"); public override string CheckErrorMessage => TextService.Localize("healthcheck/compilationDebugCheckErrorMessage"); diff --git a/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationService.cs b/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationService.cs index 396d55b735..2459698b7a 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationService.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationService.cs @@ -1,109 +1,61 @@ using System; -using System.IO; -using System.Xml; using Microsoft.Extensions.Logging; +using Umbraco.Core.HealthCheck; using Umbraco.Core.Services; -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.Configuration.HealthChecks { - // TODO: Add config transform for when config with specified XPath is not found - - public class ConfigurationService + public class ConfigurationService : IConfigurationService { - private readonly string _configFilePath; - private readonly string _xPath; private readonly ILocalizedTextService _textService; private readonly ILogger _logger; + private readonly IConfigManipulator _configManipulator; - /// 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(ILocalizedTextService textService, ILogger logger, IConfigManipulator configManipulator) { - _configFilePath = configFilePath; - _xPath = xPath; + if (textService == null) HandleNullParameter(nameof(textService)); + if (configManipulator == null) HandleNullParameter(nameof(configManipulator)); + if (logger == null) HandleNullParameter(nameof(logger)); + + _configManipulator = configManipulator; _textService = textService; _logger = logger; } - /// - /// Gets a value from a given configuration file with the given XPath - /// - public ConfigurationServiceResult GetConfigurationValue() + private void HandleNullParameter(string parameter) { - try - { - if (File.Exists(_configFilePath) == false) - return new ConfigurationServiceResult - { - Success = false, - Result = _textService.Localize("healthcheck/configurationServiceFileNotFound", new[] { _configFilePath }) - }; - - var xmlDocument = new XmlDocument(); - xmlDocument.Load(_configFilePath); - - var xmlNode = xmlDocument.SelectSingleNode(_xPath); - if (xmlNode == null) - return new ConfigurationServiceResult - { - Success = false, - Result = _textService.Localize("healthcheck/configurationServiceNodeNotFound", new[] { _xPath, _configFilePath }) - }; - - return new ConfigurationServiceResult - { - Success = true, - Result = string.Format(xmlNode.Value ?? xmlNode.InnerText) - }; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error trying to get configuration value"); - return new ConfigurationServiceResult - { - Success = false, - Result = _textService.Localize("healthcheck/configurationServiceError", new[] { ex.Message }) - }; - } + _logger.LogError("Error trying to get configuration value", parameter); + throw new ArgumentNullException(parameter); } /// - /// Updates a value in a given configuration file with the given XPath + /// Updates a value in a given configuration file with the given path /// /// + /// /// - public ConfigurationServiceResult UpdateConfigFile(string value) + public ConfigurationServiceResult UpdateConfigFile(string value, string itemPath) { try { - if (File.Exists(_configFilePath) == false) + if (itemPath == null) + { return new ConfigurationServiceResult { Success = false, - Result = _textService.Localize("healthcheck/configurationServiceFileNotFound", new[] { _configFilePath }) + Result = _textService.Localize("healthcheck/configurationServiceNodeNotFound", new[] { itemPath, value }) }; + } - var xmlDocument = new XmlDocument { PreserveWhitespace = true }; - xmlDocument.Load(_configFilePath); - - var node = xmlDocument.SelectSingleNode(_xPath); - if (node == null) - return new ConfigurationServiceResult - { - Success = false, - Result = _textService.Localize("healthcheck/configurationServiceNodeNotFound", new[] { _xPath, _configFilePath }) - }; - - if (node.NodeType == XmlNodeType.Element) - node.InnerText = value; - else - node.Value = value; - - xmlDocument.Save(_configFilePath); - return new ConfigurationServiceResult { Success = true }; + _configManipulator.SaveConfigValue(itemPath, value); + return new ConfigurationServiceResult + { + Success = true + }; } catch (Exception ex) { diff --git a/src/Umbraco.Core/Configuration/HealthChecks/MacroErrorsCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/MacroErrorsCheck.cs index 68e76dfc81..b31f23667d 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/MacroErrorsCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/MacroErrorsCheck.cs @@ -1,27 +1,40 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Services; -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.HealthCheck.Checks.Configuration { [HealthCheck("D0F7599E-9B2A-4D9E-9883-81C7EDC5616F", "Macro errors", - Description = "Checks to make sure macro errors are not set to throw a YSOD (yellow screen of death), which would prevent certain or all pages from loading completely.", + Description = + "Checks to make sure macro errors are not set to throw a YSOD (yellow screen of death), which would prevent certain or all pages from loading completely.", Group = "Configuration")] - public class MacroErrorsCheck : AbstractConfigCheck + public class MacroErrorsCheck : AbstractSettingsCheck { - public MacroErrorsCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) - : base(textService, hostingEnvironment, loggerFactory) - { } + private readonly ILocalizedTextService _textService; + private readonly ILoggerFactory _loggerFactory; + private readonly IOptionsMonitor _contentSettings; - public override string FilePath => "~/Config/umbracoSettings.config"; - - public override string XPath => "/settings/content/MacroErrors"; + public MacroErrorsCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory, + IOptionsMonitor contentSettings) + : base(textService, loggerFactory) + { + _textService = textService; + _loggerFactory = loggerFactory; + _contentSettings = contentSettings; + } public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual; + public override string ItemPath => Constants.Configuration.ConfigContentMacroErrors; + + + /// + /// Gets the values to compare against. + /// public override IEnumerable Values { get @@ -44,24 +57,35 @@ namespace Umbraco.Web.HealthCheck.Checks.Config } } + public override string CurrentValue => _contentSettings.CurrentValue.MacroErrors.ToString(); + + /// + /// Gets the message for when the check has succeeded. + /// public override string CheckSuccessMessage { get { - return TextService.Localize("healthcheck/macroErrorModeCheckSuccessMessage", + return _textService.Localize("healthcheck/macroErrorModeCheckSuccessMessage", new[] { CurrentValue, Values.First(v => v.IsRecommended).Value }); } } + /// + /// Gets the message for when the check has failed. + /// public override string CheckErrorMessage { get { - return TextService.Localize("healthcheck/macroErrorModeCheckErrorMessage", + return _textService.Localize("healthcheck/macroErrorModeCheckErrorMessage", new[] { CurrentValue, Values.First(v => v.IsRecommended).Value }); } } + /// + /// Gets the rectify success message. + /// public override string RectifySuccessMessage { get diff --git a/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs b/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs index 76269d961c..9710080f35 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs +++ b/src/Umbraco.Core/Configuration/HealthChecks/TrySkipIisCustomErrorsCheck.cs @@ -2,32 +2,40 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Services; -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.HealthCheck.Checks.Configuration { + [Obsolete("This is not currently in the appsettings.JSON and so can either be removed, or rewritten in .NET Core fashion")] [HealthCheck("046A066C-4FB2-4937-B931-069964E16C66", "Try Skip IIS Custom Errors", Description = "Starting with IIS 7.5, this must be set to true for Umbraco 404 pages to show. Otherwise, IIS will takeover and render its built-in error page.", Group = "Configuration")] - public class TrySkipIisCustomErrorsCheck : AbstractConfigCheck + public class TrySkipIisCustomErrorsCheck : AbstractSettingsCheck { + private readonly ILocalizedTextService _textService; + private readonly ILoggerFactory _loggerFactory; private readonly Version _iisVersion; + private readonly GlobalSettings _globalSettings; - public TrySkipIisCustomErrorsCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory, - IHostingEnvironment hostingEnvironment) - : base(textService, hostingEnvironment, loggerFactory) + public TrySkipIisCustomErrorsCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory, IOptions globalSettings) + : base(textService, loggerFactory) { - _iisVersion = hostingEnvironment.IISVersion; + _textService = textService; + _loggerFactory = loggerFactory; + //TODO: detect if hosted in IIS, and then IIS version if we want to go this route + _iisVersion = new Version("7.5"); + _globalSettings = globalSettings.Value; } - public override string FilePath => "~/Config/umbracoSettings.config"; - - public override string XPath => "/settings/web.routing/@trySkipIisCustomErrors"; + public override string ItemPath => "TBC"; public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual; + public override string CurrentValue => null; + public override IEnumerable Values { get @@ -36,7 +44,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config var recommendedValue = _iisVersion >= new Version("7.5") ? bool.TrueString.ToLower() : bool.FalseString.ToLower(); - return new List { new AcceptableConfiguration { IsRecommended = true, Value = recommendedValue } }; + return new List { new AcceptableConfiguration { IsRecommended = true, Value = recommendedValue } }; } } @@ -44,7 +52,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config { get { - return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckSuccessMessage", + return _textService.Localize("healthcheck/trySkipIisCustomErrorsCheckSuccessMessage", new[] { Values.First(v => v.IsRecommended).Value, _iisVersion.ToString() }); } } @@ -53,7 +61,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Config { get { - return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckErrorMessage", + return _textService.Localize("healthcheck/trySkipIisCustomErrorsCheckErrorMessage", new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, _iisVersion.ToString() }); } } @@ -62,8 +70,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Config { get { - return TextService.Localize("healthcheck/trySkipIisCustomErrorsCheckRectifySuccessMessage", - new[] { Values.First(v => v.IsRecommended).Value, _iisVersion.ToString() }); + return _textService.Localize("healthcheck/trySkipIisCustomErrorsCheckRectifySuccessMessage", + new[] { "Not implemented" }); + + //new[] { Values.First(v => v.IsRecommended).Value, _iisVersion.ToString() }); } } } diff --git a/src/Umbraco.Core/Configuration/Models/HealthChecksSettings.cs b/src/Umbraco.Core/Configuration/Models/HealthChecksSettings.cs index 0903a8f242..7600b946fd 100644 --- a/src/Umbraco.Core/Configuration/Models/HealthChecksSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/HealthChecksSettings.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Configuration.HealthChecks; +using Umbraco.Core.HealthCheck; +using Umbraco.Core.HealthCheck.Checks; namespace Umbraco.Core.Configuration.Models { diff --git a/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs b/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs index 90249abc15..44f5ae89b6 100644 --- a/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/ImagingCacheSettings.cs @@ -12,6 +12,6 @@ namespace Umbraco.Core.Configuration.Models public uint CachedNameLength { get; set; } = 8; - public string CacheFolder { get; set; } = Path.Combine("..", "Umbraco", "MediaCache"); + public string CacheFolder { get; set; } = Path.Combine("..", "umbraco", "mediacache"); } } diff --git a/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs b/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs index 414165d2e4..f0b56561e2 100644 --- a/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/ModelsBuilderSettings.cs @@ -5,9 +5,10 @@ namespace Umbraco.Core.Configuration.Models /// /// Represents the models builder configuration. /// - public class ModelsBuilderSettings + public class ModelsBuilderSettings { - public static string DefaultModelsDirectory => "~/App_Data/Models"; + // TODO: This should not go into App_Data - that folder isn't really a real thing anymore + public static string DefaultModelsDirectory => "~/umbraco/models"; /// /// Gets a value indicating whether the whole models experience is enabled. diff --git a/src/Umbraco.Core/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs index c06ec8f1ec..2c9fe3caee 100644 --- a/src/Umbraco.Core/Constants-Configuration.cs +++ b/src/Umbraco.Core/Constants-Configuration.cs @@ -11,9 +11,23 @@ /// ":" is used as marker for nested objects in json. E.g. "Umbraco:CMS:" = {"Umbraco":{"CMS":{....}} /// public const string ConfigPrefix = "Umbraco:CMS:"; + public const string ConfigContentPrefix = ConfigPrefix + "Content:"; + public const string ConfigContentNotificationsPrefix = ConfigContentPrefix + "Notifications:"; + public const string ConfigCorePrefix = ConfigPrefix + "Core:"; + public const string ConfigCustomErrorsPrefix = ConfigPrefix + "CustomErrors:"; + public const string ConfigGlobalPrefix = ConfigPrefix + "Global:"; + public const string ConfigHostingPrefix = ConfigPrefix + "Hosting:"; + public const string ConfigModelsBuilderPrefix = ConfigPrefix + "ModelsBuilder:"; + public const string ConfigSecurityPrefix = ConfigPrefix + "Security:"; + + public const string ConfigContentNotificationsEmail = ConfigContentNotificationsPrefix + "Email"; + public const string ConfigContentMacroErrors = ConfigContentPrefix + "MacroErrors"; + public const string ConfigGlobalUseHttps = ConfigGlobalPrefix + "UseHttps"; + public const string ConfigHostingDebug = ConfigHostingPrefix + "Debug"; + public const string ConfigCustomErrorsMode = ConfigCustomErrorsPrefix + "Mode"; public const string ConfigActiveDirectory = ConfigPrefix + "ActiveDirectory"; public const string ConfigContent = ConfigPrefix + "Content"; - public const string ConfigCoreDebug = ConfigPrefix + "Core:Debug"; + public const string ConfigCoreDebug = ConfigCorePrefix + "Debug"; public const string ConfigExceptionFilter = ConfigPrefix + "ExceptionFilter"; public const string ConfigGlobal = ConfigPrefix + "Global"; public const string ConfigHealthChecks = ConfigPrefix + "HealthChecks"; @@ -27,14 +41,13 @@ public const string ConfigNuCache = ConfigPrefix + "NuCache"; public const string ConfigRequestHandler = ConfigPrefix + "RequestHandler"; public const string ConfigRuntime = ConfigPrefix + "Runtime"; + public const string ConfigRuntimeMinification = ConfigPrefix + "RuntimeMinification"; + public const string ConfigRuntimeMinificationVersion = ConfigRuntimeMinification + ":Version"; 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/Configuration/HealthChecks/AcceptableConfiguration.cs b/src/Umbraco.Core/HealthCheck/AcceptableConfiguration.cs similarity index 74% rename from src/Umbraco.Core/Configuration/HealthChecks/AcceptableConfiguration.cs rename to src/Umbraco.Core/HealthCheck/AcceptableConfiguration.cs index b71bba1d14..f879172a5d 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/AcceptableConfiguration.cs +++ b/src/Umbraco.Core/HealthCheck/AcceptableConfiguration.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.HealthCheck { public class AcceptableConfiguration { diff --git a/src/Umbraco.Core/HealthCheck/Checks/AbstractSettingsCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/AbstractSettingsCheck.cs new file mode 100644 index 0000000000..62543dcfbd --- /dev/null +++ b/src/Umbraco.Core/HealthCheck/Checks/AbstractSettingsCheck.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Services; + +namespace Umbraco.Core.HealthCheck.Checks +{ + public abstract class AbstractSettingsCheck : HealthCheck + { + protected ILocalizedTextService TextService { get; } + protected ILoggerFactory LoggerFactory { get; } + + /// + /// Gets key within the JSON to check, in the colon-delimited format + /// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1 + /// + public abstract string ItemPath { get; } + + /// + /// Gets the values to compare against. + /// + public abstract IEnumerable Values { get; } + + /// + /// Gets the current value of the config setting + /// + public abstract string CurrentValue { get; } + + /// + /// Gets the provided value + /// + public string ProvidedValue { get; set; } + + /// + /// Gets the comparison type for checking the value. + /// + public abstract ValueComparisonType ValueComparisonType { get; } + + protected AbstractSettingsCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory) + { + TextService = textService; + LoggerFactory = loggerFactory; + } + + /// + /// Gets the message for when the check has succeeded. + /// + public virtual string CheckSuccessMessage + { + get + { + return TextService.Localize("healthcheck/checkSuccessMessage", new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, ItemPath }); + } + } + + /// + /// Gets the message for when the check has failed. + /// + public virtual string CheckErrorMessage + { + get + { + return ValueComparisonType == ValueComparisonType.ShouldEqual + ? TextService.Localize("healthcheck/checkErrorMessageDifferentExpectedValue", + new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, ItemPath }) + : TextService.Localize("healthcheck/checkErrorMessageUnexpectedValue", + new[] { CurrentValue, Values.First(v => v.IsRecommended).Value, ItemPath }); + } + } + + /// + /// Gets the rectify success message. + /// + public virtual string RectifySuccessMessage + { + get + { + AcceptableConfiguration recommendedValue = Values.FirstOrDefault(v => v.IsRecommended); + string rectifiedValue = recommendedValue != null ? recommendedValue.Value : ProvidedValue; + return TextService.Localize("healthcheck/rectifySuccessMessage", + new[] + { + CurrentValue, + rectifiedValue, + ItemPath + }); + } + } + + /// + /// Gets a value indicating whether this check can be rectified automatically. + /// + public virtual bool CanRectify => ValueComparisonType == ValueComparisonType.ShouldEqual; + + /// + /// Gets a value indicating whether this check can be rectified automatically if a value is provided. + /// + public virtual bool CanRectifyWithValue => ValueComparisonType == ValueComparisonType.ShouldNotEqual; + + public override IEnumerable GetStatus() + { + // update the successMessage with the CurrentValue + var successMessage = string.Format(CheckSuccessMessage, ItemPath, Values, CurrentValue); + bool valueFound = Values.Any(value => string.Equals(CurrentValue, value.Value, StringComparison.InvariantCultureIgnoreCase)); + + if (ValueComparisonType == ValueComparisonType.ShouldEqual + && valueFound || ValueComparisonType == ValueComparisonType.ShouldNotEqual + && valueFound == false) + { + return new[] + { + new HealthCheckStatus(successMessage) + { + ResultType = StatusResultType.Success + } + }; + } + + // Declare the action for rectifying the config value + var rectifyAction = new HealthCheckAction("rectify", Id) + { + Name = TextService.Localize("healthcheck/rectifyButton"), + ValueRequired = CanRectifyWithValue + }; + + string resultMessage = string.Format(CheckErrorMessage, ItemPath, Values, CurrentValue); + return new[] + { + new HealthCheckStatus(resultMessage) + { + ResultType = StatusResultType.Error, + Actions = CanRectify || CanRectifyWithValue ? new[] { rectifyAction } : new HealthCheckAction[0] + } + }; + } + + /// + /// Rectifies this check. + /// + /// + public virtual HealthCheckStatus Rectify(HealthCheckAction action) + { + if (ValueComparisonType == ValueComparisonType.ShouldNotEqual) + { + throw new InvalidOperationException(TextService.Localize("healthcheck/cannotRectifyShouldNotEqual")); + } + + //TODO: show message instead of actually fixing config + string recommendedValue = Values.First(v => v.IsRecommended).Value; + string resultMessage = string.Format(RectifySuccessMessage, ItemPath, Values); + return new HealthCheckStatus(resultMessage) { ResultType = StatusResultType.Success }; + } + + public override HealthCheckStatus ExecuteAction(HealthCheckAction action) + { + return Rectify(action); + } + } +} diff --git a/src/Umbraco.Core/Configuration/HealthChecks/NotificationEmailCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Configuration/NotificationEmailCheck.cs similarity index 61% rename from src/Umbraco.Core/Configuration/HealthChecks/NotificationEmailCheck.cs rename to src/Umbraco.Core/HealthCheck/Checks/Configuration/NotificationEmailCheck.cs index bac2cf1c3c..a6e6a83c47 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/NotificationEmailCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Configuration/NotificationEmailCheck.cs @@ -1,25 +1,26 @@ using System.Collections.Generic; using Microsoft.Extensions.Logging; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; +using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.Services; -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.HealthCheck.Checks.Configuration { [HealthCheck("3E2F7B14-4B41-452B-9A30-E67FBC8E1206", "Notification Email Settings", Description = "If notifications are used, the 'from' email address should be specified and changed from the default value.", Group = "Configuration")] - public class NotificationEmailCheck : AbstractConfigCheck + public class NotificationEmailCheck : AbstractSettingsCheck { + private readonly IOptionsMonitor _contentSettings; private const string DefaultFromEmail = "your@email.here"; - public NotificationEmailCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) - : base(textService, hostingEnvironment, loggerFactory) - { } + public NotificationEmailCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory, IOptionsMonitor contentSettings) + : base(textService, loggerFactory) + { + _contentSettings = contentSettings; + } - public override string FilePath => "~/Config/umbracoSettings.config"; - - public override string XPath => "/settings/content/notifications/email"; + public override string ItemPath => Constants.Configuration.ConfigContentNotificationsEmail; public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldNotEqual; @@ -28,8 +29,11 @@ namespace Umbraco.Web.HealthCheck.Checks.Config new AcceptableConfiguration { IsRecommended = false, Value = DefaultFromEmail } }; - public override string CheckSuccessMessage => TextService.Localize("healthcheck/notificationEmailsCheckSuccessMessage", new [] { CurrentValue } ); + public override string CurrentValue => _contentSettings.CurrentValue.Notifications.Email; + + public override string CheckSuccessMessage => TextService.Localize("healthcheck/notificationEmailsCheckSuccessMessage", new[] { CurrentValue }); public override string CheckErrorMessage => TextService.Localize("healthcheck/notificationEmailsCheckErrorMessage", new[] { DefaultFromEmail }); + } } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Data/DatabaseIntegrityCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Data/DatabaseIntegrityCheck.cs index a18edb175a..0fb34950bd 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Data/DatabaseIntegrityCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Data/DatabaseIntegrityCheck.cs @@ -5,7 +5,7 @@ using System.Text; using Umbraco.Core.Models; using Umbraco.Core.Services; -namespace Umbraco.Web.HealthCheck.Checks.Data +namespace Umbraco.Core.HealthCheck.Checks.Data { [HealthCheck( "73DD0C1C-E0CA-4C31-9564-1DCA509788AF", diff --git a/src/Umbraco.Core/Configuration/HealthChecks/DisabledHealthCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/DisabledHealthCheck.cs similarity index 80% rename from src/Umbraco.Core/Configuration/HealthChecks/DisabledHealthCheck.cs rename to src/Umbraco.Core/HealthCheck/Checks/DisabledHealthCheck.cs index c962014bd5..99ff05ed55 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/DisabledHealthCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/DisabledHealthCheck.cs @@ -1,6 +1,6 @@ using System; -namespace Umbraco.Core.Configuration.HealthChecks +namespace Umbraco.Core.HealthCheck.Checks { public class DisabledHealthCheck { diff --git a/src/Umbraco.Core/Configuration/HealthChecks/CustomErrorsCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/LiveEnvironment/CustomErrorsCheck.cs similarity index 78% rename from src/Umbraco.Core/Configuration/HealthChecks/CustomErrorsCheck.cs rename to src/Umbraco.Core/HealthCheck/Checks/LiveEnvironment/CustomErrorsCheck.cs index 9b14847bdf..b003506205 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/CustomErrorsCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/LiveEnvironment/CustomErrorsCheck.cs @@ -1,24 +1,20 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Services; -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.HealthCheck.Checks.LiveEnvironment { [HealthCheck("4090C0A1-2C52-4124-92DD-F028FD066A64", "Custom Errors", Description = "Leaving custom errors off will display a complete stack trace to your visitors if an exception occurs.", Group = "Live Environment")] - public class CustomErrorsCheck : AbstractConfigCheck + public class CustomErrorsCheck : AbstractSettingsCheck { - public CustomErrorsCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) - : base(textService, hostingEnvironment, loggerFactory) + public CustomErrorsCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory) + : base(textService, loggerFactory) { } - public override string FilePath => "~/Web.config"; - - public override string XPath => "/configuration/system.web/customErrors/@mode"; + public override string ItemPath => Constants.Configuration.ConfigCustomErrorsMode; public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual; @@ -28,6 +24,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Config new AcceptableConfiguration { IsRecommended = false, Value = "On" } }; + public override string CurrentValue { get; } + public override string CheckSuccessMessage { get diff --git a/src/Umbraco.Core/Configuration/HealthChecks/TraceCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/LiveEnvironment/TraceCheck.cs similarity index 68% rename from src/Umbraco.Core/Configuration/HealthChecks/TraceCheck.cs rename to src/Umbraco.Core/HealthCheck/Checks/LiveEnvironment/TraceCheck.cs index a2c5a84c55..03a6ecfde2 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/TraceCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/LiveEnvironment/TraceCheck.cs @@ -1,24 +1,19 @@ using System.Collections.Generic; using Microsoft.Extensions.Logging; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Services; -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.HealthCheck.Checks.LiveEnvironment { [HealthCheck("9BED6EF4-A7F3-457A-8935-B64E9AA8BAB3", "Trace Mode", Description = "Leaving trace mode enabled can make valuable information about your system available to hackers.", Group = "Live Environment")] - public class TraceCheck : AbstractConfigCheck + public class TraceCheck : AbstractSettingsCheck { - - public TraceCheck(ILocalizedTextService textService, IHostingEnvironment hostingEnvironment, ILoggerFactory loggerFactory) - : base(textService, hostingEnvironment, loggerFactory) + public TraceCheck(ILocalizedTextService textService, ILoggerFactory loggerFactory) + : base(textService, loggerFactory) { } - public override string FilePath => "~/Web.config"; - - public override string XPath => "/configuration/system.web/trace/@enabled"; + public override string ItemPath => "/configuration/system.web/trace/@enabled"; public override ValueComparisonType ValueComparisonType => ValueComparisonType.ShouldEqual; @@ -27,10 +22,13 @@ namespace Umbraco.Web.HealthCheck.Checks.Config new AcceptableConfiguration { IsRecommended = true, Value = bool.FalseString.ToLower() } }; + public override string CurrentValue { get; } + public override string CheckSuccessMessage => TextService.Localize("healthcheck/traceModeCheckSuccessMessage"); public override string CheckErrorMessage => TextService.Localize("healthcheck/traceModeCheckErrorMessage"); public override string RectifySuccessMessage => TextService.Localize("healthcheck/traceModeCheckRectifySuccessMessage"); + } } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs index d6fbfae813..1618daf028 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Permissions/FolderAndFilePermissionsCheck.cs @@ -2,27 +2,13 @@ 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; -namespace Umbraco.Web.HealthCheck.Checks.Permissions +namespace Umbraco.Core.HealthCheck.Checks.Permissions { - internal enum PermissionCheckRequirement - { - Required, - Optional - } - - internal enum PermissionCheckFor - { - Folder, - File - } - [HealthCheck( "53DBA282-4A79-4B67-B958-B29EC40FCC23", "Folder & File Permissions", @@ -31,14 +17,14 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions public class FolderAndFilePermissionsCheck : HealthCheck { private readonly ILocalizedTextService _textService; - private readonly GlobalSettings _globalSettings; + private readonly IOptionsMonitor _globalSettings; private readonly IFilePermissionHelper _filePermissionHelper; private readonly IIOHelper _ioHelper; - public FolderAndFilePermissionsCheck(ILocalizedTextService textService, IOptions globalSettings, IFilePermissionHelper filePermissionHelper, IIOHelper ioHelper) + public FolderAndFilePermissionsCheck(ILocalizedTextService textService, IOptionsMonitor globalSettings, IFilePermissionHelper filePermissionHelper, IIOHelper ioHelper) { _textService = textService; - _globalSettings = globalSettings.Value; + _globalSettings = globalSettings; _filePermissionHelper = filePermissionHelper; _ioHelper = ioHelper; } @@ -74,10 +60,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions { Constants.SystemDirectories.Preview, PermissionCheckRequirement.Required }, { Constants.SystemDirectories.AppPlugins, PermissionCheckRequirement.Required }, { Constants.SystemDirectories.Config, PermissionCheckRequirement.Optional }, - { _globalSettings.UmbracoCssPath, PermissionCheckRequirement.Optional }, - { _globalSettings.UmbracoMediaPath, PermissionCheckRequirement.Optional }, - { _globalSettings.UmbracoScriptsPath, PermissionCheckRequirement.Optional }, - { _globalSettings.UmbracoPath, PermissionCheckRequirement.Optional }, + { _globalSettings.CurrentValue.UmbracoCssPath, PermissionCheckRequirement.Optional }, + { _globalSettings.CurrentValue.UmbracoMediaPath, PermissionCheckRequirement.Optional }, + { _globalSettings.CurrentValue.UmbracoScriptsPath, PermissionCheckRequirement.Optional }, + { _globalSettings.CurrentValue.UmbracoPath, PermissionCheckRequirement.Optional }, { Constants.SystemDirectories.MvcViews, PermissionCheckRequirement.Optional } }; @@ -97,7 +83,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions //now check the special folders var requiredPathCheckResult2 = _filePermissionHelper.EnsureDirectories( - GetPathsToCheck(pathsToCheckWithRestarts, PermissionCheckRequirement.Required), out var requiredFailedPaths2, writeCausesRestart:true); + GetPathsToCheck(pathsToCheckWithRestarts, PermissionCheckRequirement.Required), out var requiredFailedPaths2, writeCausesRestart: true); var optionalPathCheckResult2 = _filePermissionHelper.EnsureDirectories( GetPathsToCheck(pathsToCheckWithRestarts, PermissionCheckRequirement.Optional), out var optionalFailedPaths2, writeCausesRestart: true); @@ -139,9 +125,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions .ToArray(); } - private HealthCheckStatus GetStatus(bool requiredPathCheckResult, IEnumerable requiredFailedPaths, - bool optionalPathCheckResult, IEnumerable optionalFailedPaths, - PermissionCheckFor checkingFor) + private HealthCheckStatus GetStatus(bool requiredPathCheckResult, IEnumerable requiredFailedPaths, bool optionalPathCheckResult, IEnumerable optionalFailedPaths, PermissionCheckFor checkingFor) { // Return error if any required paths fail the check, or warning if any optional ones do var resultType = StatusResultType.Success; @@ -164,12 +148,11 @@ namespace Umbraco.Web.HealthCheck.Checks.Permissions } var actions = new List(); - return - new HealthCheckStatus(message) - { - ResultType = resultType, - Actions = actions - }; + return new HealthCheckStatus(message) + { + ResultType = resultType, + Actions = actions + }; } private string GetMessageForPathCheckFailure(string messageKey, IEnumerable failedPaths) diff --git a/src/Umbraco.Core/HealthCheck/Checks/Permissions/PermissionCheckFor.cs b/src/Umbraco.Core/HealthCheck/Checks/Permissions/PermissionCheckFor.cs new file mode 100644 index 0000000000..bd914d064d --- /dev/null +++ b/src/Umbraco.Core/HealthCheck/Checks/Permissions/PermissionCheckFor.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.HealthCheck.Checks.Permissions +{ + internal enum PermissionCheckFor + { + Folder, + File + } +} diff --git a/src/Umbraco.Core/HealthCheck/Checks/Permissions/PermissionCheckRequirement.cs b/src/Umbraco.Core/HealthCheck/Checks/Permissions/PermissionCheckRequirement.cs new file mode 100644 index 0000000000..f77fdbf2e3 --- /dev/null +++ b/src/Umbraco.Core/HealthCheck/Checks/Permissions/PermissionCheckRequirement.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.HealthCheck.Checks.Permissions +{ + internal enum PermissionCheckRequirement + { + Required, + Optional + } +} diff --git a/src/Umbraco.Core/HealthCheck/Checks/Security/BaseHttpHeaderCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Security/BaseHttpHeaderCheck.cs index 149ad4a48a..5bf92342bf 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/BaseHttpHeaderCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/BaseHttpHeaderCheck.cs @@ -4,13 +4,11 @@ using System.IO; using System.Linq; using System.Net; using System.Text.RegularExpressions; -using System.Xml.Linq; -using System.Xml.XPath; -using Umbraco.Core; -using Umbraco.Core.IO; +using Microsoft.Extensions.Configuration; using Umbraco.Core.Services; +using Umbraco.Web; -namespace Umbraco.Web.HealthCheck.Checks.Security +namespace Umbraco.Core.HealthCheck.Checks.Security { public abstract class BaseHttpHeaderCheck : HealthCheck { @@ -23,16 +21,14 @@ namespace Umbraco.Web.HealthCheck.Checks.Security private readonly string _localizedTextPrefix; private readonly bool _metaTagOptionAvailable; private readonly IRequestAccessor _requestAccessor; - private readonly IIOHelper _ioHelper; protected BaseHttpHeaderCheck( IRequestAccessor requestAccessor, ILocalizedTextService textService, - string header, string value, string localizedTextPrefix, bool metaTagOptionAvailable, IIOHelper ioHelper) + string header, string value, string localizedTextPrefix, bool metaTagOptionAvailable) { TextService = textService ?? throw new ArgumentNullException(nameof(textService)); _requestAccessor = requestAccessor; - _ioHelper = ioHelper; _header = header; _value = value; _localizedTextPrefix = localizedTextPrefix; @@ -72,7 +68,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security var success = false; // Access the site home page and check for the click-jack protection header or meta tag - var url = _requestAccessor.GetApplicationUrl(); + var url = _requestAccessor.GetApplicationUrl(); var request = WebRequest.Create(url); request.Method = "GET"; try @@ -146,7 +142,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security private HealthCheckStatus SetHeaderInConfig() { var errorMessage = string.Empty; - var success = SaveHeaderToConfigFile(out errorMessage); + //TODO: edit to show fix suggestion instead of making fix + var success = true; if (success) { @@ -158,64 +155,10 @@ namespace Umbraco.Web.HealthCheck.Checks.Security } return - new HealthCheckStatus(TextService.Localize("healthcheck/setHeaderInConfigError", new [] { errorMessage })) + new HealthCheckStatus(TextService.Localize("healthcheck/setHeaderInConfigError", new[] { errorMessage })) { ResultType = StatusResultType.Error }; } - - private bool SaveHeaderToConfigFile(out string errorMessage) - { - try - { - // There don't look to be any useful classes defined in https://msdn.microsoft.com/en-us/library/system.web.configuration(v=vs.110).aspx - // for working with the customHeaders section, so working with the XML directly. - var configFile = _ioHelper.MapPath("~/Web.config"); - var doc = XDocument.Load(configFile); - var systemWebServerElement = doc.XPathSelectElement("/configuration/system.webServer"); - var httpProtocolElement = systemWebServerElement.Element("httpProtocol"); - if (httpProtocolElement == null) - { - httpProtocolElement = new XElement("httpProtocol"); - systemWebServerElement.Add(httpProtocolElement); - } - - var customHeadersElement = httpProtocolElement.Element("customHeaders"); - if (customHeadersElement == null) - { - customHeadersElement = new XElement("customHeaders"); - httpProtocolElement.Add(customHeadersElement); - } - - var removeHeaderElement = customHeadersElement.Elements("remove") - .SingleOrDefault(x => x.Attribute("name")?.Value.Equals(_value, StringComparison.InvariantCultureIgnoreCase) == true); - if (removeHeaderElement == null) - { - customHeadersElement.Add( - new XElement("remove", - new XAttribute("name", _header))); - } - - var addHeaderElement = customHeadersElement.Elements("add") - .SingleOrDefault(x => x.Attribute("name")?.Value.Equals(_header, StringComparison.InvariantCultureIgnoreCase) == true); - if (addHeaderElement == null) - { - customHeadersElement.Add( - new XElement("add", - new XAttribute("name", _header), - new XAttribute("value", _value))); - } - - doc.Save(configFile); - - errorMessage = string.Empty; - return true; - } - catch (Exception ex) - { - errorMessage = ex.Message; - return false; - } - } } } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Security/ClickJackingCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Security/ClickJackingCheck.cs index 048b26afca..a7b4c0ba85 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/ClickJackingCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/ClickJackingCheck.cs @@ -1,8 +1,7 @@ -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Services; +using Umbraco.Core.Services; +using Umbraco.Web; -namespace Umbraco.Web.HealthCheck.Checks.Security +namespace Umbraco.Core.HealthCheck.Checks.Security { [HealthCheck( "ED0D7E40-971E-4BE8-AB6D-8CC5D0A6A5B0", @@ -11,8 +10,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security Group = "Security")] public class ClickJackingCheck : BaseHttpHeaderCheck { - public ClickJackingCheck(IRequestAccessor requestAccessor, ILocalizedTextService textService, IIOHelper ioHelper) - : base(requestAccessor, textService, "X-Frame-Options", "sameorigin", "clickJacking", true, ioHelper) + public ClickJackingCheck(IRequestAccessor requestAccessor, ILocalizedTextService textService) + : base(requestAccessor, textService, "X-Frame-Options", "sameorigin", "clickJacking", true) { } } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs index 06367ace13..9cf1127bb0 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs @@ -2,10 +2,10 @@ using System.Collections.Generic; using System.Linq; using System.Net; -using Umbraco.Core; using Umbraco.Core.Services; +using Umbraco.Web; -namespace Umbraco.Web.HealthCheck.Checks.Security +namespace Umbraco.Core.HealthCheck.Checks.Security { [HealthCheck( "92ABBAA2-0586-4089-8AE2-9A843439D577", diff --git a/src/Umbraco.Core/HealthCheck/Checks/Security/HstsCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Security/HstsCheck.cs index 61879142f2..ee8f733fca 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/HstsCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/HstsCheck.cs @@ -1,8 +1,7 @@ -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Services; +using Umbraco.Core.Services; +using Umbraco.Web; -namespace Umbraco.Web.HealthCheck.Checks.Security +namespace Umbraco.Core.HealthCheck.Checks.Security { [HealthCheck( "E2048C48-21C5-4BE1-A80B-8062162DF124", @@ -16,8 +15,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security // and the blog post of Troy Hunt (https://www.troyhunt.com/understanding-http-strict-transport/) // If you want do to it perfectly, you have to submit it https://hstspreload.org/, // but then you should include subdomains and I wouldn't suggest to do that for Umbraco-sites. - public HstsCheck(IRequestAccessor requestAccessor, ILocalizedTextService textService, IIOHelper ioHelper) - : base(requestAccessor, textService, "Strict-Transport-Security", "max-age=10886400", "hSTS", true, ioHelper) + public HstsCheck(IRequestAccessor requestAccessor, ILocalizedTextService textService) + : base(requestAccessor, textService, "Strict-Transport-Security", "max-age=10886400", "hSTS", true) { } } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs index 3f788f7460..6bba41b7d5 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/HttpsCheck.cs @@ -3,15 +3,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.Web.HealthCheck.Checks.Config; using Umbraco.Core.Configuration.Models; using Microsoft.Extensions.Options; +using Umbraco.Core.Configuration.HealthChecks; +using Umbraco.Core.IO; +using Umbraco.Web; -namespace Umbraco.Web.HealthCheck.Checks.Security +namespace Umbraco.Core.HealthCheck.Checks.Security { [HealthCheck( "EB66BB3B-1BCD-4314-9531-9DA2C1D6D9A7", @@ -21,22 +20,20 @@ namespace Umbraco.Web.HealthCheck.Checks.Security public class HttpsCheck : HealthCheck { private readonly ILocalizedTextService _textService; - private readonly GlobalSettings _globalSettings; - private readonly IIOHelper _ioHelper; + private readonly IOptionsMonitor _globalSettings; private readonly IRequestAccessor _requestAccessor; - private readonly ILogger _logger; - + private readonly ILogger _logger; private const string FixHttpsSettingAction = "fixHttpsSetting"; + string itemPath => Constants.Configuration.ConfigGlobalUseHttps; public HttpsCheck(ILocalizedTextService textService, - IOptions globalSettings, + IOptionsMonitor globalSettings, IIOHelper ioHelper, IRequestAccessor requestAccessor, - ILogger logger) + ILogger logger) { _textService = textService; - _globalSettings = globalSettings.Value; - _ioHelper = ioHelper; + _globalSettings = globalSettings; _requestAccessor = requestAccessor; _logger = logger; } @@ -75,7 +72,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Security // Attempt to access the site over HTTPS to see if it HTTPS is supported // and a valid certificate has been configured var url = _requestAccessor.GetApplicationUrl().ToString().Replace("http:", "https:"); - var request = (HttpWebRequest) WebRequest.Create(url); + var request = (HttpWebRequest)WebRequest.Create(url); request.Method = "HEAD"; try @@ -119,8 +116,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security if (exception != null) { message = exception.Status == WebExceptionStatus.TrustFailure - ? _textService.Localize("healthcheck/httpsCheckInvalidCertificate", new [] { exception.Message }) - : _textService.Localize("healthcheck/healthCheckInvalidUrl", new [] { url, exception.Message }); + ? _textService.Localize("healthcheck/httpsCheckInvalidCertificate", new[] { exception.Message }) + : _textService.Localize("healthcheck/healthCheckInvalidUrl", new[] { url, exception.Message }); } else { @@ -132,33 +129,31 @@ namespace Umbraco.Web.HealthCheck.Checks.Security var actions = new List(); - return - new HealthCheckStatus(message) - { - ResultType = result, - Actions = actions - }; + return new HealthCheckStatus(message) + { + ResultType = result, + Actions = actions + }; } private HealthCheckStatus CheckIfCurrentSchemeIsHttps() { - var uri = _requestAccessor.GetApplicationUrl(); + var uri = _requestAccessor.GetApplicationUrl(); var success = uri.Scheme == "https"; var actions = new List(); - return - new HealthCheckStatus(_textService.Localize("healthcheck/httpsCheckIsCurrentSchemeHttps", new[] { success ? string.Empty : "not" })) - { - ResultType = success ? StatusResultType.Success : StatusResultType.Error, - Actions = actions - }; + return new HealthCheckStatus(_textService.Localize("healthcheck/httpsCheckIsCurrentSchemeHttps", new[] { success ? string.Empty : "not" })) + { + ResultType = success ? StatusResultType.Success : StatusResultType.Error, + Actions = actions + }; } private HealthCheckStatus CheckHttpsConfigurationSetting() { - var httpsSettingEnabled = _globalSettings.UseHttps; - var uri = _requestAccessor.GetApplicationUrl(); + bool httpsSettingEnabled = _globalSettings.CurrentValue.UseHttps; + Uri uri = _requestAccessor.GetApplicationUrl(); var actions = new List(); string resultMessage; @@ -171,46 +166,34 @@ namespace Umbraco.Web.HealthCheck.Checks.Security else { if (httpsSettingEnabled == false) + { actions.Add(new HealthCheckAction(FixHttpsSettingAction, Id) { Name = _textService.Localize("healthcheck/httpsCheckEnableHttpsButton"), Description = _textService.Localize("healthcheck/httpsCheckEnableHttpsDescription") }); + } resultMessage = _textService.Localize("healthcheck/httpsCheckConfigurationCheckResult", - new[] {httpsSettingEnabled.ToString(), httpsSettingEnabled ? string.Empty : "not"}); - resultType = httpsSettingEnabled ? StatusResultType.Success: StatusResultType.Error; + new[] { httpsSettingEnabled.ToString(), httpsSettingEnabled ? string.Empty : "not" }); + resultType = httpsSettingEnabled ? StatusResultType.Success : StatusResultType.Error; } - return - new HealthCheckStatus(resultMessage) - { - ResultType = resultType, - Actions = actions - }; + return new HealthCheckStatus(resultMessage) + { + ResultType = resultType, + Actions = actions + }; } private HealthCheckStatus FixHttpsSetting() { - var configFile = _ioHelper.MapPath("~/Web.config"); - const string xPath = "/configuration/appSettings/add[@key='Umbraco.Core.UseHttps']/@value"; - var configurationService = new ConfigurationService(configFile, xPath, _textService, _logger); - var updateConfigFile = configurationService.UpdateConfigFile("true"); + //TODO: return message instead of actual fix - if (updateConfigFile.Success) + return new HealthCheckStatus(_textService.Localize("healthcheck/httpsCheckEnableHttpsSuccess")) { - return - new HealthCheckStatus(_textService.Localize("healthcheck/httpsCheckEnableHttpsSuccess")) - { - ResultType = StatusResultType.Success - }; - } - - return - new HealthCheckStatus(_textService.Localize("healthcheck/httpsCheckEnableHttpsError", new [] { updateConfigFile.Result })) - { - ResultType = StatusResultType.Error - }; + ResultType = StatusResultType.Success + }; } } } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Security/NoSniffCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Security/NoSniffCheck.cs index 0b6fb9e347..c392842049 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/NoSniffCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/NoSniffCheck.cs @@ -1,8 +1,7 @@ -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Services; +using Umbraco.Core.Services; +using Umbraco.Web; -namespace Umbraco.Web.HealthCheck.Checks.Security +namespace Umbraco.Core.HealthCheck.Checks.Security { [HealthCheck( "1CF27DB3-EFC0-41D7-A1BB-EA912064E071", @@ -11,8 +10,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security Group = "Security")] public class NoSniffCheck : BaseHttpHeaderCheck { - public NoSniffCheck(IRequestAccessor requestAccessor, ILocalizedTextService textService, IIOHelper ioHelper) - : base(requestAccessor, textService, "X-Content-Type-Options", "nosniff", "noSniff", false, ioHelper) + public NoSniffCheck(IRequestAccessor requestAccessor, ILocalizedTextService textService) + : base(requestAccessor, textService, "X-Content-Type-Options", "nosniff", "noSniff", false) { } } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Security/XssProtectionCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Security/XssProtectionCheck.cs index 7d658e2082..a5f0f28f22 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Security/XssProtectionCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Security/XssProtectionCheck.cs @@ -1,8 +1,7 @@ -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Services; +using Umbraco.Core.Services; +using Umbraco.Web; -namespace Umbraco.Web.HealthCheck.Checks.Security +namespace Umbraco.Core.HealthCheck.Checks.Security { [HealthCheck( "F4D2B02E-28C5-4999-8463-05759FA15C3A", @@ -16,8 +15,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security // and the blog post of Troy Hunt (https://www.troyhunt.com/understanding-http-strict-transport/) // If you want do to it perfectly, you have to submit it https://hstspreload.appspot.com/, // but then you should include subdomains and I wouldn't suggest to do that for Umbraco-sites. - public XssProtectionCheck(IRequestAccessor requestAccessor,ILocalizedTextService textService, IIOHelper ioHelper) - : base(requestAccessor, textService, "X-XSS-Protection", "1; mode=block", "xssProtection", true, ioHelper) + public XssProtectionCheck(IRequestAccessor requestAccessor,ILocalizedTextService textService) + : base(requestAccessor, textService, "X-XSS-Protection", "1; mode=block", "xssProtection", true) { } } diff --git a/src/Umbraco.Core/HealthCheck/Checks/Services/SmtpCheck.cs b/src/Umbraco.Core/HealthCheck/Checks/Services/SmtpCheck.cs index 77b1201ef6..9e1a6f84af 100644 --- a/src/Umbraco.Core/HealthCheck/Checks/Services/SmtpCheck.cs +++ b/src/Umbraco.Core/HealthCheck/Checks/Services/SmtpCheck.cs @@ -3,12 +3,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 +namespace Umbraco.Core.HealthCheck.Checks.Services { [HealthCheck( "1B5D221B-CE99-4193-97CB-5F3261EC73DF", @@ -18,12 +16,12 @@ namespace Umbraco.Web.HealthCheck.Checks.Services public class SmtpCheck : HealthCheck { private readonly ILocalizedTextService _textService; - private readonly GlobalSettings _globalSettings; + private readonly IOptionsMonitor _globalSettings; - public SmtpCheck(ILocalizedTextService textService, IOptions globalSettings) + public SmtpCheck(ILocalizedTextService textService, IOptionsMonitor globalSettings) { _textService = textService; - _globalSettings = globalSettings.Value; + _globalSettings = globalSettings; } /// @@ -50,7 +48,7 @@ namespace Umbraco.Web.HealthCheck.Checks.Services { var success = false; - var smtpSettings = _globalSettings.Smtp; + var smtpSettings = _globalSettings.CurrentValue.Smtp; string message; if (smtpSettings == null) diff --git a/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationServiceResult.cs b/src/Umbraco.Core/HealthCheck/ConfigurationServiceResult.cs similarity index 73% rename from src/Umbraco.Core/Configuration/HealthChecks/ConfigurationServiceResult.cs rename to src/Umbraco.Core/HealthCheck/ConfigurationServiceResult.cs index 3b1400da5b..b4940f927a 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/ConfigurationServiceResult.cs +++ b/src/Umbraco.Core/HealthCheck/ConfigurationServiceResult.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.HealthCheck { public class ConfigurationServiceResult { diff --git a/src/Umbraco.Core/HealthCheck/HealthCheck.cs b/src/Umbraco.Core/HealthCheck/HealthCheck.cs index 73defd2fef..89a1f41f4d 100644 --- a/src/Umbraco.Core/HealthCheck/HealthCheck.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheck.cs @@ -1,24 +1,25 @@ using System; using System.Collections.Generic; using System.Runtime.Serialization; -using Umbraco.Core; using Umbraco.Core.Composing; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { /// - /// Provides a base class for health checks. + /// Provides a base class for health checks, filling in the healthcheck metadata on construction /// [DataContract(Name = "healthCheck", Namespace = "")] public abstract class HealthCheck : IDiscoverable { protected HealthCheck() { - //Fill in the metadata - var thisType = GetType(); - var meta = thisType.GetCustomAttribute(false); + Type thisType = GetType(); + HealthCheckAttribute meta = thisType.GetCustomAttribute(false); if (meta == null) - throw new InvalidOperationException($"The health check {thisType} requires a {typeof (HealthCheckAttribute)}"); + { + throw new InvalidOperationException($"The health check {thisType} requires a {typeof(HealthCheckAttribute)}"); + } + Name = meta.Name; Description = meta.Description; Group = meta.Group; @@ -49,7 +50,5 @@ namespace Umbraco.Web.HealthCheck /// /// public abstract HealthCheckStatus ExecuteAction(HealthCheckAction action); - - // TODO: What else? } } diff --git a/src/Umbraco.Core/HealthCheck/HealthCheckAction.cs b/src/Umbraco.Core/HealthCheck/HealthCheckAction.cs index b64eb6746a..e1771a4262 100644 --- a/src/Umbraco.Core/HealthCheck/HealthCheckAction.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheckAction.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { [DataContract(Name = "healthCheckAction", Namespace = "")] public class HealthCheckAction diff --git a/src/Umbraco.Core/HealthCheck/HealthCheckAttribute.cs b/src/Umbraco.Core/HealthCheck/HealthCheckAttribute.cs index fe206f3186..bd8c10f899 100644 --- a/src/Umbraco.Core/HealthCheck/HealthCheckAttribute.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheckAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { /// /// Metadata attribute for Health checks diff --git a/src/Umbraco.Core/HealthCheck/HealthCheckCollection.cs b/src/Umbraco.Core/HealthCheck/HealthCheckCollection.cs index 6de442b765..fc8d5dff25 100644 --- a/src/Umbraco.Core/HealthCheck/HealthCheckCollection.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheckCollection.cs @@ -1,11 +1,11 @@ using System.Collections.Generic; using Umbraco.Core.Composing; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { - public class HealthCheckCollection : BuilderCollectionBase + public class HealthCheckCollection : BuilderCollectionBase { - public HealthCheckCollection(IEnumerable items) + public HealthCheckCollection(IEnumerable items) : base(items) { } } diff --git a/src/Umbraco.Core/HealthCheck/HealthCheckGroup.cs b/src/Umbraco.Core/HealthCheck/HealthCheckGroup.cs index f01c65f854..2cd1040896 100644 --- a/src/Umbraco.Core/HealthCheck/HealthCheckGroup.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheckGroup.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { [DataContract(Name = "healthCheckGroup", Namespace = "")] public class HealthCheckGroup diff --git a/src/Umbraco.Core/HealthCheck/HealthCheckNotificationMethodAttribute.cs b/src/Umbraco.Core/HealthCheck/HealthCheckNotificationMethodAttribute.cs index d9da271d58..f78df14942 100644 --- a/src/Umbraco.Core/HealthCheck/HealthCheckNotificationMethodAttribute.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheckNotificationMethodAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { /// /// Metadata attribute for health check notification methods diff --git a/src/Umbraco.Core/Configuration/HealthChecks/HealthCheckNotificationVerbosity.cs b/src/Umbraco.Core/HealthCheck/HealthCheckNotificationVerbosity.cs similarity index 52% rename from src/Umbraco.Core/Configuration/HealthChecks/HealthCheckNotificationVerbosity.cs rename to src/Umbraco.Core/HealthCheck/HealthCheckNotificationVerbosity.cs index 95e5ca8e03..74cd4eb93b 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/HealthCheckNotificationVerbosity.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheckNotificationVerbosity.cs @@ -1,6 +1,4 @@ -using System.Runtime.Serialization; - -namespace Umbraco.Core.Configuration.HealthChecks +namespace Umbraco.Core.HealthCheck { public enum HealthCheckNotificationVerbosity { diff --git a/src/Umbraco.Core/HealthCheck/HealthCheckStatus.cs b/src/Umbraco.Core/HealthCheck/HealthCheckStatus.cs index 245267ff8e..2eb873603f 100644 --- a/src/Umbraco.Core/HealthCheck/HealthCheckStatus.cs +++ b/src/Umbraco.Core/HealthCheck/HealthCheckStatus.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Runtime.Serialization; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { /// /// The status returned for a health check when it performs it check diff --git a/src/Umbraco.Core/HealthCheck/HeathCheckCollectionBuilder.cs b/src/Umbraco.Core/HealthCheck/HeathCheckCollectionBuilder.cs index e616ba49ae..0894cb1912 100644 --- a/src/Umbraco.Core/HealthCheck/HeathCheckCollectionBuilder.cs +++ b/src/Umbraco.Core/HealthCheck/HeathCheckCollectionBuilder.cs @@ -1,6 +1,6 @@ using Umbraco.Core.Composing; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { public class HealthCheckCollectionBuilder : LazyCollectionBuilderBase { diff --git a/src/Umbraco.Core/HealthCheck/IConfigurationService.cs b/src/Umbraco.Core/HealthCheck/IConfigurationService.cs new file mode 100644 index 0000000000..dc513bb765 --- /dev/null +++ b/src/Umbraco.Core/HealthCheck/IConfigurationService.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.HealthCheck +{ + public interface IConfigurationService + { + ConfigurationServiceResult UpdateConfigFile(string value, string itemPath); + } +} diff --git a/src/Umbraco.Core/Configuration/HealthChecks/INotificationMethod.cs b/src/Umbraco.Core/HealthCheck/INotificationMethod.cs similarity index 86% rename from src/Umbraco.Core/Configuration/HealthChecks/INotificationMethod.cs rename to src/Umbraco.Core/HealthCheck/INotificationMethod.cs index 84bf55e160..9c4ec70cfe 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/INotificationMethod.cs +++ b/src/Umbraco.Core/HealthCheck/INotificationMethod.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Umbraco.Core.Configuration.HealthChecks +namespace Umbraco.Core.HealthCheck { public interface INotificationMethod { diff --git a/src/Umbraco.Core/Configuration/HealthChecks/INotificationMethodSettings.cs b/src/Umbraco.Core/HealthCheck/INotificationMethodSettings.cs similarity index 69% rename from src/Umbraco.Core/Configuration/HealthChecks/INotificationMethodSettings.cs rename to src/Umbraco.Core/HealthCheck/INotificationMethodSettings.cs index e41c82b393..01ad667d94 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/INotificationMethodSettings.cs +++ b/src/Umbraco.Core/HealthCheck/INotificationMethodSettings.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core.Configuration.HealthChecks +namespace Umbraco.Core.HealthCheck { public interface INotificationMethodSettings { diff --git a/src/Umbraco.Core/HealthCheck/StatusResultType.cs b/src/Umbraco.Core/HealthCheck/StatusResultType.cs index c6bd50f247..3f2c392933 100644 --- a/src/Umbraco.Core/HealthCheck/StatusResultType.cs +++ b/src/Umbraco.Core/HealthCheck/StatusResultType.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Core.HealthCheck { public enum StatusResultType { diff --git a/src/Umbraco.Core/Configuration/HealthChecks/ValueComparisonType.cs b/src/Umbraco.Core/HealthCheck/ValueComparisonType.cs similarity index 65% rename from src/Umbraco.Core/Configuration/HealthChecks/ValueComparisonType.cs rename to src/Umbraco.Core/HealthCheck/ValueComparisonType.cs index 8df40da9f9..c5dd6517a8 100644 --- a/src/Umbraco.Core/Configuration/HealthChecks/ValueComparisonType.cs +++ b/src/Umbraco.Core/HealthCheck/ValueComparisonType.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.HealthCheck.Checks.Config +namespace Umbraco.Core.HealthCheck { public enum ValueComparisonType { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 07dea8d299..2b3efc9349 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs b/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs index 7eebf61b22..1561645be9 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/HealthCheckResults.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; using HeyRed.MarkdownSharp; -using Umbraco.Composing; -using Umbraco.Core.Configuration.HealthChecks; using Microsoft.Extensions.Logging; +using Umbraco.Composing; +using Umbraco.Core.HealthCheck; -namespace Umbraco.Web.HealthCheck +namespace Umbraco.Infrastructure.HealthCheck { public class HealthCheckResults { @@ -16,7 +16,7 @@ namespace Umbraco.Web.HealthCheck private ILogger Logger => Current.Logger; // TODO: inject - public HealthCheckResults(IEnumerable checks) + public HealthCheckResults(IEnumerable checks) { _results = checks.ToDictionary( t => t.Name, diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs index 480654eade..8060e7c257 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/EmailNotificationMethod.cs @@ -5,9 +5,10 @@ using System.Threading.Tasks; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.HealthCheck; using Umbraco.Core.Services; +using Umbraco.Infrastructure.HealthCheck; namespace Umbraco.Web.HealthCheck.NotificationMethods { diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/IHealthCheckNotificationMethod.cs b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/IHealthCheckNotificationMethod.cs index f6e8f1d1c5..fdf72251be 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/IHealthCheckNotificationMethod.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/IHealthCheckNotificationMethod.cs @@ -1,6 +1,7 @@ using System.Threading; using System.Threading.Tasks; using Umbraco.Core.Composing; +using Umbraco.Infrastructure.HealthCheck; namespace Umbraco.Web.HealthCheck.NotificationMethods { diff --git a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs index 2c0c5bcc1f..39025df2ab 100644 --- a/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs +++ b/src/Umbraco.Infrastructure/HealthCheck/NotificationMethods/NotificationMethodBase.cs @@ -3,8 +3,10 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Options; -using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.HealthCheck; +using Umbraco.Core.HealthCheck.Checks; +using Umbraco.Infrastructure.HealthCheck; namespace Umbraco.Web.HealthCheck.NotificationMethods { diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs index 0a57954c62..f3357b19bb 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs @@ -58,7 +58,9 @@ using Umbraco.Web.Trees; using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidator; using TextStringValueConverter = Umbraco.Core.PropertyEditors.ValueConverters.TextStringValueConverter; using Microsoft.Extensions.Logging; - +using Umbraco.Core.Configuration.HealthChecks; +using Umbraco.Core.HealthCheck; +using Umbraco.Core.HealthCheck.Checks; namespace Umbraco.Core.Runtime { @@ -205,7 +207,7 @@ namespace Umbraco.Core.Runtime // Config manipulator composition.RegisterUnique(); - + // register the umbraco context factory // composition.RegisterUnique(); composition.RegisterUnique(); @@ -298,7 +300,7 @@ namespace Umbraco.Core.Runtime // register *all* checks, except those marked [HideFromTypeFinder] of course composition.HealthChecks() - .Add(() => composition.TypeLoader.GetTypes()); + .Add(() => composition.TypeLoader.GetTypes()); composition.WithCollectionBuilder() diff --git a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs index 6198e7845d..33eff2c949 100644 --- a/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs +++ b/src/Umbraco.Infrastructure/Scheduling/HealthCheckNotifier.cs @@ -3,11 +3,13 @@ using System.Threading; using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.HealthCheck; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; using Umbraco.Core.Sync; using Umbraco.Web.HealthCheck; using Microsoft.Extensions.Logging; +using Umbraco.Infrastructure.HealthCheck; namespace Umbraco.Web.Scheduling { diff --git a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs index d1dea43469..05dcbec793 100644 --- a/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs +++ b/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs @@ -7,8 +7,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.Configuration.Models; +using Umbraco.Core.HealthCheck; using Umbraco.Core.Hosting; using Umbraco.Core.Logging; using Umbraco.Core.Scoping; diff --git a/src/Umbraco.Infrastructure/Services/Implement/PropertyValidationService.cs b/src/Umbraco.Infrastructure/Services/Implement/PropertyValidationService.cs index a17cdb034d..c08c1322d3 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/PropertyValidationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/PropertyValidationService.cs @@ -21,7 +21,6 @@ namespace Umbraco.Core.Services _textService = textService; } - public IEnumerable ValidatePropertyValue( IPropertyType propertyType, object postedValue) diff --git a/src/Umbraco.Tests.Common/Builders/ContentBuilder.cs b/src/Umbraco.Tests.Common/Builders/ContentBuilder.cs index 9f30005c55..283b2b6c04 100644 --- a/src/Umbraco.Tests.Common/Builders/ContentBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/ContentBuilder.cs @@ -30,6 +30,7 @@ namespace Umbraco.Tests.Common.Builders private GenericDictionaryBuilder _propertyDataBuilder; private int? _id; + private int? _versionId; private Guid? _key; private DateTime? _createDate; private DateTime? _updateDate; @@ -48,12 +49,10 @@ namespace Umbraco.Tests.Common.Builders private string _propertyValuesCulture; private string _propertyValuesSegment; - public ContentTypeBuilder AddContentType() + public ContentBuilder WithVersionId(int versionId) { - _contentType = null; - var builder = new ContentTypeBuilder(this); - _contentTypeBuilder = builder; - return builder; + _versionId = versionId; + return this; } public ContentBuilder WithParent(IContent parent) @@ -87,6 +86,14 @@ namespace Umbraco.Tests.Common.Builders return this; } + public ContentTypeBuilder AddContentType() + { + _contentType = null; + var builder = new ContentTypeBuilder(this); + _contentTypeBuilder = builder; + return builder; + } + public GenericDictionaryBuilder AddPropertyData() { var builder = new GenericDictionaryBuilder(this); @@ -97,6 +104,7 @@ namespace Umbraco.Tests.Common.Builders public override Content Build() { var id = _id ?? 0; + var versionId = _versionId ?? 0; var key = _key ?? Guid.NewGuid(); var parentId = _parentId ?? -1; var parent = _parent ?? null; @@ -131,6 +139,7 @@ namespace Umbraco.Tests.Common.Builders } content.Id = id; + content.VersionId = versionId; content.Key = key; content.CreateDate = createDate; content.UpdateDate = updateDate; diff --git a/src/Umbraco.Tests.Common/Builders/ContentTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/ContentTypeBuilder.cs index eb4192364f..fca148f542 100644 --- a/src/Umbraco.Tests.Common/Builders/ContentTypeBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/ContentTypeBuilder.cs @@ -20,6 +20,7 @@ namespace Umbraco.Tests.Common.Builders private int? _propertyTypeIdsIncrementingFrom; private int? _defaultTemplateId; private ContentVariation? _contentVariation; + private PropertyTypeCollection _propertyTypeCollection; public ContentTypeBuilder() : base(null) { @@ -41,6 +42,12 @@ namespace Umbraco.Tests.Common.Builders return this; } + public ContentTypeBuilder WithPropertyTypeCollection(PropertyTypeCollection propertyTypeCollection) + { + _propertyTypeCollection = propertyTypeCollection; + return this; + } + public PropertyGroupBuilder AddPropertyGroup() { var builder = new PropertyGroupBuilder(this); @@ -104,9 +111,21 @@ namespace Umbraco.Tests.Common.Builders contentType.Variations = contentVariation; - contentType.NoGroupPropertyTypes = _noGroupPropertyTypeBuilders.Select(x => x.Build()); - BuildPropertyGroups(contentType, _propertyGroupBuilders.Select(x => x.Build())); - BuildPropertyTypeIds(contentType, _propertyTypeIdsIncrementingFrom); + if (_propertyTypeCollection != null) + { + var propertyGroup = new PropertyGroupBuilder() + .WithName("Content") + .WithSortOrder(1) + .WithPropertyTypeCollection(_propertyTypeCollection) + .Build(); + contentType.PropertyGroups.Add(propertyGroup); + } + else + { + contentType.NoGroupPropertyTypes = _noGroupPropertyTypeBuilders.Select(x => x.Build()); + BuildPropertyGroups(contentType, _propertyGroupBuilders.Select(x => x.Build())); + BuildPropertyTypeIds(contentType, _propertyTypeIdsIncrementingFrom); + } contentType.AllowedContentTypes = _allowedContentTypeBuilders.Select(x => x.Build()); @@ -134,7 +153,7 @@ namespace Umbraco.Tests.Common.Builders 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); + var builder = CreateSimpleContentTypeHelper(alias, name, parent, randomizeAliases: randomizeAliases, propertyGroupName: propertyGroupName); builder.AddPropertyType() .WithAlias(RandomAlias("gen", randomizeAliases)) @@ -146,54 +165,70 @@ namespace Umbraco.Tests.Common.Builders .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) + public static ContentType CreateSimpleContentType(string alias = null, string name = null, IContentType parent = null, PropertyTypeCollection propertyTypeCollection = null, bool randomizeAliases = false, string propertyGroupName = "Content", bool mandatoryProperties = false, int defaultTemplateId = 0) { - return new ContentTypeBuilder() + return (ContentType)CreateSimpleContentTypeHelper(alias, name, parent, propertyTypeCollection, randomizeAliases, propertyGroupName, mandatoryProperties, defaultTemplateId).Build(); + } + + public static ContentTypeBuilder CreateSimpleContentTypeHelper(string alias = null, string name = null, IContentType parent = null, PropertyTypeCollection propertyTypeCollection = null, bool randomizeAliases = false, string propertyGroupName = "Content", bool mandatoryProperties = false, int defaultTemplateId = 0) + { + var builder = 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") + .WithParentContentType(parent); + + if (propertyTypeCollection != null) + { + builder = builder + .WithPropertyTypeCollection(propertyTypeCollection); + } + else + { + builder = builder + .AddPropertyGroup() + .WithName(propertyGroupName) .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() + .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(); + } + + builder = builder + .AddAllowedTemplate() + .WithId(defaultTemplateId) + .WithAlias("textPage") + .WithName("Textpage") .Done() - .AddAllowedTemplate() - .WithId(defaultTemplateId) - .WithAlias("textPage") - .WithName("Textpage") - .Done() - .WithDefaultTemplateId(defaultTemplateId); + .WithDefaultTemplateId(defaultTemplateId); + + return builder; } 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 contentType = CreateSimpleContentType(alias, name, parent, randomizeAliases: randomizeAliases, propertyGroupName: propertyGroupName, defaultTemplateId: defaultTemplateId); var propertyType = new PropertyTypeBuilder() .WithPropertyEditorAlias(Constants.PropertyEditors.Aliases.Tags) @@ -215,7 +250,6 @@ namespace Umbraco.Tests.Common.Builders .WithAlias(alias) .WithName(name) .AddPropertyGroup() - .WithId(1) .WithName("Content") .WithSortOrder(1) .WithSupportsPublishing(true) @@ -234,7 +268,6 @@ namespace Umbraco.Tests.Common.Builders .Done() .Done() .AddPropertyGroup() - .WithId(2) .WithName("Meta") .WithSortOrder(2) .WithSupportsPublishing(true) diff --git a/src/Umbraco.Tests.Common/Builders/PropertyBuilder.cs b/src/Umbraco.Tests.Common/Builders/PropertyBuilder.cs index 6cb7a431f2..a79141b11c 100644 --- a/src/Umbraco.Tests.Common/Builders/PropertyBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/PropertyBuilder.cs @@ -18,9 +18,18 @@ namespace Umbraco.Tests.Common.Builders private Guid? _key; private DateTime? _createDate; private DateTime? _updateDate; + private IPropertyType _propertyType; + + public PropertyBuilder WithPropertyType(IPropertyType propertyType) + { + _propertyTypeBuilder = null; + _propertyType = propertyType; + return this; + } public PropertyTypeBuilder AddPropertyType() { + _propertyType = null; var builder = new PropertyTypeBuilder(this); _propertyTypeBuilder = builder; return builder; @@ -33,8 +42,15 @@ namespace Umbraco.Tests.Common.Builders var createDate = _createDate ?? DateTime.Now; var updateDate = _updateDate ?? DateTime.Now; + if (_propertyTypeBuilder is null && _propertyType is null) + { + throw new InvalidOperationException("A property cannot be constructed without providing a property type. Use AddPropertyType() or WithPropertyType()."); + } + + var propertyType = _propertyType ?? _propertyTypeBuilder.Build(); + // Needs to be within collection to support publishing. - var propertyTypeCollection = new PropertyTypeCollection(true, new[] { _propertyTypeBuilder.Build() }); + var propertyTypeCollection = new PropertyTypeCollection(true, new[] { propertyType }); return new Property(id, propertyTypeCollection[0]) { diff --git a/src/Umbraco.Tests.Common/Builders/PropertyGroupBuilder.cs b/src/Umbraco.Tests.Common/Builders/PropertyGroupBuilder.cs index f153283764..8fe6e1463d 100644 --- a/src/Umbraco.Tests.Common/Builders/PropertyGroupBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/PropertyGroupBuilder.cs @@ -37,11 +37,18 @@ namespace Umbraco.Tests.Common.Builders private string _name; private int? _sortOrder; private bool? _supportsPublishing; + private PropertyTypeCollection _propertyTypeCollection; public PropertyGroupBuilder(TParent parentBuilder) : base(parentBuilder) { } + public PropertyGroupBuilder WithPropertyTypeCollection(PropertyTypeCollection propertyTypeCollection) + { + _propertyTypeCollection = propertyTypeCollection; + return this; + } + public PropertyTypeBuilder> AddPropertyType() { var builder = new PropertyTypeBuilder>(this); @@ -51,7 +58,7 @@ namespace Umbraco.Tests.Common.Builders public override PropertyGroup Build() { - var id = _id ?? 1; + var id = _id ?? 0; var key = _key ?? Guid.NewGuid(); var createDate = _createDate ?? DateTime.Now; var updateDate = _updateDate ?? DateTime.Now; @@ -59,13 +66,21 @@ namespace Umbraco.Tests.Common.Builders var sortOrder = _sortOrder ?? 0; var supportsPublishing = _supportsPublishing ?? false; - var properties = new PropertyTypeCollection(supportsPublishing); - foreach (var propertyType in _propertyTypeBuilders.Select(x => x.Build())) + PropertyTypeCollection propertyTypeCollection; + if (_propertyTypeCollection != null) { - properties.Add(propertyType); + propertyTypeCollection = _propertyTypeCollection; + } + else + { + propertyTypeCollection = new PropertyTypeCollection(supportsPublishing); + foreach (var propertyType in _propertyTypeBuilders.Select(x => x.Build())) + { + propertyTypeCollection.Add(propertyType); + } } - return new PropertyGroup(properties) + return new PropertyGroup(propertyTypeCollection) { Id = id, Key = key, diff --git a/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs b/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs index 954dedd3b4..78aa0c7bc6 100644 --- a/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs +++ b/src/Umbraco.Tests.Common/TestHelpers/MockedValueEditors.cs @@ -1,4 +1,4 @@ -using Moq; +using Moq; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; diff --git a/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs b/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs index 3a0ce39493..9248a45d78 100644 --- a/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs +++ b/src/Umbraco.Tests.Common/Testing/UmbracoTestAttribute.cs @@ -50,7 +50,7 @@ namespace Umbraco.Tests.Testing /// /// Default is to use the global tests plugin manager. public UmbracoTestOptions.TypeLoader TypeLoader { get => _typeLoader.ValueOrDefault(UmbracoTestOptions.TypeLoader.Default); set => _typeLoader.Set(value); } - public bool Boot { get => _boot.ValueOrDefault(true); set => _boot.Set(value); } + public bool Boot { get => _boot.ValueOrDefault(false); set => _boot.Set(value); } private readonly Settable _boot = new Settable(); diff --git a/src/Umbraco.Tests/Logging/LogviewerTests.cs b/src/Umbraco.Tests.Integration/Logging/LogviewerTests.cs similarity index 97% rename from src/Umbraco.Tests/Logging/LogviewerTests.cs rename to src/Umbraco.Tests.Integration/Logging/LogviewerTests.cs index 04d0150f75..fd861eca2e 100644 --- a/src/Umbraco.Tests/Logging/LogviewerTests.cs +++ b/src/Umbraco.Tests.Integration/Logging/LogviewerTests.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Logging.Viewer; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.Integration.Implementations; namespace Umbraco.Tests.Logging { @@ -34,10 +35,11 @@ namespace Umbraco.Tests.Logging { //Create an example JSON log file to check results //As a one time setup for all tets in this class/fixture - var ioHelper = TestHelper.IOHelper; - var hostingEnv = TestHelper.GetHostingEnvironment(); + var testHelper = new TestHelper(); + var ioHelper = testHelper.IOHelper; + var hostingEnv = testHelper.GetHostingEnvironment(); - var loggingConfiguration = TestHelper.GetLoggingConfiguration(hostingEnv); + var loggingConfiguration = testHelper.GetLoggingConfiguration(hostingEnv); var exampleLogfilePath = Path.Combine(TestContext.CurrentContext.TestDirectory, @"Logging\", _logfileName); _newLogfileDirPath = loggingConfiguration.LogDirectory; diff --git a/src/Umbraco.Tests/Logging/UmbracoTraceLog.UNITTEST.20181112.json b/src/Umbraco.Tests.Integration/Logging/UmbracoTraceLog.UNITTEST.20181112.json similarity index 100% rename from src/Umbraco.Tests/Logging/UmbracoTraceLog.UNITTEST.20181112.json rename to src/Umbraco.Tests.Integration/Logging/UmbracoTraceLog.UNITTEST.20181112.json diff --git a/src/Umbraco.Tests/Logging/logviewer.searches.config.js b/src/Umbraco.Tests.Integration/Logging/logviewer.searches.config.js similarity index 100% rename from src/Umbraco.Tests/Logging/logviewer.searches.config.js rename to src/Umbraco.Tests.Integration/Logging/logviewer.searches.config.js diff --git a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index c50d292c97..ab1d577563 100644 --- a/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/src/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -92,7 +92,8 @@ namespace Umbraco.Tests.Integration.Testing var host = hostBuilder.StartAsync().GetAwaiter().GetResult(); Services = host.Services; var app = new ApplicationBuilder(host.Services); - Configure(app); + Configure(app); //Takes around 200 ms + OnFixtureTearDown(() => host.Dispose()); } @@ -274,14 +275,13 @@ namespace Umbraco.Tests.Integration.Testing public virtual void Configure(IApplicationBuilder app) { - Services.GetRequiredService().EnsureBackOfficeSecurity(); - Services.GetRequiredService().EnsureUmbracoContext(); - - // get the currently set options + //get the currently set options var testOptions = TestOptionAttributeBase.GetTestOptions(); if (testOptions.Boot) { - app.UseUmbracoCore(); + Services.GetRequiredService().EnsureBackOfficeSecurity(); + Services.GetRequiredService().EnsureUmbracoContext(); + app.UseUmbracoCore(); // Takes 200 ms } } @@ -448,7 +448,7 @@ namespace Umbraco.Tests.Integration.Testing public TestHelper TestHelper = new TestHelper(); - protected string TestDBConnectionString { get; private set; } + protected virtual string TestDBConnectionString { get; private set; } protected virtual Action CustomTestSetup => services => { }; diff --git a/src/Umbraco.Tests.Integration/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/ContentTypeModelMappingTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Mapping/ContentTypeModelMappingTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/ContentTypeModelMappingTests.cs index 96e49e79e9..03e8f04cfc 100644 --- a/src/Umbraco.Tests.Integration/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/ContentTypeModelMappingTests.cs @@ -13,7 +13,7 @@ using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.Models.ContentEditing; -namespace Umbraco.Tests.Models.Mapping +namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping { [TestFixture] [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] @@ -756,7 +756,7 @@ namespace Umbraco.Tests.Models.Mapping Alias = "umbracoUrlName", Name = "Slug", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); ContentTypeBuilder.EnsureAllIds(ctMain, 8888); - var ctChild1 = ContentTypeBuilder.CreateSimpleContentType("child1", "Child 1", ctMain, true); + var ctChild1 = ContentTypeBuilder.CreateSimpleContentType("child1", "Child 1", ctMain, randomizeAliases: true); ctChild1.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { Alias = "someProperty", @@ -767,7 +767,7 @@ namespace Umbraco.Tests.Models.Mapping DataTypeId = -88 }, "Another tab"); ContentTypeBuilder.EnsureAllIds(ctChild1, 7777); - var contentType = ContentTypeBuilder.CreateSimpleContentType("child2", "Child 2", ctChild1, true, "CustomGroup"); + var contentType = ContentTypeBuilder.CreateSimpleContentType("child2", "Child 2", ctChild1, randomizeAliases: true, propertyGroupName: "CustomGroup"); //not assigned to tab contentType.AddPropertyType(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.TextBox, ValueStorageType.Ntext) { diff --git a/src/Umbraco.Tests.Integration/Mapping/UmbracoMapperTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Mapping/UmbracoMapperTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs index 2b26c862f0..4028889b01 100644 --- a/src/Umbraco.Tests.Integration/Mapping/UmbracoMapperTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UmbracoMapperTests.cs @@ -13,7 +13,7 @@ using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.Models.ContentEditing; -namespace Umbraco.Tests.Integration.Mapping +namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping { [TestFixture] [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Mapping/UserModelMapperTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UserModelMapperTests.cs similarity index 97% rename from src/Umbraco.Tests.Integration/Mapping/UserModelMapperTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UserModelMapperTests.cs index e24a8a74bc..f8c276d429 100644 --- a/src/Umbraco.Tests.Integration/Mapping/UserModelMapperTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/UserModelMapperTests.cs @@ -8,7 +8,7 @@ using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.Models.ContentEditing; -namespace Umbraco.Tests.Models.Mapping +namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping { [TestFixture] [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Packaging/CreatedPackagesRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Packaging/CreatedPackagesRepositoryTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs index 2500dd97a4..6f3702765e 100644 --- a/src/Umbraco.Tests.Integration/Packaging/CreatedPackagesRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/CreatedPackagesRepositoryTests.cs @@ -15,7 +15,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Packaging +namespace Umbraco.Tests.Integration.Umbraco.Core.Packaging { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] diff --git a/src/Umbraco.Tests.Integration/Packaging/Packages/Document_Type_Picker_1.1.umb b/src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/Packages/Document_Type_Picker_1.1.umb similarity index 100% rename from src/Umbraco.Tests.Integration/Packaging/Packages/Document_Type_Picker_1.1.umb rename to src/Umbraco.Tests.Integration/Umbraco.Core/Packaging/Packages/Document_Type_Picker_1.1.umb diff --git a/src/Umbraco.Tests.Integration/Services/SectionServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Services/SectionServiceTests.cs similarity index 97% rename from src/Umbraco.Tests.Integration/Services/SectionServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Core/Services/SectionServiceTests.cs index f34ea32cff..24a4e8d772 100644 --- a/src/Umbraco.Tests.Integration/Services/SectionServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Services/SectionServiceTests.cs @@ -8,7 +8,7 @@ using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.Services; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Core.Services { /// /// Tests covering the SectionService diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/AuditRepositoryTest.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/AuditRepositoryTest.cs index 24316eb931..d62e0623b1 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/AuditRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/AuditRepositoryTest.cs @@ -10,7 +10,7 @@ using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Microsoft.Extensions.Logging; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/ContentTypeRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs index f265519e28..757e79eef3 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -24,7 +24,7 @@ using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; using Umbraco.Web.Models.ContentEditing; -namespace Umbraco.Tests.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] @@ -519,8 +519,8 @@ namespace Umbraco.Tests.Persistence.Repositories { 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); + var ctChild1 = ContentTypeBuilder.CreateSimpleContentType("child1", "Child 1", ctMain, randomizeAliases: true, defaultTemplateId: 0); + var ctChild2 = ContentTypeBuilder.CreateSimpleContentType("child2", "Child 2", ctChild1, randomizeAliases: true, defaultTemplateId: 0); repository.Save(ctMain); repository.Save(ctChild1); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index 6d991117a1..5b39eb9864 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -9,7 +9,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Web.PropertyEditors; -namespace Umbraco.Tests.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DictionaryRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DictionaryRepositoryTest.cs index 4d5bdac6b4..105d7520fd 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/DictionaryRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DictionaryRepositoryTest.cs @@ -9,7 +9,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/DocumentRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs index 7dff775c8f..5cf402be26 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs @@ -5,22 +5,20 @@ 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.Models; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.PropertyEditors; 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; +using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] @@ -36,8 +34,6 @@ namespace Umbraco.Tests.Persistence.Repositories 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] @@ -45,6 +41,9 @@ namespace Umbraco.Tests.Persistence.Repositories { CreateTestData(); + // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. + global::Umbraco.Core.Services.Implement.ContentTypeService.ClearScopeEvents(); + ContentRepositoryBase.ThrowOnWarning = true; } diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/EntityRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/EntityRepositoryTest.cs similarity index 97% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/EntityRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/EntityRepositoryTest.cs index c0da3ec8cd..3fb518661c 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/EntityRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/EntityRepositoryTest.cs @@ -11,7 +11,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/KeyValueRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/KeyValueRepositoryTests.cs similarity index 96% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/KeyValueRepositoryTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/KeyValueRepositoryTests.cs index 1b5b40cf3c..93b6ee43f5 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/KeyValueRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/KeyValueRepositoryTests.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Scoping; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/LanguageRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/LanguageRepositoryTest.cs index 0b699823cb..aa9c0ddc86 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/LanguageRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/LanguageRepositoryTest.cs @@ -13,7 +13,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/MacroRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MacroRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/MacroRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MacroRepositoryTest.cs index 901d905686..e68f9584fb 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/MacroRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MacroRepositoryTest.cs @@ -10,7 +10,7 @@ using Umbraco.Core.Scoping; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/NotificationsRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/NotificationsRepositoryTest.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/NotificationsRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/NotificationsRepositoryTest.cs index 2735f869c0..f784390ced 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/NotificationsRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/NotificationsRepositoryTest.cs @@ -12,7 +12,7 @@ using Umbraco.Core.Scoping; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/RedirectUrlRepositoryTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RedirectUrlRepositoryTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/RedirectUrlRepositoryTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RedirectUrlRepositoryTests.cs index ea1a7ed8db..8ae792b92f 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/RedirectUrlRepositoryTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RedirectUrlRepositoryTests.cs @@ -11,7 +11,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/RelationRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs index 63e4ada345..1989478186 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationRepositoryTest.cs @@ -19,7 +19,7 @@ using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationTypeRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationTypeRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/RelationTypeRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationTypeRepositoryTest.cs index 6a93d73713..8d436eeeed 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/RelationTypeRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/RelationTypeRepositoryTest.cs @@ -9,7 +9,7 @@ using Umbraco.Core.Scoping; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/ServerRegistrationRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ServerRegistrationRepositoryTest.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/ServerRegistrationRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ServerRegistrationRepositoryTest.cs index 3107770672..e5304e1e31 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/ServerRegistrationRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ServerRegistrationRepositoryTest.cs @@ -10,7 +10,7 @@ using Umbraco.Core.Scoping; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/SimilarNodeNameTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/SimilarNodeNameTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/SimilarNodeNameTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/SimilarNodeNameTests.cs index b60709c8bf..8d8bae2e61 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/SimilarNodeNameTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/SimilarNodeNameTests.cs @@ -2,7 +2,7 @@ using NUnit.Framework; using Umbraco.Core.Persistence.Repositories.Implement; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] public class SimilarNodeNameTests diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs index a7894b9dc6..3452ab22ae 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs @@ -21,7 +21,7 @@ using Umbraco.Tests.Integration.Implementations; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserGroupRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserGroupRepositoryTest.cs similarity index 97% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/UserGroupRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserGroupRepositoryTest.cs index f6444fef00..e67b9f9b60 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserGroupRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserGroupRepositoryTest.cs @@ -9,7 +9,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] @@ -17,7 +17,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories { private UserGroupRepository CreateRepository(IScopeProvider provider) { - return new UserGroupRepository((IScopeAccessor) provider, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, ShortStringHelper); + return new UserGroupRepository((IScopeAccessor) provider, global::Umbraco.Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, ShortStringHelper); } [Test] @@ -128,7 +128,7 @@ namespace Umbraco.Tests.Integration.Persistence.Repositories var id = userGroup.Id; - var repository2 = new UserGroupRepository((IScopeAccessor) provider, Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, ShortStringHelper); + var repository2 = new UserGroupRepository((IScopeAccessor) provider, global::Umbraco.Core.Cache.AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, ShortStringHelper); repository2.Delete(userGroup); scope.Complete(); diff --git a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserRepositoryTest.cs index 0df619544d..b38d326b62 100644 --- a/src/Umbraco.Tests.Integration/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserRepositoryTest.cs @@ -18,7 +18,7 @@ using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Persistence.Repositories +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true, Logger = UmbracoTestOptions.Logger.Console)] diff --git a/src/Umbraco.Tests.Integration/Services/AuditServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/AuditServiceTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Services/AuditServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/AuditServiceTests.cs index 474229372c..d7385a7acf 100644 --- a/src/Umbraco.Tests.Integration/Services/AuditServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/AuditServiceTests.cs @@ -9,7 +9,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Services/CachedDataTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs similarity index 96% rename from src/Umbraco.Tests.Integration/Services/CachedDataTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs index a5b89dc2cf..89a3cdafb1 100644 --- a/src/Umbraco.Tests.Integration/Services/CachedDataTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { /// /// Tests covering the DataTypeService with cache enabled diff --git a/src/Umbraco.Tests.Integration/Services/ConsentServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ConsentServiceTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Services/ConsentServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ConsentServiceTests.cs index 3cc8666099..905697159d 100644 --- a/src/Umbraco.Tests.Integration/Services/ConsentServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ConsentServiceTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)] diff --git a/src/Umbraco.Tests.Integration/Services/ContentEventsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/ContentEventsTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs index 913ed6dd00..45b0eb0660 100644 --- a/src/Umbraco.Tests.Integration/Services/ContentEventsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs @@ -15,7 +15,7 @@ using Umbraco.Tests.Testing; using Umbraco.Web; using Umbraco.Web.Cache; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceEventTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceEventTests.cs index 74e71351af..9e1f6a6c6c 100644 --- a/src/Umbraco.Tests.Integration/Services/ContentServiceEventTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceEventTests.cs @@ -11,7 +11,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Integration.Services ContentRepositoryBase.ThrowOnWarning = true; _globalSettings = new GlobalSettings(); // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. - Umbraco.Core.Services.Implement.ContentTypeService.ClearScopeEvents(); + global::Umbraco.Core.Services.Implement.ContentTypeService.ClearScopeEvents(); CreateTestData(); } diff --git a/src/Umbraco.Tests.Integration/Services/ContentServicePerformanceTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePerformanceTest.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/ContentServicePerformanceTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePerformanceTest.cs index 273a24337a..0ac59e240c 100644 --- a/src/Umbraco.Tests.Integration/Services/ContentServicePerformanceTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePerformanceTest.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; @@ -17,7 +16,7 @@ using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Services/ContentServicePublishBranchTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePublishBranchTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/ContentServicePublishBranchTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePublishBranchTests.cs index 54103af6f1..fccd708286 100644 --- a/src/Umbraco.Tests.Integration/Services/ContentServicePublishBranchTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServicePublishBranchTests.cs @@ -11,7 +11,7 @@ using Umbraco.Tests.Testing; // ReSharper disable CommentTypo // ReSharper disable StringLiteralTypo -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] diff --git a/src/Umbraco.Tests.Integration/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/ContentServiceTagsTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs index 3cf02f6b10..6473b69d3c 100644 --- a/src/Umbraco.Tests.Integration/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs @@ -11,7 +11,7 @@ using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, diff --git a/src/Umbraco.Tests.Integration/Services/ContentServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/ContentServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs index c4ae836bec..36b5e91f34 100644 --- a/src/Umbraco.Tests.Integration/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs @@ -3,21 +3,15 @@ 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.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.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Tests.Common.Builders; @@ -25,7 +19,7 @@ using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { /// /// Tests covering all methods in the ContentService class. diff --git a/src/Umbraco.Tests.Integration/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceTests.cs similarity index 96% rename from src/Umbraco.Tests.Integration/Services/ContentTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceTests.cs index e7a3f9d066..e5234205c4 100644 --- a/src/Umbraco.Tests.Integration/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceTests.cs @@ -13,7 +13,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] @@ -358,13 +358,13 @@ namespace Umbraco.Tests.Integration.Services var global = ContentTypeBuilder.CreateSimpleContentType("global", "Global", defaultTemplateId: template.Id); ContentTypeService.Save(global); - var components = ContentTypeBuilder.CreateSimpleContentType("components", "Components", global, true, defaultTemplateId: template.Id); + var components = ContentTypeBuilder.CreateSimpleContentType("components", "Components", global, randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(components); - var component = ContentTypeBuilder.CreateSimpleContentType("component", "Component", components, true, defaultTemplateId: template.Id); + var component = ContentTypeBuilder.CreateSimpleContentType("component", "Component", components, randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(component); - var category = ContentTypeBuilder.CreateSimpleContentType("category", "Category", global, true, defaultTemplateId: template.Id); + var category = ContentTypeBuilder.CreateSimpleContentType("category", "Category", global, randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(category); var success = category.AddContentType(component); @@ -378,10 +378,10 @@ namespace Umbraco.Tests.Integration.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("page", "Page", randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(contentType); - var childContentType = ContentTypeBuilder.CreateSimpleContentType("childPage", "Child Page", contentType, true, "Child Content", defaultTemplateId: template.Id); + var childContentType = ContentTypeBuilder.CreateSimpleContentType("childPage", "Child Page", contentType, randomizeAliases: true, propertyGroupName: "Child Content", defaultTemplateId: template.Id); ContentTypeService.Save(childContentType); var content = ContentService.Create("Page 1", -1, childContentType.Alias); ContentService.Save(content); @@ -593,10 +593,10 @@ namespace Umbraco.Tests.Integration.Services var parentContentType1 = ContentTypeBuilder.CreateSimpleContentType("parent1", "Parent1", defaultTemplateId: template.Id); ContentTypeService.Save(parentContentType1); - var parentContentType2 = ContentTypeBuilder.CreateSimpleContentType("parent2", "Parent2", null, true, defaultTemplateId: template.Id); + var parentContentType2 = ContentTypeBuilder.CreateSimpleContentType("parent2", "Parent2", randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(parentContentType2); - var simpleContentType = ContentTypeBuilder.CreateSimpleContentType("category", "Category", parentContentType1, true, defaultTemplateId: template.Id) as IContentType; + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType("category", "Category", parentContentType1, randomizeAliases: true, defaultTemplateId: template.Id) as IContentType; ContentTypeService.Save(simpleContentType); // Act @@ -690,10 +690,10 @@ namespace Umbraco.Tests.Integration.Services var parentContentType1 = ContentTypeBuilder.CreateSimpleContentType("parent1", "Parent1", defaultTemplateId: template.Id); ContentTypeService.Save(parentContentType1); - var parentContentType2 = ContentTypeBuilder.CreateSimpleContentType("parent2", "Parent2", null, true, defaultTemplateId: template.Id); + var parentContentType2 = ContentTypeBuilder.CreateSimpleContentType("parent2", "Parent2", randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(parentContentType2); - var simpleContentType = ContentTypeBuilder.CreateSimpleContentType("category", "Category", parentContentType1, true, defaultTemplateId: template.Id); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType("category", "Category", parentContentType1, randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(simpleContentType); // Act @@ -733,7 +733,7 @@ namespace Umbraco.Tests.Integration.Services var parent = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: template.Id); ContentTypeService.Save(parent); - var child = ContentTypeBuilder.CreateSimpleContentType("simpleChildPage", "Simple Child Page", parent, true, defaultTemplateId: template.Id); + var child = ContentTypeBuilder.CreateSimpleContentType("simpleChildPage", "Simple Child Page", parent, randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(child); var composition = ContentTypeBuilder.CreateMetaContentType(); ContentTypeService.Save(composition); @@ -762,11 +762,11 @@ namespace Umbraco.Tests.Integration.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var basePage = ContentTypeBuilder.CreateSimpleContentType("basePage", "Base Page", null, true, defaultTemplateId: template.Id); + var basePage = ContentTypeBuilder.CreateSimpleContentType("basePage", "Base Page", randomizeAliases: 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); + var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(advancedPage); var metaComposition = ContentTypeBuilder.CreateMetaContentType(); @@ -1048,11 +1048,11 @@ namespace Umbraco.Tests.Integration.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, true, "Content", defaultTemplateId: template.Id); + var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(page); - var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content_", defaultTemplateId: template.Id); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, randomizeAliases: true, propertyGroupName: "Content_", defaultTemplateId: template.Id); ContentTypeService.Save(contentPage); - var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Details", defaultTemplateId: template.Id); + var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, randomizeAliases: true, propertyGroupName: "Details", defaultTemplateId: template.Id); ContentTypeService.Save(advancedPage); var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); @@ -1157,11 +1157,11 @@ namespace Umbraco.Tests.Integration.Services // Arrange var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var basePage = ContentTypeBuilder.CreateSimpleContentType("basePage", "Base Page", null, true, defaultTemplateId: template.Id); + var basePage = ContentTypeBuilder.CreateSimpleContentType("basePage", "Base Page", randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(basePage); - var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", basePage, true, defaultTemplateId: template.Id); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", basePage, randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(contentPage); - var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, defaultTemplateId: template.Id); + var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, randomizeAliases: true, defaultTemplateId: template.Id); ContentTypeService.Save(advancedPage); var metaComposition = ContentTypeBuilder.CreateMetaContentType(); @@ -1200,7 +1200,7 @@ namespace Umbraco.Tests.Integration.Services // create 'page' content type with a 'Content_' group var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, false, "Content_", defaultTemplateId: template.Id); + var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", propertyGroupName: "Content_", defaultTemplateId: template.Id); Assert.AreEqual(1, page.PropertyGroups.Count); Assert.AreEqual("Content_", page.PropertyGroups.First().Name); Assert.AreEqual(3, page.PropertyTypes.Count()); @@ -1210,7 +1210,7 @@ namespace Umbraco.Tests.Integration.Services ContentTypeService.Save(page); // create 'contentPage' content type as a child of 'page' - var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, true, defaultTemplateId: template.Id); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, randomizeAliases: true, defaultTemplateId: template.Id); Assert.AreEqual(1, page.PropertyGroups.Count); Assert.AreEqual("Content_", page.PropertyGroups.First().Name); Assert.AreEqual(3, contentPage.PropertyTypes.Count()); @@ -1281,11 +1281,11 @@ namespace Umbraco.Tests.Integration.Services // Arrange var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, true, "Content_", defaultTemplateId: template.Id); + var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", randomizeAliases: true, propertyGroupName: "Content_", defaultTemplateId: template.Id); ContentTypeService.Save(page); - var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, true, "Contentx", defaultTemplateId: template.Id); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, randomizeAliases: true, propertyGroupName: "Contentx", defaultTemplateId: template.Id); ContentTypeService.Save(contentPage); - var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, true, "Contenty", defaultTemplateId: template.Id); + var advancedPage = ContentTypeBuilder.CreateSimpleContentType("advancedPage", "Advanced Page", contentPage, randomizeAliases: true, propertyGroupName: "Contenty", defaultTemplateId: template.Id); ContentTypeService.Save(advancedPage); var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); @@ -1355,9 +1355,9 @@ namespace Umbraco.Tests.Integration.Services // Arrange var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", null, true, "Content_", defaultTemplateId: template.Id); + var page = ContentTypeBuilder.CreateSimpleContentType("page", "Page", randomizeAliases: true, propertyGroupName: "Content_", defaultTemplateId: template.Id); ContentTypeService.Save(page); - var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, true, "Content", defaultTemplateId: template.Id); + var contentPage = ContentTypeBuilder.CreateSimpleContentType("contentPage", "Content Page", page, randomizeAliases: true, propertyGroupName: "Content", defaultTemplateId: template.Id); ContentTypeService.Save(contentPage); var contentMetaComposition = ContentTypeBuilder.CreateContentMetaContentType(); @@ -1589,11 +1589,11 @@ namespace Umbraco.Tests.Integration.Services typeA.PropertyTypes.First(x => x.Alias.InvariantEquals("title")).Variations = ContentVariation.Culture; // with a variant property ContentTypeService.Save(typeA); - var typeB = ContentTypeBuilder.CreateSimpleContentType("b", "B", typeA, true, defaultTemplateId: template.Id); + var typeB = ContentTypeBuilder.CreateSimpleContentType("b", "B", typeA, randomizeAliases: true, defaultTemplateId: template.Id); typeB.Variations = ContentVariation.Nothing; // make it invariant ContentTypeService.Save(typeB); - var typeC = ContentTypeBuilder.CreateSimpleContentType("c", "C", typeA, true, defaultTemplateId: template.Id); + var typeC = ContentTypeBuilder.CreateSimpleContentType("c", "C", typeA, randomizeAliases: true, defaultTemplateId: template.Id); typeC.Variations = ContentVariation.Culture; // make it variant ContentTypeService.Save(typeC); @@ -1705,7 +1705,7 @@ namespace Umbraco.Tests.Integration.Services { var contentType = ContentTypeBuilder.CreateSimpleContentType("childType" + i, "ChildType" + i, //make the last entry in the list, this one's parent - list.Last(), true, defaultTemplateId: template.Id); + list.Last(), randomizeAliases: true, defaultTemplateId: template.Id); list.Add(contentType); } diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs similarity index 76% rename from src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs index 30d68d92e0..7552ff4c41 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceVariantsTests.cs @@ -2,99 +2,31 @@ 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.Configuration.Models; -using Umbraco.Core.Hosting; using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Services; -using Umbraco.Core.Strings; using Umbraco.Core.Sync; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.PublishedCache; -using Umbraco.Web.PublishedCache.NuCache; -using Umbraco.Web.PublishedCache.NuCache.DataSource; namespace Umbraco.Tests.Services { [TestFixture] [Apartment(ApartmentState.STA)] - [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] - public class ContentTypeServiceVariantsTests : TestWithSomeContentBase + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] + public class ContentTypeServiceVariantsTests : UmbracoIntegrationTest { - protected override void Compose() - { - base.Compose(); - - // pfew - see note in ScopedNuCacheTests? - Composition.RegisterUnique(); - Composition.RegisterUnique(f => Mock.Of()); - Composition.WithCollectionBuilder() - .Add(() => Composition.TypeLoader.GetCacheRefreshers()); - } - - protected override IPublishedSnapshotService CreatePublishedSnapshotService(GlobalSettings globalSettings = null) - { - var options = new PublishedSnapshotServiceOptions { IgnoreLocalDb = true }; - var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor); - var runtimeStateMock = new Mock(); - runtimeStateMock.Setup(x => x.Level).Returns(() => RuntimeLevel.Run); - - var contentTypeFactory = Factory.GetInstance(); - var documentRepository = Factory.GetInstance(); - var mediaRepository = Mock.Of(); - var memberRepository = Mock.Of(); - var hostingEnvironment = Mock.Of(); - - var typeFinder = TestHelper.GetTypeFinder(); - - var nuCacheSettings = new NuCacheSettings(); - - return new PublishedSnapshotService( - options, - null, - runtimeStateMock.Object, - ServiceContext, - contentTypeFactory, - publishedSnapshotAccessor, - Mock.Of(), - ProfilingLogger, - NullLoggerFactory.Instance, - ScopeProvider, - documentRepository, mediaRepository, memberRepository, - DefaultCultureAccessor, - new DatabaseDataSource(Mock.Of>()), - Microsoft.Extensions.Options.Options.Create(globalSettings ?? new GlobalSettings()), - Factory.GetInstance(), - Mock.Of(), - new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider(ShortStringHelper) }), - hostingEnvironment, - Mock.Of(), - IOHelper, - Microsoft.Extensions.Options.Options.Create(nuCacheSettings)); - } - - public class LocalServerMessenger : ServerMessengerBase - { - public LocalServerMessenger() - : base(false) - { } - - protected override void DeliverRemote(ICacheRefresher refresher, MessageType messageType, IEnumerable ids = null, string json = null) - { - throw new NotImplementedException(); - } - } + private ISqlContext SqlContext => GetRequiredService(); + private IContentService ContentService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + private IRedirectUrlService RedirectUrlService => GetRequiredService(); + private ILocalizationService LocalizationService => GetRequiredService(); private void AssertJsonStartsWith(int id, string expected) { @@ -134,38 +66,38 @@ namespace Umbraco.Tests.Services [TestCase(ContentVariation.CultureAndSegment, ContentVariation.CultureAndSegment, false)] public void Change_Content_Type_Variation_Clears_Redirects(ContentVariation startingContentTypeVariation, ContentVariation changedContentTypeVariation, bool shouldUrlRedirectsBeCleared) { - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = startingContentTypeVariation; - ServiceContext.ContentTypeService.Save(contentType); - var contentType2 = MockedContentTypes.CreateBasicContentType("test"); - ServiceContext.ContentTypeService.Save(contentType2); + ContentTypeService.Save(contentType); + var contentType2 = ContentTypeBuilder.CreateBasicContentType("test"); + ContentTypeService.Save(contentType2); //create some content of this content type - IContent doc = MockedContent.CreateBasicContent(contentType); + IContent doc = ContentBuilder.CreateBasicContent(contentType); doc.Name = "Hello1"; if(startingContentTypeVariation.HasFlag(ContentVariation.Culture)) { doc.SetCultureName(doc.Name, "en-US"); } - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); - IContent doc2 = MockedContent.CreateBasicContent(contentType2); - ServiceContext.ContentService.Save(doc2); + IContent doc2 = ContentBuilder.CreateBasicContent(contentType2); + ContentService.Save(doc2); - ServiceContext.RedirectUrlService.Register("hello/world", doc.Key); - ServiceContext.RedirectUrlService.Register("hello2/world2", doc2.Key); + RedirectUrlService.Register("hello/world", doc.Key); + RedirectUrlService.Register("hello2/world2", doc2.Key); // These 2 assertions should probably be moved to a test for the Register() method? - Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc.Key).Count()); - Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc2.Key).Count()); + Assert.AreEqual(1, RedirectUrlService.GetContentRedirectUrls(doc.Key).Count()); + Assert.AreEqual(1, RedirectUrlService.GetContentRedirectUrls(doc2.Key).Count()); //change variation contentType.Variations = changedContentTypeVariation; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var expectedRedirectUrlCount = shouldUrlRedirectsBeCleared ? 0 : 1; - Assert.AreEqual(expectedRedirectUrlCount, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc.Key).Count()); - Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc2.Key).Count()); + Assert.AreEqual(expectedRedirectUrlCount, RedirectUrlService.GetContentRedirectUrls(doc.Key).Count()); + Assert.AreEqual(1, RedirectUrlService.GetContentRedirectUrls(doc2.Key).Count()); } [TestCase(ContentVariation.Nothing, ContentVariation.Culture)] @@ -174,19 +106,19 @@ namespace Umbraco.Tests.Services [TestCase(ContentVariation.Segment, ContentVariation.CultureAndSegment)] public void Change_Content_Type_From_No_Culture_To_Culture(ContentVariation from, ContentVariation to) { - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = from; var properties = CreatePropertyCollection(("title", from)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); //create some content of this content type - IContent doc = MockedContent.CreateBasicContent(contentType); + IContent doc = ContentBuilder.CreateBasicContent(contentType); doc.Name = "Hello1"; doc.SetValue("title", "hello world"); - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("Hello1", doc.Name); Assert.AreEqual("hello world", doc.GetValue("title")); @@ -195,10 +127,10 @@ namespace Umbraco.Tests.Services //change the content type to be variant, we will also update the name here to detect the copy changes doc.Name = "Hello2"; - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); contentType.Variations = to; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("Hello2", doc.GetCultureName("en-US")); Assert.AreEqual("hello world", doc.GetValue("title")); //We are not checking against en-US here because properties will remain invariant @@ -207,10 +139,10 @@ namespace Umbraco.Tests.Services //change back property type to be invariant, we will also update the name here to detect the copy changes doc.SetCultureName("Hello3", "en-US"); - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); contentType.Variations = from; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("Hello3", doc.Name); Assert.AreEqual("hello world", doc.GetValue("title")); @@ -224,19 +156,19 @@ namespace Umbraco.Tests.Services [TestCase(ContentVariation.CultureAndSegment, ContentVariation.Segment)] public void Change_Content_Type_From_Culture_To_No_Culture(ContentVariation startingContentTypeVariation, ContentVariation changeContentTypeVariationTo) { - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = startingContentTypeVariation; var properties = CreatePropertyCollection(("title", startingContentTypeVariation)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); //create some content of this content type - IContent doc = MockedContent.CreateBasicContent(contentType); + IContent doc = ContentBuilder.CreateBasicContent(contentType); doc.SetCultureName("Hello1", "en-US"); doc.SetValue("title", "hello world", "en-US"); - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("Hello1", doc.GetCultureName("en-US")); Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); Assert.IsTrue(doc.Edited); @@ -244,10 +176,10 @@ namespace Umbraco.Tests.Services //change the content type to be invariant, we will also update the name here to detect the copy changes doc.SetCultureName("Hello2", "en-US"); - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); contentType.Variations = changeContentTypeVariationTo; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("Hello2", doc.Name); Assert.AreEqual("hello world", doc.GetValue("title")); @@ -256,10 +188,10 @@ namespace Umbraco.Tests.Services //change back property type to be variant, we will also update the name here to detect the copy changes doc.Name = "Hello3"; - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); contentType.Variations = startingContentTypeVariation; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get //at this stage all property types were switched to invariant so even though the variant value //exists it will not be returned because the property type is invariant, @@ -271,8 +203,8 @@ namespace Umbraco.Tests.Services //we can now switch the property type to be variant and the value can be returned again contentType.PropertyTypes.First().Variations = startingContentTypeVariation; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("Hello3", doc.GetCultureName("en-US")); Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); @@ -298,9 +230,9 @@ namespace Umbraco.Tests.Services [TestCase(ContentVariation.CultureAndSegment, ContentVariation.CultureAndSegment)] public void Preserve_Content_Name_After_Content_Type_Variation_Change(ContentVariation contentTypeVariationFrom, ContentVariation contentTypeVariationTo) { - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = contentTypeVariationFrom; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var invariantContentName = "Content Invariant"; @@ -312,12 +244,12 @@ namespace Umbraco.Tests.Services var globalSettings = new GlobalSettings(); - ServiceContext.LocalizationService.Save(new Language(globalSettings, nlCulture)); + LocalizationService.Save(new Language(globalSettings, nlCulture)); var includeCultureNames = contentType.Variations.HasFlag(ContentVariation.Culture); // Create some content of this content type - IContent doc = MockedContent.CreateBasicContent(contentType); + IContent doc = ContentBuilder.CreateBasicContent(contentType); doc.Name = invariantContentName; if (includeCultureNames) @@ -330,15 +262,15 @@ namespace Umbraco.Tests.Services Assert.Throws(() => doc.SetCultureName(nlContentName, nlCulture)); } - ServiceContext.ContentService.Save(doc); - doc = ServiceContext.ContentService.GetById(doc.Id); + ContentService.Save(doc); + doc = ContentService.GetById(doc.Id); AssertAll(); // Change variation contentType.Variations = contentTypeVariationTo; - ServiceContext.ContentService.Save(doc); - doc = ServiceContext.ContentService.GetById(doc.Id); + ContentService.Save(doc); + doc = ContentService.GetById(doc.Id); AssertAll(); @@ -378,16 +310,16 @@ namespace Umbraco.Tests.Services [TestCase(ContentVariation.CultureAndSegment, ContentVariation.CultureAndSegment)] public void Verify_If_Property_Type_Variation_Is_Correctly_Corrected_When_Content_Type_Is_Updated(ContentVariation contentTypeVariation, ContentVariation propertyTypeVariation) { - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); // We test an updated content type so it has to be saved first. - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); // Update it contentType.Variations = contentTypeVariation; var properties = CreatePropertyCollection(("title", propertyTypeVariation)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); // Check if property type variations have been updated correctly Assert.AreEqual(properties.First().Variations, contentTypeVariation & propertyTypeVariation); @@ -399,28 +331,28 @@ namespace Umbraco.Tests.Services [TestCase(ContentVariation.Segment, ContentVariation.CultureAndSegment)] public void Change_Property_Type_From_Invariant_Variant(ContentVariation invariant, ContentVariation variant) { - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); // content type supports all variations contentType.Variations = ContentVariation.Culture | ContentVariation.Segment; var properties = CreatePropertyCollection(("title", invariant)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); //create some content of this content type - IContent doc = MockedContent.CreateBasicContent(contentType); + IContent doc = ContentBuilder.CreateBasicContent(contentType); doc.SetCultureName("Home", "en-US"); doc.SetValue("title", "hello world"); - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("hello world", doc.GetValue("title")); Assert.IsTrue(doc.IsCultureEdited("en-US")); //invariant prop changes show up on default lang Assert.IsTrue(doc.Edited); //change the property type to be variant contentType.PropertyTypes.First().Variations = variant; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); Assert.IsTrue(doc.IsCultureEdited("en-US")); @@ -428,8 +360,8 @@ namespace Umbraco.Tests.Services //change back property type to be invariant contentType.PropertyTypes.First().Variations = invariant; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("hello world", doc.GetValue("title")); Assert.IsTrue(doc.IsCultureEdited("en-US")); //invariant prop changes show up on default lang @@ -443,32 +375,32 @@ namespace Umbraco.Tests.Services public void Change_Property_Type_From_Variant_Invariant(ContentVariation variant, ContentVariation invariant) { //create content type with a property type that varies by culture - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); // content type supports all variations contentType.Variations = ContentVariation.Culture | ContentVariation.Segment; var properties = CreatePropertyCollection(("title", variant)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); //create some content of this content type - IContent doc = MockedContent.CreateBasicContent(contentType); + IContent doc = ContentBuilder.CreateBasicContent(contentType); doc.SetCultureName("Home", "en-US"); doc.SetValue("title", "hello world", "en-US"); - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); //change the property type to be invariant contentType.PropertyTypes.First().Variations = invariant; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("hello world", doc.GetValue("title")); //change back property type to be variant contentType.PropertyTypes.First().Variations = variant; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); } @@ -480,44 +412,44 @@ namespace Umbraco.Tests.Services public void Change_Property_Type_From_Variant_Invariant_On_A_Composition(ContentVariation variant, ContentVariation invariant) { //create content type with a property type that varies by culture - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); // content type supports all variations contentType.Variations = ContentVariation.Culture | ContentVariation.Segment; var properties = CreatePropertyCollection(("title", variant)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); //compose this from the other one - var contentType2 = MockedContentTypes.CreateBasicContentType("test"); + var contentType2 = ContentTypeBuilder.CreateBasicContentType("test"); contentType2.Variations = contentType.Variations; contentType2.AddContentType(contentType); - ServiceContext.ContentTypeService.Save(contentType2); + ContentTypeService.Save(contentType2); //create some content of this content type - IContent doc = MockedContent.CreateBasicContent(contentType); + IContent doc = ContentBuilder.CreateBasicContent(contentType); doc.SetCultureName("Home", "en-US"); doc.SetValue("title", "hello world", "en-US"); - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); - IContent doc2 = MockedContent.CreateBasicContent(contentType2); + IContent doc2 = ContentBuilder.CreateBasicContent(contentType2); doc2.SetCultureName("Home", "en-US"); doc2.SetValue("title", "hello world", "en-US"); - ServiceContext.ContentService.Save(doc2); + ContentService.Save(doc2); //change the property type to be invariant contentType.PropertyTypes.First().Variations = invariant; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get - doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get + doc2 = ContentService.GetById(doc2.Id); //re-get Assert.AreEqual("hello world", doc.GetValue("title")); Assert.AreEqual("hello world", doc2.GetValue("title")); //change back property type to be variant contentType.PropertyTypes.First().Variations = variant; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get - doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get + doc2 = ContentService.GetById(doc2.Id); //re-get Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); Assert.AreEqual("hello world", doc2.GetValue("title", "en-US")); @@ -530,43 +462,43 @@ namespace Umbraco.Tests.Services public void Change_Content_Type_From_Variant_Invariant_On_A_Composition(ContentVariation variant, ContentVariation invariant) { //create content type with a property type that varies by culture - var contentType = MockedContentTypes.CreateBasicContentType(); + var contentType = ContentTypeBuilder.CreateBasicContentType(); contentType.Variations = variant; var properties = CreatePropertyCollection(("title", ContentVariation.Culture)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); //compose this from the other one - var contentType2 = MockedContentTypes.CreateBasicContentType("test"); + var contentType2 = ContentTypeBuilder.CreateBasicContentType("test"); contentType2.Variations = contentType.Variations; contentType2.AddContentType(contentType); - ServiceContext.ContentTypeService.Save(contentType2); + ContentTypeService.Save(contentType2); //create some content of this content type - IContent doc = MockedContent.CreateBasicContent(contentType); + IContent doc = ContentBuilder.CreateBasicContent(contentType); doc.SetCultureName("Home", "en-US"); doc.SetValue("title", "hello world", "en-US"); - ServiceContext.ContentService.Save(doc); + ContentService.Save(doc); - IContent doc2 = MockedContent.CreateBasicContent(contentType2); + IContent doc2 = ContentBuilder.CreateBasicContent(contentType2); doc2.SetCultureName("Home", "en-US"); doc2.SetValue("title", "hello world", "en-US"); - ServiceContext.ContentService.Save(doc2); + ContentService.Save(doc2); //change the content type to be invariant contentType.Variations = invariant; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get - doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get + doc2 = ContentService.GetById(doc2.Id); //re-get Assert.AreEqual("hello world", doc.GetValue("title")); Assert.AreEqual("hello world", doc2.GetValue("title")); //change back content type to be variant contentType.Variations = variant; - ServiceContext.ContentTypeService.Save(contentType); - doc = ServiceContext.ContentService.GetById(doc.Id); //re-get - doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get + ContentTypeService.Save(contentType); + doc = ContentService.GetById(doc.Id); //re-get + doc2 = ContentService.GetById(doc2.Id); //re-get //this will be null because the doc type was changed back to variant but it's property types don't get changed back Assert.IsNull(doc.GetValue("title", "en-US")); @@ -578,7 +510,7 @@ namespace Umbraco.Tests.Services { // one simple content type, variant, with both variant and invariant properties // can change it to invariant and back - + GetRequiredService(); //hack to ensure events are initialized CreateFrenchAndEnglishLangs(); var contentType = CreateContentType(ContentVariation.Culture); @@ -588,7 +520,7 @@ namespace Umbraco.Tests.Services ("value2", ContentVariation.Nothing)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var document = (IContent)new Content("document", -1, contentType); document.SetCultureName("doc1en", "en"); @@ -596,9 +528,9 @@ namespace Umbraco.Tests.Services document.SetValue("value1", "v1en", "en"); document.SetValue("value1", "v1fr", "fr"); document.SetValue("value2", "v2"); - ServiceContext.ContentService.Save(document); + ContentService.Save(document); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -612,9 +544,9 @@ namespace Umbraco.Tests.Services // switch content type to Nothing contentType.Variations = ContentVariation.Nothing; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.IsNull(document.GetCultureName("en")); Assert.IsNull(document.GetCultureName("fr")); @@ -629,9 +561,9 @@ namespace Umbraco.Tests.Services // switch content back to Culture contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -646,9 +578,9 @@ namespace Umbraco.Tests.Services // switch property back to Culture contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -658,7 +590,7 @@ namespace Umbraco.Tests.Services Console.WriteLine(GetJson(document.Id)); AssertJsonStartsWith(document.Id, - "{'pd':{'value1':[{'c':'en','v':'v1en'},{'c':'fr','v':'v1fr'}],'value2':[{'v':'v2'}]},'cd':"); + "{'pd':{'value1':[{'c':'fr','v':'v1fr'},{'c':'en','v':'v1en'}],'value2':[{'v':'v2'}]},'cd':"); } [Test] @@ -667,13 +599,14 @@ namespace Umbraco.Tests.Services // one simple content type, invariant // can change it to variant and back // can then switch one property to variant + GetRequiredService(); //hack to ensure events are initialized var globalSettings = new GlobalSettings(); var languageEn = new Language(globalSettings, "en") { IsDefault = true }; - ServiceContext.LocalizationService.Save(languageEn); + LocalizationService.Save(languageEn); var languageFr = new Language(globalSettings, "fr"); - ServiceContext.LocalizationService.Save(languageFr); + LocalizationService.Save(languageFr); var contentType = CreateContentType(ContentVariation.Nothing); @@ -682,15 +615,15 @@ namespace Umbraco.Tests.Services ("value2", ContentVariation.Nothing)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var document = (IContent) new Content("document", -1, contentType); document.Name = "doc1"; document.SetValue("value1", "v1"); document.SetValue("value2", "v2"); - ServiceContext.ContentService.Save(document); + ContentService.Save(document); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1", document.Name); Assert.IsNull(document.GetCultureName("en")); Assert.IsNull(document.GetCultureName("fr")); @@ -705,9 +638,9 @@ namespace Umbraco.Tests.Services // switch content type to Culture contentType.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1", document.GetCultureName("en")); Assert.IsNull(document.GetCultureName("fr")); Assert.IsNull(document.GetValue("value1", "en")); @@ -721,9 +654,9 @@ namespace Umbraco.Tests.Services // switch property to Culture contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1", document.GetCultureName("en")); Assert.IsNull(document.GetCultureName("fr")); Assert.AreEqual("v1", document.GetValue("value1", "en")); @@ -736,9 +669,9 @@ namespace Umbraco.Tests.Services // switch content back to Nothing contentType.Variations = ContentVariation.Nothing; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1", document.Name); Assert.IsNull(document.GetCultureName("en")); Assert.IsNull(document.GetCultureName("fr")); @@ -757,7 +690,7 @@ namespace Umbraco.Tests.Services { // one simple content type, variant, with both variant and invariant properties // can change an invariant property to variant and back - + GetRequiredService(); //hack to ensure events are initialized CreateFrenchAndEnglishLangs(); var contentType = CreateContentType(ContentVariation.Culture); @@ -767,7 +700,7 @@ namespace Umbraco.Tests.Services ("value2", ContentVariation.Nothing)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var document = (IContent)new Content("document", -1, contentType); document.SetCultureName("doc1en", "en"); @@ -775,9 +708,9 @@ namespace Umbraco.Tests.Services document.SetValue("value1", "v1en", "en"); document.SetValue("value1", "v1fr", "fr"); document.SetValue("value2", "v2"); - ServiceContext.ContentService.Save(document); + ContentService.Save(document); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -791,9 +724,9 @@ namespace Umbraco.Tests.Services // switch property type to Nothing contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Nothing; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -808,9 +741,9 @@ namespace Umbraco.Tests.Services // switch property back to Culture contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -820,13 +753,13 @@ namespace Umbraco.Tests.Services Console.WriteLine(GetJson(document.Id)); AssertJsonStartsWith(document.Id, - "{'pd':{'value1':[{'c':'en','v':'v1en'},{'c':'fr','v':'v1fr'}],'value2':[{'v':'v2'}]},'cd':"); + "{'pd':{'value1':[{'c':'fr','v':'v1fr'},{'c':'en','v':'v1en'}],'value2':[{'v':'v2'}]},'cd':"); // switch other property to Culture contentType.PropertyTypes.First(x => x.Alias == "value2").Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -838,7 +771,7 @@ namespace Umbraco.Tests.Services Console.WriteLine(GetJson(document.Id)); AssertJsonStartsWith(document.Id, - "{'pd':{'value1':[{'c':'en','v':'v1en'},{'c':'fr','v':'v1fr'}],'value2':[{'c':'en','v':'v2'}]},'cd':"); + "{'pd':{'value1':[{'c':'fr','v':'v1fr'},{'c':'en','v':'v1en'}],'value2':[{'c':'en','v':'v2'}]},'cd':"); } [TestCase(ContentVariation.Culture, ContentVariation.Nothing)] @@ -857,25 +790,25 @@ namespace Umbraco.Tests.Services var properties = CreatePropertyCollection(("value1", variant)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); IContent document = new Content("document", -1, contentType); document.SetCultureName("doc1en", "en"); document.SetCultureName("doc1fr", "fr"); document.SetValue("value1", "v1en-init", "en"); document.SetValue("value1", "v1fr-init", "fr"); - ServiceContext.ContentService.SaveAndPublish(document); //all values are published which means the document is not 'edited' + ContentService.SaveAndPublish(document); //all values are published which means the document is not 'edited' - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.IsFalse(document.IsCultureEdited("en")); Assert.IsFalse(document.IsCultureEdited("fr")); Assert.IsFalse(document.Edited); document.SetValue("value1", "v1en", "en"); //change the property culture value, so now this culture will be edited document.SetValue("value1", "v1fr", "fr"); //change the property culture value, so now this culture will be edited - ServiceContext.ContentService.Save(document); + ContentService.Save(document); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -889,18 +822,18 @@ namespace Umbraco.Tests.Services // switch property type to Invariant contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = invariant; - ServiceContext.ContentTypeService.Save(contentType); //This is going to have to re-normalize the "Edited" flag + ContentTypeService.Save(contentType); //This is going to have to re-normalize the "Edited" flag - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.IsTrue(document.IsCultureEdited("en")); //This will remain true because there is now a pending change for the invariant property data which is flagged under the default lang Assert.IsFalse(document.IsCultureEdited("fr")); //This will be false because nothing has changed for this culture and the property no longer reflects variant changes Assert.IsTrue(document.Edited); //update the invariant value and publish document.SetValue("value1", "v1inv"); - ServiceContext.ContentService.SaveAndPublish(document); + ContentService.SaveAndPublish(document); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -916,9 +849,9 @@ namespace Umbraco.Tests.Services // switch property back to Culture contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = variant; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("v1inv", document.GetValue("value1", "en")); //The invariant property value gets copied over to the default language Assert.AreEqual("v1inv", document.GetValue("value1", "en", published: true)); Assert.AreEqual("v1fr", document.GetValue("value1", "fr")); //values are still retained @@ -930,9 +863,9 @@ namespace Umbraco.Tests.Services // publish again document.SetValue("value1", "v1en2", "en"); //update the value now that it's variant again document.SetValue("value1", "v1fr2", "fr"); //update the value now that it's variant again - ServiceContext.ContentService.SaveAndPublish(document); + ContentService.SaveAndPublish(document); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -960,23 +893,23 @@ namespace Umbraco.Tests.Services var properties = CreatePropertyCollection(("value1", invariant)); contentType.PropertyGroups.Add(new PropertyGroup(properties) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); var document = (IContent)new Content("document", -1, contentType); document.SetCultureName("doc1en", "en"); document.SetCultureName("doc1fr", "fr"); document.SetValue("value1", "v1en-init"); - ServiceContext.ContentService.SaveAndPublish(document); //all values are published which means the document is not 'edited' + ContentService.SaveAndPublish(document); //all values are published which means the document is not 'edited' - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.IsFalse(document.IsCultureEdited("en")); Assert.IsFalse(document.IsCultureEdited("fr")); Assert.IsFalse(document.Edited); document.SetValue("value1", "v1en"); //change the property value, so now the invariant (default) culture will be edited - ServiceContext.ContentService.Save(document); + ContentService.Save(document); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -988,18 +921,18 @@ namespace Umbraco.Tests.Services // switch property type to Culture contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = variant; - ServiceContext.ContentTypeService.Save(contentType); //This is going to have to re-normalize the "Edited" flag + ContentTypeService.Save(contentType); //This is going to have to re-normalize the "Edited" flag - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.IsTrue(document.IsCultureEdited("en")); //Remains true Assert.IsFalse(document.IsCultureEdited("fr")); //False because no french property has ever been edited Assert.IsTrue(document.Edited); //update the culture value and publish document.SetValue("value1", "v1en2", "en"); - ServiceContext.ContentService.SaveAndPublish(document); + ContentService.SaveAndPublish(document); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("doc1en", document.Name); Assert.AreEqual("doc1en", document.GetCultureName("en")); Assert.AreEqual("doc1fr", document.GetCultureName("fr")); @@ -1013,9 +946,9 @@ namespace Umbraco.Tests.Services // switch property back to Invariant contentType.PropertyTypes.First(x => x.Alias == "value1").Variations = invariant; - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); - document = ServiceContext.ContentService.GetById(document.Id); + document = ContentService.GetById(document.Id); Assert.AreEqual("v1en2", document.GetValue("value1")); //The variant property value gets copied over to the invariant Assert.AreEqual("v1en2", document.GetValue("value1", published: true)); Assert.IsNull(document.GetValue("value1", "fr")); //The values are there but the business logic returns null @@ -1034,6 +967,8 @@ namespace Umbraco.Tests.Services // can change the composing content type to invariant and back // can change the composed content type to invariant and back + + GetRequiredService(); //hack to ensure events are initialized CreateFrenchAndEnglishLangs(); var composing = CreateContentType(ContentVariation.Culture, "composing"); @@ -1043,7 +978,7 @@ namespace Umbraco.Tests.Services ("value12", ContentVariation.Nothing)); composing.PropertyGroups.Add(new PropertyGroup(properties1) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(composing); + ContentTypeService.Save(composing); var composed = CreateContentType(ContentVariation.Culture, "composed"); @@ -1053,7 +988,7 @@ namespace Umbraco.Tests.Services composed.PropertyGroups.Add(new PropertyGroup(properties2) { Name = "Content" }); composed.AddContentType(composing); - ServiceContext.ContentTypeService.Save(composed); + ContentTypeService.Save(composed); var document = (IContent) new Content("document", -1, composed); document.SetCultureName("doc1en", "en"); @@ -1064,7 +999,7 @@ namespace Umbraco.Tests.Services document.SetValue("value21", "v21en", "en"); document.SetValue("value21", "v21fr", "fr"); document.SetValue("value22", "v22"); - ServiceContext.ContentService.Save(document); + ContentService.Save(document); // both value11 and value21 are variant Console.WriteLine(GetJson(document.Id)); @@ -1072,7 +1007,7 @@ namespace Umbraco.Tests.Services "{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); composed.Variations = ContentVariation.Nothing; - ServiceContext.ContentTypeService.Save(composed); + ContentTypeService.Save(composed); // both value11 and value21 are invariant Console.WriteLine(GetJson(document.Id)); @@ -1080,7 +1015,7 @@ namespace Umbraco.Tests.Services "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); composed.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(composed); + ContentTypeService.Save(composed); // value11 is variant again, but value21 is still invariant Console.WriteLine(GetJson(document.Id)); @@ -1088,36 +1023,36 @@ namespace Umbraco.Tests.Services "{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); composed.PropertyTypes.First(x => x.Alias == "value21").Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(composed); + ContentTypeService.Save(composed); // we can make it variant again Console.WriteLine(GetJson(document.Id)); AssertJsonStartsWith(document.Id, - "{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); + "{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'fr','v':'v21fr'},{'c':'en','v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); composing.Variations = ContentVariation.Nothing; - ServiceContext.ContentTypeService.Save(composing); + ContentTypeService.Save(composing); // value11 is invariant Console.WriteLine(GetJson(document.Id)); AssertJsonStartsWith(document.Id, - "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); + "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'fr','v':'v21fr'},{'c':'en','v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); composing.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(composing); + ContentTypeService.Save(composing); // value11 is still invariant Console.WriteLine(GetJson(document.Id)); AssertJsonStartsWith(document.Id, - "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); + "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'fr','v':'v21fr'},{'c':'en','v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); composing.PropertyTypes.First(x => x.Alias == "value11").Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(composing); + ContentTypeService.Save(composing); // we can make it variant again Console.WriteLine(GetJson(document.Id)); AssertJsonStartsWith(document.Id, - "{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); + "{'pd':{'value11':[{'c':'fr','v':'v11fr'},{'c':'en','v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'fr','v':'v21fr'},{'c':'en','v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); } [Test] @@ -1129,6 +1064,7 @@ namespace Umbraco.Tests.Services // can change the composing content type to invariant and back // can change the variant composed content type to invariant and back + GetRequiredService(); //hack to ensure events are initialized CreateFrenchAndEnglishLangs(); var composing = CreateContentType(ContentVariation.Culture, "composing"); @@ -1138,7 +1074,7 @@ namespace Umbraco.Tests.Services ("value12", ContentVariation.Nothing)); composing.PropertyGroups.Add(new PropertyGroup(properties1) { Name = "Content" }); - ServiceContext.ContentTypeService.Save(composing); + ContentTypeService.Save(composing); var composed1 = CreateContentType(ContentVariation.Culture, "composed1"); @@ -1148,7 +1084,7 @@ namespace Umbraco.Tests.Services composed1.PropertyGroups.Add(new PropertyGroup(properties2) { Name = "Content" }); composed1.AddContentType(composing); - ServiceContext.ContentTypeService.Save(composed1); + ContentTypeService.Save(composed1); var composed2 = CreateContentType(ContentVariation.Nothing, "composed2"); @@ -1158,7 +1094,7 @@ namespace Umbraco.Tests.Services composed2.PropertyGroups.Add(new PropertyGroup(properties3) { Name = "Content" }); composed2.AddContentType(composing); - ServiceContext.ContentTypeService.Save(composed2); + ContentTypeService.Save(composed2); var document1 = (IContent) new Content ("document1", -1, composed1); document1.SetCultureName("doc1en", "en"); @@ -1169,7 +1105,7 @@ namespace Umbraco.Tests.Services document1.SetValue("value21", "v21en", "en"); document1.SetValue("value21", "v21fr", "fr"); document1.SetValue("value22", "v22"); - ServiceContext.ContentService.Save(document1); + ContentService.Save(document1); var document2 = (IContent)new Content("document2", -1, composed2); document2.Name = "doc2"; @@ -1177,7 +1113,7 @@ namespace Umbraco.Tests.Services document2.SetValue("value12", "v12"); document2.SetValue("value31", "v31"); document2.SetValue("value32", "v32"); - ServiceContext.ContentService.Save(document2); + ContentService.Save(document2); // both value11 and value21 are variant Console.WriteLine(GetJson(document1.Id)); @@ -1189,7 +1125,7 @@ namespace Umbraco.Tests.Services "{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':"); composed1.Variations = ContentVariation.Nothing; - ServiceContext.ContentTypeService.Save(composed1); + ContentTypeService.Save(composed1); // both value11 and value21 are invariant Console.WriteLine(GetJson(document1.Id)); @@ -1201,7 +1137,7 @@ namespace Umbraco.Tests.Services "{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':"); composed1.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(composed1); + ContentTypeService.Save(composed1); // value11 is variant again, but value21 is still invariant Console.WriteLine(GetJson(document1.Id)); @@ -1213,48 +1149,48 @@ namespace Umbraco.Tests.Services "{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':"); composed1.PropertyTypes.First(x => x.Alias == "value21").Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(composed1); + ContentTypeService.Save(composed1); // we can make it variant again Console.WriteLine(GetJson(document1.Id)); AssertJsonStartsWith(document1.Id, - "{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); + "{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'fr','v':'v21fr'},{'c':'en','v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); Console.WriteLine(GetJson(document2.Id)); AssertJsonStartsWith(document2.Id, "{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':"); composing.Variations = ContentVariation.Nothing; - ServiceContext.ContentTypeService.Save(composing); + ContentTypeService.Save(composing); // value11 is invariant Console.WriteLine(GetJson(document1.Id)); AssertJsonStartsWith(document1.Id, - "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); + "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'fr','v':'v21fr'},{'c':'en','v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); Console.WriteLine(GetJson(document2.Id)); AssertJsonStartsWith(document2.Id, "{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':"); composing.Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(composing); + ContentTypeService.Save(composing); // value11 is still invariant Console.WriteLine(GetJson(document1.Id)); AssertJsonStartsWith(document1.Id, - "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); + "{'pd':{'value11':[{'v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'fr','v':'v21fr'},{'c':'en','v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); Console.WriteLine(GetJson(document2.Id)); AssertJsonStartsWith(document2.Id, "{'pd':{'value11':[{'v':'v11'}],'value12':[{'v':'v12'}],'value31':[{'v':'v31'}],'value32':[{'v':'v32'}]},'cd':"); composing.PropertyTypes.First(x => x.Alias == "value11").Variations = ContentVariation.Culture; - ServiceContext.ContentTypeService.Save(composing); + ContentTypeService.Save(composing); // we can make it variant again Console.WriteLine(GetJson(document1.Id)); AssertJsonStartsWith(document1.Id, - "{'pd':{'value11':[{'c':'en','v':'v11en'},{'c':'fr','v':'v11fr'}],'value12':[{'v':'v12'}],'value21':[{'c':'en','v':'v21en'},{'c':'fr','v':'v21fr'}],'value22':[{'v':'v22'}]},'cd':"); + "{'pd':{'value11':[{'c':'fr','v':'v11fr'},{'c':'en','v':'v11en'}],'value12':[{'v':'v12'}],'value21':[{'c':'fr','v':'v21fr'},{'c':'en','v':'v21en'}],'value22':[{'v':'v22'}]},'cd':"); Console.WriteLine(GetJson(document2.Id)); AssertJsonStartsWith(document2.Id, @@ -1265,9 +1201,9 @@ namespace Umbraco.Tests.Services { var globalSettings = new GlobalSettings(); var languageEn = new Language(globalSettings, "en") { IsDefault = true }; - ServiceContext.LocalizationService.Save(languageEn); + LocalizationService.Save(languageEn); var languageFr = new Language(globalSettings, "fr"); - ServiceContext.LocalizationService.Save(languageFr); + LocalizationService.Save(languageFr); } private IContentType CreateContentType(ContentVariation variance, string alias = "contentType") => new ContentType(ShortStringHelper, -1) diff --git a/src/Umbraco.Tests.Integration/Services/DataTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Services/DataTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs index 160769439d..33762f9b3c 100644 --- a/src/Umbraco.Tests.Integration/Services/DataTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs @@ -9,7 +9,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { /// /// Tests covering the DataTypeService diff --git a/src/Umbraco.Tests.Integration/Services/EntityServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/EntityServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs index 64e7cea8dc..da933bb9d7 100644 --- a/src/Umbraco.Tests.Integration/Services/EntityServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityServiceTests.cs @@ -13,7 +13,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { /// /// Tests covering the EntityService diff --git a/src/Umbraco.Tests.Integration/Services/EntityXmlSerializerTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs similarity index 96% rename from src/Umbraco.Tests.Integration/Services/EntityXmlSerializerTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs index 5bc16a4cdb..a0068f8c3d 100644 --- a/src/Umbraco.Tests.Integration/Services/EntityXmlSerializerTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/EntityXmlSerializerTests.cs @@ -7,11 +7,11 @@ using Umbraco.Core.Models; using Umbraco.Core.Services; 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.Integration.Umbraco.Infrastructure.Services.Importing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] diff --git a/src/Umbraco.Tests.Integration/Services/FileServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs similarity index 97% rename from src/Umbraco.Tests.Integration/Services/FileServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs index 8a4a0535b6..1820573cc2 100644 --- a/src/Umbraco.Tests.Integration/Services/FileServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/FileServiceTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Apartment(ApartmentState.STA)] diff --git a/src/Umbraco.Tests.Integration/Services/Importing/Dictionary-Package.xml b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Dictionary-Package.xml similarity index 100% rename from src/Umbraco.Tests.Integration/Services/Importing/Dictionary-Package.xml rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/Dictionary-Package.xml diff --git a/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs similarity index 94% rename from src/Umbraco.Tests.Integration/Services/Importing/ImportResources.Designer.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs index 4925956fb8..488108ebda 100644 --- a/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.Designer.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace Umbraco.Tests.Integration.Services.Importing { +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing { using System; @@ -39,7 +39,8 @@ namespace Umbraco.Tests.Integration.Services.Importing { 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); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Tests.Integration.Umbraco.Infrastructure.Services.Importing.ImportResourc" + + "es", typeof(ImportResources).Assembly); resourceMan = temp; } return resourceMan; diff --git a/src/Umbraco.Tests.Integration/Services/Importing/ImportResources.resx b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.resx similarity index 100% rename from src/Umbraco.Tests.Integration/Services/Importing/ImportResources.resx rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.resx diff --git a/src/Umbraco.Tests.Integration/Services/KeyValueServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/KeyValueServiceTests.cs similarity index 97% rename from src/Umbraco.Tests.Integration/Services/KeyValueServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/KeyValueServiceTests.cs index 8694e88395..8248e89dc2 100644 --- a/src/Umbraco.Tests.Integration/Services/KeyValueServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/KeyValueServiceTests.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { /// /// Tests covering methods in the KeyValueService class. diff --git a/src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/LocalizationServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/LocalizationServiceTests.cs index a2847b64fe..5076a3bbf7 100644 --- a/src/Umbraco.Tests.Integration/Services/LocalizationServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/LocalizationServiceTests.cs @@ -12,7 +12,7 @@ using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { /// /// Tests covering all methods in the LocalizationService class. diff --git a/src/Umbraco.Tests.Integration/Services/MacroServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MacroServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/MacroServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MacroServiceTests.cs index ed663207b4..d2c1e3b7fc 100644 --- a/src/Umbraco.Tests.Integration/Services/MacroServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MacroServiceTests.cs @@ -14,7 +14,7 @@ using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Apartment(ApartmentState.STA)] diff --git a/src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaServiceTests.cs index a6b67c8b59..c3a2866d2e 100644 --- a/src/Umbraco.Tests.Integration/Services/MediaServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaServiceTests.cs @@ -13,7 +13,7 @@ using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Apartment(ApartmentState.STA)] diff --git a/src/Umbraco.Tests.Integration/Services/MediaTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaTypeServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/MediaTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaTypeServiceTests.cs index 3e4bbfa611..8a38bdc6eb 100644 --- a/src/Umbraco.Tests.Integration/Services/MediaTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MediaTypeServiceTests.cs @@ -11,7 +11,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Apartment(ApartmentState.STA)] diff --git a/src/Umbraco.Tests.Integration/Services/MemberGroupServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberGroupServiceTests.cs similarity index 93% rename from src/Umbraco.Tests.Integration/Services/MemberGroupServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberGroupServiceTests.cs index 7bca819915..e0119bccb4 100644 --- a/src/Umbraco.Tests.Integration/Services/MemberGroupServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberGroupServiceTests.cs @@ -7,7 +7,7 @@ using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Apartment(ApartmentState.STA)] diff --git a/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberServiceTests.cs index 1da701bc23..d17eead162 100644 --- a/src/Umbraco.Tests.Integration/Services/MemberServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberServiceTests.cs @@ -19,7 +19,7 @@ using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; using Umbraco.Web.PublishedCache.NuCache; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Category("Slow")] @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Integration.Services public void SetupTest() { // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. - Umbraco.Core.Services.Implement.MemberTypeService.ClearScopeEvents(); + global::Umbraco.Core.Services.Implement.MemberTypeService.ClearScopeEvents(); } [Test] diff --git a/src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberTypeServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberTypeServiceTests.cs index 3c269080a5..5c61501a10 100644 --- a/src/Umbraco.Tests.Integration/Services/MemberTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberTypeServiceTests.cs @@ -9,7 +9,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Apartment(ApartmentState.STA)] @@ -23,7 +23,7 @@ namespace Umbraco.Tests.Integration.Services public void SetupTest() { // TODO: remove this once IPublishedSnapShotService has been implemented with nucache. - Umbraco.Core.Services.Implement.MemberTypeService.ClearScopeEvents(); + global::Umbraco.Core.Services.Implement.MemberTypeService.ClearScopeEvents(); } [Test] diff --git a/src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/PublicAccessServiceTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/PublicAccessServiceTests.cs index b02bdb9b70..9b46a37245 100644 --- a/src/Umbraco.Tests.Integration/Services/PublicAccessServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/PublicAccessServiceTests.cs @@ -8,7 +8,7 @@ using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Apartment(ApartmentState.STA)] diff --git a/src/Umbraco.Tests.Integration/Services/RelationServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/RelationServiceTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Services/RelationServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/RelationServiceTests.cs index 9fe4867fc2..3196b54201 100644 --- a/src/Umbraco.Tests.Integration/Services/RelationServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/RelationServiceTests.cs @@ -6,14 +6,11 @@ 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; -namespace Umbraco.Tests.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { [TestFixture] [Apartment(ApartmentState.STA)] diff --git a/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TagServiceTests.cs similarity index 98% rename from src/Umbraco.Tests.Integration/Services/TagServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TagServiceTests.cs index f84dbfb74a..a0632668aa 100644 --- a/src/Umbraco.Tests.Integration/Services/TagServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TagServiceTests.cs @@ -8,10 +8,9 @@ using Umbraco.Core.PropertyEditors; 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.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { /// /// Tests covering methods in the TagService class. diff --git a/src/Umbraco.Tests/Services/ThreadSafetyServiceTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs similarity index 90% rename from src/Umbraco.Tests/Services/ThreadSafetyServiceTest.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs index 33ee2f737a..7425cd8d2d 100644 --- a/src/Umbraco.Tests/Services/ThreadSafetyServiceTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ThreadSafetyServiceTest.cs @@ -9,6 +9,8 @@ using Umbraco.Core.Models; using Umbraco.Core.Scoping; 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; @@ -30,20 +32,20 @@ namespace Umbraco.Tests.Services [TestFixture] [Apartment(ApartmentState.STA)] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class ThreadSafetyServiceTest : TestWithDatabaseBase + public class ThreadSafetyServiceTest : UmbracoIntegrationTest { - public override void SetUp() + private IContentService ContentService => GetRequiredService(); + private IMediaService MediaService => GetRequiredService(); + private IContentTypeService ContentTypeService => GetRequiredService(); + + [SetUp] + public void SetUp() { - base.SetUp(); CreateTestData(); } - // not sure this is doing anything really - protected override string GetDbConnectionString() - { - // need a longer timeout for tests? - return base.GetDbConnectionString() + "default lock timeout=60000;"; - } + protected override string TestDBConnectionString => base.TestDBConnectionString + "default lock timeout=60000;"; + private const int MaxThreadCount = 20; @@ -99,7 +101,7 @@ namespace Umbraco.Tests.Services Assert.Ignore("Do not run on VSTS."); // the ServiceContext in that each repository in a service (i.e. ContentService) is a singleton - var contentService = (ContentService)ServiceContext.ContentService; + var contentService = (ContentService)ContentService; var threads = new List(); var exceptions = new List(); @@ -167,7 +169,7 @@ namespace Umbraco.Tests.Services if (Environment.GetEnvironmentVariable("UMBRACO_TMP") != null) Assert.Ignore("Do not run on VSTS."); // mimick the ServiceContext in that each repository in a service (i.e. ContentService) is a singleton - var mediaService = (MediaService)ServiceContext.MediaService; + var mediaService = (MediaService)MediaService; var threads = new List(); var exceptions = new List(); @@ -228,9 +230,9 @@ namespace Umbraco.Tests.Services public void CreateTestData() { // Create and Save ContentType "umbTextpage" -> 1045 - var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage", "Textpage"); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage"); contentType.Key = new Guid("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"); - ServiceContext.ContentTypeService.Save(contentType); + ContentTypeService.Save(contentType); } } } diff --git a/src/Umbraco.Tests.Integration/Services/UserServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/UserServiceTests.cs similarity index 99% rename from src/Umbraco.Tests.Integration/Services/UserServiceTests.cs rename to src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/UserServiceTests.cs index 802bfd9e1b..8b5189378d 100644 --- a/src/Umbraco.Tests.Integration/Services/UserServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/UserServiceTests.cs @@ -13,13 +13,11 @@ using Umbraco.Core.Persistence.Querying; 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.TestHelpers.Entities; using Umbraco.Tests.Testing; using Umbraco.Web.Actions; -namespace Umbraco.Tests.Integration.Services +namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services { /// /// Tests covering the UserService diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index 84e0eebd18..551d714807 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -17,11 +17,20 @@ - + + Always + + + PreserveNewest + - + + + + + @@ -68,7 +77,7 @@ - + ImportResources.resx True True @@ -76,7 +85,7 @@ - + Designer ImportResources.Designer.cs ResXFileCodeGenerator 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 60d6a0fce8..cf535d8f82 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.DependencyInjection; - using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NUnit.Framework; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs index c0d5d9af6d..f427bd9a7b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/NavigableNavigatorTests.cs @@ -10,7 +10,6 @@ using System.Xml.Xsl; using Umbraco.Core.Xml; using Umbraco.Core.Xml.XPath; using NUnit.Framework; -using Umbraco.Tests.Testing; namespace Umbraco.Tests.CoreXml { @@ -76,7 +75,6 @@ namespace Umbraco.Tests.CoreXml { // in non-native we can't have Value dump everything, else // we'd dump the entire database? Makes not much sense. - Assert.AreEqual(native ? "\n blah\n blah\n bam\n " : string.Empty, nav.Value.Lf()); // !! Assert.IsTrue(nav.MoveToFirstChild()); Assert.AreEqual("root", nav.Name); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs index bdc4e710c0..c904f7fbf9 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreXml/RenamedRootNavigatorTests.cs @@ -1,4 +1,5 @@ -using System.Xml; +using System.Runtime.InteropServices; +using System.Xml; using System.Xml.XPath; using NUnit.Framework; using Umbraco.Core.Xml.XPath; @@ -18,10 +19,10 @@ namespace Umbraco.Tests.CoreXml "); var nav = doc.CreateNavigator(); var xml = nav.OuterXml; - Assert.AreEqual(@" + Assert.AreEqual(EnsureNativeLineEndings(@" -".CrLf(), xml); +"), xml); } [Test] @@ -34,10 +35,10 @@ namespace Umbraco.Tests.CoreXml "); var nav = doc.CreateNavigator(); var xml = nav.OuterXml; - Assert.AreEqual(@" + Assert.AreEqual(EnsureNativeLineEndings(@" -".CrLf(), xml); +"), xml); } [Test] @@ -50,10 +51,16 @@ namespace Umbraco.Tests.CoreXml "); var nav = new RenamedRootNavigator(doc.CreateNavigator(), "test"); var xml = nav.OuterXml; - Assert.AreEqual(@" + Assert.AreEqual(EnsureNativeLineEndings(@" -".CrLf(), xml); +"), xml); + } + + private string EnsureNativeLineEndings(string text) + { + var useCrLf = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + return useCrLf ? text.CrLf() : text.Lf(); } [Test] @@ -66,10 +73,10 @@ namespace Umbraco.Tests.CoreXml "); var nav = new RenamedRootNavigator(doc.CreateNavigator(), "test"); var xml = nav.OuterXml; - Assert.AreEqual(@" + Assert.AreEqual(EnsureNativeLineEndings(@" -".CrLf(), xml); +"), xml); } [Test] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/ContentScheduleTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentScheduleTests.cs similarity index 98% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/ContentScheduleTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentScheduleTests.cs index 83dbfa08a5..36bf5418b3 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/ContentScheduleTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentScheduleTests.cs @@ -3,7 +3,7 @@ using System.Linq; using NUnit.Framework; using Umbraco.Core.Models; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class ContentScheduleTests diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs similarity index 69% rename from src/Umbraco.Tests/Models/ContentTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs index 8fb3f60cc8..e6adc2eb5e 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTests.cs @@ -7,62 +7,40 @@ using System.Threading; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Newtonsoft.Json; -using Umbraco.Core; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Composing.CompositionExtensions; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; -using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; -using Umbraco.Core.Services.Implement; -using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.TestHelpers.Stubs; using Umbraco.Tests.Testing; -using Umbraco.Web.PropertyEditors; -namespace Umbraco.Tests.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] - public class ContentTests : UmbracoTestBase + public class ContentTests { - private IContentTypeService _contentTypeService; - - protected override void Compose() - { - base.Compose(); - - Composition.ComposeFileSystems(); - - Composition.Register(_ => Mock.Of()); - - // all this is required so we can validate properties... - 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(); - Mock.Get(dataType).Setup(x => x.Configuration).Returns(() => new object()); - var dataTypeService = Mock.Of(); - Mock.Get(dataTypeService) - .Setup(x => x.GetDataType(It.IsAny())) - .Returns(() => dataType); - - _contentTypeService = Mock.Of(); - var mediaTypeService = Mock.Of(); - var memberTypeService = Mock.Of(); - Composition.Register(_ => ServiceContext.CreatePartial(dataTypeService: dataTypeService, contentTypeBaseServiceProvider: new ContentTypeBaseServiceProvider(_contentTypeService, mediaTypeService, memberTypeService))); - - } + private IContentTypeService _contentTypeService = Mock.Of(); [Test] public void Variant_Culture_Names_Track_Dirty_Changes() { - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "contentType" }; - contentType.Variations = ContentVariation.Culture; + var contentType = new ContentTypeBuilder() + .WithAlias("contentType") + .WithContentVariation(ContentVariation.Culture) + .Build(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + var content = new ContentBuilder() + .WithId(1) + .WithVersionId(1) + .WithName("content") + .WithContentType(contentType) + .Build(); const string langFr = "fr-FR"; @@ -88,13 +66,19 @@ namespace Umbraco.Tests.Models [Test] public void Variant_Published_Culture_Names_Track_Dirty_Changes() { - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "contentType" }; - var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + var contentType = new ContentTypeBuilder() + .WithAlias("contentType") + .WithContentVariation(ContentVariation.Culture) + .Build(); + var content = new ContentBuilder() + .WithId(1) + .WithVersionId(1) + .WithName("content") + .WithContentType(contentType) + .Build(); const string langFr = "fr-FR"; - contentType.Variations = ContentVariation.Culture; - content.ChangeContentType(contentType); Assert.IsFalse(content.IsPropertyDirty("PublishCultureInfos")); //hasn't been changed @@ -121,18 +105,25 @@ namespace Umbraco.Tests.Models [Test] public void Get_Non_Grouped_Properties() { - var contentType = MockedContentTypes.CreateSimpleContentType(); - //add non-grouped properties - contentType.AddPropertyType(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "nonGrouped1") { Name = "Non Grouped 1", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); - contentType.AddPropertyType(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "nonGrouped2") { Name = "Non Grouped 2", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 }); + var contentType = ContentTypeBuilder.CreateSimpleContentType(); - //ensure that nothing is marked as dirty + // Add non-grouped properties + var pt1 = new PropertyTypeBuilder() + .WithAlias("nonGrouped1") + .WithName("Non Grouped 1") + .Build(); + var pt2 = new PropertyTypeBuilder() + .WithAlias("nonGrouped2") + .WithName("Non Grouped 2") + .Build(); + contentType.AddPropertyType(pt1); + contentType.AddPropertyType(pt2); + + // Ensure that nothing is marked as dirty contentType.ResetDirtyProperties(false); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - - var content = MockedContent.CreateSimpleContent(contentType); - //need to id the p + var content = ContentBuilder.CreateSimpleContent(contentType); var nonGrouped = content.GetNonGroupedProperties(); @@ -143,10 +134,10 @@ namespace Umbraco.Tests.Models [Test] public void All_Dirty_Properties_Get_Reset() { - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(false); @@ -161,10 +152,10 @@ namespace Umbraco.Tests.Models public void Can_Verify_Mocked_Content() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act @@ -176,10 +167,10 @@ namespace Umbraco.Tests.Models public void Can_Change_Property_Value() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.Properties["title"].SetValue("This is the new title"); @@ -194,10 +185,10 @@ namespace Umbraco.Tests.Models public void Can_Set_Property_Value_As_String() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.SetValue("title", "This is the new title"); @@ -212,10 +203,10 @@ namespace Umbraco.Tests.Models public void Can_Clone_Content_With_Reset_Identity() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.Id = 10; content.Key = new Guid("29181B97-CB8F-403F-86DE-5FEB497F4800"); @@ -243,9 +234,9 @@ namespace Umbraco.Tests.Models public void Can_Deep_Clone_Perf_Test() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.Id = 99; - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); var i = 200; foreach (var property in content.Properties) { @@ -291,12 +282,12 @@ namespace Umbraco.Tests.Models public void Can_Deep_Clone() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.Id = 99; contentType.Variations = ContentVariation.Culture; Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.SetCultureName("Hello", "en-US"); content.SetCultureName("World", "es-ES"); @@ -313,6 +304,7 @@ namespace Umbraco.Tests.Models { property.Id = ++i; } + content.Id = 10; content.CreateDate = DateTime.Now; content.CreatorId = 22; @@ -326,8 +318,6 @@ namespace Umbraco.Tests.Models content.UpdateDate = DateTime.Now; content.WriterId = 23; - - // Act var clone = (Content)content.DeepClone(); @@ -378,20 +368,25 @@ namespace Umbraco.Tests.Models Assert.AreEqual(clone.CultureInfos[key], content.CultureInfos[key]); } - //This double verifies by reflection + // This double verifies by reflection var allProps = clone.GetType().GetProperties(); foreach (var propertyInfo in allProps) { Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(content, null)); } - //need to ensure the event handlers are wired + // Need to ensure the event handlers are wired var asDirty = (ICanBeDirty)clone; Assert.IsFalse(asDirty.IsPropertyDirty("Properties")); - var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "blah"); - var newProperty = new Property(1, propertyType); + var propertyType = new PropertyTypeBuilder() + .WithAlias("blah") + .Build(); + var newProperty = new PropertyBuilder() + .WithId(1) + .WithPropertyType(propertyType) + .Build(); newProperty.SetValue("blah"); clone.Properties.Add(newProperty); @@ -402,12 +397,12 @@ namespace Umbraco.Tests.Models public void Remember_Dirty_Properties() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.Id = 99; contentType.Variations = ContentVariation.Culture; Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.SetCultureName("Hello", "en-US"); content.SetCultureName("World", "es-ES"); @@ -418,6 +413,7 @@ namespace Umbraco.Tests.Models { property.Id = ++i; } + content.Id = 10; content.CreateDate = DateTime.Now; content.CreatorId = 22; @@ -427,7 +423,6 @@ namespace Umbraco.Tests.Models content.Path = "-1,4,10"; content.SortOrder = 5; content.TemplateId = 88; - content.Trashed = true; content.UpdateDate = DateTime.Now; content.WriterId = 23; @@ -454,6 +449,7 @@ namespace Umbraco.Tests.Models Assert.IsTrue(prop.WasDirty()); Assert.IsTrue(prop.WasPropertyDirty("Id")); } + Assert.IsTrue(content.WasPropertyDirty("CultureInfos")); foreach (var culture in content.CultureInfos) { @@ -461,6 +457,7 @@ namespace Umbraco.Tests.Models Assert.IsTrue(culture.WasPropertyDirty("Name")); Assert.IsTrue(culture.WasPropertyDirty("Date")); } + Assert.IsTrue(content.WasPropertyDirty("PublishCultureInfos")); foreach (var culture in content.PublishCultureInfos) { @@ -474,16 +471,17 @@ namespace Umbraco.Tests.Models public void Can_Serialize_Without_Error() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.Id = 99; Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); var i = 200; foreach (var property in content.Properties) { property.Id = ++i; } + content.Id = 10; content.CreateDate = DateTime.Now; content.CreatorId = 22; @@ -506,8 +504,8 @@ namespace Umbraco.Tests.Models public void Cannot_Change_Property_With_Invalid_Value() { // Arrange - var contentType = MockedContentTypes.CreateTextpageContentType(); - var content = MockedContent.CreateTextpageContent(contentType); + var contentType = ContentTypeBuilder.CreateTextpageContentType(); + var content = ContentBuilder.CreateTextpageContent(contentType); // Act var model = new TestEditorModel @@ -527,10 +525,10 @@ namespace Umbraco.Tests.Models public void Can_Change_Property_Value_Through_Anonymous_Object() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.PropertyValues(new { title = "This is the new title" }); @@ -547,10 +545,10 @@ namespace Umbraco.Tests.Models public void Can_Verify_Dirty_Property_On_Content() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.ResetDirtyProperties(); @@ -565,7 +563,7 @@ namespace Umbraco.Tests.Models public void Can_Add_PropertyGroup_On_ContentType() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); // Act contentType.PropertyGroups.Add(new PropertyGroup(true) { Name = "Test Group", SortOrder = 3 }); @@ -578,7 +576,7 @@ namespace Umbraco.Tests.Models public void Can_Remove_PropertyGroup_From_ContentType() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.ResetDirtyProperties(); // Act @@ -593,17 +591,14 @@ namespace Umbraco.Tests.Models public void Can_Add_PropertyType_To_Group_On_ContentType() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); // Act - contentType.PropertyGroups["Content"].PropertyTypes.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") - { - Name = "Subtitle", - Description = "Optional subtitle", - Mandatory = false, - SortOrder = 3, - DataTypeId = -88 - }); + var propertyType = new PropertyTypeBuilder() + .WithAlias("subtitle") + .WithName("Subtitle") + .Build(); + contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType); // Assert Assert.That(contentType.PropertyGroups["Content"].PropertyTypes.Count, Is.EqualTo(3)); @@ -613,20 +608,16 @@ namespace Umbraco.Tests.Models public void Can_Add_New_Property_To_New_PropertyType() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act - var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") - { - Name = "Subtitle", - Description = "Optional subtitle", - Mandatory = false, - SortOrder = 3, - DataTypeId = -88 - }; + var propertyType = new PropertyTypeBuilder() + .WithAlias("subtitle") + .WithName("Subtitle") + .Build(); contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType); var newProperty = new Property(propertyType); newProperty.SetValue("This is a subtitle Test"); @@ -641,20 +632,16 @@ namespace Umbraco.Tests.Models public void Can_Add_New_Property_To_New_PropertyType_In_New_PropertyGroup() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act - var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") - { - Name = "Subtitle", - Description = "Optional subtitle", - Mandatory = false, - SortOrder = 3, - DataTypeId = -88 - }; + var propertyType = new PropertyTypeBuilder() + .WithAlias("subtitle") + .WithName("Subtitle") + .Build(); var propertyGroup = new PropertyGroup(true) { Name = "Test Group", SortOrder = 3 }; propertyGroup.PropertyTypes.Add(propertyType); contentType.PropertyGroups.Add(propertyGroup); @@ -672,20 +659,16 @@ namespace Umbraco.Tests.Models public void Can_Update_PropertyType_Through_Content_Properties() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act - note that the PropertyType's properties like SortOrder is not updated through the Content object - var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "title") - { - Name = "Title", - Description = "Title description added", - Mandatory = false, - SortOrder = 10, - DataTypeId = -88 - }; + var propertyType = new PropertyTypeBuilder() + .WithAlias("title") + .WithName("Title") + .Build(); content.Properties.Add(new Property(propertyType)); // Assert @@ -698,11 +681,11 @@ namespace Umbraco.Tests.Models public void Can_Change_ContentType_On_Content() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); - var simpleContentType = MockedContentTypes.CreateSimpleContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.ChangeContentType(simpleContentType); @@ -717,11 +700,11 @@ namespace Umbraco.Tests.Models public void Can_Change_ContentType_On_Content_And_Set_Property_Value() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); - var simpleContentType = MockedContentTypes.CreateSimpleContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.ChangeContentType(simpleContentType); @@ -736,11 +719,11 @@ namespace Umbraco.Tests.Models public void Can_Change_ContentType_On_Content_And_Still_Get_Old_Properties() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); - var simpleContentType = MockedContentTypes.CreateSimpleContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); // Act content.ChangeContentType(simpleContentType); @@ -761,9 +744,9 @@ namespace Umbraco.Tests.Models //Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); //// Arrange - //var contentType = MockedContentTypes.CreateTextPageContentType(); - //var simpleContentType = MockedContentTypes.CreateSimpleContentType(); - //var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + //var contentType = ContentTypeBuilder.CreateTextPageContentType(); + //var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + //var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); //// Act //content.ChangeContentType(simpleContentType, true); @@ -777,10 +760,10 @@ namespace Umbraco.Tests.Models [Test] public void Can_Verify_Content_Is_Published() { - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "Textpage", -1); content.ResetDirtyProperties(); content.PublishedState = PublishedState.Publishing; @@ -813,7 +796,7 @@ namespace Umbraco.Tests.Models public void Adding_PropertyGroup_To_ContentType_Results_In_Dirty_Entity() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.ResetDirtyProperties(); // Act @@ -830,7 +813,7 @@ namespace Umbraco.Tests.Models public void After_Committing_Changes_Was_Dirty_Is_True() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.ResetDirtyProperties(); //reset // Act @@ -847,11 +830,11 @@ namespace Umbraco.Tests.Models public void After_Committing_Changes_Was_Dirty_Is_True_On_Changed_Property() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.ResetDirtyProperties(); //reset Mock.Get(_contentTypeService).As().Setup(x => x.Get(It.IsAny())).Returns(contentType); - var content = MockedContent.CreateTextpageContent(contentType, "test", -1); + var content = ContentBuilder.CreateTextpageContent(contentType, "test", -1); content.ResetDirtyProperties(); // Act @@ -880,7 +863,7 @@ namespace Umbraco.Tests.Models public void If_Not_Committed_Was_Dirty_Is_False() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); // Act contentType.Alias = "newAlias"; @@ -894,7 +877,7 @@ namespace Umbraco.Tests.Models public void Detect_That_A_Property_Is_Removed() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); Assert.That(contentType.WasPropertyDirty("HasPropertyTypeBeenRemoved"), Is.False); // Act @@ -908,18 +891,14 @@ namespace Umbraco.Tests.Models public void Adding_PropertyType_To_PropertyGroup_On_ContentType_Results_In_Dirty_Entity() { // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); + var contentType = ContentTypeBuilder.CreateTextPageContentType(); contentType.ResetDirtyProperties(); // Act - var propertyType = new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle") - { - Name = "Subtitle", - Description = "Optional subtitle", - Mandatory = false, - SortOrder = 3, - DataTypeId = -88 - }; + var propertyType = new PropertyTypeBuilder() + .WithAlias("subtitle") + .WithName("Subtitle") + .Build(); contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType); // Assert @@ -932,20 +911,13 @@ namespace Umbraco.Tests.Models public void Can_Compose_Composite_ContentType_Collection() { // Arrange - var simpleContentType = MockedContentTypes.CreateSimpleContentType(); - var simple2ContentType = MockedContentTypes.CreateSimpleContentType("anotherSimple", "Another Simple Page", - new PropertyTypeCollection(true, - new List - { - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "coauthor") - { - Name = "Co-Author", - Description = "Name of the Co-Author", - Mandatory = false, - SortOrder = 4, - DataTypeId = -88 - } - })); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + var propertyType = new PropertyTypeBuilder() + .WithAlias("coauthor") + .WithName("Co-author") + .Build(); + var simple2ContentType = ContentTypeBuilder.CreateSimpleContentType("anotherSimple", "Another Simple Page", + propertyTypeCollection: new PropertyTypeCollection(true, new List { propertyType })); // Act var added = simpleContentType.AddContentType(simple2ContentType); @@ -962,21 +934,14 @@ namespace Umbraco.Tests.Models public void Can_Compose_Nested_Composite_ContentType_Collection() { // Arrange - var metaContentType = MockedContentTypes.CreateMetaContentType(); - var simpleContentType = MockedContentTypes.CreateSimpleContentType(); - var simple2ContentType = MockedContentTypes.CreateSimpleContentType("anotherSimple", "Another Simple Page", - new PropertyTypeCollection(true, - new List - { - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "coauthor") - { - Name = "Co-Author", - Description = "Name of the Co-Author", - Mandatory = false, - SortOrder = 4, - DataTypeId = -88 - } - })); + var metaContentType = ContentTypeBuilder.CreateMetaContentType(); + var simpleContentType = ContentTypeBuilder.CreateSimpleContentType(); + var propertyType = new PropertyTypeBuilder() + .WithAlias("coauthor") + .WithName("Co-author") + .Build(); + var simple2ContentType = ContentTypeBuilder.CreateSimpleContentType("anotherSimple", "Another Simple Page", + propertyTypeCollection: new PropertyTypeCollection(true, new List { propertyType })); // Act var addedMeta = simple2ContentType.AddContentType(metaContentType); @@ -995,33 +960,21 @@ namespace Umbraco.Tests.Models [Test] public void Can_Avoid_Circular_Dependencies_In_Composition() { - var textPage = MockedContentTypes.CreateTextPageContentType(); - var parent = MockedContentTypes.CreateSimpleContentType("parent", "Parent", null, true); - var meta = MockedContentTypes.CreateMetaContentType(); - var mixin1 = MockedContentTypes.CreateSimpleContentType("mixin1", "Mixin1", new PropertyTypeCollection(true, - new List - { - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "coauthor") - { - Name = "Co-Author", - Description = "Name of the Co-Author", - Mandatory = false, - SortOrder = 4, - DataTypeId = -88 - } - })); - var mixin2 = MockedContentTypes.CreateSimpleContentType("mixin2", "Mixin2", new PropertyTypeCollection(true, - new List - { - new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "author") - { - Name = "Author", - Description = "Name of the Author", - Mandatory = false, - SortOrder = 4, - DataTypeId = -88 - } - })); + var textPage = ContentTypeBuilder.CreateTextPageContentType(); + var parent = ContentTypeBuilder.CreateSimpleContentType("parent", "Parent", null, randomizeAliases: true); + var meta = ContentTypeBuilder.CreateMetaContentType(); + var propertyType1 = new PropertyTypeBuilder() + .WithAlias("coauthor") + .WithName("Co-author") + .Build(); + var mixin1 = ContentTypeBuilder.CreateSimpleContentType("mixin1", "Mixin1", + propertyTypeCollection: new PropertyTypeCollection(true, new List { propertyType1 })); + var propertyType2 = new PropertyTypeBuilder() + .WithAlias("author") + .WithName("Author") + .Build(); + var mixin2 = ContentTypeBuilder.CreateSimpleContentType("mixin2", "Mixin2", + propertyTypeCollection: new PropertyTypeCollection(true, new List { propertyType2 })); // Act var addedMetaMixin2 = mixin2.AddContentType(meta); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/ContentTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTypeTests.cs similarity index 99% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/ContentTypeTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTypeTests.cs index d5ba104d78..c571a79785 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/ContentTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentTypeTests.cs @@ -3,13 +3,12 @@ using System.Diagnostics; using System.Linq; using Newtonsoft.Json; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class ContentTypeTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/CultureImpactTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/CultureImpactTests.cs similarity index 98% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/CultureImpactTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/CultureImpactTests.cs index dd782ee1c4..753c0e2b4d 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/CultureImpactTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/CultureImpactTests.cs @@ -2,7 +2,7 @@ using NUnit.Framework; using Umbraco.Core.Models; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class CultureImpactTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DeepCloneHelperTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DeepCloneHelperTests.cs similarity index 99% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DeepCloneHelperTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DeepCloneHelperTests.cs index 525b8bec0f..fcad67c221 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DeepCloneHelperTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DeepCloneHelperTests.cs @@ -5,7 +5,7 @@ using System.Linq; using NUnit.Framework; using Umbraco.Core.Models; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class DeepCloneHelperTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryItemTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryItemTests.cs similarity index 96% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryItemTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryItemTests.cs index 44a62521f3..54a935c891 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryItemTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryItemTests.cs @@ -4,7 +4,7 @@ using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class DictionaryItemTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryTranslationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryTranslationTests.cs similarity index 97% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryTranslationTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryTranslationTests.cs index 0badf150b6..957acf293e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DictionaryTranslationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DictionaryTranslationTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class DictionaryTranslationTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DocumentEntityTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DocumentEntityTests.cs similarity index 94% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DocumentEntityTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DocumentEntityTests.cs index 3f79675d06..1829720aad 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DocumentEntityTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DocumentEntityTests.cs @@ -4,7 +4,7 @@ using NUnit.Framework; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class DocumentEntityTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/LanguageTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/LanguageTests.cs similarity index 96% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/LanguageTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/LanguageTests.cs index eb2ae7235a..5b1fc2d56b 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/LanguageTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/LanguageTests.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class LanguageTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MacroTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MacroTests.cs similarity index 97% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MacroTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MacroTests.cs index 9137c67e7e..9d22387cd6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MacroTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MacroTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class MacroTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MemberGroupTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberGroupTests.cs similarity index 97% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MemberGroupTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberGroupTests.cs index 6c539c969a..47138a5fb4 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MemberGroupTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberGroupTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class MemberGroupTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MemberTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberTests.cs similarity index 97% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MemberTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberTests.cs index 8092342e90..58f88affa1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/MemberTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/MemberTests.cs @@ -1,14 +1,12 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using System.Linq; using Newtonsoft.Json; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class MemberTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyGroupTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyGroupTests.cs similarity index 97% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyGroupTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyGroupTests.cs index 81ea9d9443..08e025a6b1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyGroupTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyGroupTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class PropertyGroupTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTests.cs similarity index 96% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTests.cs index dbf0dfc2f3..ce87174d7c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTests.cs @@ -5,7 +5,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class PropertyTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTypeTests.cs similarity index 97% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyTypeTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTypeTests.cs index f2b568054c..6fa061b1d2 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PropertyTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/PropertyTypeTests.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class PropertyTypeTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTests.cs similarity index 97% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTests.cs index 3a6c85c721..fa7e540533 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class RelationTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTypeTests.cs similarity index 96% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTypeTests.cs index b96d937c72..2d5b88d945 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/RelationTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/RelationTypeTests.cs @@ -5,7 +5,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class RelationTypeTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/StylesheetTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/StylesheetTests.cs similarity index 98% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/StylesheetTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/StylesheetTests.cs index 386efcced8..f744fee829 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/StylesheetTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/StylesheetTests.cs @@ -6,7 +6,7 @@ using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class StylesheetTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/TemplateTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/TemplateTests.cs similarity index 97% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/TemplateTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/TemplateTests.cs index d76d2daed5..d1c731184e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/TemplateTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/TemplateTests.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class TemplateTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/UserExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs similarity index 98% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/UserExtensionsTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs index d3d59e77ba..faf96a6457 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/UserExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class UserExtensionsTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/UserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserTests.cs similarity index 94% rename from src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/UserTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserTests.cs index db0761b165..e4b9f89067 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/UserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using System.Linq; using Newtonsoft.Json; using NUnit.Framework; @@ -7,7 +6,7 @@ using Umbraco.Core.Models.Membership; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class UserTests diff --git a/src/Umbraco.Tests/Models/VariationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs similarity index 84% rename from src/Umbraco.Tests/Models/VariationTests.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs index df63461f4d..ec1d60ba1b 100644 --- a/src/Umbraco.Tests/Models/VariationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs @@ -3,69 +3,21 @@ using Microsoft.Extensions.Logging.Abstractions; using Moq; using NUnit.Framework; using Umbraco.Core; -using Umbraco.Core.Composing; +using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Strings; +using Umbraco.Tests.Common.Builders; +using Umbraco.Tests.Common.Builders.Extensions; using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Entities; -using Current = Umbraco.Web.Composing.Current; +using Umbraco.Web.PropertyEditors; -namespace Umbraco.Tests.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models { [TestFixture] public class VariationTests { - private IFactory _factory; - private IShortStringHelper ShortStringHelper { get; } = TestHelper.ShortStringHelper; - - [SetUp] - public void SetUp() - { - // 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 - // need to be able to retrieve them all... - - Current.Reset(); - - _factory = Mock.Of(); - - var dataTypeService = Mock.Of(); - var localizationService = Mock.Of(); - - var dataEditors = new DataEditorCollection(new IDataEditor[] - { - new DataEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()) { Alias = "editor", ExplicitValueEditor = MockedValueEditors.CreateDataValueEditor("view") } - }); - var propertyEditors = new PropertyEditorCollection(dataEditors); - - var dataType = Mock.Of(); - Mock.Get(dataType) - .Setup(x => x.Configuration) - .Returns(null); - - Mock.Get(dataTypeService) - .Setup(x => x.GetDataType(It.IsAny())) - .Returns(x => dataType); - - var serviceContext = ServiceContext.CreatePartial( - dataTypeService: dataTypeService, - localizedTextService: Mock.Of()); - - Mock.Get(_factory) - .Setup(x => x.GetInstance(It.IsAny())) - .Returns(x => - { - //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; - throw new NotSupportedException(x.FullName); - }); - } - [Test] public void ValidateVariationTests() { @@ -292,8 +244,10 @@ namespace Umbraco.Tests.Models [Test] public void ContentNames() { - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "contentType" }; - var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + var contentType = new ContentTypeBuilder() + .WithAlias("contentType") + .Build(); + var content = CreateContent(contentType); const string langFr = "fr-FR"; const string langUk = "en-UK"; @@ -305,7 +259,7 @@ namespace Umbraco.Tests.Models contentType.Variations = ContentVariation.Culture; // recreate content to re-capture content type variations - content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + content = CreateContent(contentType); // invariant name works content.Name = "name"; @@ -333,11 +287,15 @@ namespace Umbraco.Tests.Models { const string langFr = "fr-FR"; - var propertyType = new PropertyType(ShortStringHelper, "editor", ValueStorageType.Nvarchar) { Alias = "prop" }; - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "contentType" }; + var propertyType = new PropertyTypeBuilder() + .WithAlias("prop") + .Build(); + var contentType = new ContentTypeBuilder() + .WithAlias("contentType") + .Build(); contentType.AddPropertyType(propertyType); - var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + var content = CreateContent(contentType); // can set value // and get edited value, published is null @@ -419,7 +377,8 @@ namespace Umbraco.Tests.Models Assert.IsNull(content.GetValue("prop")); Assert.IsNull(content.GetValue("prop", published: true)); - var other = new Content("other", -1, contentType) { Id = 2, VersionId = 1 }; + var other = CreateContent(contentType, 2, "other"); + Assert.Throws(() => other.SetValue("prop", "o")); // don't even try other.SetValue("prop", "o1", langFr); @@ -441,26 +400,32 @@ namespace Umbraco.Tests.Models [Test] public void ContentPublishValuesWithMixedPropertyTypeVariations() { - var propertyValidationService = new PropertyValidationService( - _factory.GetInstance(), - _factory.GetInstance().DataTypeService, - _factory.GetInstance().TextService); + var propertyValidationService = GetPropertyValidationService(); const string langFr = "fr-FR"; // content type varies by Culture // prop1 varies by Culture // prop2 is invariant - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "contentType" }; + var contentType = new ContentTypeBuilder() + .WithAlias("contentType") + .Build(); contentType.Variations |= ContentVariation.Culture; - var variantPropType = new PropertyType(ShortStringHelper, "editor", ValueStorageType.Nvarchar) { Alias = "prop1", Variations = ContentVariation.Culture, Mandatory = true }; - var invariantPropType = new PropertyType(ShortStringHelper, "editor", ValueStorageType.Nvarchar) { Alias = "prop2", Variations = ContentVariation.Nothing, Mandatory = true}; - + var variantPropType = new PropertyTypeBuilder() + .WithAlias("prop1") + .WithVariations(ContentVariation.Culture) + .WithMandatory(true) + .Build(); + var invariantPropType = new PropertyTypeBuilder() + .WithAlias("prop2") + .WithVariations(ContentVariation.Nothing) + .WithMandatory(true) + .Build(); contentType.AddPropertyType(variantPropType); contentType.AddPropertyType(invariantPropType); - var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + var content = CreateContent(contentType); content.SetCultureName("hello", langFr); @@ -490,11 +455,15 @@ namespace Umbraco.Tests.Models const string langUk = "en-UK"; const string langEs = "es-ES"; - var propertyType = new PropertyType(ShortStringHelper, "editor", ValueStorageType.Nvarchar) { Alias = "prop" }; - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "contentType" }; + var propertyType = new PropertyTypeBuilder() + .WithAlias("prop") + .Build(); + var contentType = new ContentTypeBuilder() + .WithAlias("contentType") + .Build(); contentType.AddPropertyType(propertyType); - var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + var content = CreateContent(contentType); // change - now we vary by culture contentType.Variations |= ContentVariation.Culture; @@ -545,12 +514,16 @@ namespace Umbraco.Tests.Models [Test] public void IsDirtyTests() { - var propertyType = new PropertyType(ShortStringHelper, "editor", ValueStorageType.Nvarchar) { Alias = "prop" }; + var propertyType = new PropertyTypeBuilder() + .WithAlias("prop") + .Build(); var prop = new Property(propertyType); - var contentType = new ContentType(ShortStringHelper, -1) { Alias = "contentType" }; + var contentType = new ContentTypeBuilder() + .WithAlias("contentType") + .Build(); contentType.AddPropertyType(propertyType); - var content = new Content("content", -1, contentType) { Id = 1, VersionId = 1 }; + var content = CreateContent(contentType); prop.SetValue("a"); Assert.AreEqual("a", prop.GetValue()); @@ -570,17 +543,17 @@ namespace Umbraco.Tests.Models [Test] public void ValidationTests() { - var propertyType = new PropertyType(ShortStringHelper, "editor", ValueStorageType.Nvarchar) { Alias = "prop", SupportsPublishing = true }; + var propertyType = new PropertyTypeBuilder() + .WithAlias("prop") + .WithSupportsPublishing(true) + .Build(); + var prop = new Property(propertyType); prop.SetValue("a"); Assert.AreEqual("a", prop.GetValue()); Assert.IsNull(prop.GetValue(published: true)); - var propertyValidationService = new PropertyValidationService( - _factory.GetInstance(), - _factory.GetInstance().DataTypeService, - _factory.GetInstance().TextService - ); + var propertyValidationService = GetPropertyValidationService(); Assert.IsTrue(propertyValidationService.IsPropertyValid(prop)); @@ -593,5 +566,43 @@ namespace Umbraco.Tests.Models // can publish, even though invalid prop.PublishValues(); } + + private static Content CreateContent(IContentType contentType, int id = 1, string name = "content") + { + return new ContentBuilder() + .WithId(id) + .WithVersionId(1) + .WithName(name) + .WithContentType(contentType) + .Build(); + } + + private static PropertyValidationService GetPropertyValidationService() + { + var ioHelper = Mock.Of(); + var dataTypeService = Mock.Of(); + var localizedTextService = Mock.Of(); + var localizationService = Mock.Of(); + var shortStringHelper = Mock.Of(); + + var textBoxEditor = new TextboxPropertyEditor( + NullLoggerFactory.Instance, + dataTypeService, + localizationService, + ioHelper, + shortStringHelper, + localizedTextService + ); + + var mockDataTypeService = new Mock(); + Mock.Get(dataTypeService).Setup(x => x.GetDataType(It.Is(y => y == Constants.DataTypes.Textbox))) + .Returns(new DataType(textBoxEditor)); + + var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(new[] { textBoxEditor })); + return new PropertyValidationService( + propertyEditorCollection, + dataTypeService, + localizedTextService); + } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs index ad76b060ce..140173282c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Packaging/PackageExtractionTests.cs @@ -14,7 +14,7 @@ namespace Umbraco.Tests.Packaging private static FileInfo GetTestPackagePath(string packageName) { - const string testPackagesDirName = "Umbraco.Core\\Packaging\\Packages"; + var testPackagesDirName = Path.Combine("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.Infrastructure/HealthChecks/HealthCheckResultsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs index 39a9ca6211..17e528fb05 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HealthChecks/HealthCheckResultsTests.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using Umbraco.Core.Configuration.HealthChecks; +using Umbraco.Core.HealthCheck; +using Umbraco.Core.HealthCheck.Checks; +using Umbraco.Infrastructure.HealthCheck; using Umbraco.Web.HealthCheck; namespace Umbraco.Tests.Web.HealthChecks @@ -135,7 +137,7 @@ namespace Umbraco.Tests.Web.HealthChecks var results = new HealthCheckResults(checks); var resultAsMarkdown = results.ResultsAsMarkDown(HealthCheckNotificationVerbosity.Summary); - Assert.IsTrue(resultAsMarkdown.IndexOf("Result: 'Success'\r\n") > -1); + Assert.IsTrue(resultAsMarkdown.IndexOf("Result: 'Success'" + Environment.NewLine) > -1); } [Test] @@ -149,8 +151,8 @@ namespace Umbraco.Tests.Web.HealthChecks var results = new HealthCheckResults(checks); var resultAsMarkdown = results.ResultsAsMarkDown(HealthCheckNotificationVerbosity.Detailed); - Assert.IsFalse(resultAsMarkdown.IndexOf("Result: 'Success'\r\n") > -1); - Assert.IsTrue(resultAsMarkdown.IndexOf("Result: 'Success', Message: 'First check was successful'\r\n") > -1); + Assert.IsFalse(resultAsMarkdown.IndexOf("Result: 'Success'" + Environment.NewLine) > -1); + Assert.IsTrue(resultAsMarkdown.IndexOf("Result: 'Success', Message: 'First check was successful'" + Environment.NewLine) > -1); } } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Macros/MacroParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Macros/MacroParserTests.cs new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Macros/MacroParserTests.cs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestContentAppTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestContentAppTests.cs new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestContentAppTests.cs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestParserTests.cs new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Manifest/ManifestParserTests.cs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Media/ImageSharpImageUrlGeneratorTests.cs similarity index 99% rename from src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs rename to src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Media/ImageSharpImageUrlGeneratorTests.cs index a44d240ea9..febb36145b 100644 --- a/src/Umbraco.Tests/Models/ImageProcessorImageUrlGeneratorTest.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Media/ImageSharpImageUrlGeneratorTests.cs @@ -3,10 +3,10 @@ using Umbraco.Core.Models; using Umbraco.Infrastructure.Media; using Umbraco.Web.Models; -namespace Umbraco.Tests.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Media { [TestFixture] - public class ImageProcessorImageUrlGeneratorTest + public class ImageSharpImageUrlGeneratorTests { private const string MediaPath = "/media/1005/img_0671.jpg"; private static readonly ImageUrlGenerationOptions.CropCoordinates Crop = new ImageUrlGenerationOptions.CropCoordinates(0.58729977382575338m, 0.055768992440203169m, 0m, 0.32457553600198386m); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs index b94effb907..d5c5ab7fd1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/DataTypeTests.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastucture.Models { [TestFixture] public class DataTypeTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs index 117b9d87cc..a557bdf64f 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Models/PathValidationTests.cs @@ -7,7 +7,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; -namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Models +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastucture.Models { [TestFixture] public class PathValidationTests diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/StylesheetBuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/StylesheetBuilderTests.cs index a9104b5dd4..c770860b9c 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/StylesheetBuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Tests.Common/Builders/StylesheetBuilderTests.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using NUnit.Framework; using Umbraco.Core.Routing; using Umbraco.Tests.Common.Builders; @@ -24,7 +25,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Tests.Common.Builders .Build(); // Assert - Assert.AreEqual("\\css\\styles.css", stylesheet.Path); + Assert.AreEqual(Path.DirectorySeparatorChar + Path.Combine("css", "styles.css"), stylesheet.Path); Assert.AreEqual(testContent, stylesheet.Content); } } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs index e7cf097dd5..bee0b8bf15 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/FileNameTests.cs @@ -48,7 +48,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common var viewResult = await sut.Index() as ViewResult; var fileName = GetViewName(viewResult, Path.DirectorySeparatorChar.ToString()); - var views = GetUiFiles(new[] { "Umbraco", "UmbracoInstall" }); + var views = GetUiFiles(new[] { "umbraco", "UmbracoInstall" }); Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't"); } @@ -63,7 +63,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common var viewResult = sut.Index() as ViewResult; var fileName = GetViewName(viewResult); - var views = GetUiFiles(new[] { "Umbraco", "UmbracoBackOffice" }); + var views = GetUiFiles(new[] { "umbraco", "UmbracoBackOffice" }); Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't"); } @@ -85,7 +85,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common var viewResult = await sut.Default() as ViewResult; var fileName = GetViewName(viewResult); - var views = GetUiFiles(new[] { "Umbraco", "UmbracoBackOffice" }); + var views = GetUiFiles(new[] { "umbraco", "UmbracoBackOffice" }); Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't"); } @@ -94,7 +94,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common [Test] public void LanguageFilesAreLowercase() { - var files = GetUiFiles(new[] { "Umbraco", "config", "lang" }); + var files = GetUiFiles(new[] { "umbraco", "config", "lang" }); foreach (var fileName in files) { Assert.AreEqual(fileName.ToLower(), fileName, diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs index 1d9e9012e0..afa74ed213 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Macros/MacroParserTests.cs @@ -323,7 +323,7 @@ test""> Macro alias: Map -

asdfasdf

".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty)); +

asdfasdf

".NoCrLf(), result.NoCrLf()); } [Test] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs index 0ad8e2c421..b414e49e95 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/ContentModelBinderTests.cs @@ -45,17 +45,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders } [Test] - public void Does_Not_Bind_Model_When_Source_Type_Matches_Model_Type() + public void BindModel_Returns_If_Same_Type() { // Arrange - var bindingContext = CreateBindingContext(typeof(ContentModel), source: new ContentModel(CreatePublishedContent())); + var content = new ContentModel(CreatePublishedContent()); + var bindingContext = CreateBindingContext(typeof(ContentModel), source: content); var binder = new ContentModelBinder(); // Act binder.BindModelAsync(bindingContext); // Assert - Assert.False(bindingContext.Result.IsModelSet); + Assert.AreSame(content, bindingContext.Result.Model); } [Test] diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/RenderModelBinderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/RenderModelBinderTests.cs new file mode 100644 index 0000000000..501c10551d --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/ModelBinders/RenderModelBinderTests.cs @@ -0,0 +1,175 @@ +using System; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Routing; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.Common.ModelBinders; +using Umbraco.Web.Models; + +namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders +{ + [TestFixture] + public class RenderModelBinderTests + { + private ContentModelBinder _contentModelBinder; + [SetUp] + public void SetUp() + { + _contentModelBinder = new ContentModelBinder(); + } + + [Test] + [TestCase(typeof(IPublishedContent), false)] + [TestCase(typeof(ContentModel), false)] + [TestCase(typeof(MyContent), false)] + [TestCase(typeof(ContentModel), false)] + [TestCase(typeof(MyOtherContent), true)] + [TestCase(typeof(MyCustomContentModel), true)] + [TestCase(typeof(IContentModel), true)] + public void Returns_Binder_For_IPublishedContent_And_IRenderModel(Type testType, bool expectNull) + { + var binderProvider = new ContentModelBinderProvider(); + var contextMock = new Mock(); + contextMock.Setup(x => x.Metadata).Returns(new EmptyModelMetadataProvider().GetMetadataForType(testType)); + + var found = binderProvider.GetBinder(contextMock.Object); + if (expectNull) + { + Assert.IsNull(found); + } + else + { + Assert.IsNotNull(found); + } + } + + [Test] + public void BindModel_Null_Source_Returns_Null() + { + var bindingContext = new DefaultModelBindingContext(); + _contentModelBinder.BindModelAsync(bindingContext, null, typeof(MyContent)); + Assert.IsNull(bindingContext.Result.Model); + } + + [Test] + public void BindModel_Returns_If_Same_Type() + { + var content = new MyContent(Mock.Of()); + var bindingContext = new DefaultModelBindingContext(); + + _contentModelBinder.BindModelAsync(bindingContext, content, typeof(MyContent)); + + Assert.AreSame(content, bindingContext.Result.Model); + } + + [Test] + public void BindModel_RenderModel_To_IPublishedContent() + { + var content = new MyContent(Mock.Of()); + var renderModel = new ContentModel(content); + + var bindingContext = new DefaultModelBindingContext(); + _contentModelBinder.BindModelAsync(bindingContext, renderModel, typeof(IPublishedContent)); + + Assert.AreSame(content, bindingContext.Result.Model); + } + + [Test] + public void BindModel_IPublishedContent_To_RenderModel() + { + var content = new MyContent(Mock.Of()); + var bindingContext = new DefaultModelBindingContext(); + + _contentModelBinder.BindModelAsync(bindingContext, content, typeof(ContentModel)); + var bound = (IContentModel) bindingContext.Result.Model; + + Assert.AreSame(content, bound.Content); + } + + [Test] + public void BindModel_IPublishedContent_To_Generic_RenderModel() + { + var content = new MyContent(Mock.Of()); + var bindingContext = new DefaultModelBindingContext(); + + _contentModelBinder.BindModelAsync(bindingContext, content, typeof(ContentModel)); + var bound = (IContentModel) bindingContext.Result.Model; + + Assert.AreSame(content, bound.Content); + } + + [Test] + public void No_DataToken_Returns_Null() + { + var content = new MyContent(Mock.Of()); + var bindingContext = CreateBindingContext(typeof(ContentModel), false, content); + + _contentModelBinder.BindModelAsync(bindingContext); + + Assert.IsNull(bindingContext.Result.Model); + } + + [Test] + public void Invalid_DataToken_Model_Type_Returns_Null() + { + var bindingContext = CreateBindingContext(typeof(IPublishedContent), source: "Hello"); + _contentModelBinder.BindModelAsync(bindingContext); + Assert.IsNull(bindingContext.Result.Model); + } + + [Test] + public void IPublishedContent_DataToken_Model_Type_Uses_DefaultImplementation() + { + var content = new MyContent(Mock.Of()); + var bindingContext = CreateBindingContext(typeof(MyContent), source: content); + + _contentModelBinder.BindModelAsync(bindingContext); + + Assert.AreEqual(content, bindingContext.Result.Model); + } + + private ModelBindingContext CreateBindingContext(Type modelType, bool withUmbracoDataToken = true, object source = null) + { + var httpContext = new DefaultHttpContext(); + var routeData = new RouteData(); + if (withUmbracoDataToken) + routeData.DataTokens.Add(Constants.Web.UmbracoDataToken, source); + + var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor()); + var metadataProvider = new EmptyModelMetadataProvider(); + var routeValueDictionary = new RouteValueDictionary(); + var valueProvider = new RouteValueProvider(BindingSource.Path, routeValueDictionary); + return new DefaultModelBindingContext + { + ActionContext = actionContext, + ModelMetadata = metadataProvider.GetMetadataForType(modelType), + ModelName = modelType.Name, + ValueProvider = valueProvider, + }; + } + + public class MyCustomContentModel : ContentModel + { + public MyCustomContentModel(IPublishedContent content) + : base(content) + { } + } + + public class MyOtherContent + { + + } + + public class MyContent : PublishedContentWrapped + { + public MyContent(IPublishedContent content) : base(content) + { + } + } + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Views/UmbracoViewPageTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Views/UmbracoViewPageTests.cs new file mode 100644 index 0000000000..3b52d0701e --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Common/Views/UmbracoViewPageTests.cs @@ -0,0 +1,350 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using NUnit.Framework; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.Common.AspNetCore; +using Umbraco.Web.Common.ModelBinders; +using Umbraco.Web.Models; + +namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views +{ + [TestFixture] + public class UmbracoViewPageTests + { + #region RenderModel To ... + [Test] + public void RenderModel_To_RenderModel() + { + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new RenderModelTestPage(); + var viewData = GetViewDataDictionary(model); + view.ViewData = viewData; + + Assert.AreSame(model, view.Model); + } + + [Test] + public void RenderModel_ContentType1_To_ContentType1() + { + var content = new ContentType1(null); + var view = new ContentType1TestPage(); + var viewData = GetViewDataDictionary(content); + + view.ViewData = viewData; + + Assert.IsInstanceOf(view.Model); + } + + [Test] + public void RenderModel_ContentType2_To_ContentType1() + { + var content = new ContentType2(null); + var view = new ContentType1TestPage(); + + var viewData = GetViewDataDictionary(content); + view.ViewData = viewData; + + Assert.IsInstanceOf(view.Model); + } + + [Test] + public void RenderModel_ContentType1_To_ContentType2() + { + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new ContentType2TestPage(); + var viewData = GetViewDataDictionary(model); + + Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + } + + [Test] + public void RenderModel_ContentType1_To_RenderModelOf_ContentType1() + { + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new RenderModelOfContentType1TestPage(); + var viewData = GetViewDataDictionary>(model); + + view.ViewData = viewData; + + Assert.IsInstanceOf>(view.Model); + Assert.IsInstanceOf(view.Model.Content); + } + + [Test] + public void RenderModel_ContentType2_To_RenderModelOf_ContentType1() + { + var content = new ContentType2(null); + var model = new ContentModel(content); + var view = new RenderModelOfContentType1TestPage(); + var viewData = GetViewDataDictionary>(model); + view.ViewData = viewData; + + Assert.IsInstanceOf>(view.Model); + Assert.IsInstanceOf(view.Model.Content); + } + + [Test] + public void RenderModel_ContentType1_To_RenderModelOf_ContentType2() + { + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new RenderModelOfContentType2TestPage(); + var viewData = GetViewDataDictionary(model); + + Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + } + + #endregion + + #region RenderModelOf To ... + + [Test] + public void RenderModelOf_ContentType1_To_RenderModel() + { + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new RenderModelTestPage(); + var viewData = GetViewDataDictionary(model); + + view.ViewData = viewData; + + Assert.AreSame(model, view.Model); + } + + [Test] + public async Task RenderModelOf_ContentType1_To_ContentType1() + { + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new ContentType1TestPage(); + var viewData = GetViewDataDictionary>(model); + + await view.SetViewDataAsyncX(viewData); + + Assert.IsInstanceOf(view.Model); + } + + [Test] + public async Task RenderModelOf_ContentType2_To_ContentType1() + { + var content = new ContentType2(null); + var model = new ContentModel(content); + var view = new ContentType1TestPage(); + var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) + { + Model = model + }; + + await view.SetViewDataAsyncX(viewData); + + Assert.IsInstanceOf(view.Model); + } + + [Test] + public async Task RenderModelOf_ContentType1_To_ContentType2() + { + + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new ContentType2TestPage(); + var viewData = GetViewDataDictionary(model); + + Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + } + + [Test] + public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType1() + { + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new RenderModelOfContentType1TestPage(); + var viewData = GetViewDataDictionary>(model); + + view.ViewData = viewData; + + Assert.IsInstanceOf>(view.Model); + Assert.IsInstanceOf(view.Model.Content); + } + + [Test] + public async Task RenderModelOf_ContentType2_To_RenderModelOf_ContentType1() + { + var content = new ContentType2(null); + var model = new ContentModel(content); + var view = new RenderModelOfContentType1TestPage(); + var viewData = GetViewDataDictionary>(model); + + await view.SetViewDataAsyncX(viewData); + + Assert.IsInstanceOf>(view.Model); + Assert.IsInstanceOf(view.Model.Content); + } + + [Test] + public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType2() + { + var content = new ContentType1(null); + var model = new ContentModel(content); + var view = new RenderModelOfContentType2TestPage(); + var viewData = GetViewDataDictionary(model); + + Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + } + + #endregion + + #region ContentType To ... + + [Test] + public async Task ContentType1_To_RenderModel() + { + var content = new ContentType1(null); + var view = new RenderModelTestPage(); + + var viewData = GetViewDataDictionary(content); + + await view.SetViewDataAsyncX(viewData); + + Assert.IsInstanceOf(view.Model); + } + + [Test] + public async Task ContentType1_To_RenderModelOf_ContentType1() + { + var content = new ContentType1(null); + var view = new RenderModelOfContentType1TestPage(); + + var viewData = GetViewDataDictionary(content); + await view.SetViewDataAsyncX(viewData); + + Assert.IsInstanceOf>(view.Model); + Assert.IsInstanceOf(view.Model.Content); + } + + [Test] + public async Task ContentType2_To_RenderModelOf_ContentType1() + { + // Same as above but with ContentModel + var content = new ContentType2(null); + var view = new RenderModelOfContentType1TestPage(); + var viewData = GetViewDataDictionary(content); + + await view.SetViewDataAsyncX(viewData); + + Assert.IsInstanceOf>(view.Model); + Assert.IsInstanceOf(view.Model.Content); + } + + [Test] + public void ContentType1_To_RenderModelOf_ContentType2() + { + var content = new ContentType1(null); + var view = new RenderModelOfContentType2TestPage(); + var viewData = GetViewDataDictionary(content); + + Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + } + + [Test] + public async Task ContentType1_To_ContentType1() + { + var content = new ContentType1(null); + var view = new ContentType1TestPage(); + var viewData = GetViewDataDictionary(content); + + await view.SetViewDataAsyncX(viewData); + + Assert.IsInstanceOf(view.Model); + } + + [Test] + public void ContentType1_To_ContentType2() + { + var content = new ContentType1(null); + var view = new ContentType2TestPage(); + var viewData = GetViewDataDictionary(content); + + Assert.ThrowsAsync(async () => await view.SetViewDataAsyncX(viewData)); + } + + [Test] + public async Task ContentType2_To_ContentType1() + { + var content = new ContentType2(null); + var view = new ContentType1TestPage(); + var viewData = GetViewDataDictionary(content); + + await view.SetViewDataAsyncX(viewData); + + Assert.IsInstanceOf(view.Model); + } + + #endregion + + #region Test helpers methods + + private ViewDataDictionary GetViewDataDictionary(object model) + { + var sourceViewDataDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()); + return new ViewDataDictionary(sourceViewDataDictionary, model); + } + + private ViewDataDictionary GetViewDataDictionary(object model) + { + var sourceViewDataDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()); + return new ViewDataDictionary(sourceViewDataDictionary) + { + Model = model + }; + } + + #endregion + + #region Test elements + + public class ContentType1 : PublishedContentWrapped + { + public ContentType1(IPublishedContent content) : base(content) {} + } + + public class ContentType2 : ContentType1 + { + public ContentType2(IPublishedContent content) : base(content) { } + } + + public class TestPage : UmbracoViewPage + { + public override Task ExecuteAsync() + { + throw new NotImplementedException(); + } + + public async Task SetViewDataAsyncX(ViewDataDictionary viewData) + { + await SetViewDataAsync(viewData); + } + } + + public class RenderModelTestPage : TestPage + { } + + public class ContentType1TestPage : TestPage + { } + + public class ContentType2TestPage : TestPage + { } + + public class RenderModelOfContentType1TestPage : TestPage> + { } + + public class RenderModelOfContentType2TestPage : TestPage> + { } + + #endregion + } +} diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs new file mode 100644 index 0000000000..3a987fb038 --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttributeTests.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; + +namespace Umbraco.Tests.UnitTests.Umbraco.Web.Website.Controllers +{ + [TestFixture] + public class RenderIndexActionSelectorAttributeTests + { + [Test] + public void IsValidForRequest__ensure_caching_works() + { + var sut = new RenderIndexActionSelectorAttribute(); + + var actionDescriptor = + GetRenderMvcControllerIndexMethodFromCurrentType(typeof(MatchesDefaultIndexController)).First(); + var actionDescriptorCollectionProviderMock = new Mock(); + actionDescriptorCollectionProviderMock.Setup(x => x.ActionDescriptors) + .Returns(new ActionDescriptorCollection(Array.Empty(), 1)); + + var routeContext = CreateRouteContext(actionDescriptorCollectionProviderMock.Object); + + // Call the method multiple times + for (var i = 0; i < 1; i++) + { + sut.IsValidForRequest(routeContext, actionDescriptor); + } + + //Ensure the underlying ActionDescriptors is only called once. + actionDescriptorCollectionProviderMock.Verify(x=>x.ActionDescriptors, Times.Once); + } + + [Test] + [TestCase(typeof(MatchesDefaultIndexController), + "Index", new[] { typeof(ContentModel) }, typeof(IActionResult), ExpectedResult = true)] + [TestCase(typeof(MatchesOverriddenIndexController), + "Index", new[] { typeof(ContentModel) }, typeof(IActionResult), ExpectedResult = true)] + [TestCase(typeof(MatchesCustomIndexController), + "Index", new[] { typeof(ContentModel), typeof(int) }, typeof(IActionResult), ExpectedResult = false)] + [TestCase(typeof(MatchesAsyncIndexController), + "Index", new[] { typeof(ContentModel) }, typeof(Task), ExpectedResult = false)] + public bool IsValidForRequest__must_return_the_expected_result(Type controllerType, string actionName, Type[] parameterTypes, Type returnType) + { + //Fake all IActionDescriptor's that will be returned by IActionDescriptorCollectionProvider + var actionDescriptors = GetRenderMvcControllerIndexMethodFromCurrentType(controllerType); + + // Find the one that match the current request + var actualActionDescriptor = actionDescriptors.Single(x => x.ActionName == actionName + && x.ControllerTypeInfo.Name == controllerType.Name + && x.MethodInfo.ReturnType == returnType + && x.MethodInfo.GetParameters().Select(m => m.ParameterType).SequenceEqual(parameterTypes)); + + //Fake the IActionDescriptorCollectionProvider and add it to the service collection on httpcontext + var sut = new RenderIndexActionSelectorAttribute(); + + var routeContext = CreateRouteContext(new TestActionDescriptorCollectionProvider(actionDescriptors)); + + //Act + var result = sut.IsValidForRequest(routeContext, actualActionDescriptor); + return result; + } + + private ControllerActionDescriptor[] GetRenderMvcControllerIndexMethodFromCurrentType(Type controllerType) + { + var actions = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(m => !m.IsSpecialName + && m.GetCustomAttribute() is null + && m.Module.Name.Contains("Umbraco")); + + var actionDescriptors = actions + .Select(x => new ControllerActionDescriptor() + { + ControllerTypeInfo = controllerType.GetTypeInfo(), + ActionName = x.Name, + MethodInfo = x + }).ToArray(); + + return actionDescriptors; + } + + private static RouteContext CreateRouteContext(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) + { + //Fake the IActionDescriptorCollectionProvider and add it to the service collection on httpcontext + var httpContext = new DefaultHttpContext(); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton(actionDescriptorCollectionProvider); + httpContext.RequestServices = + new DefaultServiceProviderFactory(new ServiceProviderOptions()) + .CreateServiceProvider(serviceCollection); + + // Put the fake httpcontext on the route context. + var routeContext = new RouteContext(httpContext); + return routeContext; + } + + private class TestActionDescriptorCollectionProvider : IActionDescriptorCollectionProvider + { + public TestActionDescriptorCollectionProvider(IReadOnlyList items) + { + ActionDescriptors = new ActionDescriptorCollection(items, 1); + } + + public ActionDescriptorCollection ActionDescriptors { get; } + } + + private class MatchesDefaultIndexController : RenderMvcController + { + public MatchesDefaultIndexController(ILogger logger, + ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) + { + } + } + + private class MatchesOverriddenIndexController : RenderMvcController + { + public override IActionResult Index(ContentModel model) + { + return base.Index(model); + } + + public MatchesOverriddenIndexController(ILogger logger, + ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) + { + } + } + + private class MatchesCustomIndexController : RenderMvcController + { + public IActionResult Index(ContentModel model, int page) + { + return base.Index(model); + } + + public MatchesCustomIndexController(ILogger logger, + ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) + { + } + } + + private class MatchesAsyncIndexController : RenderMvcController + { + public new async Task Index(ContentModel model) + { + return await Task.FromResult(base.Index(model)); + } + + public MatchesAsyncIndexController(ILogger logger, + ICompositeViewEngine compositeViewEngine) : base(logger, compositeViewEngine) + { + } + } + } +} diff --git a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs index 00ab29bfea..342aa99b47 100644 --- a/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs +++ b/src/Umbraco.Tests/Publishing/PublishingStrategyTests.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using System.Linq; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Core.Services; using Umbraco.Tests.Testing; @@ -15,13 +16,6 @@ namespace Umbraco.Tests.Publishing [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class PublishingStrategyTests : TestWithDatabaseBase { - public override void SetUp() - { - base.SetUp(); - - //LegacyUmbracoSettings.SettingsFilePath = Current.IOHelper.MapPath(SystemDirectories.Config + Path.DirectorySeparatorChar, false); - } - private IContent _homePage; [NUnit.Framework.Ignore("fixme - ignored test")] diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 2262499347..d74a8c68fe 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -198,7 +198,7 @@ namespace Umbraco.Tests.Routing public class CustomDocumentController : RenderMvcController { 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/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 2e87628612..24abe3f774 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -136,16 +136,14 @@ - - - + @@ -169,7 +167,6 @@ - @@ -221,7 +218,6 @@ - @@ -239,9 +235,7 @@ - - @@ -287,7 +281,6 @@ - @@ -308,7 +301,6 @@ - @@ -320,7 +312,6 @@ True ImportResources.resx - @@ -428,12 +419,6 @@
- - Always - - - PreserveNewest - @@ -459,9 +444,6 @@ - - - $(NuGetPackageFolders.Split(';')[0]) @@ -474,4 +456,4 @@ - \ No newline at end of file + diff --git a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs deleted file mode 100644 index bd9b646872..0000000000 --- a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs +++ /dev/null @@ -1,216 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; -using Moq; -using NUnit.Framework; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.UmbracoSettings; -using Umbraco.Core.Logging; -using Umbraco.Core.Services; -using Umbraco.Tests.Common; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Web; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.PublishedCache; -using Umbraco.Web.Routing; -using Umbraco.Web.Security; -using Current = Umbraco.Web.Composing.Current; - -namespace Umbraco.Tests.Web.Mvc -{ - [TestFixture] - public class RenderIndexActionSelectorAttributeTests - { - [SetUp] - public void SetUp() - { - Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); - Current.Factory = Mock.Of(); - } - - [TearDown] - public void TearDown() - { - Current.Reset(); - } - - private TestObjects TestObjects = new TestObjects(null); - - private MethodInfo GetRenderMvcControllerIndexMethodFromCurrentType(Type currType) - { - return currType.GetMethods().Single(x => - { - if (x.Name != "Index") return false; - if (x.ReturnParameter == null || x.ReturnParameter.ParameterType != typeof (ActionResult)) return false; - var p = x.GetParameters(); - if (p.Length != 1) return false; - if (p[0].ParameterType != typeof (ContentModel)) return false; - return true; - }); - } - - [Test] - public void Matches_Default_Index() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var attr = new RenderIndexActionSelectorAttribute(); - var req = new RequestContext(); - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - Current.UmbracoContextAccessor, - Mock.Of(), - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; - - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); - var ctrl = new MatchesDefaultIndexController { UmbracoContextAccessor = umbracoContextAccessor }; - var controllerCtx = new ControllerContext(req, ctrl); - var result = attr.IsValidForRequest(controllerCtx, - GetRenderMvcControllerIndexMethodFromCurrentType(ctrl.GetType())); - - Assert.IsTrue(result); - } - - [Test] - public void Matches_Overriden_Index() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var attr = new RenderIndexActionSelectorAttribute(); - var req = new RequestContext(); - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - Current.UmbracoContextAccessor, - Mock.Of(), - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; - - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); - var ctrl = new MatchesOverriddenIndexController { UmbracoContextAccessor = umbracoContextAccessor }; - var controllerCtx = new ControllerContext(req, ctrl); - var result = attr.IsValidForRequest(controllerCtx, - GetRenderMvcControllerIndexMethodFromCurrentType(ctrl.GetType())); - - Assert.IsTrue(result); - } - - [Test] - public void Matches_Custom_Index() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var attr = new RenderIndexActionSelectorAttribute(); - var req = new RequestContext(); - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - Current.UmbracoContextAccessor, - Mock.Of(), - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; - - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); - var ctrl = new MatchesCustomIndexController { UmbracoContextAccessor = umbracoContextAccessor }; - var controllerCtx = new ControllerContext(req, ctrl); - var result = attr.IsValidForRequest(controllerCtx, - GetRenderMvcControllerIndexMethodFromCurrentType(ctrl.GetType())); - - Assert.IsFalse(result); - } - - [Test] - public void Matches_Async_Index_Same_Signature() - { - var globalSettings = TestObjects.GetGlobalSettings(); - var attr = new RenderIndexActionSelectorAttribute(); - var req = new RequestContext(); - var httpContextAccessor = TestHelper.GetHttpContextAccessor(); - - var umbracoContextFactory = new UmbracoContextFactory( - Current.UmbracoContextAccessor, - Mock.Of(), - new TestVariationContextAccessor(), - new TestDefaultCultureAccessor(), - globalSettings, - Mock.Of(), - TestHelper.GetHostingEnvironment(), - TestHelper.UriUtility, - httpContextAccessor, - new AspNetCookieManager(httpContextAccessor)); - - var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(); - var umbCtx = umbracoContextReference.UmbracoContext; - - var umbracoContextAccessor = new TestUmbracoContextAccessor(umbCtx); - var ctrl = new MatchesAsyncIndexController { UmbracoContextAccessor = umbracoContextAccessor }; - var controllerCtx = new ControllerContext(req, ctrl); - var result = attr.IsValidForRequest(controllerCtx, - GetRenderMvcControllerIndexMethodFromCurrentType(ctrl.GetType())); - - Assert.IsFalse(result); - } - - public class MatchesDefaultIndexController : RenderMvcController - { - } - - public class MatchesOverriddenIndexController : RenderMvcController - { - public override ActionResult Index(ContentModel model) - { - return base.Index(model); - } - } - - public class MatchesCustomIndexController : RenderMvcController - { - public ActionResult Index(ContentModel model, int page) - { - return base.Index(model); - } - } - - public class MatchesAsyncIndexController : RenderMvcController - { - public new async Task Index(ContentModel model) - { - return await Task.FromResult(base.Index(model)); - } - } - } -} diff --git a/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs deleted file mode 100644 index aa94272964..0000000000 --- a/src/Umbraco.Tests/Web/Mvc/RenderModelBinderTests.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; -using Moq; -using NUnit.Framework; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Tests.Common; -using Umbraco.Tests.TestHelpers.Stubs; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Current = Umbraco.Web.Composing.Current; - -namespace Umbraco.Tests.Web.Mvc -{ - [TestFixture] - public class RenderModelBinderTests - { - [SetUp] - public void SetUp() - { - Current.UmbracoContextAccessor = new TestUmbracoContextAccessor(); - } - - [TearDown] - public void TearDown() - { - Current.Reset(); - } - - [Test] - public void Returns_Binder_For_IPublishedContent_And_IRenderModel() - { - var binder = ContentModelBinder.Instance; - var found = binder.GetBinder(typeof (IPublishedContent)); - Assert.IsNotNull(found); - found = binder.GetBinder(typeof(ContentModel)); - Assert.IsNotNull(found); - found = binder.GetBinder(typeof(MyContent)); - Assert.IsNotNull(found); - found = binder.GetBinder(typeof(ContentModel)); - Assert.IsNotNull(found); - - found = binder.GetBinder(typeof(MyOtherContent)); - Assert.IsNull(found); - found = binder.GetBinder(typeof(MyCustomContentModel)); - Assert.IsNull(found); - found = binder.GetBinder(typeof(IContentModel)); - Assert.IsNull(found); - } - - [Test] - public void BindModel_Null_Source_Returns_Null() - { - Assert.IsNull(ContentModelBinder.BindModel(null, typeof(MyContent))); - } - - [Test] - public void BindModel_Returns_If_Same_Type() - { - var content = new MyContent(Mock.Of()); - var bound = ContentModelBinder.BindModel(content, typeof (IPublishedContent)); - Assert.AreSame(content, bound); - } - - [Test] - public void BindModel_RenderModel_To_IPublishedContent() - { - var content = new MyContent(Mock.Of()); - var renderModel = new ContentModel(content); - var bound = ContentModelBinder.BindModel(renderModel, typeof(IPublishedContent)); - Assert.AreSame(content, bound); - } - - [Test] - public void BindModel_IPublishedContent_To_RenderModel() - { - var content = new MyContent(Mock.Of()); - var bound = (IContentModel)ContentModelBinder.BindModel(content, typeof(ContentModel)); - Assert.AreSame(content, bound.Content); - } - - [Test] - public void BindModel_IPublishedContent_To_Generic_RenderModel() - { - var content = new MyContent(Mock.Of()); - var bound = (IContentModel)ContentModelBinder.BindModel(content, typeof(ContentModel)); - Assert.AreSame(content, bound.Content); - } - - [Test] - public void No_DataToken_Returns_Null() - { - var binder = ContentModelBinder.Instance; - var routeData = new RouteData(); - var result = binder.BindModel(new ControllerContext(Mock.Of(), routeData, Mock.Of()), - new ModelBindingContext()); - - Assert.IsNull(result); - } - - [Test] - public void Invalid_DataToken_Model_Type_Returns_Null() - { - var binder = ContentModelBinder.Instance; - var routeData = new RouteData(); - routeData.DataTokens[Core.Constants.Web.UmbracoDataToken] = "hello"; - - //the value provider is the default implementation - var valueProvider = new Mock(); - //also IUnvalidatedValueProvider - var invalidatedValueProvider = valueProvider.As(); - invalidatedValueProvider.Setup(x => x.GetValue(It.IsAny(), It.IsAny())).Returns(() => - new ValueProviderResult(null, "", CultureInfo.CurrentCulture)); - - var controllerCtx = new ControllerContext( - Mock.Of(http => http.Items == new Dictionary()), - routeData, - Mock.Of()); - - var result = binder.BindModel(controllerCtx, - new ModelBindingContext - { - ValueProvider = valueProvider.Object, - ModelMetadata = new ModelMetadata(new EmptyModelMetadataProvider(), null, () => null, typeof(IPublishedContent), "content") - }); - - Assert.IsNull(result); - } - - [Test] - public void IPublishedContent_DataToken_Model_Type_Uses_DefaultImplementation() - { - var content = new MyContent(Mock.Of()); - var binder = ContentModelBinder.Instance; - var routeData = new RouteData(); - routeData.DataTokens[Core.Constants.Web.UmbracoDataToken] = content; - - //the value provider is the default implementation - var valueProvider = new Mock(); - //also IUnvalidatedValueProvider - var invalidatedValueProvider = valueProvider.As(); - invalidatedValueProvider.Setup(x => x.GetValue(It.IsAny(), It.IsAny())).Returns(() => - new ValueProviderResult(content, "content", CultureInfo.CurrentCulture)); - - var controllerCtx = new ControllerContext( - Mock.Of(http => http.Items == new Dictionary()), - routeData, - Mock.Of()); - var result = binder.BindModel(controllerCtx, - new ModelBindingContext - { - ValueProvider = valueProvider.Object, - ModelMetadata = new ModelMetadata(new EmptyModelMetadataProvider(), null, () => null, typeof(IPublishedContent), "content") - }); - - Assert.AreEqual(content, result); - } - - public class MyCustomContentModel : ContentModel - { - public MyCustomContentModel(IPublishedContent content) - : base(content) - { } - } - - public class MyOtherContent - { - - } - - public class MyContent : PublishedContentWrapped - { - public MyContent(IPublishedContent content) : base(content) - { - } - } - } -} diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs deleted file mode 100644 index 44cb4fe300..0000000000 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ /dev/null @@ -1,466 +0,0 @@ -using System; -using System.Globalization; -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.Core.Configuration.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; -using Umbraco.Tests.Common; -using Umbraco.Tests.LegacyXmlPublishedCache; -using Umbraco.Tests.TestHelpers; -using Umbraco.Tests.Testing; -using Umbraco.Web; -using Umbraco.Web.Composing; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.Routing; -using Umbraco.Web.Security; - -namespace Umbraco.Tests.Web.Mvc -{ - [TestFixture] - [UmbracoTest(WithApplication = true)] - public class UmbracoViewPageTests : UmbracoTestBase - { - private XmlPublishedSnapshotService _service; - - [TearDown] - public override void TearDown() - { - if (_service == null) return; - _service.Dispose(); - _service = null; - } - - #region RenderModel To ... - - [Test] - public void RenderModel_To_RenderModel() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new RenderModelTestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.AreSame(model, view.Model); - } - - [Test] - public void RenderModel_ContentType1_To_ContentType1() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new ContentType1TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf(view.Model); - } - - [Test] - public void RenderModel_ContentType2_To_ContentType1() - { - var content = new ContentType2(null); - var model = new ContentModel(content); - var view = new ContentType1TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf(view.Model); - } - - [Test] - public void RenderModel_ContentType1_To_ContentType2() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new ContentType2TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - - Assert.Throws(() => view.SetViewDataX(viewData)); - } - - [Test] - public void RenderModel_ContentType1_To_RenderModelOf_ContentType1() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new RenderModelOfContentType1TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf>(view.Model); - Assert.IsInstanceOf(view.Model.Content); - } - - [Test] - public void RenderModel_ContentType2_To_RenderModelOf_ContentType1() - { - var content = new ContentType2(null); - var model = new ContentModel(content); - var view = new RenderModelOfContentType1TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf>(view.Model); - Assert.IsInstanceOf(view.Model.Content); - } - - [Test] - public void RenderModel_ContentType1_To_RenderModelOf_ContentType2() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new RenderModelOfContentType2TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - - Assert.Throws(() => view.SetViewDataX(viewData)); - } - - #endregion - - #region RenderModelOf To ... - - [Test] - public void RenderModelOf_ContentType1_To_RenderModel() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new RenderModelTestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.AreSame(model, view.Model); - } - - [Test] - public void RenderModelOf_ContentType1_To_ContentType1() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new ContentType1TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf(view.Model); - } - - [Test] - public void RenderModelOf_ContentType2_To_ContentType1() - { - var content = new ContentType2(null); - var model = new ContentModel(content); - var view = new ContentType1TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf(view.Model); - } - - [Test] - public void RenderModelOf_ContentType1_To_ContentType2() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new ContentType2TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - Assert.Throws(() => view.SetViewDataX(viewData)); - } - - [Test] - public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType1() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new RenderModelOfContentType1TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf>(view.Model); - Assert.IsInstanceOf(view.Model.Content); - } - - [Test] - public void RenderModelOf_ContentType2_To_RenderModelOf_ContentType1() - { - var content = new ContentType2(null); - var model = new ContentModel(content); - var view = new RenderModelOfContentType1TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf>(view.Model); - Assert.IsInstanceOf(view.Model.Content); - } - - [Test] - public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType2() - { - var content = new ContentType1(null); - var model = new ContentModel(content); - var view = new RenderModelOfContentType2TestPage(); - var viewData = new ViewDataDictionary(model); - - view.ViewContext = GetViewContext(); - Assert.Throws(() => view.SetViewDataX(viewData)); - } - - #endregion - - #region ContentType To ... - - [Test] - public void ContentType1_To_RenderModel() - { - var content = new ContentType1(null); - var view = new RenderModelTestPage(); - var viewData = new ViewDataDictionary(content); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf(view.Model); - } - - [Test] - public void ContentType1_To_RenderModelOf_ContentType1() - { - var content = new ContentType1(null); - var view = new RenderModelOfContentType1TestPage(); - var viewData = new ViewDataDictionary(content); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf>(view.Model); - Assert.IsInstanceOf(view.Model.Content); - } - - [Test] - public void ContentType2_To_RenderModelOf_ContentType1() - { - var content = new ContentType2(null); - var view = new RenderModelOfContentType1TestPage(); - var viewData = new ViewDataDictionary(content); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf>(view.Model); - Assert.IsInstanceOf(view.Model.Content); - } - - [Test] - public void ContentType1_To_RenderModelOf_ContentType2() - { - var content = new ContentType1(null); - var view = new RenderModelOfContentType2TestPage(); - var viewData = new ViewDataDictionary(content); - - view.ViewContext = GetViewContext(); - Assert.Throws(() =>view.SetViewDataX(viewData)); - } - - [Test] - public void ContentType1_To_ContentType1() - { - var content = new ContentType1(null); - var view = new ContentType1TestPage(); - var viewData = new ViewDataDictionary(content); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf(view.Model); - } - - [Test] - public void ContentType1_To_ContentType2() - { - var content = new ContentType1(null); - var view = new ContentType2TestPage(); - var viewData = new ViewDataDictionary(content); - - view.ViewContext = GetViewContext(); - Assert.Throws(() => view.SetViewDataX(viewData)); - } - - [Test] - public void ContentType2_To_ContentType1() - { - var content = new ContentType2(null); - var view = new ContentType1TestPage(); - var viewData = new ViewDataDictionary(content); - - view.ViewContext = GetViewContext(); - view.SetViewDataX(viewData); - - Assert.IsInstanceOf(view.Model); - } - - #endregion - - #region Test elements - - public class TestPage : UmbracoViewPage - { - public override void Execute() - { - throw new NotImplementedException(); - } - - public void SetViewDataX(ViewDataDictionary viewData) - { - SetViewData(viewData); - } - } - - public class RenderModelTestPage : TestPage - { } - - public class RenderModelOfContentType1TestPage : TestPage> - { } - - public class RenderModelOfContentType2TestPage : TestPage> - { } - - public class ContentType1TestPage : TestPage - { } - - public class ContentType2TestPage : TestPage - { } - - public class ContentType1 : PublishedContentWrapped - { - public ContentType1(IPublishedContent content) : base(content) {} - } - - public class ContentType2 : ContentType1 - { - public ContentType2(IPublishedContent content) : base(content) { } - } - - #endregion - - #region Test helpers - - ServiceContext GetServiceContext() - { - return TestObjects.GetServiceContextMock(); - } - - ViewContext GetViewContext() - { - var umbracoContext = GetUmbracoContext("/dang", 0); - - var webRoutingSettings = new WebRoutingSettings(); - var publishedRouter = BaseWebTest.CreatePublishedRouter(webRoutingSettings); - var frequest = publishedRouter.CreateRequest(umbracoContext, new Uri("http://localhost/dang")); - - frequest.Culture = CultureInfo.InvariantCulture; - umbracoContext.PublishedRequest = frequest; - - var context = new ViewContext(); - context.RouteData = new RouteData(); - context.RouteData.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbracoContext); - - return context; - } - - protected IUmbracoContext GetUmbracoContext(string url, int templateId, RouteData routeData = null, bool setSingleton = false) - { - var svcCtx = GetServiceContext(); - - var databaseFactory = TestObjects.GetDatabaseFactoryMock(); - - //var appCtx = new ApplicationContext( - // new DatabaseContext(databaseFactory, logger, Mock.Of(), Mock.Of()), - // svcCtx, - // CacheHelper.CreateDisabledCacheHelper(), - // new ProfilingLogger(logger, Mock.Of())) { /*IsReady = true*/ }; - - var cache = NoAppCache.Instance; - //var provider = new ScopeUnitOfWorkProvider(databaseFactory, new RepositoryFactory(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.LoggerFactory, TestObjects.GetGlobalSettings(), - TestHelper.GetHostingEnvironment(), - TestHelper.GetHostingEnvironmentLifetime(), - ShortStringHelper, - new SiteDomainHelper(), - Factory.GetInstance(), - null, true, false - ); // no events - - var http = GetHttpContextFactory(url, routeData).HttpContext; - - var httpContextAccessor = TestHelper.GetHttpContextAccessor(http); - var globalSettings = TestObjects.GetGlobalSettings(); - - var ctx = new UmbracoContext( - httpContextAccessor, - _service, - Mock.Of(), - globalSettings, - HostingEnvironment, - new TestVariationContextAccessor(), - UriUtility, - new AspNetCookieManager(httpContextAccessor)); - - //if (setSingleton) - //{ - // UmbracoContext.Current = ctx; - //} - - return ctx; - } - - protected FakeHttpContextFactory GetHttpContextFactory(string url, RouteData routeData = null) - { - var factory = routeData != null - ? new FakeHttpContextFactory(url, routeData) - : new FakeHttpContextFactory(url); - - return factory; - } - - #endregion - } -} diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index 0fcca3ae8d..d1e67375e5 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -26,6 +26,7 @@ using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Filters; using Umbraco.Web.Common.Security; using Umbraco.Web.Models; +using Umbraco.Web.Mvc; using Umbraco.Web.WebAssets; using Constants = Umbraco.Core.Constants; using Microsoft.AspNetCore.Identity; @@ -34,9 +35,8 @@ using System.Security.Claims; namespace Umbraco.Web.BackOffice.Controllers { //[UmbracoRequireHttps] //TODO Reintroduce - [DisableBrowserCache] [PluginController(Constants.Web.Mvc.BackOfficeArea)] - public class BackOfficeController : Controller + public class BackOfficeController : UmbracoController { private readonly IBackOfficeUserManager _userManager; private readonly IRuntimeMinifier _runtimeMinifier; diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs index 9f109d7bbf..874cb6fe1d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Hosting; using Umbraco.Core.Media; using Umbraco.Core.WebAssets; using Umbraco.Extensions; +using Umbraco.Web.BackOffice.HealthCheck; using Umbraco.Web.BackOffice.Profiling; using Umbraco.Web.BackOffice.PropertyEditors; using Umbraco.Web.BackOffice.Routing; diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs index 58242851bd..0026cc9bed 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -29,14 +29,13 @@ using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Routing; using Constants = Umbraco.Core.Constants; using Umbraco.Extensions; -using Umbraco.Web.BackOffice.Controllers; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.ModelBinders; using Umbraco.Web.Common.ActionResults; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; +using Umbraco.Web.Common.Filters; using Umbraco.Web.Models.Mapping; -using Umbraco.Web.Security; using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.BackOffice.Controllers diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index a394428606..7248c62c96 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -24,9 +24,9 @@ using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.BackOffice.Security; using Umbraco.Web.Common.Attributes; using Umbraco.Web.Common.Exceptions; +using Umbraco.Web.Common.Filters; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Security; namespace Umbraco.Web.BackOffice.Controllers { diff --git a/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs b/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs index af87b8494b..a878910bf3 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs @@ -24,11 +24,6 @@ namespace Umbraco.Web.BackOffice.Controllers /// /// API controller to deal with Macro data /// - /// - /// Note that this implements IRequiresSessionState which will enable HttpContext.Session - generally speaking we don't normally - /// enable this for webapi controllers, however since this controller is used to render macro content and macros can access - /// Session, we don't want it to throw null reference exceptions. - /// [PluginController(Constants.Web.Mvc.BackOfficeApiArea)] public class MacroRenderingController : UmbracoAuthorizedJsonController { diff --git a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs index 471aed51e1..3c6b538506 100644 --- a/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.BackOffice/Extensions/BackOfficeApplicationBuilderExtensions.cs @@ -35,6 +35,9 @@ namespace Umbraco.Extensions app.UseImageSharp(); app.UseStaticFiles(); + // Must be called after UseRouting and before UseEndpoints + app.UseSession(); + if (!app.UmbracoCanBoot()) return app; app.UseEndpoints(endpoints => diff --git a/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs b/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs index 99535d3d30..768ede1787 100644 --- a/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs +++ b/src/Umbraco.Web.BackOffice/HealthCheck/HealthCheckController.cs @@ -2,16 +2,16 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; -using Umbraco.Core; -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 Umbraco.Core; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.HealthCheck; +using Umbraco.Web.BackOffice.Controllers; +using Umbraco.Web.BackOffice.Filters; +using Umbraco.Web.Common.Attributes; using Microsoft.Extensions.Logging; -namespace Umbraco.Web.BackOffice.Controllers +namespace Umbraco.Web.BackOffice.HealthCheck { /// /// The API controller used to display the health check info and execute any actions @@ -85,7 +85,7 @@ namespace Umbraco.Web.BackOffice.Controllers return check.ExecuteAction(action); } - private HealthCheck.HealthCheck GetCheckById(Guid id) + private Core.HealthCheck.HealthCheck GetCheckById(Guid id) { var check = _checks .Where(x => _disabledCheckIds.Contains(x.Id) == false) diff --git a/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs b/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs index fde3d095fe..cf41670d8e 100644 --- a/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs +++ b/src/Umbraco.Web.Common/AspNetCore/UmbracoViewPage.cs @@ -1,7 +1,10 @@ using System; using System.Text; +using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Core; @@ -11,6 +14,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Strings; +using Umbraco.Web.Common.ModelBinders; namespace Umbraco.Web.Common.AspNetCore { @@ -29,6 +33,7 @@ namespace Umbraco.Web.Common.AspNetCore private ContentSettings ContentSettings => Context.RequestServices.GetRequiredService>().Value; private IProfilerHtml ProfilerHtml => Context.RequestServices.GetRequiredService(); private IIOHelper IOHelper => Context.RequestServices.GetRequiredService(); + private ContentModelBinder ContentModelBinder => new ContentModelBinder(); protected IUmbracoContext UmbracoContext => _umbracoContext ??= UmbracoContextAccessor.UmbracoContext; @@ -85,5 +90,58 @@ namespace Umbraco.Web.Common.AspNetCore base.WriteLiteral(value); } + + // maps model + protected async Task SetViewDataAsync(ViewDataDictionary viewData) + { + // capture the model before we tinker with the viewData + var viewDataModel = viewData.Model; + + // map the view data (may change its type, may set model to null) + viewData = MapViewDataDictionary(viewData, typeof (TModel)); + + // bind the model + var bindingContext = new DefaultModelBindingContext(); + await ContentModelBinder.BindModelAsync(bindingContext, viewDataModel, typeof (TModel)); + + viewData.Model = bindingContext.Result.Model; + + // set the view data + ViewData = (ViewDataDictionary) viewData; + } + + // viewData is the ViewDataDictionary (maybe ) that we have + // modelType is the type of the model that we need to bind to + // + // figure out whether viewData can accept modelType else replace it + // + private static ViewDataDictionary MapViewDataDictionary(ViewDataDictionary viewData, Type modelType) + { + var viewDataType = viewData.GetType(); + + + if (viewDataType.IsGenericType) + { + // ensure it is the proper generic type + var def = viewDataType.GetGenericTypeDefinition(); + if (def != typeof(ViewDataDictionary<>)) + throw new Exception("Could not map viewData of type \"" + viewDataType.FullName + "\"."); + + // get the viewData model type and compare with the actual view model type: + // viewData is ViewDataDictionary and we will want to assign an + // object of type modelType to the Model property of type viewDataModelType, we + // need to check whether that is possible + var viewDataModelType = viewDataType.GenericTypeArguments[0]; + + if (viewDataModelType.IsAssignableFrom(modelType)) + return viewData; + } + + // if not possible or it is not generic then we need to create a new ViewDataDictionary + var nViewDataType = typeof(ViewDataDictionary<>).MakeGenericType(modelType); + var tViewData = new ViewDataDictionary(viewData) { Model = null }; // temp view data to copy values + var nViewData = (ViewDataDictionary)Activator.CreateInstance(nViewDataType, tViewData); + return nViewData; + } } } diff --git a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs index 5b4876baca..2725e1b7a6 100644 --- a/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Builder/UmbracoBuilderExtensions.cs @@ -6,6 +6,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using Umbraco.Extensions; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Common.ModelBinders; namespace Umbraco.Web.Common.Builder { @@ -38,11 +40,19 @@ namespace Umbraco.Web.Common.Builder 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(); + var mvcBuilder = builder.Services.AddControllersWithViews(options => + { + options.ModelBinderProviders.Insert(0, new ContentModelBinderProvider()); + + options.Filters.Insert(0, new EnsurePartialViewMacroViewContextFilterAttribute()); + mvcOptions?.Invoke(options); + }).AddRazorRuntimeCompilation(); mvcBuilding?.Invoke(mvcBuilder); }); diff --git a/src/Umbraco.Web.Common/Controllers/IRenderController.cs b/src/Umbraco.Web.Common/Controllers/IRenderController.cs new file mode 100644 index 0000000000..3eaf1c35c3 --- /dev/null +++ b/src/Umbraco.Web.Common/Controllers/IRenderController.cs @@ -0,0 +1,11 @@ +namespace Umbraco.Web.Mvc +{ + /// + /// A marker interface to designate that a controller will be used for Umbraco front-end requests and/or route hijacking + /// + /// Migrated already to .Net Core + public interface IRenderController + { + + } +} diff --git a/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs b/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs new file mode 100644 index 0000000000..8727918bf4 --- /dev/null +++ b/src/Umbraco.Web.Common/Controllers/IRenderMvcController.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; +using Umbraco.Core.Composing; +using Umbraco.Web.Models; + +namespace Umbraco.Web.Mvc +{ + /// + /// The interface that must be implemented for a controller to be designated to execute for route hijacking + /// + public interface IRenderMvcController : IRenderController, IDiscoverable + { + /// + /// The default action to render the front-end view + /// + /// + /// + IActionResult Index(ContentModel model); + } +} diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs index 43058616de..b95859ccbe 100644 --- a/src/Umbraco.Web.Common/Controllers/RenderController.cs +++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs @@ -1,8 +1,9 @@ using Microsoft.AspNetCore.Mvc; +using Umbraco.Web.Mvc; namespace Umbraco.Web.Common.Controllers { - public abstract class RenderController : Controller + public abstract class RenderController : Controller, IRenderController { } diff --git a/src/Umbraco.Web.Common/Controllers/UmbracoController.cs b/src/Umbraco.Web.Common/Controllers/UmbracoController.cs new file mode 100644 index 0000000000..1498b2c75c --- /dev/null +++ b/src/Umbraco.Web.Common/Controllers/UmbracoController.cs @@ -0,0 +1,23 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Composing; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Services; +using Umbraco.Web.Security; + +namespace Umbraco.Web.Mvc +{ + /// + /// Provides a base class for Umbraco controllers. + /// + public abstract class UmbracoController : Controller + { + // for debugging purposes + internal Guid InstanceId { get; } = Guid.NewGuid(); + + } +} diff --git a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs index dcc9bbca70..2415b4e924 100644 --- a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Serilog.Context; using Smidge; +using Smidge.Nuglify; using StackExchange.Profiling; using Umbraco.Core; using Umbraco.Core.Hosting; @@ -110,6 +111,7 @@ namespace Umbraco.Extensions if (!app.UmbracoCanBoot()) return app; app.UseSmidge(); + app.UseSmidgeNuglify(); return app; } diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs index adae78bd74..f91fdceb4f 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs @@ -241,6 +241,15 @@ namespace Umbraco.Extensions if (container is null) throw new ArgumentNullException(nameof(container)); if (entryAssembly is null) throw new ArgumentNullException(nameof(entryAssembly)); + // Add service session + // This can be overwritten by the user by adding their own call to AddSession + // since the last call of AddSession take precedence + services.AddSession(options => + { + options.Cookie.Name = "UMB_SESSION"; + options.Cookie.HttpOnly = true; + }); + // Add supported databases services.AddUmbracoSqlCeSupport(); services.AddUmbracoSqlServerSupport(); @@ -295,13 +304,6 @@ namespace Umbraco.Extensions factory = coreRuntime.Configure(container); - - services.Configure(hostingSettings => - { - hostingSettings.Debug = false; - }); - - return services; } diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs index e37b6f81fd..37ac5c7683 100644 --- a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs @@ -1,14 +1,10 @@ -using System.Buffers; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; -using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.Options; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Web.Caching; @@ -18,12 +14,8 @@ using SixLabors.ImageSharp.Web.Processors; using SixLabors.ImageSharp.Web.Providers; 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; namespace Umbraco.Extensions { diff --git a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs index 269e437d0d..360396fe04 100644 --- a/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/EnsurePartialViewMacroViewContextFilterAttribute.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Umbraco.Web.Common.Constants; using Umbraco.Web.Common.Controllers; +using Umbraco.Web.Mvc; namespace Umbraco.Web.Common.Filters { @@ -28,7 +29,7 @@ namespace Umbraco.Web.Common.Filters /// public class EnsurePartialViewMacroViewContextFilterAttribute : ActionFilterAttribute { - + /// /// Ensures the custom ViewContext datatoken is set before the RenderController action is invoked, /// this ensures that any calls to GetPropertyValue with regards to RTE or Grid editors can still @@ -40,7 +41,7 @@ namespace Umbraco.Web.Common.Filters if (!(context.Controller is Controller controller)) return; //ignore anything that is not IRenderController - if (!(controller is RenderController)) return; + if (!(controller is IRenderController)) return; SetViewContext(context, controller); } diff --git a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs index 3c1de1e138..6cec04e0b6 100644 --- a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs +++ b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionFilter.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web.Common.Filters /// /// This is only enabled when running PureLive /// - internal class ModelBindingExceptionFilter : ActionFilterAttribute, IExceptionFilter + public class ModelBindingExceptionFilter : ActionFilterAttribute, IExceptionFilter { private static readonly Regex _getPublishedModelsTypesRegex = new Regex("Umbraco.Web.PublishedModels.(\\w+)", RegexOptions.Compiled); diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs similarity index 96% rename from src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeAttribute.cs rename to src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs index a4b47522ee..8a7c7b04d5 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeAttribute.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Mvc; -namespace Umbraco.Web.BackOffice.Filters +namespace Umbraco.Web.Common.Filters { /// /// Ensures authorization is successful for a back office user. diff --git a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs similarity index 99% rename from src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs rename to src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs index 6cf2eac5f0..66b1462ae9 100644 --- a/src/Umbraco.Web.BackOffice/Filters/UmbracoAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoAuthorizeFilter.cs @@ -7,7 +7,7 @@ using Umbraco.Extensions; using Umbraco.Web.Security; using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment; -namespace Umbraco.Web.BackOffice.Filters +namespace Umbraco.Web.Common.Filters { /// diff --git a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs index 43d9df4586..3c2da057f7 100644 --- a/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs +++ b/src/Umbraco.Web.Common/ModelBinders/ContentModelBinder.cs @@ -27,7 +27,7 @@ namespace Umbraco.Web.Common.ModelBinders // No need for type checks to ensure we have the appropriate binder, as in .NET Core this is handled in the provider, // in this case ContentModelBinderProvider. - // Being defensice though.... if for any reason the model is not either IContentModel or IPublishedContent, + // Being defensive though.... if for any reason the model is not either IContentModel or IPublishedContent, // then we return since those are the only types this binder is dealing with. if (source is IContentModel == false && source is IPublishedContent == false) { @@ -36,7 +36,7 @@ namespace Umbraco.Web.Common.ModelBinders BindModelAsync(bindingContext, source, bindingContext.ModelType); return Task.CompletedTask; - } + } // source is the model that we have // modelType is the type of the model that we need to bind to @@ -58,6 +58,7 @@ namespace Umbraco.Web.Common.ModelBinders var sourceType = source.GetType(); if (sourceType.Inherits(modelType)) // includes == { + bindingContext.Result = ModelBindingResult.Success(source); return Task.CompletedTask; } diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs index 6046f9eee6..0cb7bc71d2 100644 --- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeComposer.cs @@ -1,4 +1,5 @@ -using Umbraco.Core; +using Smidge.FileProcessors; +using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Runtime; using Umbraco.Core.WebAssets; @@ -16,6 +17,7 @@ namespace Umbraco.Web.Common.RuntimeMinification composition.RegisterUnique(); composition.RegisterUnique(); + composition.Register(); } } } diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeNuglifyJs.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeNuglifyJs.cs new file mode 100644 index 0000000000..bab4abde53 --- /dev/null +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeNuglifyJs.cs @@ -0,0 +1,28 @@ +using Smidge.Nuglify; + +namespace Umbraco.Web.Common.RuntimeMinification +{ + /// + /// Custom Nuglify Js pre-process to specify custom nuglify options without changing the global defaults + /// + public class SmidgeNuglifyJs : NuglifyJs + { + public SmidgeNuglifyJs(NuglifySettings settings, ISourceMapDeclaration sourceMapDeclaration) + : base(GetSettings(settings), sourceMapDeclaration) + { + } + + private static NuglifySettings GetSettings(NuglifySettings defaultSettings) + { + var nuglifyCodeSettings = defaultSettings.JsCodeSettings.CodeSettings.Clone(); + + // Don't rename locals, this will kill a lot of angular stuff because we aren't correctly coding our + // angular injection to handle minification correctly which requires declaring string named versions of all + // dependencies injected (which is a pain). So we just turn this option off. + nuglifyCodeSettings.LocalRenaming = NUglify.JavaScript.LocalRenaming.KeepAll; + nuglifyCodeSettings.PreserveFunctionNames = true; + + return new NuglifySettings(new NuglifyCodeSettings(nuglifyCodeSettings), defaultSettings.CssCodeSettings); + } + } +} diff --git a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs index a33ac6f966..29a0e41998 100644 --- a/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs +++ b/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs @@ -21,31 +21,39 @@ namespace Umbraco.Web.Common.RuntimeMinification private readonly IHostingEnvironment _hostingEnvironment; private readonly ISmidgeConfig _smidgeConfig; private readonly IConfigManipulator _configManipulator; - private readonly PreProcessPipelineFactory _preProcessPipelineFactory; private readonly IBundleManager _bundles; private readonly SmidgeHelperAccessor _smidge; - private PreProcessPipeline _jsPipeline; - private PreProcessPipeline _cssPipeline; + // used only for minifying in MinifyAsync not for an actual pipeline + private Lazy _jsMinPipeline; + private Lazy _cssMinPipeline; + + // default pipelines for processing js/css files for the back office + private Lazy _jsPipeline; + private Lazy _cssPipeline; public SmidgeRuntimeMinifier( IBundleManager bundles, SmidgeHelperAccessor smidge, - PreProcessPipelineFactory preProcessPipelineFactory, IHostingEnvironment hostingEnvironment, ISmidgeConfig smidgeConfig, IConfigManipulator configManipulator) { _bundles = bundles; _smidge = smidge; - _preProcessPipelineFactory = preProcessPipelineFactory; _hostingEnvironment = hostingEnvironment; _smidgeConfig = smidgeConfig; _configManipulator = configManipulator; - } - private PreProcessPipeline JsPipeline => _jsPipeline ??= _preProcessPipelineFactory.Create(typeof(JsMinifier)); - private PreProcessPipeline CssPipeline => _cssPipeline ??= _preProcessPipelineFactory.Create(typeof(NuglifyCss)); + _jsMinPipeline = new Lazy(() => _bundles.PipelineFactory.Create(typeof(JsMinifier))); + _cssMinPipeline = new Lazy(() => _bundles.PipelineFactory.Create(typeof(NuglifyCss))); + + // replace the default JsMinifier with NuglifyJs and CssMinifier with NuglifyCss in the default pipelines + // for use with our bundles only (not modifying global options) + _jsPipeline = new Lazy(() => bundles.PipelineFactory.DefaultJs().Replace(_bundles.PipelineFactory)); + _cssPipeline = new Lazy(() => bundles.PipelineFactory.DefaultCss().Replace(_bundles.PipelineFactory)); + + } public string CacheBuster => _smidgeConfig.Version; @@ -58,11 +66,10 @@ namespace Umbraco.Web.Common.RuntimeMinification if (_bundles.Exists(bundleName)) throw new InvalidOperationException($"The bundle name {bundleName} already exists"); - var bundle = _bundles.Create(bundleName, WebFileType.Css, filePaths); - // Here we could configure bundle options instead of using smidge's global defaults. // For example we can use our own custom cache buster for this bundle without having the global one // affect this or vice versa. + var bundle = _bundles.Create(bundleName, _cssPipeline.Value, WebFileType.Css, filePaths); } public async Task RenderCssHereAsync(string bundleName) => (await _smidge.SmidgeHelper.CssHereAsync(bundleName, _hostingEnvironment.IsDebugMode)).ToString(); @@ -75,11 +82,10 @@ namespace Umbraco.Web.Common.RuntimeMinification if (_bundles.Exists(bundleName)) throw new InvalidOperationException($"The bundle name {bundleName} already exists"); - var bundle = _bundles.Create(bundleName, WebFileType.Js, filePaths); - // Here we could configure bundle options instead of using smidge's global defaults. // For example we can use our own custom cache buster for this bundle without having the global one // affect this or vice versa. + var bundle = _bundles.Create(bundleName, _jsPipeline.Value, WebFileType.Js, filePaths); } public async Task RenderJsHereAsync(string bundleName) => (await _smidge.SmidgeHelper.JsHereAsync(bundleName, _hostingEnvironment.IsDebugMode)).ToString(); @@ -92,11 +98,11 @@ namespace Umbraco.Web.Common.RuntimeMinification switch (assetType) { case AssetType.Javascript: - return await JsPipeline + return await _jsMinPipeline.Value .ProcessAsync( new FileProcessContext(fileContent, new JavaScriptFile(), BundleContext.CreateEmpty())); case AssetType.Css: - return await CssPipeline + return await _cssMinPipeline.Value .ProcessAsync(new FileProcessContext(fileContent, new CssFile(), BundleContext.CreateEmpty())); default: throw new NotSupportedException("Unexpected AssetType"); diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj index 421621e668..a712a43a45 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -26,8 +26,8 @@ - - + + 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 6d41ea087d..ed0a1c602c 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 @@ -370,7 +370,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt //This is the ideal button order but depends on circumstance, we'll use this array to create the button list // Publish, SendToPublish, Save var actionOrder = ["U", "H", "A"]; - var defaultActions; + var defaultAction = null; var actions = []; //Create the first button (primary button) diff --git a/src/Umbraco.Web.UI.NetCore/appsettings.json b/src/Umbraco.Web.UI.NetCore/appsettings.json index 70e3d6376d..0d068bbd43 100644 --- a/src/Umbraco.Web.UI.NetCore/appsettings.json +++ b/src/Umbraco.Web.UI.NetCore/appsettings.json @@ -38,7 +38,7 @@ "ConvertUrlsToAscii": "try" }, "RuntimeMinification": { - "dataFolder": "App_Data\\Smidge", + "dataFolder": "App_Data/TEMP/Smidge", "version": "1" }, "Security": { diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/cs.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/cs.xml index 914ac366cd..739b8d4684 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/cs.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/cs.xml @@ -2029,7 +2029,6 @@ Try Skip IIS Custom Errors je aktuálně nastaveno na '%0%'. Doporučuje se nastavit %1% pro vaši verzi služby IIS (%2%). Try Skip IIS Custom Errors úspěšně nastaveno na '%0%'. - Soubor neexistuje: '%0%'. '% 0%' v konfiguračním souboru '% 1%'.]]> Došlo k chybě, zkontrolujte ji v logu: %0%. Databáze - Databázové schéma je pro tuto verzi Umbraco správné @@ -2059,6 +2058,10 @@ Režim sledování je aktuálně povolen. Před spuštěním se doporučuje toto nastavení deaktivovat. Režim sledování byl úspěšně deaktivován. Všechny složky mají nastavena správná oprávnění. + + Soubor neexistuje: '%0%'. diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/de.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/de.xml index 86b1d6c130..cb95283bb7 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/de.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/de.xml @@ -2101,7 +2101,6 @@ "trySkipIisCustomErrors" ist auf '%0%' gestellt und Sie verwenden IIS-Version '%1%'. "trySkipIisCustomErrors" ist aktuell auf '%0%' gestellt. Für Ihre IIS-Version (%2%) wird empfohlen, diese auf '%1%' zu stellen. "trySkipIisCustomErrors" wurde erfolgreich auf '%0%' gestellt. - Folgende Datei ist nicht vorhanden: '%0%'. '%0%' wurde nicht in der Konfigurationsdatei '%1%' gefunden.]]> Es trat ein Fehler auf, für eine vollständige Fehlermeldung suchen Sie in den Logs nach: %0% Datenbank - Das Datenbank-Schema ist korrekt für diese Umbraco-Version @@ -2130,6 +2129,10 @@ Trace-Modus ist gegenwertig eingeschaltet. Es ist empfehlenswert diesen vor Live-Gang abzuschalten. Trace-Modus wurde erfolgreich abgeschaltet. Alle Ordner haben die korrekten Zugriffsrechte. + + Folgende Datei ist nicht vorhanden: '%0%'. %0%.]]> %0%. Falls nicht in diese geschrieben wird, brauchen Sie nichts zu unternehmen.]]> Alle Dateien haben die korrekten Zugriffsrechte. diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml index 0165f22a2a..3969e08654 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml @@ -2097,7 +2097,6 @@ To manage your website, simply open the Umbraco back office and start adding con Try Skip IIS Custom Errors is currently '%0%'. It is recommended to set this to '%1%' for your IIS version (%2%). Try Skip IIS Custom Errors successfully set to '%0%'. - File does not exist: '%0%'. '%0%' in config file '%1%'.]]> There was an error, check log for full error: %0%. Database - The database schema is correct for this version of Umbraco @@ -2127,6 +2126,10 @@ To manage your website, simply open the Umbraco back office and start adding con Trace mode is currently enabled. It is recommended to disable this setting before go live. Trace mode successfully disabled. All folders have the correct permissions set. + + File does not exist: '%0%'. diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml index c45049087d..0599caee9c 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml @@ -2116,7 +2116,6 @@ To manage your website, simply open the Umbraco back office and start adding con Try Skip IIS Custom Errors is currently '%0%'. It is recommended to set this to '%1%' for your IIS version (%2%). Try Skip IIS Custom Errors successfully set to '%0%'. - File does not exist: '%0%'. '%0%' in config file '%1%'.]]> There was an error, check log for full error: %0%. Database - The database schema is correct for this version of Umbraco @@ -2152,6 +2151,10 @@ To manage your website, simply open the Umbraco back office and start adding con %0%.]]> %0%. If they aren't being written to no action need be taken.]]> All files have the correct permissions set. + + File does not exist: '%0%'. diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/es.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/es.xml index c35c84ebdc..678afa10d6 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/es.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/es.xml @@ -1568,8 +1568,6 @@ Intentar saltar Errores Personalizados de IIS está '%0%'. Se recomienda configurarlo como '%1%' para tu versión (%2%) de IIS. Intentar saltar Errores Personalizados de IIS se configuró como con '%0%' éxito. - Archivo no existe: '%0%'. - '%0%' en archivo de configuración '%1%'.]]> Hubo un error, revisa los logs para ver el error completo: %0%. El certificado de tu sitio es válido. Error validando certificado: '%0%' @@ -1601,6 +1599,10 @@ %0%.]]> %0%. Opcional.]]> Todos los archivos tienen los permisos correspondientes. + + '%0%' en archivo de configuración '%1%'.]]> diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/fr.xml index b83ee4f9fe..17875e53e4 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/fr.xml @@ -2040,7 +2040,6 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Try Skip IIS Custom Errors est actuellement fixé à '%0%'. Il est recommandé de fixer la valeur à '%1%' pour votre version IIS (%2%). Try Skip IIS Custom Errors a été rectifié avec succès à la valeur '%0%'. - Le fichier n'existe pas : '%0%'. '%0%' dans le fichier config '%1%'.]]> Une erreur est survenue, consultez le log pour voir l'erreur complète : %0%. Base de données - Le schéma de la base de données est correct pour cette version de Umbraco @@ -2070,6 +2069,10 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à Le mode tracing est actuellement activé. Il est recommandé de désactiver cette configuration avant la mise en ligne. Le mode tracing a été désactivé avec succès. Tous les répertoires ont les configurations de permissions adéquates. + + Le fichier n'existe pas : '%0%'. @@ -2355,4 +2358,4 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à ]]> - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/nl.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/nl.xml index 8361383b58..27894b4a1d 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/nl.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/nl.xml @@ -1326,7 +1326,6 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je Try Skip IIS Custom foutmeldingen is ingesteld op '%0%'. Het wordt voor de gebruikte IIS versie (%2%) aangeraden deze in te stellen op '%1%'. Try Skip IIS Custom foutmeldingen ingesteld op '%0%'. - Het volgende bestand bestaat niet: '%0%'. '%0%' kon niet gevonden worden in configuratie bestand '%1%'.]]> Er is een fout opgetreden. Bekijk de log file voor de volledige fout: %0%. Het cerficaat van de website is ongeldig. @@ -1357,6 +1356,10 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je %0%.]]> %0%. Als deze niet in gebruik zijn voor deze omgeving hoeft er geen actie te worden ondernomen.]]> All files have the correct permissions set. + + Het volgende bestand bestaat niet: '%0%'. diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/pl.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/pl.xml index fd806041c5..1c095448b5 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/pl.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/pl.xml @@ -1403,7 +1403,6 @@ Naciśnij przycisk instaluj, aby zainstalować bazę danych Umb Try Skip IIS Custom Errors wynosi obecnie '%0%'. Zalecane jest ustawienie go na '%1%' dla Twojego IIS w wersji (%2%). Try Skip IIS Custom Errors ustawiono z powodzeniem na '%0%'. - Plik nie istnieje: '%0%'. '%0%' w pliku konfiguracyjnym '%1%'.]]> Wystąpił błąd, sprawdź logi, aby wyświetlić pełen opis błędu: %0%. Certifikat Twojej strony jest poprawny. @@ -1436,6 +1435,7 @@ Naciśnij przycisk instaluj, aby zainstalować bazę danych Umb %0%.]]> %0%. Jeśli nie będzie nic w nich pisane, żadne działania nie muszą być podejmowane.]]> Wszystkie pliki mają ustawione poprawne uprawnienia. + Plik nie istnieje: '%0%'. diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/ru.xml index 7a3e099262..6654543ec8 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/ru.xml @@ -694,7 +694,6 @@ Параметр 'Try Skip IIS Custom Errors' сейчас установлен в '%0%'. Рекомендуется установить в '%1%' для Вашего текущего IIS версии (%2%). Параметр 'Try Skip IIS Custom Errors' успешно установлен в '%0%'. - Файл не существует: '%0%'. '%0%' в файле конфигурации '%1%'.]]> Обнаружена ошибка, для получения полной информации обратитесь к журналу: %0%. Ошибка проверки адреса URL %0% - '%1%' @@ -725,6 +724,10 @@ %0%.]]> %0%. Если в них не разрешена запись, не нужно предпринимать никаких действий.]]> Все файлы имеют корректно установленные параметры безопасности. + + Файл не существует: '%0%'. diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/zh.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/zh.xml index 5210b46bcc..5a470583a8 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/zh.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/zh.xml @@ -1190,7 +1190,6 @@ Try Skip IIS Custom Errors is currently '%0%'. It is recommended to set this to '%1%' for your IIS version (%2%). Try Skip IIS Custom Errors successfully set to '%0%'. - File does not exist: '%0%'. '%0%' in config file '%1%'.]]> There was an error, check log for full error: %0%. Your site certificate was marked as valid. @@ -1221,6 +1220,10 @@ %0%.]]> %0%. If they aren't being written to no action need be taken.]]> All files have the correct permissions set. + + File does not exist: '%0%'. diff --git a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/zh_tw.xml b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/zh_tw.xml index 320c3f63d8..06e8ec3e54 100644 --- a/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/zh_tw.xml +++ b/src/Umbraco.Web.UI.NetCore/umbraco/config/lang/zh_tw.xml @@ -1170,7 +1170,6 @@ 嘗試略過IIS自訂錯誤目前設為 %0%,然而在您使用的IIS版本為 %2% 時,建議設定是 %1%。 嘗試略過IIS自訂錯誤已成功設為 %0%。 - 檔案不存在:%0%。 '%1%'中無法找到'%0%'。]]> 有錯誤產生,請參閱下列錯誤的紀錄:%0%。 憑證驗證錯誤:%0% @@ -1200,6 +1199,10 @@ %0%。]]> %0%。如果無須寫入,不需採取行動。]]> 所有檔案已有正確權限設定。 + + 檔案不存在:%0%。 diff --git a/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs b/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs new file mode 100644 index 0000000000..f1ea65e983 --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/RenderIndexActionSelectorAttribute.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.ActionConstraints; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; + +namespace Umbraco.Web.Mvc +{ + /// + /// A custom ActionMethodSelector which will ensure that the RenderMvcController.Index(ContentModel model) action will be executed + /// if the + /// + internal class RenderIndexActionSelectorAttribute : ActionMethodSelectorAttribute + { + private static readonly ConcurrentDictionary> _controllerActionsCache = new ConcurrentDictionary>(); + + /// + /// Determines whether the action method selection is valid for the specified controller context. + /// + /// + /// true if the action method selection is valid for the specified controller context; otherwise, false. + /// + /// The route context. + /// Information about the action method. + public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action) + { + if (action is ControllerActionDescriptor controllerAction) + { + var currType = controllerAction.ControllerTypeInfo.UnderlyingSystemType; + var baseType = controllerAction.ControllerTypeInfo.BaseType; + + //It's the same type, so this must be the Index action to use + if (currType == baseType) return true; + + var actions = _controllerActionsCache.GetOrAdd(currType, type => + { + var actionDescriptors = routeContext.HttpContext.RequestServices + .GetRequiredService().ActionDescriptors.Items + .Where(x=>x is ControllerActionDescriptor).Cast() + .Where(x => x.ControllerTypeInfo == controllerAction.ControllerTypeInfo); + + return actionDescriptors; + }); + + //If there are more than one Index action for this controller, then + // this base class one should not be matched + return actions.Count(x => x.ActionName == "Index") <= 1; + } + + return false; + + } + } +} diff --git a/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs b/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs new file mode 100644 index 0000000000..62ffb010ea --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/RenderMvcController.cs @@ -0,0 +1,92 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.Extensions.Logging; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Models; +using Umbraco.Web.Routing; + +namespace Umbraco.Web.Mvc +{ + + /// + /// Represents the default front-end rendering controller. + /// + [PreRenderViewActionFilter] + [TypeFilter(typeof(ModelBindingExceptionFilter))] + public class RenderMvcController : UmbracoController, IRenderMvcController + { + private IPublishedRequest _publishedRequest; + private readonly ILogger _logger; + private readonly ICompositeViewEngine _compositeViewEngine; + + public RenderMvcController(ILogger logger, ICompositeViewEngine compositeViewEngine) + { + _logger = logger; + _compositeViewEngine = compositeViewEngine; + } + + /// + /// Gets the current content item. + /// + protected IPublishedContent CurrentPage => PublishedRequest.PublishedContent; + + /// + /// Gets the current published content request. + /// + protected internal virtual IPublishedRequest PublishedRequest + { + get + { + if (_publishedRequest != null) + return _publishedRequest; + if (RouteData.DataTokens.ContainsKey(Core.Constants.Web.PublishedDocumentRequestDataToken) == false) + { + throw new InvalidOperationException("DataTokens must contain an 'umbraco-doc-request' key with a PublishedRequest object"); + } + _publishedRequest = (IPublishedRequest)RouteData.DataTokens[Core.Constants.Web.PublishedDocumentRequestDataToken]; + return _publishedRequest; + } + } + + /// + /// Ensures that a physical view file exists on disk. + /// + /// The view name. + protected bool EnsurePhsyicalViewExists(string template) + { + var result = _compositeViewEngine.FindView(ControllerContext, template, false); + if (result.View != null) return true; + + _logger.LogWarning("No physical template file was found for template {Template}", template); + return false; + } + + /// + /// Gets an action result based on the template name found in the route values and a model. + /// + /// The type of the model. + /// The model. + /// The action result. + /// If the template found in the route values doesn't physically exist, then an empty ContentResult will be returned. + protected IActionResult CurrentTemplate(T model) + { + var template = ControllerContext.RouteData.Values["action"].ToString(); + if (EnsurePhsyicalViewExists(template) == false) + throw new InvalidOperationException("No physical template file was found for template " + template); + return View(template, model); + } + + /// + /// The default action to render the front-end view. + /// + /// + /// + [RenderIndexActionSelector] + public virtual IActionResult Index(ContentModel model) + { + return CurrentTemplate(model); + } + } +} diff --git a/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs b/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs new file mode 100644 index 0000000000..2b5d7a61da --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/UmbracoAuthorizedController.cs @@ -0,0 +1,18 @@ +using Umbraco.Web.Common.Filters; + +namespace Umbraco.Web.Mvc +{ + /// + /// Provides a base class for authorized Umbraco controllers. + /// + /// + /// This controller essentially just uses a global UmbracoAuthorizeAttribute, inheritors that require more granular control over the + /// authorization of each method can use this attribute instead of inheriting from this controller. + /// + [UmbracoAuthorize] + [DisableBrowserCache] + public abstract class UmbracoAuthorizedController : UmbracoController + { + + } +} diff --git a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj index 683fd2cc6d..daba18d51b 100644 --- a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj +++ b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj @@ -23,4 +23,13 @@ + + + + <_Parameter1>Umbraco.Tests.UnitTests + + + <_Parameter1>Umbraco.Tests.Integration + + diff --git a/src/Umbraco.Web/Composing/Current.cs b/src/Umbraco.Web/Composing/Current.cs index 44468f2943..0889a9c019 100644 --- a/src/Umbraco.Web/Composing/Current.cs +++ b/src/Umbraco.Web/Composing/Current.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; +using Umbraco.Core.HealthCheck; using Umbraco.Core.Hosting; using Umbraco.Core.Mapping; using Umbraco.Core.Templates; diff --git a/src/Umbraco.Web/Composing/LightInject/LightInjectContainer.cs b/src/Umbraco.Web/Composing/LightInject/LightInjectContainer.cs deleted file mode 100644 index 863e406067..0000000000 --- a/src/Umbraco.Web/Composing/LightInject/LightInjectContainer.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Web.Http; -using LightInject; -using LightInject.Web; -using Umbraco.Core.Composing.LightInject; - -namespace Umbraco.Web.Composing.LightInject -{ - /// - /// Implements DI with LightInject. - /// - public class LightInjectContainer : Core.Composing.LightInject.LightInjectContainer - { - /// - /// Initializes a new instance of the with a LightInject container. - /// - protected LightInjectContainer(ServiceContainer container) - : base(container) - { } - - /// - /// Creates a new instance of the class. - /// - public new static LightInjectContainer Create() - => new LightInjectContainer(CreateServiceContainer()); - - /// - /// Overridden to supply the .Net Framework based PerWebRequestScopeManagerProvider - /// - public override void EnablePerWebRequestScope() - { - if (!(Container.ScopeManagerProvider is MixedLightInjectScopeManagerProvider smp)) - throw new Exception("Container.ScopeManagerProvider is not MixedLightInjectScopeManagerProvider."); - smp.EnablePerWebRequestScope(new PerWebRequestScopeManagerProvider()); - } - - /// - public override void ConfigureForWeb() - { - // IoC setup for LightInject for MVC/WebApi - // see comments on MixedLightInjectScopeManagerProvider for explanations of what we are doing here - if (!(Container.ScopeManagerProvider is MixedLightInjectScopeManagerProvider smp)) - throw new Exception("Container.ScopeManagerProvider is not MixedLightInjectScopeManagerProvider."); - Container.EnableMvc(); // does container.EnablePerWebRequestScope() - Container.ScopeManagerProvider = smp; // reverts - we will do it last (in WebRuntime) - Container.EnableWebApi(GlobalConfiguration.Configuration); - } - } -} diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs deleted file mode 100644 index bfb2448926..0000000000 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ /dev/null @@ -1,297 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Web; -using System.Web.Mvc; -using Microsoft.Extensions.Options; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Hosting; -using Umbraco.Core.Media; -using Umbraco.Core.WebAssets; -using Umbraco.Web.Features; -using Umbraco.Web.Mvc; -using Umbraco.Web.Security; -using Umbraco.Web.Trees; -using Constants = Umbraco.Core.Constants; - -namespace Umbraco.Web.Editors -{ - /// - /// Used to collect the server variables for use in the back office angular app - /// - internal class BackOfficeServerVariables - { - private readonly UrlHelper _urlHelper; - private readonly IRuntimeState _runtimeState; - private readonly UmbracoFeatures _features; - private readonly GlobalSettings _globalSettings; - private readonly IUmbracoVersion _umbracoVersion; - private readonly ContentSettings _contentSettings; - private readonly TreeCollection _treeCollection; - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly IHostingEnvironment _hostingEnvironment; - private readonly RuntimeSettings _settings; - private readonly SecuritySettings _securitySettings; - private readonly IRuntimeMinifier _runtimeMinifier; - private readonly IImageUrlGenerator _imageUrlGenerator; - - internal BackOfficeServerVariables( - UrlHelper urlHelper, - IRuntimeState runtimeState, - UmbracoFeatures features, - GlobalSettings globalSettings, - IUmbracoVersion umbracoVersion, - IOptions contentSettings, - TreeCollection treeCollection, - IHostingEnvironment hostingEnvironment, - IOptions settings, - IOptions securitySettings, - IRuntimeMinifier runtimeMinifier, - IImageUrlGenerator imageUrlGenerator) - { - _urlHelper = urlHelper; - _runtimeState = runtimeState; - _features = features; - _globalSettings = globalSettings; - _umbracoVersion = umbracoVersion; - _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); - _treeCollection = treeCollection ?? throw new ArgumentNullException(nameof(treeCollection)); - _hostingEnvironment = hostingEnvironment; - _settings = settings.Value; - _securitySettings = securitySettings.Value; - _runtimeMinifier = runtimeMinifier; - _imageUrlGenerator = imageUrlGenerator; - } - - /// - /// Returns the server variables for non-authenticated users - /// - /// - internal Dictionary BareMinimumServerVariables() - { - //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", "iconApiBaseUrl"}}, - {"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage", "canSendRequiredEmail", "usernameIsEmail"}}, - {"application", new[] {"applicationPath", "cacheBuster"}}, - {"isDebuggingEnabled", new string[] { }}, - {"features", new [] {"disabledFeatures"}} - }; - //now do the filtering... - var defaults = GetServerVariables(); - foreach (var key in defaults.Keys.ToArray()) - { - if (keepOnlyKeys.ContainsKey(key) == false) - { - defaults.Remove(key); - } - else - { - var asDictionary = defaults[key] as IDictionary; - if (asDictionary != null) - { - var toKeep = keepOnlyKeys[key]; - foreach (var k in asDictionary.Keys.Cast().ToArray()) - { - if (toKeep.Contains(k) == false) - { - asDictionary.Remove(k); - } - } - } - } - } - - // TODO: This is ultra confusing! this same key is used for different things, when returning the full app when authenticated it is this URL but when not auth'd it's actually the ServerVariables address - // so based on compat and how things are currently working we need to replace the serverVarsJs one - ((Dictionary)defaults["umbracoUrls"])["serverVarsJs"] = _urlHelper.Action("ServerVariables", "BackOffice"); - - return defaults; - } - - /// - /// Returns the server variables for authenticated users - /// - /// - internal Dictionary GetServerVariables() - { - var globalSettings = _globalSettings; - var defaultVals = new Dictionary - { - { - "umbracoUrls", new Dictionary - { - // TODO: Add 'umbracoApiControllerBaseUrl' which people can use in JS - // to prepend their URL. We could then also use this in our own resources instead of - // having each url defined here explicitly - we can do that in v8! for now - // for umbraco services we'll stick to explicitly defining the endpoints. - - {"externalLoginsUrl", _urlHelper.Action("ExternalLogin", "BackOffice")}, - {"externalLinkLoginsUrl", _urlHelper.Action("LinkLogin", "BackOffice")}, - {"gridConfig", _urlHelper.Action("GetGridConfig", "BackOffice")}, - // TODO: This is ultra confusing! this same key is used for different things, when returning the full app when authenticated it is this URL but when not auth'd it's actually the ServerVariables address - {"serverVarsJs", _urlHelper.Action("Application", "BackOffice")}, - //API URLs - { - "packagesRestApiBaseUrl", Constants.PackageRepository.RestApiBaseUrl - }, - - } - }, - { - "umbracoSettings", new Dictionary - { - {"umbracoPath", _globalSettings.GetBackOfficePath(_hostingEnvironment)}, - {"mediaPath", _hostingEnvironment.ToAbsolute(globalSettings.UmbracoMediaPath).TrimEnd('/')}, - {"appPluginsPath", _hostingEnvironment.ToAbsolute(Constants.SystemDirectories.AppPlugins).TrimEnd('/')}, - { - "imageFileTypes", - string.Join(",", _imageUrlGenerator.SupportedImageFileTypes) - }, - { - "disallowedUploadFiles", - string.Join(",", _contentSettings.DisallowedUploadFiles) - }, - { - "allowedUploadFiles", - string.Join(",", _contentSettings.AllowedUploadFiles) - }, - { - "maxFileSize", - GetMaxRequestLength() - }, - {"keepUserLoggedIn", _securitySettings.KeepUserLoggedIn}, - {"usernameIsEmail", _securitySettings.UsernameIsEmail}, - {"cssPath", _hostingEnvironment.ToAbsolute(globalSettings.UmbracoCssPath).TrimEnd('/')}, - {"allowPasswordReset", _securitySettings.AllowPasswordReset}, - {"loginBackgroundImage", _contentSettings.LoginBackgroundImage}, - {"showUserInvite", EmailSender.CanSendRequiredEmail(globalSettings)}, - {"canSendRequiredEmail", EmailSender.CanSendRequiredEmail(globalSettings)}, - {"showAllowSegmentationForDocumentTypes", false}, - } - }, - { - "umbracoPlugins", new Dictionary - { - // for each tree that is [PluginController], get - // alias -> areaName - // so that routing (route.js) can look for views - { "trees", GetPluginTrees().ToArray() } - } - }, - { - "isDebuggingEnabled", _hostingEnvironment.IsDebugMode - }, - { - "application", GetApplicationState() - }, - { - "externalLogins", new Dictionary - { - { - "providers", _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().Authentication.GetExternalAuthenticationTypes() - .Where(p => p.Properties.ContainsKey("UmbracoBackOffice")) - .Select(p => new - { - authType = p.AuthenticationType, caption = p.Caption, - // TODO: Need to see if this exposes any sensitive data! - properties = p.Properties - }) - .ToArray() - } - } - }, - { - "features", new Dictionary - { - { - "disabledFeatures", new Dictionary - { - { "disableTemplates", _features.Disabled.DisableTemplates} - } - } - - } - } - }; - return defaultVals; - } - - [DataContract] - private class PluginTree - { - [DataMember(Name = "alias")] - public string Alias { get; set; } - - [DataMember(Name = "packageFolder")] - public string PackageFolder { get; set; } - } - - private IEnumerable GetPluginTrees() - { - // used to be (cached) - //var treeTypes = Current.TypeLoader.GetAttributedTreeControllers(); - // - // ie inheriting from TreeController and marked with TreeAttribute - // - // do this instead - // inheriting from TreeControllerBase and marked with TreeAttribute - - foreach (var tree in _treeCollection) - { - var treeType = tree.TreeControllerType; - - // exclude anything marked with CoreTreeAttribute - var coreTree = treeType.GetCustomAttribute(false); - if (coreTree != null) continue; - - // exclude anything not marked with PluginControllerAttribute - var pluginController = treeType.GetCustomAttribute(false); - if (pluginController == null) continue; - - yield return new PluginTree { Alias = tree.TreeAlias, PackageFolder = pluginController.AreaName }; - } - } - - /// - /// Returns the server variables regarding the application state - /// - /// - private Dictionary GetApplicationState() - { - var app = new Dictionary - { - // add versions - see UmbracoVersion for details & differences - - // the complete application version (eg "8.1.2-alpha.25") - { "version", _umbracoVersion.SemanticVersion.ToSemanticString() }, - - // the assembly version (eg "8.0.0") - { "assemblyVersion", _umbracoVersion.AssemblyVersion.ToString() } - }; - - var version = _runtimeState.SemanticVersion.ToSemanticString(); - - //the value is the hash of the version, cdf version and the configured state - app.Add("cacheBuster", $"{version}.{_runtimeState.Level}.{_runtimeMinifier.CacheBuster}".GenerateHash()); - - //useful for dealing with virtual paths on the client side when hosted in virtual directories especially - app.Add("applicationPath", _httpContextAccessor.GetRequiredHttpContext().Request.ApplicationPath.EnsureEndsWith('/')); - - //add the server's GMT time offset in minutes - app.Add("serverTimeOffset", Convert.ToInt32(DateTimeOffset.Now.Offset.TotalMinutes)); - - return app; - } - - private string GetMaxRequestLength() - { - return _settings.MaxRequestLength.HasValue ? _settings.MaxRequestLength.Value.ToString() : string.Empty; - } - } -} diff --git a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs b/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs deleted file mode 100644 index 4cd5a76fa4..0000000000 --- a/src/Umbraco.Web/Editors/UmbracoAuthorizedJsonController.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using Microsoft.Extensions.Options; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Logging; -using Umbraco.Core.Mapping; -using Umbraco.Core.Persistence; -using Umbraco.Core.Services; -using Umbraco.Core.Strings; -using Umbraco.Web.Composing; -using Umbraco.Web.Routing; -using Umbraco.Web.WebApi; -using Umbraco.Web.WebApi.Filters; - -namespace Umbraco.Web.Editors -{ - /// - /// An abstract API controller that only supports JSON and all requests must contain the correct csrf header - /// - /// - /// Inheriting from this controller means that ALL of your methods are JSON methods that are called by Angular, - /// methods that are not called by Angular or don't contain a valid csrf header will NOT work. - /// - [ValidateAngularAntiForgeryToken] - [AngularJsonOnlyConfiguration] - public abstract class UmbracoAuthorizedJsonController : UmbracoAuthorizedApiController - { - protected UmbracoAuthorizedJsonController() - { - ShortStringHelper = Current.ShortStringHelper; - } - - protected UmbracoAuthorizedJsonController( - GlobalSettings globalSettings, - IUmbracoContextAccessor umbracoContextAccessor, - ISqlContext sqlContext, - ServiceContext services, - AppCaches appCaches, - IProfilingLogger logger, - IRuntimeState runtimeState, - IShortStringHelper shortStringHelper, - UmbracoMapper umbracoMapper, - IPublishedUrlProvider publishedUrlProvider) - : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider) - { - ShortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper)); - } - - protected IShortStringHelper ShortStringHelper { get; } - } -} diff --git a/src/Umbraco.Web/FormDataCollectionExtensions.cs b/src/Umbraco.Web/FormDataCollectionExtensions.cs deleted file mode 100644 index 3f2840c8ca..0000000000 --- a/src/Umbraco.Web/FormDataCollectionExtensions.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http.Formatting; -using System.Text; -using Umbraco.Core; - -namespace Umbraco.Web -{ - // Migrated to .NET Core (as FormCollectionExtensions) - public static class FormDataCollectionExtensions - { - /// - /// Converts a dictionary object to a query string representation such as: - /// firstname=shannon&lastname=deminick - /// - /// - /// Any keys found in this collection will be removed from the output - /// - public static string ToQueryString(this FormDataCollection items, params string[] keysToIgnore) - { - if (items == null) return ""; - if (items.Any() == false) return ""; - - var builder = new StringBuilder(); - foreach (var i in items.Where(i => keysToIgnore.InvariantContains(i.Key) == false)) - { - builder.Append(string.Format("{0}={1}&", i.Key, i.Value)); - } - return builder.ToString().TrimEnd('&'); - } - - /// - /// Converts the FormCollection to a dictionary - /// - /// - /// - public static IDictionary ToDictionary(this FormDataCollection items) - { - return items.ToDictionary(x => x.Key, x => (object)x.Value); - } - - /// - /// Returns the value of a mandatory item in the FormCollection - /// - /// - /// - /// - public static string GetRequiredString(this FormDataCollection items, string key) - { - if (items.HasKey(key) == false) - throw new ArgumentNullException("The " + key + " query string parameter was not found but is required"); - return items.Single(x => x.Key.InvariantEquals(key)).Value; - } - - /// - /// Checks if the collection contains the key - /// - /// - /// - /// - public static bool HasKey(this FormDataCollection items, string key) - { - return items.Any(x => x.Key.InvariantEquals(key)); - } - - /// - /// Returns the object based in the collection based on it's key. This does this with a conversion so if it doesn't convert a null object is returned. - /// - /// - /// - /// - /// - public static T GetValue(this FormDataCollection items, string key) - { - var val = items.Get(key); - if (string.IsNullOrEmpty(val)) return default(T); - - var converted = val.TryConvertTo(); - return converted.Success - ? converted.Result - : default(T); - } - - /// - /// Returns the object based in the collection based on it's key. This does this with a conversion so if it doesn't convert or the query string is no there an exception is thrown - /// - /// - /// - /// - /// - public static T GetRequiredValue(this FormDataCollection items, string key) - { - var val = items.Get(key); - if (string.IsNullOrEmpty(val)) - throw new InvalidOperationException($"The required query string parameter {key} is missing"); - - var converted = val.TryConvertTo(); - return converted.Success - ? converted.Result - : throw new InvalidOperationException($"The required query string parameter {key} cannot be converted to type {typeof(T)}"); - } - } -} diff --git a/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs deleted file mode 100644 index f443abbb70..0000000000 --- a/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.IO; -using System.Web.Mvc; - -namespace Umbraco.Web.Mvc -{ - /// - /// This is a special filter which is required for the RTE to be able to render Partial View Macros that - /// contain forms when the RTE value is resolved outside of an MVC view being rendered - /// - /// - /// The entire way that we support partial view macros that contain forms isn't really great, these forms - /// need to be executed as ChildActions so that the ModelState,ViewData,TempData get merged into that action - /// so the form can show errors, viewdata, etc... - /// Under normal circumstances, macros will be rendered after a ViewContext is created but in some cases - /// developers will resolve the RTE value in the controller, in this case the Form won't be rendered correctly - /// with merged ModelState from the controller because the special DataToken hasn't been set yet (which is - /// normally done in the UmbracoViewPageOfModel when a real ViewContext is available. - /// So we need to detect if the currently rendering controller is IRenderController and if so we'll ensure that - /// this DataToken exists before the action executes in case the developer resolves an RTE value that contains - /// a partial view macro form. - /// - /// Migrated already to .Net Core - internal class EnsurePartialViewMacroViewContextFilterAttribute : ActionFilterAttribute - { - /// - /// Ensures the custom ViewContext datatoken is set before the RenderController action is invoked, - /// this ensures that any calls to GetPropertyValue with regards to RTE or Grid editors can still - /// render any PartialViewMacro with a form and maintain ModelState - /// - /// - public override void OnActionExecuting(ActionExecutingContext filterContext) - { - //ignore anything that is not IRenderController - if ((filterContext.Controller is IRenderController) == false && filterContext.IsChildAction == false) - return; - - SetViewContext(filterContext); - } - - /// - /// Ensures that the custom ViewContext datatoken is set after the RenderController action is invoked, - /// this ensures that any custom ModelState that may have been added in the RenderController itself is - /// passed onwards in case it is required when rendering a PartialViewMacro with a form - /// - /// The filter context. - public override void OnResultExecuting(ResultExecutingContext filterContext) - { - //ignore anything that is not IRenderController - if ((filterContext.Controller is IRenderController) == false && filterContext.IsChildAction == false) - return; - - SetViewContext(filterContext); - } - - private void SetViewContext(ControllerContext controllerContext) - { - var viewCtx = new ViewContext( - controllerContext, - new DummyView(), - controllerContext.Controller.ViewData, controllerContext.Controller.TempData, - new StringWriter()); - - //set the special data token - controllerContext.RequestContext.RouteData.DataTokens[Constants.DataTokenCurrentViewContext] = viewCtx; - } - - private class DummyView : IView - { - public void Render(ViewContext viewContext, TextWriter writer) - { - } - } - } -} diff --git a/src/Umbraco.Web/Mvc/IRenderController.cs b/src/Umbraco.Web/Mvc/IRenderController.cs index 0de585959c..cddd51ef5f 100644 --- a/src/Umbraco.Web/Mvc/IRenderController.cs +++ b/src/Umbraco.Web/Mvc/IRenderController.cs @@ -1,12 +1,7 @@ -using System.Web.Mvc; - -namespace Umbraco.Web.Mvc +namespace Umbraco.Web.Mvc { - /// - /// A marker interface to designate that a controller will be used for Umbraco front-end requests and/or route hijacking - /// - /// Migrated already to .Net Core - public interface IRenderController : IController + //Migrated to .NET Core + public interface IRenderController { } diff --git a/src/Umbraco.Web/Mvc/IRenderMvcController.cs b/src/Umbraco.Web/Mvc/IRenderMvcController.cs index 492291d7c0..542e46ac2c 100644 --- a/src/Umbraco.Web/Mvc/IRenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/IRenderMvcController.cs @@ -1,19 +1,8 @@ -using System.Web.Mvc; -using Umbraco.Core.Composing; -using Umbraco.Web.Models; - -namespace Umbraco.Web.Mvc +namespace Umbraco.Web.Mvc { - /// - /// The interface that must be implemented for a controller to be designated to execute for route hijacking - /// - public interface IRenderMvcController : IRenderController, IDiscoverable + //Migrated to .NET Core + public interface IRenderMvcController : IRenderController { - /// - /// The default action to render the front-end view - /// - /// - /// - ActionResult Index(ContentModel model); + } } diff --git a/src/Umbraco.Web/Mvc/JsonNetResult.cs b/src/Umbraco.Web/Mvc/JsonNetResult.cs deleted file mode 100644 index c086b5f375..0000000000 --- a/src/Umbraco.Web/Mvc/JsonNetResult.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using System.Web.Mvc; -using Newtonsoft.Json; - -namespace Umbraco.Web.Mvc -{ - - /// - /// Custom json result using newtonsoft json.net - /// - /// Migrated already to .Net Core - public class JsonNetResult : ActionResult - { - public Encoding ContentEncoding { get; set; } - public string ContentType { get; set; } - public object Data { get; set; } - - public JsonSerializerSettings SerializerSettings { get; set; } - public Formatting Formatting { get; set; } - - public JsonNetResult() - { - SerializerSettings = new JsonSerializerSettings(); - } - - public override void ExecuteResult(ControllerContext context) - { - if (context == null) - throw new ArgumentNullException("context"); - - HttpResponseBase response = context.HttpContext.Response; - - response.ContentType = string.IsNullOrEmpty(ContentType) == false - ? ContentType - : "application/json"; - - if (ContentEncoding != null) - response.ContentEncoding = ContentEncoding; - - if (Data != null) - { - var writer = new JsonTextWriter(response.Output) { Formatting = Formatting }; - - var serializer = JsonSerializer.Create(SerializerSettings); - serializer.Serialize(writer, Data); - - writer.Flush(); - } - } - } - -} diff --git a/src/Umbraco.Web/Mvc/MinifyJavaScriptResultAttribute.cs b/src/Umbraco.Web/Mvc/MinifyJavaScriptResultAttribute.cs deleted file mode 100644 index 635a7314c5..0000000000 --- a/src/Umbraco.Web/Mvc/MinifyJavaScriptResultAttribute.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Web.Mvc; -using Umbraco.Web.Composing; -using Umbraco.Core.Hosting; -using Umbraco.Core.Runtime; -using Umbraco.Core.WebAssets; - -namespace Umbraco.Web.Mvc -{ - /// - /// Minifies the result for the JavaScriptResult - /// - /// - /// Only minifies in release mode - /// - /// Migrated already to .Net Core - public class MinifyJavaScriptResultAttribute : ActionFilterAttribute - { - private readonly IHostingEnvironment _hostingEnvironment; - private readonly IRuntimeMinifier _runtimeMinifier; - - public MinifyJavaScriptResultAttribute() - { - _hostingEnvironment = Current.HostingEnvironment; - _runtimeMinifier = Current.RuntimeMinifier; - } - - public MinifyJavaScriptResultAttribute(IHostingEnvironment hostingEnvironment, IRuntimeMinifier runtimeMinifier) - { - _hostingEnvironment = hostingEnvironment; - _runtimeMinifier = runtimeMinifier; - } - - /// - /// Minify the result if in release mode - /// - /// - public override void OnResultExecuting(ResultExecutingContext filterContext) - { - base.OnResultExecuting(filterContext); - - if (filterContext.Result == null) return; - var jsResult = filterContext.Result as JavaScriptResult; - if (jsResult == null) return; - if (_hostingEnvironment.IsDebugMode) return; - - //minify the result - var result = jsResult.Script; - var minified = _runtimeMinifier.MinifyAsync(result, AssetType.Javascript).GetAwaiter().GetResult(); - jsResult.Script = minified; - } - } -} diff --git a/src/Umbraco.Web/Mvc/RenderActionInvoker.cs b/src/Umbraco.Web/Mvc/RenderActionInvoker.cs index c86d2f77c3..47e77bb4f4 100644 --- a/src/Umbraco.Web/Mvc/RenderActionInvoker.cs +++ b/src/Umbraco.Web/Mvc/RenderActionInvoker.cs @@ -13,8 +13,6 @@ namespace Umbraco.Web.Mvc /// public class RenderActionInvoker : AsyncControllerActionInvoker { - - /// /// Ensures that if an action for the Template name is not explicitly defined by a user, that the 'Index' action will execute /// diff --git a/src/Umbraco.Web/Mvc/RenderIndexActionSelectorAttribute.cs b/src/Umbraco.Web/Mvc/RenderIndexActionSelectorAttribute.cs deleted file mode 100644 index 99aa88b3e2..0000000000 --- a/src/Umbraco.Web/Mvc/RenderIndexActionSelectorAttribute.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Linq; -using System.Reflection; -using System.Web.Mvc; - -namespace Umbraco.Web.Mvc -{ - /// - /// A custom ActionMethodSelector which will ensure that the RenderMvcController.Index(ContentModel model) action will be executed - /// if the - /// - internal class RenderIndexActionSelectorAttribute : ActionMethodSelectorAttribute - { - private static readonly ConcurrentDictionary ControllerDescCache = new ConcurrentDictionary(); - - /// - /// Determines whether the action method selection is valid for the specified controller context. - /// - /// - /// true if the action method selection is valid for the specified controller context; otherwise, false. - /// - /// The controller context.Information about the action method. - public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) - { - var currType = methodInfo.ReflectedType; - var baseType = methodInfo.DeclaringType; - - //It's the same type, so this must be the Index action to use - if (currType == baseType) return true; - - if (currType == null) return false; - - var controllerDesc = ControllerDescCache.GetOrAdd(currType, type => new ReflectedControllerDescriptor(currType)); - var actions = controllerDesc.GetCanonicalActions(); - - //If there are more than one Index action for this controller, then - // this base class one should not be matched - return actions.Count(x => x.ActionName == "Index") <= 1; - } - } -} diff --git a/src/Umbraco.Web/Mvc/RenderMvcController.cs b/src/Umbraco.Web/Mvc/RenderMvcController.cs index 42fef69f0f..1a4a32eadf 100644 --- a/src/Umbraco.Web/Mvc/RenderMvcController.cs +++ b/src/Umbraco.Web/Mvc/RenderMvcController.cs @@ -1,106 +1,11 @@ -using System; using System.Web.Mvc; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Logging; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.Services; -using Umbraco.Web.Models; -using Umbraco.Web.Routing; namespace Umbraco.Web.Mvc { - - /// - /// Represents the default front-end rendering controller. - /// - [PreRenderViewActionFilter] - [ModelBindingExceptionFilter] - public class RenderMvcController : UmbracoController, IRenderMvcController + //Migrated to .NET Core + public class RenderMvcController : Controller, IRenderMvcController { - private IPublishedRequest _publishedRequest; - private readonly ILogger _logger; - public RenderMvcController() - { - ActionInvoker = new RenderActionInvoker(); - } - public RenderMvcController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory) - : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, loggerFactory) - { - ActionInvoker = new RenderActionInvoker(); - _logger = loggerFactory.CreateLogger(); - } - - /// - /// Gets the Umbraco context. - /// - public override IUmbracoContext UmbracoContext => PublishedRequest.UmbracoContext; //TODO: Why? - - /// - /// Gets the current content item. - /// - protected IPublishedContent CurrentPage => PublishedRequest.PublishedContent; - - /// - /// Gets the current published content request. - /// - protected internal virtual IPublishedRequest PublishedRequest - { - get - { - if (_publishedRequest != null) - return _publishedRequest; - if (RouteData.DataTokens.ContainsKey(Core.Constants.Web.PublishedDocumentRequestDataToken) == false) - { - throw new InvalidOperationException("DataTokens must contain an 'umbraco-doc-request' key with a PublishedRequest object"); - } - _publishedRequest = (IPublishedRequest)RouteData.DataTokens[Core.Constants.Web.PublishedDocumentRequestDataToken]; - return _publishedRequest; - } - } - - /// - /// Ensures that a physical view file exists on disk. - /// - /// The view name. - protected bool EnsurePhsyicalViewExists(string template) - { - var result = ViewEngines.Engines.FindView(ControllerContext, template, null); - if (result.View != null) return true; - - _logger.LogWarning("No physical template file was found for template {Template}", template); - return false; - } - - /// - /// Gets an action result based on the template name found in the route values and a model. - /// - /// The type of the model. - /// The model. - /// The action result. - /// If the template found in the route values doesn't physically exist, then an empty ContentResult will be returned. - protected ActionResult CurrentTemplate(T model) - { - var template = ControllerContext.RouteData.Values["action"].ToString(); - if (EnsurePhsyicalViewExists(template) == false) - throw new Exception("No physical template file was found for template " + template); - return View(template, model); - } - - /// - /// The default action to render the front-end view. - /// - /// - /// - [RenderIndexActionSelector] - public virtual ActionResult Index(ContentModel model) - { - return CurrentTemplate(model); - } } } diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs deleted file mode 100644 index 520a0ef738..0000000000 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Logging; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Core.Services; - -namespace Umbraco.Web.Mvc -{ - /// - /// Provides a base class for authorized Umbraco controllers. - /// - /// - /// This controller essentially just uses a global UmbracoAuthorizeAttribute, inheritors that require more granular control over the - /// authorization of each method can use this attribute instead of inheriting from this controller. - /// - [UmbracoAuthorize] - [DisableBrowserCache] - public abstract class UmbracoAuthorizedController : UmbracoController - { - protected UmbracoAuthorizedController() - { - } - - protected UmbracoAuthorizedController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory) - : base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, loggerFactory) - { - } - } -} diff --git a/src/Umbraco.Web/Mvc/UmbracoController.cs b/src/Umbraco.Web/Mvc/UmbracoController.cs deleted file mode 100644 index 2e95cd9d8f..0000000000 --- a/src/Umbraco.Web/Mvc/UmbracoController.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Web; -using System.Web.Mvc; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.Owin; -using Umbraco.Core.Cache; -using Umbraco.Web.Composing; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core; -using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Services; -using Umbraco.Web.Security; - -namespace Umbraco.Web.Mvc -{ - /// - /// Provides a base class for Umbraco controllers. - /// - public abstract class UmbracoController : Controller - { - // for debugging purposes - internal Guid InstanceId { get; } = Guid.NewGuid(); - - /// - /// Gets or sets the Umbraco context. - /// - public IOptions GlobalSettings { get; } - - /// - /// Gets the Umbraco context. - /// - public virtual IUmbracoContext UmbracoContext => UmbracoContextAccessor.UmbracoContext; - - /// - /// Gets or sets the Umbraco context accessor. - /// - public IUmbracoContextAccessor UmbracoContextAccessor { get; set; } - - /// - /// Gets or sets the services context. - /// - public ServiceContext Services { get; } - - /// - /// Gets or sets the application cache. - /// - public AppCaches AppCaches { get; } - - - /// - /// Gets or sets the profiling logger. - /// - public IProfilingLogger ProfilingLogger { get; set; } - - /// - /// Gets the LoggerFactory - /// - public ILoggerFactory LoggerFactory { get; } - - protected IOwinContext OwinContext => Request.GetOwinContext(); - - /// - /// Gets the Umbraco helper. - /// - public UmbracoHelper Umbraco { get; } - - /// - /// Gets the web security helper. - /// - public virtual IBackOfficeSecurity Security => UmbracoContext.Security; - - protected UmbracoController() - : this( - Current.Factory.GetInstance>(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance(), - Current.Factory.GetInstance() - ) - { - } - - protected UmbracoController(IOptions globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory) - { - GlobalSettings = globalSettings; - UmbracoContextAccessor = umbracoContextAccessor; - Services = services; - AppCaches = appCaches; - ProfilingLogger = profilingLogger; - LoggerFactory = loggerFactory; - } - } -} diff --git a/src/Umbraco.Web/Mvc/UmbracoViewPage.cs b/src/Umbraco.Web/Mvc/UmbracoViewPage.cs deleted file mode 100644 index a41d692b86..0000000000 --- a/src/Umbraco.Web/Mvc/UmbracoViewPage.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Web.WebPages; -using Umbraco.Core.Models.PublishedContent; - -namespace Umbraco.Web.Mvc -{ - public abstract class UmbracoViewPage : UmbracoViewPage - { - - } -} diff --git a/src/Umbraco.Web/Runtime/WebInitialComponent.cs b/src/Umbraco.Web/Runtime/WebInitialComponent.cs index 9108dd820e..a5c7db12c9 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComponent.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComponent.cs @@ -66,7 +66,7 @@ namespace Umbraco.Web.Runtime private static void ConfigureGlobalFilters() { - GlobalFilters.Filters.Add(new EnsurePartialViewMacroViewContextFilterAttribute()); + //GlobalFilters.Filters.Add(new EnsurePartialViewMacroViewContextFilterAttribute()); } // internal for tests diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 90706f346f..591a3698e7 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -1,4 +1,5 @@ -using System.Web.Security; +using System.Web.Mvc; +using System.Web.Security; using Microsoft.AspNet.SignalR; using Umbraco.Core; using Umbraco.Core.Composing; @@ -58,7 +59,7 @@ namespace Umbraco.Web.Runtime composition // TODO: This will depend on if we use ServiceBasedControllerActivator - see notes in Startup.cs .ComposeUmbracoControllers(GetType().Assembly) - .SetDefaultRenderMvcController(); // default controller for template views + .SetDefaultRenderMvcController(); // default controller for template views //we need to eagerly scan controller types since they will need to be routed composition.WithCollectionBuilder() diff --git a/src/Umbraco.Web/Security/ConfiguredPasswordValidator.cs b/src/Umbraco.Web/Security/ConfiguredPasswordValidator.cs deleted file mode 100644 index bbc9722f69..0000000000 --- a/src/Umbraco.Web/Security/ConfiguredPasswordValidator.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.AspNet.Identity; -using System.Collections.Generic; -using System.Threading.Tasks; -using Umbraco.Core.Configuration; - -namespace Umbraco.Core.Security -{ - // NOTE: Migrated to netcore (in a different way) - public interface IPasswordValidator - { - Task>> ValidateAsync(IPasswordConfiguration config, string password); - } - - // NOTE: Migrated to netcore (in a different way) - public class ConfiguredPasswordValidator : PasswordValidator, IPasswordValidator - { - async Task>> IPasswordValidator.ValidateAsync(IPasswordConfiguration passwordConfiguration, string password) - { - RequiredLength = passwordConfiguration.RequiredLength; - RequireNonLetterOrDigit = passwordConfiguration.RequireNonLetterOrDigit; - RequireDigit = passwordConfiguration.RequireDigit; - RequireLowercase = passwordConfiguration.RequireLowercase; - RequireUppercase = passwordConfiguration.RequireUppercase; - - var result = await ValidateAsync(password); - if (result.Succeeded) - return Attempt>.Succeed(); - return Attempt>.Fail(result.Errors); - } - } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index fb04f02232..1758aa54c6 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -148,19 +148,20 @@ - + + + - @@ -188,7 +189,6 @@ - @@ -208,14 +208,12 @@ - - @@ -233,17 +231,13 @@ - - - - @@ -268,10 +262,7 @@ - - - @@ -281,8 +272,6 @@ - - @@ -292,9 +281,9 @@ - + @@ -306,26 +295,18 @@ - - - - - - - - @@ -359,7 +340,6 @@ - diff --git a/src/Umbraco.Web/WebApi/Filters/AppendUserModifiedHeaderAttribute.cs b/src/Umbraco.Web/WebApi/Filters/AppendUserModifiedHeaderAttribute.cs deleted file mode 100644 index 95e1a94787..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/AppendUserModifiedHeaderAttribute.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Web.Http.Filters; -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Web.Composing; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Appends a custom response header to notify the UI that the current user data has been modified - /// - /// Migrated to NET core - public sealed class AppendUserModifiedHeaderAttribute : ActionFilterAttribute - { - private readonly string _userIdParameter; - - /// - /// An empty constructor which will always set the header - /// - public AppendUserModifiedHeaderAttribute() - { - } - - /// - /// A constructor specifying the action parameter name containing the user id to match against the current user and if they match the header will be appended - /// - /// - public AppendUserModifiedHeaderAttribute(string userIdParameter) - { - if (userIdParameter == null) throw new ArgumentNullException("userIdParameter"); - _userIdParameter = userIdParameter; - } - - public static void AppendHeader(HttpActionExecutedContext actionExecutedContext) - { - if (actionExecutedContext.Response.Headers.Contains("X-Umb-User-Modified") == false) - { - actionExecutedContext.Response.Headers.Add("X-Umb-User-Modified", "1"); - } - } - - public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) - { - base.OnActionExecuted(actionExecutedContext); - - if (_userIdParameter.IsNullOrWhiteSpace()) - { - AppendHeader(actionExecutedContext); - } - else - { - var actionContext = actionExecutedContext.ActionContext; - if (actionContext.ActionArguments[_userIdParameter] == null) - { - throw new InvalidOperationException("No argument found for the current action with the name: " + _userIdParameter); - } - - var user = Current.UmbracoContext.Security.CurrentUser; - if (user == null) return; - - var userId = GetUserIdFromParameter(actionContext.ActionArguments[_userIdParameter]); - - if (userId == user.Id) - AppendHeader(actionExecutedContext); - } - - } - - private int GetUserIdFromParameter(object parameterValue) - { - if (parameterValue is int) - { - return (int)parameterValue; - } - throw new InvalidOperationException("The id type: " + parameterValue.GetType() + " is not a supported id"); - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs b/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs deleted file mode 100644 index cfb7ddb6bc..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/DisableBrowserCacheAttribute.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Net.Http.Headers; -using System.Web.Http.Filters; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Ensures that the request is not cached by the browser - /// - public class DisableBrowserCacheAttribute : ActionFilterAttribute - { - public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) - { - //See: http://stackoverflow.com/questions/17755239/how-to-stop-chrome-from-caching-rest-response-from-webapi - - base.OnActionExecuted(actionExecutedContext); - if (actionExecutedContext == null || actionExecutedContext.Response == null || - actionExecutedContext.Response.Headers == null) - { - return; - } - //NOTE: Until we upgraded to WebApi 2, this didn't work correctly and we had to revert to using - // HttpContext.Current responses. I've changed this back to what it should be now since it works - // and now with WebApi2, the HttpContext.Current responses don't! Anyways, all good now. - actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue() - { - NoCache = true, - NoStore = true, - MaxAge = new TimeSpan(0), - MustRevalidate = true - }; - - actionExecutedContext.Response.Headers.Pragma.Add(new NameValueHeaderValue("no-cache")); - if (actionExecutedContext.Response.Content != null) - { - actionExecutedContext.Response.Content.Headers.Expires = - //Mon, 01 Jan 1990 00:00:00 GMT - new DateTimeOffset(1990, 1, 1, 0, 0, 0, TimeSpan.Zero); - } - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs deleted file mode 100644 index b12fc51ca6..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Web.Http.Filters; -using Microsoft.Extensions.Logging; -using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Web.Composing; -using Umbraco.Web.Models.ContentEditing; -using File = System.IO.File; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Checks if the parameter is IHaveUploadedFiles and then deletes any temporary saved files from file uploads associated with the request - /// - internal sealed class FileUploadCleanupFilterAttribute : ActionFilterAttribute - { - private readonly bool _incomingModel; - - /// - /// Constructor specifies if the filter should analyze the incoming or outgoing model - /// - /// - public FileUploadCleanupFilterAttribute(bool incomingModel = true) - { - _incomingModel = incomingModel; - } - - public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) - { - base.OnActionExecuted(actionExecutedContext); - - var tempFolders = new List(); - - if (_incomingModel) - { - if (actionExecutedContext.ActionContext.ActionArguments.Any()) - { - if (actionExecutedContext.ActionContext.ActionArguments.First().Value is IHaveUploadedFiles contentItem) - { - //cleanup any files associated - foreach (var f in contentItem.UploadedFiles) - { - //track all temp folders so we can remove old files afterwards - var dir = Path.GetDirectoryName(f.TempFilePath); - if (tempFolders.Contains(dir) == false) - { - tempFolders.Add(dir); - } - - try - { - File.Delete(f.TempFilePath); - } - catch (System.Exception ex) - { - Current.Logger.LogError(ex, "Could not delete temp file {FileName}", f.TempFilePath); - } - } - } - } - } - else - { - if (actionExecutedContext == null) - { - Current.Logger.LogWarning("The actionExecutedContext is null!!??"); - return; - } - if (actionExecutedContext.Request == null) - { - Current.Logger.LogWarning("The actionExecutedContext.Request is null!!??"); - return; - } - if (actionExecutedContext.Request.Content == null) - { - Current.Logger.LogWarning("The actionExecutedContext.Request.Content is null!!??"); - return; - } - - ObjectContent objectContent; - - try - { - objectContent = actionExecutedContext.Response.Content as ObjectContent; - } - catch (System.Exception ex) - { - Current.Logger.LogError(ex, "Could not acquire actionExecutedContext.Response.Content"); - return; - } - - if (objectContent != null) - { - if (objectContent.Value is IHaveUploadedFiles uploadedFiles) - { - if (uploadedFiles.UploadedFiles != null) - { - //cleanup any files associated - foreach (var f in uploadedFiles.UploadedFiles) - { - if (f.TempFilePath.IsNullOrWhiteSpace() == false) - { - //track all temp folders so we can remove old files afterwards - var dir = Path.GetDirectoryName(f.TempFilePath); - if (tempFolders.Contains(dir) == false) - { - tempFolders.Add(dir); - } - - Current.Logger.LogDebug("Removing temp file {FileName}", f.TempFilePath); - - try - { - File.Delete(f.TempFilePath); - } - catch (System.Exception ex) - { - Current.Logger.LogError(ex, "Could not delete temp file {FileName}", f.TempFilePath); - } - - //clear out the temp path so it's not returned in the response - f.TempFilePath = ""; - } - else - { - Current.Logger.LogWarning("The f.TempFilePath is null or whitespace!!??"); - } - } - } - else - { - Current.Logger.LogWarning("The uploadedFiles.UploadedFiles is null!!??"); - } - } - else - { - Current.Logger.LogWarning("The actionExecutedContext.Request.Content.Value is not IHaveUploadedFiles, it is {ObjectType}", objectContent.Value.GetType()); - } - } - else - { - Current.Logger.LogWarning("The actionExecutedContext.Request.Content is not ObjectContent, it is {RequestObjectType}", actionExecutedContext.Request.Content.GetType()); - } - } - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/FilterGrouping.cs b/src/Umbraco.Web/WebApi/Filters/FilterGrouping.cs deleted file mode 100644 index fc3dc65675..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/FilterGrouping.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Web.Http.Filters; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Quickly split filters into different types - /// - internal class FilterGrouping - { - private readonly List _actionFilters = new List(); - private readonly List _authorizationFilters = new List(); - private readonly List _exceptionFilters = new List(); - - public FilterGrouping(IEnumerable filters) - { - if (filters == null) throw new ArgumentNullException("filters"); - - foreach (FilterInfo f in filters) - { - var filter = f.Instance; - Categorize(filter, _actionFilters); - Categorize(filter, _authorizationFilters); - Categorize(filter, _exceptionFilters); - } - } - - public IEnumerable ActionFilters - { - get { return _actionFilters; } - } - - public IEnumerable AuthorizationFilters - { - get { return _authorizationFilters; } - } - - public IEnumerable ExceptionFilters - { - get { return _exceptionFilters; } - } - - private static void Categorize(IFilter filter, List list) where T : class - { - T match = filter as T; - if (match != null) - { - list.Add(match); - } - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/HttpQueryStringModelBinder.cs b/src/Umbraco.Web/WebApi/Filters/HttpQueryStringModelBinder.cs deleted file mode 100644 index 3b8e4bea3f..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/HttpQueryStringModelBinder.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net.Http.Formatting; -using System.Web.Http.Controllers; -using System.Web.Http.ModelBinding; -using Umbraco.Core; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Allows an Action to execute with an arbitrary number of QueryStrings - /// - /// - /// Just like you can POST an arbitrary number of parameters to an Action, you can't GET an arbitrary number - /// but this will allow you to do it - /// - /// Migrated to .NET core - public sealed class HttpQueryStringModelBinder : IModelBinder - { - public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) - { - //get the query strings from the request properties - if (actionContext.Request.Properties.ContainsKey("MS_QueryNameValuePairs")) - { - if (actionContext.Request.Properties["MS_QueryNameValuePairs"] is IEnumerable> queryStrings) - { - var queryStringKeys = queryStrings.Select(kvp => kvp.Key).ToArray(); - var additionalParameters = new Dictionary(); - if(queryStringKeys.InvariantContains("culture") == false) { - additionalParameters["culture"] = actionContext.Request.ClientCulture(); - } - - var formData = new FormDataCollection(queryStrings.Union(additionalParameters)); - bindingContext.Model = formData; - return true; - } - } - return false; - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoApplicationAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoApplicationAuthorizeAttribute.cs deleted file mode 100644 index 37a8f8a4b4..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/UmbracoApplicationAuthorizeAttribute.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Linq; -using System.Web.Http; -using System.Web.Http.Controllers; -using Umbraco.Web.Composing; - -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Ensures that the current user has access to the specified application - /// - public sealed class UmbracoApplicationAuthorizeAttribute : OverridableAuthorizationAttribute - { - /// - /// Can be used by unit tests to enable/disable this filter - /// - internal static bool Enable = true; - - 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 UmbracoApplicationAuthorizeAttribute(params string[] appName) - { - _appNames = appName; - } - - protected override bool IsAuthorized(HttpActionContext actionContext) - { - if (Enable == false) - { - return true; - } - - var authorized = Current.UmbracoContext.Security.CurrentUser != null - && _appNames.Any(app => Current.UmbracoContext.Security.UserHasSectionAccess( - app, Current.UmbracoContext.Security.CurrentUser)); - - return authorized; - } - } -} diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs deleted file mode 100644 index 07829648c3..0000000000 --- a/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Linq; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; -using Umbraco.Core; -using Umbraco.Web.Composing; - -//MOVED to netcore -namespace Umbraco.Web.WebApi.Filters -{ - /// - /// Ensures that the current user has access to the application for which the specified tree(s) belongs - /// - /// - /// This would allow a tree to be moved between sections - /// - public sealed class UmbracoTreeAuthorizeAttribute : OverridableAuthorizationAttribute - { - /// - /// Can be used by unit tests to enable/disable this filter - /// - internal static bool Enable = true; - - private readonly string[] _treeAliases; - - /// - /// 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 UmbracoTreeAuthorizeAttribute(params string[] treeAliases) - { - _treeAliases = treeAliases; - } - - protected override bool IsAuthorized(HttpActionContext actionContext) - { - if (Enable == false) - { - return true; - } - - var apps = _treeAliases.Select(x => Current.TreeService - .GetByAlias(x)) - .WhereNotNull() - .Select(x => x.SectionAlias) - .Distinct() - .ToArray(); - - return Current.UmbracoContext.Security.CurrentUser != null - && apps.Any(app => Current.UmbracoContext.Security.UserHasSectionAccess( - app, Current.UmbracoContext.Security.CurrentUser)); - } - } -} diff --git a/src/Umbraco.Web/WebApi/JsonCamelCaseFormatter.cs b/src/Umbraco.Web/WebApi/JsonCamelCaseFormatter.cs deleted file mode 100644 index 62cde68cd4..0000000000 --- a/src/Umbraco.Web/WebApi/JsonCamelCaseFormatter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Linq; -using System.Net.Http.Formatting; -using System.Web.Http.Controllers; -using Newtonsoft.Json.Serialization; - -namespace Umbraco.Web.WebApi -{ - /// - /// Applying this attribute to any webapi controller will ensure that it only contains one json formatter with a camelCase formatter - /// - public class JsonCamelCaseFormatter : Attribute, IControllerConfiguration - { - public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) - { - //remove all json formatters then add our custom one - var toRemove = controllerSettings.Formatters.Where(t => (t is JsonMediaTypeFormatter)).ToList(); - foreach (var r in toRemove) - { - controllerSettings.Formatters.Remove(r); - } - - var jsonFormatter = new JsonMediaTypeFormatter - { - SerializerSettings = - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - } - }; - controllerSettings.Formatters.Add(jsonFormatter); - } - - } -} diff --git a/src/Umbraco.Web/WebApi/PrefixlessBodyModelValidator.cs b/src/Umbraco.Web/WebApi/PrefixlessBodyModelValidator.cs deleted file mode 100644 index a9838f3413..0000000000 --- a/src/Umbraco.Web/WebApi/PrefixlessBodyModelValidator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Web.Http.Controllers; -using System.Web.Http.Metadata; -using System.Web.Http.Validation; - -namespace Umbraco.Web.WebApi -{ - /// - /// By default WebApi always appends a prefix to any ModelState error but we don't want this, - /// so this is a custom validator that ensures there is no prefix set. - /// - /// - /// We were already doing this with the content/media/members validation since we had to manually validate because we - /// were posting multi-part values. We were always passing in an empty prefix so it worked. However for other editors we - /// are validating with normal data annotations (for the most part) and we don't want the prefix there either. - /// - internal class PrefixlessBodyModelValidator : IBodyModelValidator - { - private readonly IBodyModelValidator _innerValidator; - - public PrefixlessBodyModelValidator(IBodyModelValidator innerValidator) - { - if (innerValidator == null) - { - throw new ArgumentNullException("innerValidator"); - } - - _innerValidator = innerValidator; - } - - public bool Validate(object model, Type type, ModelMetadataProvider metadataProvider, HttpActionContext actionContext, string keyPrefix) - { - // Remove the keyPrefix but otherwise let innerValidator do what it normally does. - return _innerValidator.Validate(model, type, metadataProvider, actionContext, string.Empty); - } - } -} diff --git a/src/Umbraco.Web/WebApi/PrefixlessBodyModelValidatorAttribute.cs b/src/Umbraco.Web/WebApi/PrefixlessBodyModelValidatorAttribute.cs deleted file mode 100644 index b13cf983a5..0000000000 --- a/src/Umbraco.Web/WebApi/PrefixlessBodyModelValidatorAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Web.Http; -using System.Web.Http.Controllers; -using System.Web.Http.Validation; - -namespace Umbraco.Web.WebApi -{ - /// - /// Applying this attribute to any webapi controller will ensure that the is of type - /// - internal class PrefixlessBodyModelValidatorAttribute : Attribute, IControllerConfiguration - { - public virtual void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) - { - //replace the normal validator with our custom one for this controller - controllerSettings.Services.Replace(typeof(IBodyModelValidator), - new PrefixlessBodyModelValidator(controllerSettings.Services.GetBodyModelValidator())); - } - } -} diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index 993fd36bc2..87627501bd 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -23,9 +23,9 @@ namespace Umbraco.Web.WebApi [IsBackOffice] // [UmbracoUserTimeoutFilter] has been migrated to netcore [UmbracoAuthorize] - [DisableBrowserCache] - // [UmbracoWebApiRequireHttps] - // [CheckIfUserTicketDataIsStale] + // [DisableBrowserCache] has been migrated to netcore + // [UmbracoWebApiRequireHttps] + // [CheckIfUserTicketDataIsStale] // [UnhandedExceptionLoggerConfiguration] [EnableDetailedErrors] public abstract class UmbracoAuthorizedApiController : UmbracoApiController