Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/unit-test-project

This commit is contained in:
Bjarke Berg
2020-03-18 07:03:03 +01:00
2536 changed files with 40622 additions and 20198 deletions

View File

@@ -2,7 +2,7 @@
using System.Resources;
[assembly: AssemblyCompany("Umbraco")]
[assembly: AssemblyCopyright("Copyright © Umbraco 2019")]
[assembly: AssemblyCopyright("Copyright © Umbraco 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

View File

@@ -1,29 +0,0 @@
using Umbraco.Core.Sync;
namespace Umbraco.Core.Cache
{
/// <summary>
/// A base class for "json" cache refreshers.
/// </summary>
/// <typeparam name="TInstanceType">The actual cache refresher type.</typeparam>
/// <remarks>The actual cache refresher type is used for strongly typed events.</remarks>
public abstract class JsonCacheRefresherBase<TInstanceType> : CacheRefresherBase<TInstanceType>, IJsonCacheRefresher
where TInstanceType : class, ICacheRefresher
{
/// <summary>
/// Initializes a new instance of the <see cref="JsonCacheRefresherBase{TInstanceType}"/>.
/// </summary>
/// <param name="appCaches">A cache helper.</param>
protected JsonCacheRefresherBase(AppCaches appCaches) : base(appCaches)
{ }
/// <summary>
/// Refreshes as specified by a json payload.
/// </summary>
/// <param name="json">The json payload.</param>
public virtual void Refresh(string json)
{
OnCacheUpdated(This, new CacheRefresherEventArgs(json, MessageType.RefreshByJson));
}
}
}

View File

@@ -1,10 +0,0 @@
using Umbraco.Core.Logging;
namespace Umbraco.Composing
{
public static class Current
{
public static ILogger Logger { get; set; } = new NullLogger();
}
}

View File

@@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Umbraco.Core.Composing;
namespace Umbraco.Core
{
public static partial class CompositionExtensions
{
#region Collection Builders
/// <summary>
/// Gets the components collection builder.
/// </summary>
public static ComponentCollectionBuilder Components(this Composition composition)
=> composition.WithCollectionBuilder<ComponentCollectionBuilder>();
#endregion
}
}

View File

@@ -1,119 +0,0 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Configuration
{
/// <summary>
/// Represents Umbraco configurations.
/// </summary>
/// <remarks>
/// <para>During composition, use composition.Configs. When running, either inject the required configuration,
/// or use Current.Configs.</para>
/// </remarks>
public class Configs
{
private readonly Func<string, object> _configSectionResolver;
public Configs(Func<string, object> configSectionResolver)
{
_configSectionResolver = configSectionResolver ?? throw new ArgumentNullException(nameof(configSectionResolver));
}
private readonly Dictionary<Type, Lazy<object>> _configs = new Dictionary<Type, Lazy<object>>();
private Dictionary<Type, Action<IRegister>> _registerings = new Dictionary<Type, Action<IRegister>>();
private Lazy<IFactory> _factory;
/// <summary>
/// Gets a configuration.
/// </summary>
public TConfig GetConfig<TConfig>()
where TConfig : class
{
if (!_configs.TryGetValue(typeof(TConfig), out var configFactory))
throw new InvalidOperationException($"No configuration of type {typeof(TConfig)} has been added.");
return (TConfig) configFactory.Value;
}
/// <summary>
/// Adds a configuration, provided by a factory.
/// </summary>
public void Add<TConfig>(Func<TConfig> configFactory)
where TConfig : class
{
// make sure it is not too late
if (_registerings == null)
throw new InvalidOperationException("Configurations have already been registered.");
var typeOfConfig = typeof(TConfig);
var lazyConfigFactory = _configs[typeOfConfig] = new Lazy<object>(configFactory);
_registerings[typeOfConfig] = register => register.Register(_ => (TConfig) lazyConfigFactory.Value, Lifetime.Singleton);
}
/// <summary>
/// Adds a configuration, provided by a factory.
/// </summary>
public void Add<TConfig>(Func<IFactory, TConfig> configFactory)
where TConfig : class
{
// make sure it is not too late
if (_registerings == null)
throw new InvalidOperationException("Configurations have already been registered.");
var typeOfConfig = typeof(TConfig);
_configs[typeOfConfig] = new Lazy<object>(() =>
{
if (!(_factory is null)) return _factory.Value.GetInstance<TConfig>();
throw new InvalidOperationException($"Cannot get configuration of type {typeOfConfig} during composition.");
});
_registerings[typeOfConfig] = register => register.Register(configFactory, Lifetime.Singleton);
}
/// <summary>
/// Adds a configuration, provided by a configuration section.
/// </summary>
public void Add<TConfig>(string sectionName)
where TConfig : class
{
Add(() => GetConfig<TConfig>(sectionName));
}
private TConfig GetConfig<TConfig>(string sectionName)
where TConfig : class
{
// note: need to use SafeCallContext here because ConfigurationManager.GetSection ends up getting AppDomain.Evidence
// which will want to serialize the call context including anything that is in there - what a mess!
using (new SafeCallContext())
{
if ((_configSectionResolver(sectionName) is TConfig config))
return config;
var ex = new InvalidOperationException($"Could not get configuration section \"{sectionName}\" from config files.");
throw ex;
}
}
/// <summary>
/// Registers configurations in a register.
/// </summary>
public void RegisterWith(IRegister register, Func<IFactory> factory)
{
// do it only once
if (_registerings == null)
throw new InvalidOperationException("Configurations have already been registered.");
_factory = new Lazy<IFactory>(factory);
register.Register(this);
foreach (var registering in _registerings.Values)
registering(register);
// no need to keep them around
_registerings = null;
}
}
}

View File

@@ -1,71 +0,0 @@
using System.IO;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Grid;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
namespace Umbraco.Core
{
/// <summary>
/// Provides extension methods for the <see cref="Configs"/> class.
/// </summary>
public static class ConfigsExtensions
{
public static IGlobalSettings Global(this Configs configs)
=> configs.GetConfig<IGlobalSettings>();
public static IHostingSettings Hosting(this Configs configs)
=> configs.GetConfig<IHostingSettings>();
public static IConnectionStrings ConnectionStrings(this Configs configs)
=> configs.GetConfig<IConnectionStrings>();
public static IUmbracoSettingsSection Settings(this Configs configs)
=> configs.GetConfig<IUmbracoSettingsSection>();
public static IHealthChecks HealthChecks(this Configs configs)
=> configs.GetConfig<IHealthChecks>();
public static IGridConfig Grids(this Configs configs)
=> configs.GetConfig<IGridConfig>();
public static ICoreDebug CoreDebug(this Configs configs)
=> configs.GetConfig<ICoreDebug>();
public static IUserPasswordConfiguration UserPasswordConfiguration(this Configs configs)
=> configs.GetConfig<IUserPasswordConfiguration>();
public static IMemberPasswordConfiguration MemberPasswordConfiguration(this Configs configs)
=> configs.GetConfig<IMemberPasswordConfiguration>();
public static void AddPasswordConfigurations(this Configs configs)
{
configs.Add<IUserPasswordConfiguration>(() =>
{
return new UserPasswordConfiguration(configs.Settings().Security.UserPasswordConfiguration);
});
configs.Add<IMemberPasswordConfiguration>(() =>
{
return new MemberPasswordConfiguration(configs.Settings().Security.MemberPasswordConfiguration);
});
}
public static void AddCoreConfigs(this Configs configs, IIOHelper ioHelper)
{
var configDir = new DirectoryInfo(ioHelper.MapPath(Constants.SystemDirectories.Config));
// GridConfig depends on runtime caches, manifest parsers... and cannot be available during composition
configs.Add<IGridConfig>(factory => new GridConfig(
factory.GetInstance<ILogger>(),
factory.GetInstance<AppCaches>(),
configDir,
factory.GetInstance<IManifestParser>(),
factory.GetInstance<IRuntimeState>().Debug));
}
}
}

View File

@@ -1,45 +0,0 @@
using System;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
{
public static class GlobalSettingsExtensions
{
private static string _mvcArea;
/// <summary>
/// This returns the string of the MVC Area route.
/// </summary>
/// <remarks>
/// This will return the MVC area that we will route all custom routes through like surface controllers, etc...
/// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin
/// we will convert the '/' to '-' and use that as the path. its a bit lame but will work.
///
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
/// </remarks>
public static string GetUmbracoMvcArea(this IGlobalSettings globalSettings, IIOHelper ioHelper)
{
if (_mvcArea != null) return _mvcArea;
_mvcArea = GetUmbracoMvcAreaNoCache(globalSettings, ioHelper);
return _mvcArea;
}
internal static string GetUmbracoMvcAreaNoCache(this IGlobalSettings globalSettings, IIOHelper ioHelper)
{
if (globalSettings.Path.IsNullOrWhiteSpace())
{
throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
}
var path = globalSettings.Path;
if (path.StartsWith(ioHelper.Root)) // beware of TrimStart, see U4-2518
path = path.Substring(ioHelper.Root.Length);
return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
}
}
}

View File

@@ -1,17 +0,0 @@
using System.IO;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
namespace Umbraco.Core.Configuration.Grid
{
public class GridConfig : IGridConfig
{
public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, IManifestParser manifestParser, bool isDebug)
{
EditorsConfig = new GridEditorsConfig(logger, appCaches, configFolder, manifestParser, isDebug);
}
public IGridEditorsConfig EditorsConfig { get; }
}
}

View File

@@ -1,10 +0,0 @@
namespace Umbraco.Core.Configuration
{
public interface IConnectionStrings
{
ConfigConnectionString this[string key]
{
get;
}
}
}

View File

@@ -1,41 +0,0 @@
using System;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Core.Configuration
{
public abstract class PasswordConfiguration : IPasswordConfiguration
{
protected PasswordConfiguration(IPasswordConfigurationSection configSection)
{
if (configSection == null)
{
throw new ArgumentNullException(nameof(configSection));
}
RequiredLength = configSection.RequiredLength;
RequireNonLetterOrDigit = configSection.RequireNonLetterOrDigit;
RequireDigit = configSection.RequireDigit;
RequireLowercase = configSection.RequireLowercase;
RequireUppercase = configSection.RequireUppercase;
UseLegacyEncoding = configSection.UseLegacyEncoding;
HashAlgorithmType = configSection.HashAlgorithmType;
MaxFailedAccessAttemptsBeforeLockout = configSection.MaxFailedAccessAttemptsBeforeLockout;
}
public int RequiredLength { get; }
public bool RequireNonLetterOrDigit { get; }
public bool RequireDigit { get; }
public bool RequireLowercase { get; }
public bool RequireUppercase { get; }
public bool UseLegacyEncoding { get; }
public string HashAlgorithmType { get; }
public int MaxFailedAccessAttemptsBeforeLockout { get; }
}
}

View File

@@ -1,6 +0,0 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IMemberPasswordConfigurationSection : IPasswordConfigurationSection
{
}
}

