Merge remote-tracking branch 'origin/temp8' into temp8-remove-legacy-controls

This commit is contained in:
Warren Buckley
2019-01-24 14:45:57 +00:00
9 changed files with 197 additions and 93 deletions

View File

@@ -283,48 +283,60 @@ namespace Umbraco.Core.Migrations.Install
if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentNullOrEmptyException(nameof(connectionString));
if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentNullOrEmptyException(nameof(providerName));
// set the connection string for the new datalayer
var connectionStringSettings = new ConnectionStringSettings(Constants.System.UmbracoConnectionName, connectionString, providerName);
var fileSource = "web.config";
var fileName = IOHelper.MapPath(Path.Combine(SystemDirectories.Root, fileSource));
var fileName = IOHelper.MapPath($"{SystemDirectories.Root}/web.config");
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
if (xml.Root == null) throw new Exception("Invalid web.config file.");
var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault();
if (connectionStrings == null) throw new Exception("Invalid web.config file.");
if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root).");
// honour configSource, if its set, change the xml file we are saving the configuration
// to the one set in the configSource attribute
if (connectionStrings.Attribute("configSource") != null)
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)
{
var source = connectionStrings.Attribute("configSource").Value;
var configFile = IOHelper.MapPath($"{SystemDirectories.Root}/{source}");
logger.Info<DatabaseBuilder>("Storing ConnectionString in {ConfigFile}", configFile);
if (File.Exists(configFile))
{
xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
fileName = configFile;
}
fileSource = configSourceAttribute.Value;
fileName = IOHelper.MapPath(Path.Combine(SystemDirectories.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 web.config file.");
if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings).");
}
// update connectionString if it exists, or else create a new connectionString
var setting = connectionStrings.Descendants("add").FirstOrDefault(s => s.Attribute("name").Value == Constants.System.UmbracoConnectionName);
// 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", connectionStringSettings),
new XAttribute("connectionString", connectionString),
new XAttribute("providerName", providerName)));
}
else
{
setting.Attribute("connectionString").Value = connectionString;
setting.Attribute("providerName").Value = providerName;
AddOrUpdateAttribute(setting, "connectionString", connectionString);
AddOrUpdateAttribute(setting, "providerName", providerName);
}
// save
logger.Info<DatabaseBuilder>("Saving connection string to {ConfigFile}.", fileSource);
xml.Save(fileName, SaveOptions.DisableFormatting);
logger.Info<DatabaseBuilder>("Configured a new ConnectionString using the '{ProviderName}' provider.", providerName);
logger.Info<DatabaseBuilder>("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;
}
internal bool IsConnectionStringConfigured(ConnectionStringSettings databaseSettings)
@@ -422,7 +434,7 @@ namespace Umbraco.Core.Migrations.Install
_logger.Info<DatabaseBuilder>("Database configuration status: Started");
var database = scope.Database;
var message = string.Empty;
var schemaResult = ValidateSchema();
@@ -482,7 +494,7 @@ namespace Umbraco.Core.Migrations.Install
}
_logger.Info<DatabaseBuilder>("Database upgrade started");
// upgrade
var upgrader = new UmbracoUpgrader();
upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger, _postMigrations);

View File

