diff --git a/.github/BUILD.md b/.github/BUILD.md
index ad33872423..5f962a8911 100644
--- a/.github/BUILD.md
+++ b/.github/BUILD.md
@@ -39,7 +39,7 @@ To build Umbraco, fire up PowerShell and move to Umbraco's repository root (the
build/build.ps1
-If you only see a build.bat-file, you're probably on the wrong branch. If you switch to the correct branch (dev-v8) the file will appear and you can build it.
+If you only see a build.bat-file, you're probably on the wrong branch. If you switch to the correct branch (v8/contrib) the file will appear and you can build it.
You might run into [Powershell quirks](#powershell-quirks).
diff --git a/.gitignore b/.gitignore
index ea2ddfbb68..15c9fb52f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -198,3 +198,5 @@ src/Umbraco.Tests.Integration/Views/
src/Umbraco.Tests/TEMP/
/src/Umbraco.Web.UI.NetCore/Umbraco/Data/*
+
+/src/Umbraco.Web.UI/config/umbracoSettings.config
diff --git a/build/NuSpecs/tools/ReadmeUpgrade.txt b/build/NuSpecs/tools/ReadmeUpgrade.txt
index 91d49d896c..fd1b2174e2 100644
--- a/build/NuSpecs/tools/ReadmeUpgrade.txt
+++ b/build/NuSpecs/tools/ReadmeUpgrade.txt
@@ -11,7 +11,7 @@ Y88 88Y 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
Don't forget to build!
-We've done our best to transform your configuration files but in case something is not quite right: we recommmend you look in source control for the previous version so you can find the original files before they were transformed.
+We've done our best to transform your configuration files but in case something is not quite right: we recommend you look in source control for the previous version so you can find the original files before they were transformed.
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs
index 0a2e2c5c54..3a1f151388 100644
--- a/src/SolutionInfo.cs
+++ b/src/SolutionInfo.cs
@@ -2,7 +2,7 @@
using System.Resources;
[assembly: AssemblyCompany("Umbraco")]
-[assembly: AssemblyCopyright("Copyright © Umbraco 2020")]
+[assembly: AssemblyCopyright("Copyright © Umbraco 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs b/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs
new file mode 100644
index 0000000000..af25cc1b4a
--- /dev/null
+++ b/src/Umbraco.Core/Collections/EventClearingObservableCollection.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+
+namespace Umbraco.Core.Collections
+{
+ ///
+ /// Allows clearing all event handlers
+ ///
+ ///
+ public class EventClearingObservableCollection : ObservableCollection, INotifyCollectionChanged
+ {
+ public EventClearingObservableCollection()
+ {
+ }
+
+ public EventClearingObservableCollection(List list) : base(list)
+ {
+ }
+
+ public EventClearingObservableCollection(IEnumerable collection) : base(collection)
+ {
+ }
+
+ // need to explicitly implement with event accessor syntax in order to override in order to to clear
+ // c# events are weird, they do not behave the same way as other c# things that are 'virtual',
+ // a good article is here: https://medium.com/@unicorn_dev/virtual-events-in-c-something-went-wrong-c6f6f5fbe252
+ // and https://stackoverflow.com/questions/2268065/c-sharp-language-design-explicit-interface-implementation-of-an-event
+ private NotifyCollectionChangedEventHandler _changed;
+ event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
+ {
+ add { _changed += value; }
+ remove { _changed -= value; }
+ }
+
+ ///
+ /// Clears all event handlers for the event
+ ///
+ public void ClearCollectionChangedEvents() => _changed = null;
+ }
+}
diff --git a/src/Umbraco.Core/Collections/ObservableDictionary.cs b/src/Umbraco.Core/Collections/ObservableDictionary.cs
index c6aedab377..fd9e469f07 100644
--- a/src/Umbraco.Core/Collections/ObservableDictionary.cs
+++ b/src/Umbraco.Core/Collections/ObservableDictionary.cs
@@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
namespace Umbraco.Core.Collections
{
+
///
/// An ObservableDictionary
///
@@ -15,7 +18,7 @@ namespace Umbraco.Core.Collections
///
/// The type of elements contained in the BindableCollection
/// The type of the indexing key
- public class ObservableDictionary : ObservableCollection, IReadOnlyDictionary, IDictionary
+ public class ObservableDictionary : ObservableCollection, IReadOnlyDictionary, IDictionary, INotifyCollectionChanged
{
protected Dictionary Indecies { get; }
protected Func KeySelector { get; }
@@ -74,6 +77,22 @@ namespace Umbraco.Core.Collections
#endregion
+ // need to explicitly implement with event accessor syntax in order to override in order to to clear
+ // c# events are weird, they do not behave the same way as other c# things that are 'virtual',
+ // a good article is here: https://medium.com/@unicorn_dev/virtual-events-in-c-something-went-wrong-c6f6f5fbe252
+ // and https://stackoverflow.com/questions/2268065/c-sharp-language-design-explicit-interface-implementation-of-an-event
+ private NotifyCollectionChangedEventHandler _changed;
+ event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
+ {
+ add { _changed += value; }
+ remove { _changed -= value; }
+ }
+
+ ///
+ /// Clears all event handlers
+ ///
+ public void ClearCollectionChangedEvents() => _changed = null;
+
public bool ContainsKey(TKey key)
{
return Indecies.ContainsKey(key);
diff --git a/src/Umbraco.Core/Composing/ComponentComposer.cs b/src/Umbraco.Core/Composing/ComponentComposer.cs
index 853d4f4502..fca0161d05 100644
--- a/src/Umbraco.Core/Composing/ComponentComposer.cs
+++ b/src/Umbraco.Core/Composing/ComponentComposer.cs
@@ -1,5 +1,4 @@
-
-using Umbraco.Core.DependencyInjection;
+using Umbraco.Core.DependencyInjection;
namespace Umbraco.Core.Composing
{
diff --git a/src/Umbraco.Core/Configuration/IConfigManipulator.cs b/src/Umbraco.Core/Configuration/IConfigManipulator.cs
index bc89b7bd1d..16c5a509f2 100644
--- a/src/Umbraco.Core/Configuration/IConfigManipulator.cs
+++ b/src/Umbraco.Core/Configuration/IConfigManipulator.cs
@@ -1,6 +1,4 @@
-using Umbraco.Core.IO;
-
-namespace Umbraco.Core.Configuration
+namespace Umbraco.Core.Configuration
{
public interface IConfigManipulator
{
@@ -8,5 +6,6 @@ namespace Umbraco.Core.Configuration
void SaveConnectionString(string connectionString, string providerName);
void SaveConfigValue(string itemPath, object value);
void SaveDisableRedirectUrlTracking(bool disable);
+ void SetGlobalId(string id);
}
}
diff --git a/src/Umbraco.Core/Configuration/Models/ContentSettings.cs b/src/Umbraco.Core/Configuration/Models/ContentSettings.cs
index 55881cd8db..01ffffa190 100644
--- a/src/Umbraco.Core/Configuration/Models/ContentSettings.cs
+++ b/src/Umbraco.Core/Configuration/Models/ContentSettings.cs
@@ -193,8 +193,15 @@ namespace Umbraco.Core.Configuration.Models
public bool ShowDeprecatedPropertyEditors { get; set; } = false;
///
- /// Gets or sets a value for the pate to the login screen background image.
+ /// Gets or sets a value for the path to the login screen background image.
///
public string LoginBackgroundImage { get; set; } = "assets/img/login.jpg";
+
+ ///
+ /// Gets or sets a value for the path to the login screen logo image.
+ ///
+ public string LoginLogoImage { get; set; } = "assets/img/application/umbraco_logo_white.svg";
+
+
}
}
diff --git a/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs b/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs
index eb13427d2b..c6e5d92794 100644
--- a/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs
+++ b/src/Umbraco.Core/Configuration/Models/GlobalSettings.cs
@@ -94,10 +94,15 @@ namespace Umbraco.Core.Configuration.Models
public bool InstallMissingDatabase { get; set; } = false;
///
- /// Gets or sets a value indicating whether to install the database when it is empty.
+ /// Gets or sets a value indicating whether unattended installs are enabled.
///
- public bool InstallEmptyDatabase { get; set; } = false;
-
+ ///
+ /// 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 Install level.
+ /// If this option is set to true an unattended install will be performed and the runtime enters
+ /// the Run level.
+ ///
+ public bool InstallUnattended { get; set; } = false;
///
/// Gets or sets a value indicating whether to disable the election for a single server.
///
@@ -112,6 +117,7 @@ namespace Umbraco.Core.Configuration.Models
/// Gets or sets a value for the main dom lock.
///
public string MainDomLock { get; set; } = string.Empty;
+ public string Id { get; set; } = string.Empty;
///
/// Gets or sets a value for the path to the no content view.
diff --git a/src/Umbraco.Core/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs
index a60f29c39d..451ac5d438 100644
--- a/src/Umbraco.Core/Constants-Configuration.cs
+++ b/src/Umbraco.Core/Constants-Configuration.cs
@@ -16,10 +16,10 @@
public const string ConfigCorePrefix = ConfigPrefix + "Core:";
public const string ConfigCustomErrorsPrefix = ConfigPrefix + "CustomErrors:";
public const string ConfigGlobalPrefix = ConfigPrefix + "Global:";
+ public const string ConfigGlobalId = ConfigGlobalPrefix + "Id";
public const string ConfigHostingPrefix = ConfigPrefix + "Hosting:";
public const string ConfigModelsBuilderPrefix = ConfigPrefix + "ModelsBuilder:";
public const string ConfigSecurityPrefix = ConfigPrefix + "Security:";
-
public const string ConfigContentNotificationsEmail = ConfigContentNotificationsPrefix + "Email";
public const string ConfigContentMacroErrors = ConfigContentPrefix + "MacroErrors";
public const string ConfigGlobalUseHttps = ConfigGlobalPrefix + "UseHttps";
diff --git a/src/Umbraco.Core/Constants-SqlTemplates.cs b/src/Umbraco.Core/Constants-SqlTemplates.cs
index 984bc495b0..5a78b62f5b 100644
--- a/src/Umbraco.Core/Constants-SqlTemplates.cs
+++ b/src/Umbraco.Core/Constants-SqlTemplates.cs
@@ -14,7 +14,16 @@
public const string GetParentNode = "Umbraco.Core.VersionableRepository.GetParentNode";
public const string GetReservedId = "Umbraco.Core.VersionableRepository.GetReservedId";
}
+ public static class RelationRepository
+ {
+ public const string DeleteByParentAll = "Umbraco.Core.RelationRepository.DeleteByParent";
+ public const string DeleteByParentIn = "Umbraco.Core.RelationRepository.DeleteByParentIn";
+ }
+ public static class DataTypeRepository
+ {
+ public const string EnsureUniqueNodeName = "Umbraco.Core.DataTypeDefinitionRepository.EnsureUniqueNodeName";
+ }
}
}
}
diff --git a/src/Umbraco.Core/Constants-SvgSanitizer.cs b/src/Umbraco.Core/Constants-SvgSanitizer.cs
index 447ea66668..c92b9f56c7 100644
--- a/src/Umbraco.Core/Constants-SvgSanitizer.cs
+++ b/src/Umbraco.Core/Constants-SvgSanitizer.cs
@@ -17,7 +17,7 @@ namespace Umbraco.Core
///
/// Allowlist for SVG tabs.
///
- public static readonly IList Tags = new [] { "a", "altGlyph", "altGlyphDef", "altGlyphItem", "animate", "animateColor", "animateMotion", "animateTransform", "circle", "clipPath", "color-profile", "cursor", "defs", "desc", "discard", "ellipse", "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feDropShadow", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence", "filter", "font", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignObject", "g", "glyph", "glyphRef", "hatch", "hatchpath", "hkern", "image", "line", "linearGradient", "marker", "mask", "mesh", "meshgradient", "meshpatch", "meshrow", "metadata", "missing-glyph", "mpath", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", "set", "solidcolor", "stop", "style", "svg", "switch", "symbol", "text", "textPath", "title", "tref", "tspan", "unknown", "use", "view", "vkern" };
+ public static readonly IList Tags = new [] { "a", "altGlyph", "altGlyphDef", "altGlyphItem", "animate", "animateColor", "animateMotion", "animateTransform", "circle", "clipPath", "color-profile", "cursor", "defs", "desc", "discard", "ellipse", "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feDropShadow", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence", "filter", "font", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignObject", "g", "glyph", "glyphRef", "hatch", "hatchpath", "hkern", "image", "line", "linearGradient", "marker", "mask", "mesh", "meshgradient", "meshpatch", "meshrow", "metadata", "missing-glyph", "mpath", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", "set", "solidcolor", "stop", "svg", "switch", "symbol", "text", "textPath", "title", "tref", "tspan", "unknown", "use", "view", "vkern" };
}
}
}
diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
index 260ec5487f..54e5982a58 100644
--- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
+++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
@@ -114,9 +114,7 @@ namespace Umbraco.Core.DependencyInjection
// Adds no-op registrations as many core services require these dependencies but these
// dependencies cannot be fulfilled in the Core project
Services.AddUnique();
- Services.AddUnique();
Services.AddUnique();
- Services.AddUnique();
Services.AddUnique();
Services.AddUnique();
diff --git a/src/Umbraco.Core/Exceptions/UnattendedInstallException.cs b/src/Umbraco.Core/Exceptions/UnattendedInstallException.cs
new file mode 100644
index 0000000000..6f672d17cd
--- /dev/null
+++ b/src/Umbraco.Core/Exceptions/UnattendedInstallException.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Umbraco.Core.Exceptions
+{
+ ///
+ /// An exception that is thrown if an unattended installation occurs.
+ ///
+ [Serializable]
+ public class UnattendedInstallException : Exception
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UnattendedInstallException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error message.
+ ///
+ /// The message that describes the error.
+ public UnattendedInstallException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error message
+ /// and a reference to the inner exception which is the cause of this exception.
+ ///
+ /// The message that describes the error.
+ /// The inner exception, or null.
+ public UnattendedInstallException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The that holds the serialized object data about the exception being thrown.
+ /// The that contains contextual information about the source or destination.
+ protected UnattendedInstallException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs
index a4368a2634..50b7727ecf 100644
--- a/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs
+++ b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetime.cs
@@ -1,5 +1,3 @@
-using System;
-
namespace Umbraco.Core.Hosting
{
public interface IUmbracoApplicationLifetime
@@ -13,8 +11,5 @@ namespace Umbraco.Core.Hosting
/// Terminates the current application. The application restarts the next time a request is received for it.
///
void Restart();
-
- // TODO: Should be killed and replaced with UmbracoApplicationStarting notifications
- event EventHandler ApplicationInit;
}
}
diff --git a/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs b/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs
deleted file mode 100644
index 778edc24dd..0000000000
--- a/src/Umbraco.Core/Hosting/IUmbracoApplicationLifetimeManager.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Umbraco.Core.Hosting
-{
- // TODO: Should be killed and replaced with UmbracoApplicationStarting notifications
- public interface IUmbracoApplicationLifetimeManager
- {
- void InvokeApplicationInit();
- }
-}
diff --git a/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs b/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs
deleted file mode 100644
index 7833fd1224..0000000000
--- a/src/Umbraco.Core/Hosting/NoopUmbracoApplicationLifetimeManager.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Umbraco.Core.Hosting
-{
- internal class NoopUmbracoApplicationLifetimeManager : IUmbracoApplicationLifetimeManager
- {
- public void InvokeApplicationInit() { }
- }
-}
diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs
index c8151d076c..92e9156f2f 100644
--- a/src/Umbraco.Core/IO/SystemFiles.cs
+++ b/src/Umbraco.Core/IO/SystemFiles.cs
@@ -9,8 +9,6 @@ namespace Umbraco.Core.IO
{
public static string TinyMceConfig => Constants.SystemDirectories.Config + "/tinyMceConfig.config";
- public static string TelemetricsIdentifier => Constants.SystemDirectories.Data + "/telemetrics-id.umb";
-
// TODO: Kill this off we don't have umbraco.config XML cache we now have NuCache
public static string GetContentCacheXml(IHostingEnvironment hostingEnvironment)
{
diff --git a/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs b/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs
new file mode 100644
index 0000000000..01d8e428c7
--- /dev/null
+++ b/src/Umbraco.Core/Install/InstallSteps/TelemetryIdentifierStep.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.Configuration.Models;
+using Umbraco.Web.Install.Models;
+
+namespace Umbraco.Web.Install.InstallSteps
+{
+ [InstallSetupStep(InstallationType.NewInstall | InstallationType.Upgrade,
+ "TelemetryIdConfiguration", 0, "",
+ PerformsAppRestart = false)]
+ public class TelemetryIdentifierStep : InstallSetupStep