View File

@@ -1,21 +0,0 @@
using System;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IUmbracoSettingsSection : IUmbracoConfigurationSection
{
IBackOfficeSection BackOffice { get; }
IContentSection Content { get; }
ISecuritySection Security { get; }
IRequestHandlerSection RequestHandler { get; }
ILoggingSection Logging { get; }
IWebRoutingSection WebRouting { get; }
IKeepAliveSection KeepAlive { get; }
}
}

View File

@@ -1,6 +0,0 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IUserPasswordConfigurationSection : IPasswordConfigurationSection
{
}
}

View File

@@ -1,24 +0,0 @@
namespace Umbraco.Core
{
public static partial class Constants
{
/// <summary>
/// Defines the identifiers for Umbraco system nodes.
/// </summary>
public static class Web
{
public const string UmbracoContextDataToken = "umbraco-context";
public const string UmbracoDataToken = "umbraco";
public const string PublishedDocumentRequestDataToken = "umbraco-doc-request";
public const string CustomRouteDataToken = "umbraco-custom-route";
public const string UmbracoRouteDefinitionDataToken = "umbraco-route-def";
/// <summary>
/// The preview cookie name
/// </summary>
public const string PreviewCookieName = "UMB_PREVIEW";
public const string InstallerCookieName = "umb_installId";
}
}
}

View File

@@ -1,83 +0,0 @@
using System;
namespace Umbraco.Core
{
/// <summary>
/// Provides extension methods to enums.
/// </summary>
public static class EnumExtensions
{
// note:
// - no need to HasFlagExact, that's basically an == test
// - HasFlagAll cannot be named HasFlag because ext. methods never take priority over instance methods
/// <summary>
/// Determines whether a flag enum has all the specified values.
/// </summary>
/// <remarks>
/// <para>True when all bits set in <paramref name="uses"/> are set in <paramref name="use"/>, though other bits may be set too.</para>
/// <para>This is the behavior of the original <see cref="Enum.HasFlag"/> method.</para>
/// </remarks>
public static bool HasFlagAll<T>(this T use, T uses)
where T : Enum
{
var num = Convert.ToUInt64(use);
var nums = Convert.ToUInt64(uses);
return (num & nums) == nums;
}
/// <summary>
/// Determines whether a flag enum has any of the specified values.
/// </summary>
/// <remarks>
/// <para>True when at least one of the bits set in <paramref name="uses"/> is set in <paramref name="use"/>.</para>
/// </remarks>
public static bool HasFlagAny<T>(this T use, T uses)
where T : Enum
{
var num = Convert.ToUInt64(use);
var nums = Convert.ToUInt64(uses);
return (num & nums) > 0;
}
/// <summary>
/// Sets a flag of the given input enum
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="input">Enum to set flag of</param>
/// <param name="flag">Flag to set</param>
/// <returns>A new enum with the flag set</returns>
public static T SetFlag<T>(this T input, T flag)
where T : Enum
{
var i = Convert.ToUInt64(input);
var f = Convert.ToUInt64(flag);
// bitwise OR to set flag f of enum i
var result = i | f;
return (T)Enum.ToObject(typeof(T), result);
}
/// <summary>
/// Unsets a flag of the given input enum
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="input">Enum to unset flag of</param>
/// <param name="flag">Flag to unset</param>
/// <returns>A new enum with the flag unset</returns>
public static T UnsetFlag<T>(this T input, T flag)
where T : Enum
{
var i = Convert.ToUInt64(input);
var f = Convert.ToUInt64(flag);
// bitwise AND combined with bitwise complement to unset flag f of enum i
var result = i & ~f;
return (T)Enum.ToObject(typeof(T), result);
}
}
}

View File

@@ -1,55 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.Core.Exceptions
{
/// <summary>
/// The exception that is thrown when a null reference, or an empty argument, is passed to a method that does not accept it as a valid argument.
/// </summary>
/// <seealso cref="System.ArgumentNullException" />
[Obsolete("Throw an ArgumentNullException when the parameter is null or an ArgumentException when its empty instead.")]
[Serializable]
public class ArgumentNullOrEmptyException : ArgumentNullException
{
/// <summary>
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class.
/// </summary>
public ArgumentNullOrEmptyException()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class with the name of the parameter that caused this exception.
/// </summary>
/// <param name="paramName">The named of the parameter that caused the exception.</param>
public ArgumentNullOrEmptyException(string paramName)
: base(paramName)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class with a specified error message and the name of the parameter that caused this exception.
/// </summary>
/// <param name="paramName">The named of the parameter that caused the exception.</param>
/// <param name="message">A message that describes the error.</param>
public ArgumentNullOrEmptyException(string paramName, string message)
: base(paramName, message)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class.
/// </summary>
/// <param name="message">The error message that explains the reason for this exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
public ArgumentNullOrEmptyException(string message, Exception innerException)
: base(message, innerException)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ArgumentNullOrEmptyException" /> class.
/// </summary>
/// <param name="info">The object that holds the serialized object data.</param>
/// <param name="context">An object that describes the source or destination of the serialized data.</param>
protected ArgumentNullOrEmptyException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
}
}

View File

@@ -1,52 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.Core.Exceptions
{
/// <summary>
/// The exception that is thrown when a requested method or operation is not, and will not be, implemented.
/// </summary>
/// <remarks>
/// The <see cref="NotImplementedException" /> is to be used when some code is not implemented,
/// but should eventually be implemented (i.e. work in progress) and is reported by tools such as ReSharper.
/// This exception is to be used when some code is not implemented, and is not meant to be, for whatever
/// reason.
/// </remarks>
/// <seealso cref="System.NotImplementedException" />
[Serializable]
[Obsolete("If a method or operation is not, and will not be, implemented, it is invalid or not supported, so we should throw either an InvalidOperationException or NotSupportedException instead.")]
public class WontImplementException : NotImplementedException
{
/// <summary>
/// Initializes a new instance of the <see cref="WontImplementException" /> class.
/// </summary>
public WontImplementException()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="WontImplementException" /> class with a specified reason message.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
public WontImplementException(string message)
: base(message)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="WontImplementException" /> class.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="inner">The exception that is the cause of the current exception. If the <paramref name="inner" /> parameter is not <see langword="null" />, the current exception is raised in a <see langword="catch" /> block that handles the inner exception.</param>
public WontImplementException(string message, Exception inner)
: base(message, inner)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="WontImplementException" /> class.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
protected WontImplementException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
}
}

View File

@@ -1,46 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.Core.IO
{
/// <summary>
/// The exception that is thrown when the caller does not have the required permission to access a file.
/// </summary>
/// <seealso cref="System.Exception" />
[Obsolete("Throw an UnauthorizedAccessException instead.")]
[Serializable]
public class FileSecurityException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="FileSecurityException" /> class.
/// </summary>
public FileSecurityException()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="FileSecurityException" /> class.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public FileSecurityException(string message)
: base(message)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="FileSecurityException" /> class.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference (<see langword="Nothing" /> in Visual Basic) if no inner exception is specified.</param>
public FileSecurityException(string message, Exception innerException)
: base(message, innerException)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="FileSecurityException" /> class.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
protected FileSecurityException(SerializationInfo info, StreamingContext context)
: base(info, context)
{ }
}
}

View File

@@ -1,19 +0,0 @@
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Must be implemented by property editors that store media and return media paths
/// </summary>
/// <remarks>
/// Currently there are only 2x core editors that do this: upload and image cropper.
/// It would be possible for developers to know implement their own media property editors whereas previously this was not possible.
/// </remarks>
public interface IDataEditorWithMediaPath
{
/// <summary>
/// Returns the media path for the value stored for a property
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
string GetMediaPath(object value);
}
}

View File

@@ -1,18 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.Core.Models
{
/// <summary>
/// Enum for the various types of Macros
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public enum MacroTypes
{
[EnumMember]
Unknown = 4,
[EnumMember]
PartialView = 7
}
}