@@ -59,14 +59,18 @@ namespace Umbraco.Core.Persistence
/// <remarks>Used by the other ctor and in tests.</remarks>
public UmbracoDatabaseFactory(string connectionStringName, ILogger logger, Lazy<IMapperCollection> mappers)
{
if (string.IsNullOrWhiteSpace(connectionStringName)) throw new ArgumentNullOrEmptyException(nameof(connectionStringName));
if (string.IsNullOrWhiteSpace(connectionStringName))
throw new ArgumentNullOrEmptyException(nameof(connectionStringName));
_mappers = mappers ?? throw new ArgumentNullException(nameof(mappers));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
var settings = ConfigurationManager.ConnectionStrings[connectionStringName];
if (settings == null)
{
logger.Debug<UmbracoDatabaseFactory>("Missing connection string, defer configuration.");
return; // not configured
}
// could as well be <add name="umbracoDbDSN" connectionString="" providerName="" />
// so need to test the values too
@@ -74,7 +78,7 @@ namespace Umbraco.Core.Persistence
var providerName = settings.ProviderName;
if (string.IsNullOrWhiteSpace(connectionString) || string.IsNullOrWhiteSpace(providerName))
{
logger.Debug<UmbracoDatabaseFactory>("Missing connection string or provider name, defer configuration.");
logger.Debug<UmbracoDatabaseFactory>("Empty connection string or provider name, defer configuration.");
return; // not configured
}

View File

@@ -100,6 +100,9 @@ namespace Umbraco.Core.Runtime
// throws if not full-trust
new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted).Demand();
// run handlers
RuntimeOptions.DoRuntimeBoot(ProfilingLogger);
// application caches
var appCaches = GetAppCaches();
@@ -131,12 +134,17 @@ namespace Umbraco.Core.Runtime
composition = new Composition(register, typeLoader, ProfilingLogger, _state, configs);
composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, mainDom, appCaches, databaseFactory, typeLoader, _state);
// run handlers
RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory);
// register runtime-level services
// there should be none, really - this is here "just in case"
Compose(composition);
// acquire the main domain, determine our runtime level
// acquire the main domain
AcquireMainDom(mainDom);
// determine our runtime level
DetermineRuntimeLevel(databaseFactory, ProfilingLogger);
// get composers, and compose
@@ -288,7 +296,7 @@ namespace Umbraco.Core.Runtime
/// <inheritdoc/>
public virtual void Terminate()
{
_components.Terminate();
_components?.Terminate();
}
/// <summary>

View File

@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Runtime.CompilerServices;
using Umbraco.Core.Cache;
using Umbraco.Core.Components;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
namespace Umbraco.Core
{
/// <summary>
/// Provides static options for the runtime.
/// </summary>
/// <remarks>
/// These options can be configured in PreApplicationStart or via appSettings.
/// </remarks>
public static class RuntimeOptions
{
private static List<Action<IProfilingLogger>> _onBoot;
private static List<Action<Composition, AppCaches, TypeLoader, IUmbracoDatabaseFactory>> _onEssentials;
private static bool? _installMissingDatabase;
private static bool? _installEmptyDatabase;
// reads a boolean appSetting
private static bool BoolSetting(string key, bool missing) => ConfigurationManager.AppSettings[key]?.InvariantEquals("true") ?? missing;
/// <summary>
/// Gets a value indicating whether the runtime should enter Install level when the database is missing.
/// </summary>
/// <remarks>
/// <para>By default, when a database connection string is configured but it is not possible to
/// connect to the database, the runtime enters the BootFailed level. If this options is set to true,
/// it enters the Install level instead.</para>
/// <para>It is then up to the implementor, that is setting this value, to take over the installation
/// sequence.</para>
/// </remarks>
public static bool InstallMissingDatabase
{
get => _installEmptyDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallMissingDatabase", false);
set => _installEmptyDatabase = value;
}
/// <summary>
/// Gets a value indicating whether the runtime should enter Install level when the database is empty.
/// </summary>
/// <remarks>
/// <para>By default, when a database connection string is configured and it is possible to connect to
/// the database, but the database is empty, the runtime enters the BootFailed level. If this options
/// is set to true, it enters the Install level instead.</para>
/// <para>It is then up to the implementor, that is setting this value, to take over the installation
/// sequence.</para>
/// </remarks>
public static bool InstallEmptyDatabase
{
get => _installMissingDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false);
set => _installMissingDatabase = value;
}
/// <summary>
/// Executes the RuntimeBoot handlers.
/// </summary>
internal static void DoRuntimeBoot(IProfilingLogger logger)
{
if (_onBoot == null)
return;
foreach (var action in _onBoot)
action(logger);
}
/// <summary>
/// Executes the RuntimeEssentials handlers.
/// </summary>
internal static void DoRuntimeEssentials(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory)
{
if (_onEssentials== null)
return;
foreach (var action in _onEssentials)
action(composition, appCaches, typeLoader, databaseFactory);
}
/// <summary>
/// Registers a RuntimeBoot handler.
/// </summary>
/// <remarks>
/// <para>A RuntimeBoot handler runs when the runtime boots, right after the
/// loggers have been created, but before anything else.</para>
/// </remarks>
public static void OnRuntimeBoot(Action<IProfilingLogger> action)
{
if (_onBoot == null)
_onBoot = new List<Action<IProfilingLogger>>();
_onBoot.Add(action);
}
/// <summary>
/// Registers a RuntimeEssentials handler.
/// </summary>
/// <remarks>
/// <para>A RuntimeEssentials handler runs after the runtime has created a few
/// essential things (AppCaches, a TypeLoader, and a database factory) but
/// before anything else.</para>
/// </remarks>
public static void OnRuntimeEssentials(Action<Composition, AppCaches, TypeLoader, IUmbracoDatabaseFactory> action)
{
if (_onEssentials == null)
_onEssentials = new List<Action<Composition, AppCaches, TypeLoader, IUmbracoDatabaseFactory>>();
_onEssentials.Add(action);
}
}
}