View File

@@ -1,35 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: Guid("DA322714-FB89-4943-92BD-BB122B82F66B")]
// Umbraco Cms
[assembly: InternalsVisibleTo("Umbraco.Web")]
[assembly: InternalsVisibleTo("Umbraco.Web.UI")]
[assembly: InternalsVisibleTo("Umbraco.Examine")]
[assembly: InternalsVisibleTo("Umbraco.ModelsBuilder.Embedded")]
[assembly: InternalsVisibleTo("Umbraco.Tests")]
[assembly: InternalsVisibleTo("Umbraco.Tests.Benchmarks")]
// Allow this to be mocked in our unit tests
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
// Umbraco Deploy
[assembly: InternalsVisibleTo("Umbraco.Deploy")]
[assembly: InternalsVisibleTo("Umbraco.Deploy.UI")]
[assembly: InternalsVisibleTo("Umbraco.Deploy.Cloud")]
// Umbraco Forms
[assembly: InternalsVisibleTo("Umbraco.Forms.Core")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Core.Providers")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Web")]
// Umbraco Headless
[assembly: InternalsVisibleTo("Umbraco.Cloud.Headless")]
// code analysis
// IDE1006 is broken, wants _value syntax for consts, etc - and it's even confusing ppl at MS, kill it
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "~_~")]

View File

@@ -0,0 +1,15 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public class ActiveDirectorySettings : IActiveDirectorySettings
{
public ActiveDirectorySettings()
{
ActiveDirectoryDomain = ConfigurationManager.AppSettings["ActiveDirectoryDomain"];
}
public string ActiveDirectoryDomain { get; }
}
}

View File

@@ -1,39 +1,63 @@
using System.Configuration;
using Umbraco.Configuration;
using Umbraco.Configuration.Implementations;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.Implementations;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
{
public class ConfigsFactory : IConfigsFactory
{
public ConfigsFactory()
{
}
public IHostingSettings HostingSettings { get; } = new HostingSettings();
public ICoreDebug CoreDebug { get; } = new CoreDebug();
public IMachineKeyConfig MachineKeyConfig { get; } = new MachineKeyConfig();
public IIndexCreatorSettings IndexCreatorSettings { get; } = new IndexCreatorSettings();
public INuCacheSettings NuCacheSettings { get; } = new NuCacheSettings();
public ITypeFinderSettings TypeFinderSettings { get; } = new TypeFinderSettings();
public IRuntimeSettings RuntimeSettings { get; } = new RuntimeSettings();
public IActiveDirectorySettings ActiveDirectorySettings { get; } = new ActiveDirectorySettings();
public IExceptionFilterSettings ExceptionFilterSettings { get; } = new ExceptionFilterSettings();
public ITourSettings TourSettings { get; } = new TourSettings();
public ILoggingSettings LoggingSettings { get; } = new LoggingSettings();
public IKeepAliveSettings KeepAliveSettings { get; } = new KeepAliveSettings();
public IWebRoutingSettings WebRoutingSettings { get; } = new WebRoutingSettings();
public IRequestHandlerSettings RequestHandlerSettings { get; } = new RequestHandlerSettings();
public ISecuritySettings SecuritySettings { get; } = new SecuritySettings();
public IUserPasswordConfiguration UserPasswordConfigurationSettings { get; } = new UserPasswordConfigurationSettings();
public IMemberPasswordConfiguration MemberPasswordConfigurationSettings { get; } = new MemberPasswordConfigurationSettings();
public IContentSettings ContentSettings { get; } = new ContentSettings();
public IGlobalSettings GlobalSettings { get; } = new GlobalSettings();
public IHealthChecks HealthChecksSettings { get; } = new HealthChecksSettings();
public IConnectionStrings ConnectionStrings { get; } = new ConnectionStrings();
public IModelsBuilderConfig ModelsBuilderConfig { get; } = new ModelsBuilderConfig();
public IUmbracoSettingsSection UmbracoSettings { get; }
public Configs Create(IIOHelper ioHelper)
public Configs Create()
{
var configs = new Configs(section => ConfigurationManager.GetSection(section));
configs.Add<IGlobalSettings>(() => new GlobalSettings(ioHelper));
configs.Add(() => HostingSettings);
var configs = new Configs();
configs.Add<IUmbracoSettingsSection>("umbracoConfiguration/settings");
configs.Add<IHealthChecks>("umbracoConfiguration/HealthChecks");
configs.Add<IGlobalSettings>(() => GlobalSettings);
configs.Add<IHostingSettings>(() => HostingSettings);
configs.Add<IHealthChecks>(() => HealthChecksSettings);
configs.Add<ICoreDebug>(() => CoreDebug);
configs.Add<IMachineKeyConfig>(() => MachineKeyConfig);
configs.Add<IConnectionStrings>(() => ConnectionStrings);
configs.Add<IModelsBuilderConfig>(() => ModelsBuilderConfig);
configs.Add<IIndexCreatorSettings>(() => IndexCreatorSettings);
configs.Add<INuCacheSettings>(() => NuCacheSettings);
configs.Add<ITypeFinderSettings>(() => TypeFinderSettings);
configs.Add<IRuntimeSettings>(() => RuntimeSettings);
configs.Add<IActiveDirectorySettings>(() => ActiveDirectorySettings);
configs.Add<IExceptionFilterSettings>(() => ExceptionFilterSettings);
configs.Add<ITourSettings>(() => TourSettings);
configs.Add<ILoggingSettings>(() => LoggingSettings);
configs.Add<IKeepAliveSettings>(() => KeepAliveSettings);
configs.Add<IWebRoutingSettings>(() => WebRoutingSettings);
configs.Add<IRequestHandlerSettings>(() => RequestHandlerSettings);
configs.Add<ISecuritySettings>(() => SecuritySettings);
configs.Add<IUserPasswordConfiguration>(() => UserPasswordConfigurationSettings);
configs.Add<IMemberPasswordConfiguration>(() => MemberPasswordConfigurationSettings);
configs.Add<IContentSettings>(() => ContentSettings);
// Password configuration is held within IUmbracoSettingsSection from umbracoConfiguration/settings but we'll add explicitly
// so it can be independently retrieved in classes that need it.
configs.AddPasswordConfigurations();
configs.Add(() => CoreDebug);
configs.Add<IConnectionStrings>(() => new ConnectionStrings());
configs.AddCoreConfigs(ioHelper);
return configs;
}
}

View File

@@ -1,13 +1,17 @@
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Umbraco.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration
{
public class ConnectionStrings : IConnectionStrings
{
public ConfigConnectionString this[string key]
{
get
@@ -17,5 +21,94 @@ namespace Umbraco.Core.Configuration
return new ConfigConnectionString(settings.ConnectionString, settings.ProviderName, settings.Name);
}
}
public void RemoveConnectionString(string key, IIOHelper ioHelper)
{
var fileName = ioHelper.MapPath(string.Format("{0}/web.config", ioHelper.Root));
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key);
if (setting != null)
{
setting.Remove();
xml.Save(fileName, SaveOptions.DisableFormatting);
ConfigurationManager.RefreshSection("appSettings");
}
var settings = ConfigurationManager.ConnectionStrings[key];
}
/// <summary>
/// Saves the connection string as a proper .net connection string in web.config.
/// </summary>
/// <remarks>Saves the ConnectionString in the very nasty 'medium trust'-supportive way.</remarks>
/// <param name="connectionString">The connection string.</param>
/// <param name="providerName">The provider name.</param>
public void SaveConnectionString(string connectionString, string providerName, IIOHelper ioHelper)
{
if (connectionString == null) throw new ArgumentNullException(nameof(connectionString));
if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(connectionString));
if (providerName == null) throw new ArgumentNullException(nameof(providerName));
if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(providerName));
var fileSource = "web.config";
var fileName = ioHelper.MapPath(ioHelper.Root +"/" + fileSource);
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root).");
var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault();
if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings).");
// handle configSource
var configSourceAttribute = connectionStrings.Attribute("configSource");
if (configSourceAttribute != null)
{
fileSource = configSourceAttribute.Value;
fileName = ioHelper.MapPath(ioHelper.Root + "/" + fileSource);
if (!File.Exists(fileName))
throw new Exception($"Invalid configSource \"{fileSource}\" (no such file).");
xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root).");
connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault();
if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings).");
}
// create or update connection string
var setting = connectionStrings.Descendants("add").FirstOrDefault(s => s.Attribute("name")?.Value == Constants.System.UmbracoConnectionName);
if (setting == null)
{
connectionStrings.Add(new XElement("add",
new XAttribute("name", Constants.System.UmbracoConnectionName),
new XAttribute("connectionString", connectionString),
new XAttribute("providerName", providerName)));
}
else
{
AddOrUpdateAttribute(setting, "connectionString", connectionString);
AddOrUpdateAttribute(setting, "providerName", providerName);
}
// save
Current.Logger.Info<ConnectionStrings>("Saving connection string to {ConfigFile}.", fileSource);
xml.Save(fileName, SaveOptions.DisableFormatting);
Current.Logger.Info<ConnectionStrings>("Saved connection string to {ConfigFile}.", fileSource);
}
private static void AddOrUpdateAttribute(XElement element, string name, string value)
{
var attribute = element.Attribute(name);
if (attribute == null)
element.Add(new XAttribute(name, value));
else
attribute.Value = value;
}
}
}

View File

@@ -0,0 +1,18 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public class ExceptionFilterSettings : IExceptionFilterSettings
{
public ExceptionFilterSettings()
{
if (bool.TryParse(ConfigurationManager.AppSettings["Umbraco.Web.DisableModelBindingExceptionFilter"],
out var disabled))
{
Disabled = disabled;
}
}
public bool Disabled { get; }
}
}

View File

@@ -1,7 +1,10 @@
using System;
using System.Configuration;
using System.Linq;
using System.Net.Mail;
using System.Xml.Linq;
using Umbraco.Composing;
using Umbraco.Configuration;
using Umbraco.Core.IO;
namespace Umbraco.Core.Configuration
@@ -62,7 +65,6 @@ namespace Umbraco.Core.Configuration
/// </summary>
public class GlobalSettings : IGlobalSettings
{
private readonly IIOHelper _ioHelper;
// TODO these should not be static
private static string _reservedPaths;
@@ -72,11 +74,6 @@ namespace Umbraco.Core.Configuration
internal const string StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma!
internal const string StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma!
public GlobalSettings(IIOHelper ioHelper)
{
_ioHelper = ioHelper;
}
/// <summary>
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
/// </summary>
@@ -84,7 +81,6 @@ namespace Umbraco.Core.Configuration
{
_reservedPaths = null;
_reservedUrls = null;
HasSmtpServer = null;
}
/// <summary>
@@ -95,29 +91,39 @@ namespace Umbraco.Core.Configuration
{
ResetInternal();
}
public bool IsSmtpServerConfigured
{
get
{
var smtpSection = ConfigurationManager.GetSection("system.net/mailSettings/smtp") as ConfigurationSection;
if (smtpSection is null) return false;
var smtpSettings = SmtpSettings;
if (smtpSettings is null) return false;
if (!(smtpSettings.From is null)) return true;
if (!(smtpSettings.Host is null)) return true;
if (!(smtpSettings.PickupDirectoryLocation is null)) return true;
return false;
}
}
public ISmtpSettings SmtpSettings
{
get
{
var smtpSection = ConfigurationManager.GetSection("system.net/mailSettings/smtp") as ConfigurationSection;
if (smtpSection is null) return null;
var result = new SmtpSettings();
var from = smtpSection.ElementInformation.Properties["from"];
if (@from != null
&& @from.Value is string fromPropValue
&& string.IsNullOrEmpty(fromPropValue) == false
&& !string.Equals("noreply@example.com", fromPropValue, StringComparison.OrdinalIgnoreCase))
{
return true;
}
var networkSection = ConfigurationManager.GetSection("system.net/mailSettings/smtp/network") as ConfigurationSection;
var host = networkSection?.ElementInformation.Properties["host"];
if (host != null
&& host.Value is string hostPropValue
&& string.IsNullOrEmpty(hostPropValue) == false)
{
return true;
result.From = fromPropValue;
}
var specifiedPickupDirectorySection = ConfigurationManager.GetSection("system.net/mailSettings/smtp/specifiedPickupDirectory") as ConfigurationSection;
@@ -126,18 +132,21 @@ namespace Umbraco.Core.Configuration
&& pickupDirectoryLocation.Value is string pickupDirectoryLocationPropValue
&& string.IsNullOrEmpty(pickupDirectoryLocationPropValue) == false)
{
return true;
result.PickupDirectoryLocation = pickupDirectoryLocationPropValue;
}
return false;
// SmtpClient can magically read the section system.net/mailSettings/smtp/network, witch is always
// null if we use ConfigurationManager.GetSection. SmtpSection does not exist in .Net Standard
var smtpClient = new SmtpClient();
result.Host = smtpClient.Host;
result.Port = smtpClient.Port;
return result;
}
}
/// <summary>
/// For testing only
/// </summary>
internal static bool? HasSmtpServer { get; set; }
/// <summary>
/// Gets the reserved urls from web.config.
/// </summary>
@@ -185,36 +194,11 @@ namespace Umbraco.Core.Configuration
}
}
/// <summary>
/// Gets the name of the content XML file.
/// </summary>
/// <value>The content XML.</value>
/// <remarks>
/// Defaults to ~/App_Data/umbraco.config
/// </remarks>
public string ContentXmlFile
{
get
{
return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.ContentXML)
? ConfigurationManager.AppSettings[Constants.AppSettings.ContentXML]
: "~/App_Data/umbraco.config";
}
}
/// <summary>
/// Gets the path to umbraco's root directory (/umbraco by default).
/// </summary>
/// <value>The path.</value>
public string Path
{
get
{
return ConfigurationManager.AppSettings.ContainsKey(Constants.AppSettings.Path)
? _ioHelper.ResolveUrl(ConfigurationManager.AppSettings[Constants.AppSettings.Path])
: string.Empty;
}
}
public string Path => ConfigurationManager.AppSettings[Constants.AppSettings.Path];
/// <summary>
/// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
@@ -230,7 +214,7 @@ namespace Umbraco.Core.Configuration
}
set
{
SaveSetting(Constants.AppSettings.ConfigurationStatus, value, _ioHelper);
SaveSetting(Constants.AppSettings.ConfigurationStatus, value, Current.IOHelper); //TODO remove
}
}
@@ -257,26 +241,6 @@ namespace Umbraco.Core.Configuration
ConfigurationManager.RefreshSection("appSettings");
}
/// <summary>
/// Removes a setting from the configuration file.
/// </summary>
/// <param name="key">Key of the setting to be removed.</param>
public static void RemoveSetting(string key, IIOHelper ioHelper)
{
var fileName = ioHelper.MapPath(string.Format("{0}/web.config", ioHelper.Root));
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var appSettings = xml.Root.DescendantsAndSelf("appSettings").Single();
var setting = appSettings.Descendants("add").FirstOrDefault(s => s.Attribute("key").Value == key);
if (setting != null)
{
setting.Remove();
xml.Save(fileName, SaveOptions.DisableFormatting);
ConfigurationManager.RefreshSection("appSettings");
}
}
/// <summary>
/// Gets the time out in minutes.
@@ -405,6 +369,10 @@ namespace Umbraco.Core.Configuration
private string _databaseFactoryServerVersion;
public string DatabaseFactoryServerVersion => GetterWithDefaultValue(Constants.AppSettings.Debug.DatabaseFactoryServerVersion, string.Empty, ref _databaseFactoryServerVersion);
private string _mainDomLock;
public string MainDomLock => GetterWithDefaultValue(Constants.AppSettings.MainDomLock, string.Empty, ref _mainDomLock);
private T GetterWithDefaultValue<T>(string appSettingKey, T defaultValue, ref T backingField)
{
if (backingField != null) return backingField;
@@ -430,5 +398,22 @@ namespace Umbraco.Core.Configuration
return backingField;
}
/// <summary>
/// Gets the path to the razor file used when no published content is available.
/// </summary>
public string NoNodesViewPath
{
get
{
var configuredValue = ConfigurationManager.AppSettings[Constants.AppSettings.NoNodesViewPath];
if (!string.IsNullOrWhiteSpace(configuredValue))
{
return configuredValue;
}
return "~/config/splashes/NoNodes.cshtml";
}
}
}
}

View File