View File

@@ -169,7 +169,7 @@ namespace Umbraco.Core
else if (databaseFactory.Configured == false)
{
// local version *does* match code version, but the database is not configured
// install (again? this is a weird situation...)
// install - may happen with Deploy/Cloud/etc
logger.Debug<RuntimeState>("Database is not configured, need to install Umbraco.");
Level = RuntimeLevel.Install;
Reason = RuntimeLevelReason.InstallNoDatabase;
@@ -179,7 +179,7 @@ namespace Umbraco.Core
// else, keep going,
// anything other than install wants a database - see if we can connect
// (since this is an already existing database, assume localdb is ready)
var tries = RuntimeStateOptions.InstallMissingDatabase ? 2 : 5;
var tries = RuntimeOptions.InstallMissingDatabase ? 2 : 5;
for (var i = 0;;)
{
connect = databaseFactory.CanConnect;
@@ -193,7 +193,7 @@ namespace Umbraco.Core
// cannot connect to configured database, this is bad, fail
logger.Debug<RuntimeState>("Could not connect to database.");
if (RuntimeStateOptions.InstallMissingDatabase)
if (RuntimeOptions.InstallMissingDatabase)
{
// ok to install on a configured but missing database
Level = RuntimeLevel.Install;
@@ -222,7 +222,7 @@ namespace Umbraco.Core
// can connect to the database but cannot check the upgrade state... oops
logger.Warn<RuntimeState>(e, "Could not check the upgrade state.");
if (RuntimeStateOptions.InstallEmptyDatabase)
if (RuntimeOptions.InstallEmptyDatabase)
{
// ok to install on an empty database
Level = RuntimeLevel.Install;

View File

@@ -1,40 +0,0 @@
using System.Configuration;
namespace Umbraco.Core
{
/// <summary>
/// Allows configuration of the <see cref="RuntimeState"/> in PreApplicationStart or in appSettings
/// </summary>
public static class RuntimeStateOptions
{
// configured statically or via app settings
private static bool BoolSetting(string key, bool missing) => ConfigurationManager.AppSettings[key]?.InvariantEquals("true") ?? missing;
/// <summary>
/// If true the RuntimeState will continue the installation sequence when a database is missing
/// </summary>
/// <remarks>
/// In this case it will be up to the implementor that is setting this value to true to take over the bootup/installation sequence
/// </remarks>
public static bool InstallMissingDatabase
{
get => _installEmptyDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallMissingDatabase", false);
set => _installEmptyDatabase = value;
}
/// <summary>
/// If true the RuntimeState will continue the installation sequence when a database is available but is empty
/// </summary>
/// <remarks>
/// In this case it will be up to the implementor that is setting this value to true to take over the bootup/installation sequence
/// </remarks>
public static bool InstallEmptyDatabase
{
get => _installMissingDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false);
set => _installMissingDatabase = value;
}
private static bool? _installMissingDatabase;
private static bool? _installEmptyDatabase;
}
}

View File

@@ -530,7 +530,7 @@
<Compile Include="ReadLock.cs" />
<Compile Include="ReflectionUtilities-Unused.cs" />
<Compile Include="RuntimeLevelReason.cs" />
<Compile Include="RuntimeStateOptions.cs" />
<Compile Include="RuntimeOptions.cs" />
<Compile Include="Runtime\CoreRuntime.cs" />
<Compile Include="Runtime\CoreRuntimeComponent.cs" />
<Compile Include="CustomBooleanTypeConverter.cs" />

View File

@@ -41,9 +41,9 @@ body {
#mainwrapper {
position: absolute;
top: 0;
left: 0;
right: 0;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
}
@@ -56,10 +56,10 @@ body.umb-drawer-is-visible #mainwrapper{
position: absolute;
top: 0px;
bottom: 0px;
right: 0px;
right: 0px;
left: 0px;
z-index: 10;
margin: 0
margin: 0;
}
#umb-notifications-wrapper {
@@ -151,17 +151,23 @@ body.umb-drawer-is-visible #mainwrapper{
}
.ui-resizable-e {
cursor: e-resize;
width: 4px;
cursor: col-resize;
width: 10px;
right: -5px;
top: 0;
bottom: 0;
background-color: @gray-10;
border: solid 1px @purple-l3;
border-top: none;
border-bottom: none;
position:absolute;
z-index:9999 !important;
&:hover::after {
content: '';
position: absolute;
background-color: @gray-8;
top: 0;
bottom: 0;
width: 1px;
right: 5px;
}
}
@media (min-width: 1101px) {

View File

@@ -749,9 +749,9 @@ namespace Umbraco.Web
/// <remarks>
/// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot
/// </remarks>
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IEnumerable<IPublishedContent> parentNodes, string docTypeAlias, string culture = null)
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(this IEnumerable<IPublishedContent> parentNodes, string docTypeAlias, string culture = null)
{
return parentNodes.SelectMany(x => x.DescendantsOrSelf(docTypeAlias, culture));
return parentNodes.SelectMany(x => x.DescendantsOrSelfOfType(docTypeAlias, culture));
}
/// <summary>
@@ -799,7 +799,7 @@ namespace Umbraco.Web
return content.DescendantsOrSelf(false, p => p.Level >= level, culture);
}
public static IEnumerable<IPublishedContent> Descendants(this IPublishedContent content, string contentTypeAlias, string culture)
public static IEnumerable<IPublishedContent> DescendantsOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
return content.DescendantsOrSelf(false, p => p.ContentType.Alias == contentTypeAlias, culture);
}
@@ -826,7 +826,7 @@ namespace Umbraco.Web
return content.DescendantsOrSelf(true, p => p.Level >= level, culture);
}
public static IEnumerable<IPublishedContent> DescendantsOrSelf(this IPublishedContent content, string contentTypeAlias, string culture)
public static IEnumerable<IPublishedContent> DescendantsOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
return content.DescendantsOrSelf(true, p => p.ContentType.Alias == contentTypeAlias, culture);
}
@@ -853,7 +853,7 @@ namespace Umbraco.Web
return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.Level == level);
}
public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias, string culture)
public static IPublishedContent DescendantOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias);
}
@@ -880,7 +880,7 @@ namespace Umbraco.Web
return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.Level == level);
}
public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias, string culture)
public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null)
{
return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias);
}
@@ -1010,7 +1010,7 @@ namespace Umbraco.Web
/// <summary>
/// Gets the first child of the content, of a given content type.
/// </summary>
public static IPublishedContent FirstChild(this IPublishedContent content, string alias, string culture)
public static IPublishedContent FirstChildOfType(this IPublishedContent content, string alias, string culture = null)
{
return content.Children(culture,alias).FirstOrDefault();
}