@@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class HealthChecksSection : ConfigurationSection, IHealthChecks
public class HealthChecksSection : ConfigurationSection
{
private const string DisabledChecksKey = "disabledChecks";
private const string NotificationSettingsKey = "notificationSettings";
@@ -21,14 +20,5 @@ namespace Umbraco.Core.Configuration.HealthChecks
get { return ((HealthCheckNotificationSettingsElement)(base[NotificationSettingsKey])); }
}
IEnumerable<IDisabledHealthCheck> IHealthChecks.DisabledChecks
{
get { return DisabledChecks; }
}
IHealthCheckNotificationSettings IHealthChecks.NotificationSettings
{
get { return NotificationSettings; }
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal abstract class ConfigurationManagerConfigBase
{
private UmbracoSettingsSection _umbracoSettingsSection;
protected UmbracoSettingsSection UmbracoSettingsSection
{
get
{
if (_umbracoSettingsSection is null)
{
_umbracoSettingsSection = ConfigurationManager.GetSection("umbracoConfiguration/settings") as UmbracoSettingsSection;
}
return _umbracoSettingsSection;
}
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Collections.Generic;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Macros;
namespace Umbraco.Configuration.Implementations
{
internal class ContentSettings : ConfigurationManagerConfigBase, IContentSettings
{
public string NotificationEmailAddress => UmbracoSettingsSection.Content.Notifications.NotificationEmailAddress;
public bool DisableHtmlEmail => UmbracoSettingsSection.Content.Notifications.DisableHtmlEmail;
public IEnumerable<string> ImageFileTypes => UmbracoSettingsSection.Content.Imaging.ImageFileTypes;
public IEnumerable<IImagingAutoFillUploadField> ImageAutoFillProperties => UmbracoSettingsSection.Content.Imaging.ImageAutoFillProperties;
public bool ResolveUrlsFromTextString => UmbracoSettingsSection.Content.ResolveUrlsFromTextString;
public IEnumerable<IContentErrorPage> Error404Collection => UmbracoSettingsSection.Content.Error404Collection;
public string PreviewBadge => UmbracoSettingsSection.Content.PreviewBadge;
public MacroErrorBehaviour MacroErrorBehaviour => UmbracoSettingsSection.Content.MacroErrors;
public IEnumerable<string> DisallowedUploadFiles => UmbracoSettingsSection.Content.DisallowedUploadFiles;
public IEnumerable<string> AllowedUploadFiles => UmbracoSettingsSection.Content.AllowedUploadFiles;
public bool ShowDeprecatedPropertyEditors => UmbracoSettingsSection.Content.ShowDeprecatedPropertyEditors;
public string LoginBackgroundImage => UmbracoSettingsSection.Content.LoginBackgroundImage;
}
}

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
namespace Umbraco.Core.Configuration.Implementations
{
public class HealthChecksSettings : IHealthChecks
{
private HealthChecksSection _healthChecksSection;
private HealthChecksSection HealthChecksSection
{
get
{
if (_healthChecksSection is null)
{
_healthChecksSection = ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks") as HealthChecksSection;
}
return _healthChecksSection;
}
}
public IEnumerable<IDisabledHealthCheck> DisabledChecks => HealthChecksSection.DisabledChecks;
public IHealthCheckNotificationSettings NotificationSettings => HealthChecksSection.NotificationSettings;
}
}

View File

@@ -0,0 +1,10 @@
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class KeepAliveSettings : ConfigurationManagerConfigBase, IKeepAliveSettings
{
public bool DisableKeepAliveTask => UmbracoSettingsSection.KeepAlive.DisableKeepAliveTask;
public string KeepAlivePingUrl => UmbracoSettingsSection.KeepAlive.KeepAlivePingUrl;
}
}

View File

@@ -0,0 +1,9 @@
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class LoggingSettings : ConfigurationManagerConfigBase, ILoggingSettings
{
public int MaxLogAge => UmbracoSettingsSection.Logging.MaxLogAge;
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration.Implementations
{
internal class MemberPasswordConfigurationSettings : ConfigurationManagerConfigBase, IMemberPasswordConfiguration
{
public int RequiredLength => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequiredLength;
public bool RequireNonLetterOrDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireNonLetterOrDigit;
public bool RequireDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireDigit;
public bool RequireLowercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireLowercase;
public bool RequireUppercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireUppercase;
public bool UseLegacyEncoding=> UmbracoSettingsSection.Security.UserPasswordConfiguration.UseLegacyEncoding;
public string HashAlgorithmType=> UmbracoSettingsSection.Security.UserPasswordConfiguration.HashAlgorithmType;
public int MaxFailedAccessAttemptsBeforeLockout => UmbracoSettingsSection.Security.UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout;
}
}

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class RequestHandlerSettings : ConfigurationManagerConfigBase, IRequestHandlerSettings
{
public bool AddTrailingSlash => UmbracoSettingsSection.RequestHandler.AddTrailingSlash;
public bool ConvertUrlsToAscii => UmbracoSettingsSection.RequestHandler.UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true");
public bool TryConvertUrlsToAscii => UmbracoSettingsSection.RequestHandler.UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try");
public IEnumerable<IChar> CharCollection => UmbracoSettingsSection.RequestHandler.UrlReplacing.CharCollection;
}
}

View File

@@ -0,0 +1,14 @@
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class SecuritySettings : ConfigurationManagerConfigBase, ISecuritySettings
{
public bool KeepUserLoggedIn => UmbracoSettingsSection.Security.KeepUserLoggedIn;
public bool HideDisabledUsersInBackoffice => UmbracoSettingsSection.Security.HideDisabledUsersInBackoffice;
public bool AllowPasswordReset => UmbracoSettingsSection.Security.AllowPasswordReset;
public string AuthCookieName => UmbracoSettingsSection.Security.AuthCookieName;
public string AuthCookieDomain => UmbracoSettingsSection.Security.AuthCookieDomain;
public bool UsernameIsEmail => UmbracoSettingsSection.Security.UsernameIsEmail;
}
}

View File

@@ -0,0 +1,9 @@
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class TourSettings : ConfigurationManagerConfigBase, ITourSettings
{
public bool EnableTours => UmbracoSettingsSection.BackOffice.Tours.EnableTours;
}
}

View File

@@ -0,0 +1,15 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration.Implementations
{
internal class UserPasswordConfigurationSettings : ConfigurationManagerConfigBase, IUserPasswordConfiguration
{
public int RequiredLength => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequiredLength;
public bool RequireNonLetterOrDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireNonLetterOrDigit;
public bool RequireDigit => UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireDigit;
public bool RequireLowercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireLowercase;
public bool RequireUppercase=> UmbracoSettingsSection.Security.UserPasswordConfiguration.RequireUppercase;
public bool UseLegacyEncoding=> UmbracoSettingsSection.Security.UserPasswordConfiguration.UseLegacyEncoding;
public string HashAlgorithmType=> UmbracoSettingsSection.Security.UserPasswordConfiguration.HashAlgorithmType;
public int MaxFailedAccessAttemptsBeforeLockout => UmbracoSettingsSection.Security.UserPasswordConfiguration.MaxFailedAccessAttemptsBeforeLockout;
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Configuration.Implementations
{
internal class WebRoutingSettings : ConfigurationManagerConfigBase, IWebRoutingSettings
{
public bool TrySkipIisCustomErrors => UmbracoSettingsSection.WebRouting.TrySkipIisCustomErrors;
public bool InternalRedirectPreservesTemplate => UmbracoSettingsSection.WebRouting.InternalRedirectPreservesTemplate;
public bool DisableAlternativeTemplates => UmbracoSettingsSection.WebRouting.DisableAlternativeTemplates;
public bool ValidateAlternativeTemplates => UmbracoSettingsSection.WebRouting.ValidateAlternativeTemplates;
public bool DisableFindContentByIdPath => UmbracoSettingsSection.WebRouting.DisableFindContentByIdPath;
public bool DisableRedirectUrlTracking => UmbracoSettingsSection.WebRouting.DisableRedirectUrlTracking;
public string UrlProviderMode => UmbracoSettingsSection.WebRouting.UrlProviderMode;
public string UmbracoApplicationUrl => UmbracoSettingsSection.WebRouting.UmbracoApplicationUrl;
}
}

View File

@@ -0,0 +1,15 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public class IndexCreatorSettings : IIndexCreatorSettings
{
public IndexCreatorSettings()
{
LuceneDirectoryFactory = ConfigurationManager.AppSettings["Umbraco.Examine.LuceneDirectoryFactory"];
}
public string LuceneDirectoryFactory { get; }
}
}

View File

@@ -0,0 +1,20 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public class MachineKeyConfig : IMachineKeyConfig
{
//TODO all the machineKey stuff should be replaced: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/replacing-machinekey?view=aspnetcore-3.1
public bool HasMachineKey
{
get
{
var machineKeySection =
ConfigurationManager.GetSection("system.web/machineKey") as ConfigurationSection;
return !(machineKeySection?.ElementInformation?.Source is null);
}
}
}
}

View File

@@ -1,110 +1,81 @@
using System;
using System.Configuration;
using System.IO;
using System.Web.Configuration;
using System.Threading;
using Umbraco.Core.Configuration;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
namespace Umbraco.ModelsBuilder.Embedded.Configuration
namespace Umbraco.Configuration
{
/// <summary>
/// Represents the models builder configuration.
/// </summary>
public class ModelsBuilderConfig : IModelsBuilderConfig
{
private readonly IIOHelper _ioHelper;
public const string DefaultModelsNamespace = "Umbraco.Web.PublishedModels";
public string DefaultModelsDirectory => _ioHelper.MapPath("~/App_Data/Models");
private const string Prefix = "Umbraco.ModelsBuilder.";
private object _modelsModelLock;
private bool _modelsModelConfigured;
private ModelsMode _modelsMode;
private object _flagOutOfDateModelsLock;
private bool _flagOutOfDateModelsConfigured;
private bool _flagOutOfDateModels;
public string DefaultModelsDirectory => "~/App_Data/Models";
/// <summary>
/// Initializes a new instance of the <see cref="ModelsBuilderConfig"/> class.
/// </summary>
public ModelsBuilderConfig(IIOHelper ioHelper)
public ModelsBuilderConfig()
{
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
const string prefix = "Umbraco.ModelsBuilder.";
// giant kill switch, default: false
// must be explicitely set to true for anything else to happen
Enable = ConfigurationManager.AppSettings[prefix + "Enable"] == "true";
Enable = ConfigurationManager.AppSettings[Prefix + "Enable"] == "true";
// ensure defaults are initialized for tests
ModelsNamespace = DefaultModelsNamespace;
ModelsNamespace = Constants.ModelsBuilder.DefaultModelsNamespace;
ModelsDirectory = DefaultModelsDirectory;
DebugLevel = 0;
// stop here, everything is false
if (!Enable) return;
// mode
var modelsMode = ConfigurationManager.AppSettings[prefix + "ModelsMode"];
if (!string.IsNullOrWhiteSpace(modelsMode))
{
switch (modelsMode)
{
case nameof(ModelsMode.Nothing):
ModelsMode = ModelsMode.Nothing;
break;
case nameof(ModelsMode.PureLive):
ModelsMode = ModelsMode.PureLive;
break;
case nameof(ModelsMode.AppData):
ModelsMode = ModelsMode.AppData;
break;
case nameof(ModelsMode.LiveAppData):
ModelsMode = ModelsMode.LiveAppData;
break;
default:
throw new ConfigurationErrorsException($"ModelsMode \"{modelsMode}\" is not a valid mode."
+ " Note that modes are case-sensitive. Possible values are: " + string.Join(", ", Enum.GetNames(typeof(ModelsMode))));
}
}
// default: false
AcceptUnsafeModelsDirectory = ConfigurationManager.AppSettings[prefix + "AcceptUnsafeModelsDirectory"].InvariantEquals("true");
AcceptUnsafeModelsDirectory = ConfigurationManager.AppSettings[Prefix + "AcceptUnsafeModelsDirectory"].InvariantEquals("true");
// default: true
EnableFactory = !ConfigurationManager.AppSettings[prefix + "EnableFactory"].InvariantEquals("false");
FlagOutOfDateModels = !ConfigurationManager.AppSettings[prefix + "FlagOutOfDateModels"].InvariantEquals("false");
EnableFactory = !ConfigurationManager.AppSettings[Prefix + "EnableFactory"].InvariantEquals("false");
// default: initialized above with DefaultModelsNamespace const
var value = ConfigurationManager.AppSettings[prefix + "ModelsNamespace"];
var value = ConfigurationManager.AppSettings[Prefix + "ModelsNamespace"];
if (!string.IsNullOrWhiteSpace(value))
ModelsNamespace = value;
// default: initialized above with DefaultModelsDirectory const
value = ConfigurationManager.AppSettings[prefix + "ModelsDirectory"];
value = ConfigurationManager.AppSettings[Prefix + "ModelsDirectory"];
if (!string.IsNullOrWhiteSpace(value))
{
var root = Current.IOHelper.MapPath("~/");
if (root == null)
throw new ConfigurationErrorsException("Could not determine root directory.");
// GetModelsDirectory will ensure that the path is safe
ModelsDirectory = GetModelsDirectory(root, value, AcceptUnsafeModelsDirectory);
ModelsDirectory = value;
}
// default: 0
value = ConfigurationManager.AppSettings[prefix + "DebugLevel"];
value = ConfigurationManager.AppSettings[Prefix + "DebugLevel"];
if (!string.IsNullOrWhiteSpace(value))
{
int debugLevel;
if (!int.TryParse(value, out debugLevel))
if (!int.TryParse(value, out var debugLevel))
throw new ConfigurationErrorsException($"Invalid debug level \"{value}\".");
DebugLevel = debugLevel;
}
// not flagging if not generating, or live (incl. pure)
if (ModelsMode == ModelsMode.Nothing || ModelsMode.IsLive())
FlagOutOfDateModels = false;
}
/// <summary>
/// Initializes a new instance of the <see cref="ModelsBuilderConfig"/> class.
/// </summary>
public ModelsBuilderConfig(IIOHelper ioHelper,
public ModelsBuilderConfig(
bool enable = false,
ModelsMode modelsMode = ModelsMode.Nothing,
string modelsNamespace = null,
@@ -114,48 +85,18 @@ namespace Umbraco.ModelsBuilder.Embedded.Configuration
bool acceptUnsafeModelsDirectory = false,
int debugLevel = 0)
{
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
Enable = enable;
ModelsMode = modelsMode;
_modelsMode = modelsMode;
ModelsNamespace = string.IsNullOrWhiteSpace(modelsNamespace) ? DefaultModelsNamespace : modelsNamespace;
ModelsNamespace = string.IsNullOrWhiteSpace(modelsNamespace) ? Constants.ModelsBuilder.DefaultModelsNamespace : modelsNamespace;
EnableFactory = enableFactory;
FlagOutOfDateModels = flagOutOfDateModels;
_flagOutOfDateModels = flagOutOfDateModels;
ModelsDirectory = string.IsNullOrWhiteSpace(modelsDirectory) ? DefaultModelsDirectory : modelsDirectory;
AcceptUnsafeModelsDirectory = acceptUnsafeModelsDirectory;
DebugLevel = debugLevel;
}
// internal for tests
internal static string GetModelsDirectory(string root, string config, bool acceptUnsafe)
{
// making sure it is safe, ie under the website root,
// unless AcceptUnsafeModelsDirectory and then everything is OK.
if (!Path.IsPathRooted(root))
throw new ConfigurationErrorsException($"Root is not rooted \"{root}\".");
if (config.StartsWith("~/"))
{
var dir = Path.Combine(root, config.TrimStart("~/"));
// sanitize - GetFullPath will take care of any relative
// segments in path, eg '../../foo.tmp' - it may throw a SecurityException
// if the combined path reaches illegal parts of the filesystem
dir = Path.GetFullPath(dir);
root = Path.GetFullPath(root);
if (!dir.StartsWith(root) && !acceptUnsafe)
throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
return dir;
}
if (acceptUnsafe)
return Path.GetFullPath(config);
throw new ConfigurationErrorsException($"Invalid models directory \"{config}\".");
}
/// <summary>
/// Gets a value indicating whether the whole models experience is enabled.
@@ -169,7 +110,26 @@ namespace Umbraco.ModelsBuilder.Embedded.Configuration
/// <summary>
/// Gets the models mode.
/// </summary>
public ModelsMode ModelsMode { get; }
public ModelsMode ModelsMode =>
LazyInitializer.EnsureInitialized(ref _modelsMode, ref _modelsModelConfigured, ref _modelsModelLock, () =>
{
// mode
var modelsMode = ConfigurationManager.AppSettings[Prefix + "ModelsMode"];
if (string.IsNullOrWhiteSpace(modelsMode)) return ModelsMode.Nothing; //default
switch (modelsMode)
{
case nameof(ModelsMode.Nothing):
return ModelsMode.Nothing;
case nameof(ModelsMode.PureLive):
return ModelsMode.PureLive;
case nameof(ModelsMode.AppData):
return ModelsMode.AppData;
case nameof(ModelsMode.LiveAppData):
return ModelsMode.LiveAppData;
default:
throw new ConfigurationErrorsException($"ModelsMode \"{modelsMode}\" is not a valid mode." + " Note that modes are case-sensitive. Possible values are: " + string.Join(", ", Enum.GetNames(typeof(ModelsMode))));
}
});
/// <summary>
/// Gets a value indicating whether system.web/compilation/@debug is true.
@@ -178,8 +138,13 @@ namespace Umbraco.ModelsBuilder.Embedded.Configuration
{
get
{
var section = (CompilationSection)ConfigurationManager.GetSection("system.web/compilation");
return section != null && section.Debug;
if (ConfigurationManager.GetSection("system.web/compilation") is ConfigurationSection section &&
bool.TryParse(section.ElementInformation.Properties["debug"].Value.ToString(), out var isDebug))
{
return isDebug;
}
return false;
}
}
@@ -201,7 +166,17 @@ namespace Umbraco.ModelsBuilder.Embedded.Configuration
/// <remarks>Models become out-of-date when data types or content types are updated. When this
/// setting is activated the ~/App_Data/Models/ood.txt file is then created. When models are
/// generated through the dashboard, the files is cleared. Default value is <c>false</c>.</remarks>
public bool FlagOutOfDateModels { get; }
public bool FlagOutOfDateModels
=> LazyInitializer.EnsureInitialized(ref _flagOutOfDateModels, ref _flagOutOfDateModelsConfigured, ref _flagOutOfDateModelsLock, () =>
{
var flagOutOfDateModels = !ConfigurationManager.AppSettings[Prefix + "FlagOutOfDateModels"].InvariantEquals("false");
if (ModelsMode == ModelsMode.Nothing || ModelsMode.IsLive())
{
flagOutOfDateModels = false;
}
return flagOutOfDateModels;
});
/// <summary>
/// Gets the models directory.

View File

@@ -0,0 +1,14 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public class NuCacheSettings : INuCacheSettings
{
public NuCacheSettings()
{
BTreeBlockSize = ConfigurationManager.AppSettings["Umbraco.Web.PublishedCache.NuCache.BTree.BlockSize"];
}
public string BTreeBlockSize { get; }
}
}

View File

@@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
// Umbraco Cms
[assembly: InternalsVisibleTo("Umbraco.Tests")]
[assembly: InternalsVisibleTo("Umbraco.Tests.Common")]
[assembly: InternalsVisibleTo("Umbraco.Tests.Benchmarks")]
// Allow this to be mocked in our unit tests

View File

@@ -0,0 +1,29 @@
using System.Configuration;
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public class RuntimeSettings : IRuntimeSettings
{
public RuntimeSettings()
{
if (ConfigurationManager.GetSection("system.web/httpRuntime") is ConfigurationSection section)
{
var maxRequestLengthProperty = section.ElementInformation.Properties["maxRequestLength"];
if (maxRequestLengthProperty != null && maxRequestLengthProperty.Value is int requestLength)
{
MaxRequestLength = requestLength;
}
var maxQueryStringProperty = section.ElementInformation.Properties["maxQueryStringLength"];
if (maxQueryStringProperty != null && maxQueryStringProperty.Value is int maxQueryStringLength)
{
MaxQueryStringLength = maxQueryStringLength;
}
}
}
public int? MaxQueryStringLength { get; }
public int? MaxRequestLength { get; }
}
}

View File

@@ -0,0 +1,12 @@
using Umbraco.Core.Configuration;
namespace Umbraco.Configuration
{
public class SmtpSettings : ISmtpSettings
{
public string From { get; set; }
public string Host { get; set; }
public int Port { get; set; }
public string PickupDirectoryLocation { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System.Configuration;
using Umbraco.Core.Configuration;
using Umbraco.Core;
namespace Umbraco.Configuration
{
public class TypeFinderSettings : ITypeFinderSettings
{
public TypeFinderSettings()
{
AssembliesAcceptingLoadExceptions = ConfigurationManager.AppSettings[
Constants.AppSettings.AssembliesAcceptingLoadExceptions];
}
public string AssembliesAcceptingLoadExceptions { get; }
}
}

View File

@@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>8</LangVersion>
</PropertyGroup>
<ItemGroup>
@@ -25,7 +26,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Umbraco.Abstractions\Umbraco.Abstractions.csproj" />
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -7,6 +7,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("tours")]
internal TourConfigElement Tours => (TourConfigElement)this["tours"];
ITourSection IBackOfficeSection.Tours => Tours;
ITourSettings IBackOfficeSection.Tours => Tours;
}
}

View File

@@ -4,7 +4,7 @@ using Umbraco.Core.Macros;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class ContentElement : UmbracoConfigurationElement, IContentSection
internal class ContentElement : UmbracoConfigurationElement, IContentSettings
{
private const string DefaultPreviewBadge = @"<div id=""umbracoPreviewBadge"" class=""umbraco-preview-badge""><span class=""umbraco-preview-badge__header"">Preview mode</span><a href=""{0}/preview/end?redir={1}"" class=""umbraco-preview-badge__end""><svg viewBox=""0 0 100 100"" xmlns=""http://www.w3.org/2000/svg""><title>Click to end</title><path d=""M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z""/><path d=""M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z""/><path d=""M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z""/><path d=""M42.7 2.5h14.6v49.4H42.7z""/></svg></a></div><style type=""text/css"">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>";
@@ -40,26 +40,26 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("loginBackgroundImage")]
internal InnerTextConfigurationElement<string> LoginBackgroundImage => GetOptionalTextElement("loginBackgroundImage", string.Empty);
string IContentSection.NotificationEmailAddress => Notifications.NotificationEmailAddress;
string IContentSettings.NotificationEmailAddress => Notifications.NotificationEmailAddress;
bool IContentSection.DisableHtmlEmail => Notifications.DisableHtmlEmail;
bool IContentSettings.DisableHtmlEmail => Notifications.DisableHtmlEmail;
IEnumerable<string> IContentSection.ImageFileTypes => Imaging.ImageFileTypes;
IEnumerable<string> IContentSettings.ImageFileTypes => Imaging.ImageFileTypes;
IEnumerable<IImagingAutoFillUploadField> IContentSection.ImageAutoFillProperties => Imaging.ImageAutoFillProperties;
IEnumerable<IImagingAutoFillUploadField> IContentSettings.ImageAutoFillProperties => Imaging.ImageAutoFillProperties;
bool IContentSection.ResolveUrlsFromTextString => ResolveUrlsFromTextString;
bool IContentSettings.ResolveUrlsFromTextString => ResolveUrlsFromTextString;
string IContentSection.PreviewBadge => PreviewBadge;
string IContentSettings.PreviewBadge => PreviewBadge;
MacroErrorBehaviour IContentSection.MacroErrorBehaviour => MacroErrors;
MacroErrorBehaviour IContentSettings.MacroErrorBehaviour => MacroErrors;
IEnumerable<string> IContentSection.DisallowedUploadFiles => DisallowedUploadFiles;
IEnumerable<string> IContentSettings.DisallowedUploadFiles => DisallowedUploadFiles;
IEnumerable<string> IContentSection.AllowedUploadFiles => AllowedUploadFiles;
IEnumerable<string> IContentSettings.AllowedUploadFiles => AllowedUploadFiles;
bool IContentSection.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors;
bool IContentSettings.ShowDeprecatedPropertyEditors => ShowDeprecatedPropertyEditors;
string IContentSection.LoginBackgroundImage => LoginBackgroundImage;
string IContentSettings.LoginBackgroundImage => LoginBackgroundImage;
}
}

View File

@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class KeepAliveElement : ConfigurationElement, IKeepAliveSection
internal class KeepAliveElement : ConfigurationElement, IKeepAliveSettings
{
[ConfigurationProperty("disableKeepAliveTask", DefaultValue = "false")]
public bool DisableKeepAliveTask => (bool)base["disableKeepAliveTask"];

View File

@@ -3,12 +3,12 @@ using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class LoggingElement : UmbracoConfigurationElement, ILoggingSection
internal class LoggingElement : UmbracoConfigurationElement, ILoggingSettings
{
[ConfigurationProperty("maxLogAge")]
internal InnerTextConfigurationElement<int> MaxLogAge => GetOptionalTextElement("maxLogAge", -1);
int ILoggingSection.MaxLogAge => MaxLogAge;
int ILoggingSettings.MaxLogAge => MaxLogAge;
}
}

View File

@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfigurationSection
internal class MemberPasswordConfigurationElement : PasswordConfigurationElement, IMemberPasswordConfiguration
{
}
}

View File

@@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSection
internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSettings
{
[ConfigurationProperty("addTrailingSlash")]
public InnerTextConfigurationElement<bool> AddTrailingSlash => GetOptionalTextElement("addTrailingSlash", true);
@@ -85,12 +85,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
return collection;
}
bool IRequestHandlerSection.AddTrailingSlash => AddTrailingSlash;
bool IRequestHandlerSettings.AddTrailingSlash => AddTrailingSlash;
bool IRequestHandlerSection.ConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true");
bool IRequestHandlerSettings.ConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true");
bool IRequestHandlerSection.TryConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try");
bool IRequestHandlerSettings.TryConvertUrlsToAscii => UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try");
IEnumerable<IChar> IRequestHandlerSection.CharCollection => UrlReplacing.CharCollection;
IEnumerable<IChar> IRequestHandlerSettings.CharCollection => UrlReplacing.CharCollection;
}
}

View File

@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class SecurityElement : UmbracoConfigurationElement, ISecuritySection
internal class SecurityElement : UmbracoConfigurationElement, ISecuritySettings
{
[ConfigurationProperty("keepUserLoggedIn")]
internal InnerTextConfigurationElement<bool> KeepUserLoggedIn => GetOptionalTextElement("keepUserLoggedIn", true);
@@ -38,14 +38,14 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("memberPasswordConfiguration")]
public MemberPasswordConfigurationElement MemberPasswordConfiguration => (MemberPasswordConfigurationElement)this["memberPasswordConfiguration"];
bool ISecuritySection.KeepUserLoggedIn => KeepUserLoggedIn;
bool ISecuritySettings.KeepUserLoggedIn => KeepUserLoggedIn;
bool ISecuritySection.HideDisabledUsersInBackoffice => HideDisabledUsersInBackoffice;
bool ISecuritySettings.HideDisabledUsersInBackoffice => HideDisabledUsersInBackoffice;
/// <summary>
/// Used to enable/disable the forgot password functionality on the back office login screen
/// </summary>
bool ISecuritySection.AllowPasswordReset => AllowPasswordReset;
bool ISecuritySettings.AllowPasswordReset => AllowPasswordReset;
/// <summary>
/// A boolean indicating that by default the email address will be the username
@@ -54,14 +54,10 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
/// Even if this is true and the username is different from the email in the database, the username field will still be shown.
/// When this is false, the username and email fields will be shown in the user section.
/// </remarks>
bool ISecuritySection.UsernameIsEmail => UsernameIsEmail;
bool ISecuritySettings.UsernameIsEmail => UsernameIsEmail;
string ISecuritySection.AuthCookieName => AuthCookieName;
string ISecuritySettings.AuthCookieName => AuthCookieName;
string ISecuritySection.AuthCookieDomain => AuthCookieDomain;
IUserPasswordConfigurationSection ISecuritySection.UserPasswordConfiguration => UserPasswordConfiguration;
IMemberPasswordConfigurationSection ISecuritySection.MemberPasswordConfiguration => MemberPasswordConfiguration;
string ISecuritySettings.AuthCookieDomain => AuthCookieDomain;
}
}

View File

@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class TourConfigElement : UmbracoConfigurationElement, ITourSection
internal class TourConfigElement : UmbracoConfigurationElement, ITourSettings
{
//disabled by default so that upgraders don't get it enabled by default
// TODO: we probably just want to disable the initial one from automatically loading ?

View File

@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class UmbracoSettingsSection : ConfigurationSection, IUmbracoSettingsSection
internal class UmbracoSettingsSection : ConfigurationSection
{
[ConfigurationProperty("backOffice")]
public BackOfficeElement BackOffice => (BackOfficeElement)this["backOffice"];
@@ -24,19 +24,5 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("keepAlive")]
internal KeepAliveElement KeepAlive => (KeepAliveElement)this["keepAlive"];
IContentSection IUmbracoSettingsSection.Content => Content;
ISecuritySection IUmbracoSettingsSection.Security => Security;
IRequestHandlerSection IUmbracoSettingsSection.RequestHandler => RequestHandler;
IBackOfficeSection IUmbracoSettingsSection.BackOffice => BackOffice;
ILoggingSection IUmbracoSettingsSection.Logging => Logging;
IWebRoutingSection IUmbracoSettingsSection.WebRouting => WebRouting;
IKeepAliveSection IUmbracoSettingsSection.KeepAlive => KeepAlive;
}
}

View File

@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfigurationSection
internal class UserPasswordConfigurationElement : PasswordConfigurationElement, IUserPasswordConfiguration
{
}
}

View File

@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class WebRoutingElement : ConfigurationElement, IWebRoutingSection
internal class WebRoutingElement : ConfigurationElement, IWebRoutingSettings
{
[ConfigurationProperty("trySkipIisCustomErrors", DefaultValue = "false")]
public bool TrySkipIisCustomErrors => (bool) base["trySkipIisCustomErrors"];

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Web.Actions
: base(items)
{ }
internal T GetAction<T>()
public T GetAction<T>()
where T : IAction
{
return this.OfType<T>().FirstOrDefault();

View File

@@ -12,5 +12,7 @@
public const string MacroContentCacheKey = "macroContent_"; // used in MacroRenderers
public const string MacroFromAliasCacheKey = "macroFromAlias_";
public const string UserGroupGetByAliasCacheKeyPrefix = "UserGroupRepository_GetByAlias_";
}
}

View File

@@ -1,17 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.Repositories.Implement;
using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Changes;
using Umbraco.Web.Composing;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.Cache
@@ -19,14 +15,14 @@ namespace Umbraco.Web.Cache
public sealed class ContentCacheRefresher : PayloadCacheRefresherBase<ContentCacheRefresher, ContentCacheRefresher.JsonPayload>
{
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IdkMap _idkMap;
private readonly IIdKeyMap _idKeyMap;
private readonly IDomainService _domainService;
public ContentCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IPublishedSnapshotService publishedSnapshotService, IdkMap idkMap, IDomainService domainService)
public ContentCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IPublishedSnapshotService publishedSnapshotService, IIdKeyMap idKeyMap, IDomainService domainService)
: base(appCaches, serializer)
{
_publishedSnapshotService = publishedSnapshotService;
_idkMap = idkMap;
_idKeyMap = idKeyMap;
_domainService = domainService;
}
@@ -58,7 +54,7 @@ namespace Umbraco.Web.Cache
//By GUID Key
isolatedCache.Clear(RepositoryCacheKeys.GetKey<IContent>(payload.Key));
_idkMap.ClearCache(payload.Id);
_idKeyMap.ClearCache(payload.Id);
// remove those that are in the branch
if (payload.ChangeTypes.HasTypesAny(TreeChangeTypes.RefreshBranch | TreeChangeTypes.Remove))
@@ -141,7 +137,6 @@ namespace Umbraco.Web.Cache
public class JsonPayload
{
[JsonConstructor]
public JsonPayload(int id, Guid? key, TreeChangeTypes changeTypes)
{
Id = id;

View File

@@ -17,14 +17,14 @@ namespace Umbraco.Web.Cache
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IContentTypeCommonRepository _contentTypeCommonRepository;
private readonly IdkMap _idkMap;
private readonly IIdKeyMap _idKeyMap;
public ContentTypeCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IPublishedSnapshotService publishedSnapshotService, IPublishedModelFactory publishedModelFactory, IdkMap idkMap, IContentTypeCommonRepository contentTypeCommonRepository)
public ContentTypeCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IPublishedSnapshotService publishedSnapshotService, IPublishedModelFactory publishedModelFactory, IIdKeyMap idKeyMap, IContentTypeCommonRepository contentTypeCommonRepository)
: base(appCaches, serializer)
{
_publishedSnapshotService = publishedSnapshotService;
_publishedModelFactory = publishedModelFactory;
_idkMap = idkMap;
_idKeyMap = idKeyMap;
_contentTypeCommonRepository = contentTypeCommonRepository;
}
@@ -70,7 +70,7 @@ namespace Umbraco.Web.Cache
foreach (var id in payloads.Select(x => x.Id))
{
_idkMap.ClearCache(id);
_idKeyMap.ClearCache(id);
}
if (payloads.Any(x => x.ItemType == typeof(IContentType).Name))

View File

@@ -15,14 +15,14 @@ namespace Umbraco.Web.Cache
{
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IdkMap _idkMap;
private readonly IIdKeyMap _idKeyMap;
public DataTypeCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IPublishedSnapshotService publishedSnapshotService, IPublishedModelFactory publishedModelFactory, IdkMap idkMap)
public DataTypeCacheRefresher(AppCaches appCaches, IJsonSerializer serializer, IPublishedSnapshotService publishedSnapshotService, IPublishedModelFactory publishedModelFactory, IIdKeyMap idKeyMap)
: base(appCaches, serializer)
{
_publishedSnapshotService = publishedSnapshotService;
_publishedModelFactory = publishedModelFactory;
_idkMap = idkMap;
_idKeyMap = idKeyMap;
}
#region Define
@@ -56,7 +56,7 @@ namespace Umbraco.Web.Cache
foreach (var payload in payloads)
{
_idkMap.ClearCache(payload.Id);
_idKeyMap.ClearCache(payload.Id);
}
// TODO: not sure I like these?

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text.RegularExpressions;
@@ -101,5 +102,9 @@ namespace Umbraco.Core.Cache
var compiled = new Regex(regex, RegexOptions.Compiled);
_items.RemoveAll(kvp => compiled.IsMatch(kvp.Key));
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Web.Composing;
using Umbraco.Core.Sync;
namespace Umbraco.Web.Cache
{
@@ -21,6 +21,15 @@ namespace Umbraco.Web.Cache
/// </remarks>
public sealed class DistributedCache
{
private readonly IServerMessenger _serverMessenger;
private readonly CacheRefresherCollection _cacheRefreshers;
public DistributedCache(IServerMessenger serverMessenger, CacheRefresherCollection cacheRefreshers)
{
_serverMessenger = serverMessenger;
_cacheRefreshers = cacheRefreshers;
}
#region Core notification methods
/// <summary>
@@ -37,7 +46,7 @@ namespace Umbraco.Web.Cache
{
if (refresherGuid == Guid.Empty || instances.Length == 0 || getNumericId == null) return;
Current.ServerMessenger.PerformRefresh(
_serverMessenger.PerformRefresh(
GetRefresherById(refresherGuid),
getNumericId,
instances);
@@ -52,7 +61,7 @@ namespace Umbraco.Web.Cache
{
if (refresherGuid == Guid.Empty || id == default(int)) return;
Current.ServerMessenger.PerformRefresh(
_serverMessenger.PerformRefresh(
GetRefresherById(refresherGuid),
id);
}
@@ -66,7 +75,7 @@ namespace Umbraco.Web.Cache
{
if (refresherGuid == Guid.Empty || id == Guid.Empty) return;
Current.ServerMessenger.PerformRefresh(
_serverMessenger.PerformRefresh(
GetRefresherById(refresherGuid),
id);
}
@@ -77,7 +86,7 @@ namespace Umbraco.Web.Cache
{
if (refresherGuid == Guid.Empty || payload == null) return;
Current.ServerMessenger.PerformRefresh(
_serverMessenger.PerformRefresh(
GetRefresherById(refresherGuid),
payload);
}
@@ -88,23 +97,10 @@ namespace Umbraco.Web.Cache
{
if (refresherGuid == Guid.Empty || payloads == null) return;
Current.ServerMessenger.PerformRefresh(
_serverMessenger.PerformRefresh(
GetRefresherById(refresherGuid),
payloads.ToArray());
}
/// <summary>
/// Notifies the distributed cache, for a specified <see cref="ICacheRefresher"/>.
/// </summary>
/// <param name="refresherGuid">The unique identifier of the ICacheRefresher.</param>
/// <param name="jsonPayload">The notification content.</param>
public void RefreshByJson(Guid refresherGuid, string jsonPayload)
{
if (refresherGuid == Guid.Empty || jsonPayload.IsNullOrWhiteSpace()) return;
Current.ServerMessenger.PerformRefresh(
GetRefresherById(refresherGuid),
jsonPayload);
}
///// <summary>
///// Notifies the distributed cache, for a specified <see cref="ICacheRefresher"/>.
@@ -115,7 +111,7 @@ namespace Umbraco.Web.Cache
//{
// if (refresherId == Guid.Empty || payload == null) return;
// Current.ServerMessenger.Notify(
// _serverMessenger.Notify(
// Current.ServerRegistrar.Registrations,
// GetRefresherById(refresherId),
// json);
@@ -129,7 +125,7 @@ namespace Umbraco.Web.Cache
{
if (refresherGuid == Guid.Empty) return;
Current.ServerMessenger.PerformRefreshAll(
_serverMessenger.PerformRefreshAll(
GetRefresherById(refresherGuid));
}
@@ -142,7 +138,7 @@ namespace Umbraco.Web.Cache
{
if (refresherGuid == Guid.Empty || id == default(int)) return;
Current.ServerMessenger.PerformRemove(
_serverMessenger.PerformRemove(
GetRefresherById(refresherGuid),
id);
}
@@ -159,7 +155,7 @@ namespace Umbraco.Web.Cache
/// </remarks>
public void Remove<T>(Guid refresherGuid, Func<T, int> getNumericId, params T[] instances)
{
Current.ServerMessenger.PerformRemove(
_serverMessenger.PerformRemove(
GetRefresherById(refresherGuid),
getNumericId,
instances);
@@ -168,9 +164,9 @@ namespace Umbraco.Web.Cache
#endregion
// helper method to get an ICacheRefresher by its unique identifier
private static ICacheRefresher GetRefresherById(Guid refresherGuid)
private ICacheRefresher GetRefresherById(Guid refresherGuid)
{
return Current.CacheRefreshers[refresherGuid];
return _cacheRefreshers[refresherGuid];
}
}
}

Some files were not shown because too many files have changed in this diff Show More