From 79316d6eaa6455f6d248782bdf4e6d113616ad99 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 8 Sep 2021 13:34:51 +0200 Subject: [PATCH 01/73] Store certificate days to expiry in request message properties and clean-up HttpsCheck --- .../Checks/Security/HttpsCheck.cs | 82 ++++++++++--------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/src/Umbraco.Core/HealthChecks/Checks/Security/HttpsCheck.cs b/src/Umbraco.Core/HealthChecks/Checks/Security/HttpsCheck.cs index 2e3ef9f5c8..02c726c0c7 100644 --- a/src/Umbraco.Core/HealthChecks/Checks/Security/HttpsCheck.cs +++ b/src/Umbraco.Core/HealthChecks/Checks/Security/HttpsCheck.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -17,7 +17,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.HealthChecks.Checks.Security { /// - /// Health checks for the recommended production setup regarding https. + /// Health checks for the recommended production setup regarding HTTPS. /// [HealthCheck( "EB66BB3B-1BCD-4314-9531-9DA2C1D6D9A7", @@ -26,17 +26,26 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security Group = "Security")] public class HttpsCheck : HealthCheck { + private const int NumberOfDaysForExpiryWarning = 14; + private const string HttpPropertyKeyCertificateDaysToExpiry = "CertificateDaysToExpiry"; + private readonly ILocalizedTextService _textService; private readonly IOptionsMonitor _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; private static HttpClient s_httpClient; - private static HttpClientHandler s_httpClientHandler; - private static int s_certificateDaysToExpiry; + + private static HttpClient HttpClient => s_httpClient ??= new HttpClient(new HttpClientHandler() + { + ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation + }); /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// + /// The text service. + /// The global settings. + /// The hosting environment. public HttpsCheck( ILocalizedTextService textService, IOptionsMonitor globalSettings, @@ -47,33 +56,22 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security _hostingEnvironment = hostingEnvironment; } - private static HttpClient HttpClient => s_httpClient ??= new HttpClient(HttpClientHandler); - - private static HttpClientHandler HttpClientHandler => s_httpClientHandler ??= new HttpClientHandler() - { - ServerCertificateCustomValidationCallback = ServerCertificateCustomValidation - }; - - /// - /// Get the status for this health check - /// + /// public override async Task> GetStatus() => await Task.WhenAll( CheckIfCurrentSchemeIsHttps(), CheckHttpsConfigurationSetting(), CheckForValidCertificate()); - /// - /// Executes the action and returns it's status - /// + /// public override HealthCheckStatus ExecuteAction(HealthCheckAction action) => throw new InvalidOperationException("HttpsCheck action requested is either not executable or does not exist"); private static bool ServerCertificateCustomValidation(HttpRequestMessage requestMessage, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslErrors) { - if (!(certificate is null) && s_certificateDaysToExpiry == default) + if (certificate is not null) { - s_certificateDaysToExpiry = (int)Math.Floor((certificate.NotAfter - DateTime.Now).TotalDays); + requestMessage.Properties[HttpPropertyKeyCertificateDaysToExpiry] = (int)Math.Floor((certificate.NotAfter - DateTime.Now).TotalDays); } return sslErrors == SslPolicyErrors.None; @@ -84,30 +82,37 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security string message; StatusResultType result; - // Attempt to access the site over HTTPS to see if it HTTPS is supported - // and a valid certificate has been configured - var url = _hostingEnvironment.ApplicationMainUrl.ToString().Replace("http:", "https:"); + // Attempt to access the site over HTTPS to see if it HTTPS is supported and a valid certificate has been configured + var urlBuilder = new UriBuilder(_hostingEnvironment.ApplicationMainUrl) + { + Scheme = Uri.UriSchemeHttps + }; + var url = urlBuilder.Uri; var request = new HttpRequestMessage(HttpMethod.Head, url); try { using HttpResponseMessage response = await HttpClient.SendAsync(request); + if (response.StatusCode == HttpStatusCode.OK) { - // Got a valid response, check now for if certificate expiring within 14 days - // Hat-tip: https://stackoverflow.com/a/15343898/489433 - const int numberOfDaysForExpiryWarning = 14; + // Got a valid response, check now if the certificate is expiring within the specified amount of days + int daysToExpiry = 0; + if (request.Properties.TryGetValue(HttpPropertyKeyCertificateDaysToExpiry, out var certificateDaysToExpiry)) + { + daysToExpiry = (int)certificateDaysToExpiry; + } - if (s_certificateDaysToExpiry <= 0) + if (daysToExpiry <= 0) { result = StatusResultType.Error; message = _textService.Localize("healthcheck","httpsCheckExpiredCertificate"); } - else if (s_certificateDaysToExpiry < numberOfDaysForExpiryWarning) + else if (daysToExpiry < NumberOfDaysForExpiryWarning) { result = StatusResultType.Warning; - message = _textService.Localize("healthcheck","httpsCheckExpiringCertificate", new[] { s_certificateDaysToExpiry.ToString() }); + message = _textService.Localize("healthcheck","httpsCheckExpiringCertificate", new[] { daysToExpiry.ToString() }); } else { @@ -118,21 +123,20 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security else { result = StatusResultType.Error; - message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, response.ReasonPhrase }); + message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url.AbsoluteUri, response.ReasonPhrase }); } } catch (Exception ex) { - var exception = ex as WebException; - if (exception != null) + if (ex is WebException exception) { message = exception.Status == WebExceptionStatus.TrustFailure - ? _textService.Localize("healthcheck","httpsCheckInvalidCertificate", new[] { exception.Message }) - : _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, exception.Message }); + ? _textService.Localize("healthcheck", "httpsCheckInvalidCertificate", new[] { exception.Message }) + : _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url.AbsoluteUri, exception.Message }); } else { - message = _textService.Localize("healthcheck","healthCheckInvalidUrl", new[] { url, ex.Message }); + message = _textService.Localize("healthcheck", "healthCheckInvalidUrl", new[] { url.AbsoluteUri, ex.Message }); } result = StatusResultType.Error; @@ -150,7 +154,7 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security private Task CheckIfCurrentSchemeIsHttps() { Uri uri = _hostingEnvironment.ApplicationMainUrl; - var success = uri.Scheme == "https"; + var success = uri.Scheme == Uri.UriSchemeHttps; return Task.FromResult(new HealthCheckStatus(_textService.Localize("healthcheck","httpsCheckIsCurrentSchemeHttps", new[] { success ? string.Empty : "not" })) { @@ -166,16 +170,14 @@ namespace Umbraco.Cms.Core.HealthChecks.Checks.Security string resultMessage; StatusResultType resultType; - if (uri.Scheme != "https") + if (uri.Scheme != Uri.UriSchemeHttps) { resultMessage = _textService.Localize("healthcheck","httpsCheckConfigurationRectifyNotPossible"); resultType = StatusResultType.Info; } else { - resultMessage = _textService.Localize( - "healthcheck","httpsCheckConfigurationCheckResult", - new[] { httpsSettingEnabled.ToString(), httpsSettingEnabled ? string.Empty : "not" }); + resultMessage = _textService.Localize("healthcheck","httpsCheckConfigurationCheckResult", new[] { httpsSettingEnabled.ToString(), httpsSettingEnabled ? string.Empty : "not" }); resultType = httpsSettingEnabled ? StatusResultType.Success : StatusResultType.Error; } From 3d60d2b967c7bc1e62ad26d6a69b34b978f88dd1 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Wed, 8 Sep 2021 13:41:46 +0200 Subject: [PATCH 02/73] Update MaxRequestBodySize on both IIS Server and Kestrel Server --- .../UmbracoBuilderExtensions.cs | 3 +++ .../Security/ConfigureIISServerOptions.cs | 18 ++++++++++++++++++ .../Security/ConfigureKestrelServerOptions.cs | 18 ++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs create mode 100644 src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 5073eefe2f..f1ea5699ad 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -103,6 +103,9 @@ namespace Umbraco.Extensions var requestCache = new HttpContextRequestAppCache(httpContextAccessor); var appCaches = AppCaches.Create(requestCache); + services.ConfigureOptions(); + services.ConfigureOptions(); + IProfiler profiler = GetWebProfiler(config); ILoggerFactory loggerFactory = LoggerFactory.Create(cfg => cfg.AddSerilog(Log.Logger, false)); diff --git a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs new file mode 100644 index 0000000000..22d958377c --- /dev/null +++ b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; + +namespace Umbraco.Cms.Web.Common.Security +{ + public class ConfigureIISServerOptions : IConfigureOptions + { + private readonly IOptions _runtimeSettings; + + public ConfigureIISServerOptions(IOptions runtimeSettings) => _runtimeSettings = runtimeSettings; + public void Configure(IISServerOptions options) + { + // convert from KB to bytes + options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength * 1024; + } + } +} diff --git a/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs new file mode 100644 index 0000000000..2483981b7f --- /dev/null +++ b/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; + +namespace Umbraco.Cms.Web.Common.Security +{ + public class ConfigureKestrelServerOptions : IConfigureOptions + { + private readonly IOptions _runtimeSettings; + + public ConfigureKestrelServerOptions(IOptions runtimeSettings) => _runtimeSettings = runtimeSettings; + public void Configure(KestrelServerOptions options) + { + // convert from KB to bytes + options.Limits.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength * 1024; + } + } +} From aaf1b464babba6c669993147cd2c6917cc3c2aae Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Thu, 9 Sep 2021 11:39:47 +0200 Subject: [PATCH 03/73] Update MultipartBodyLengthLimit on FormsOptions --- .../UmbracoBuilderExtensions.cs | 1 + .../Security/ConfigureFormOptions.cs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index f1ea5699ad..ce0aed6cd0 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -105,6 +105,7 @@ namespace Umbraco.Extensions services.ConfigureOptions(); services.ConfigureOptions(); + services.ConfigureOptions(); IProfiler profiler = GetWebProfiler(config); diff --git a/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs new file mode 100644 index 0000000000..a05ac5b3c6 --- /dev/null +++ b/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Http.Features; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; + +namespace Umbraco.Cms.Web.Common.Security +{ + public class ConfigureFormOptions : IConfigureOptions + { + private readonly IOptions _runtimeSettings; + + public ConfigureFormOptions(IOptions runtimeSettings) => _runtimeSettings = runtimeSettings; + public void Configure(FormOptions options) + { + // convert from KB to bytes + options.MultipartBodyLengthLimit = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : int.MaxValue; + } + } +} From f68717c1c8c7dfe994f5c8931052c9c8b793e2b3 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 14 Sep 2021 22:13:39 +0200 Subject: [PATCH 04/73] Temp commit --- .../Extensions/ClaimsIdentityExtensions.cs | 3 +- .../Extensions/ObjectExtensions.cs | 39 ++++++++++--------- .../Media/Exif/ExifBitConverter.cs | 5 ++- src/Umbraco.Core/Media/Exif/MathEx.cs | 9 +++-- src/Umbraco.Core/Media/Exif/SvgFile.cs | 7 ++-- .../Mapping/ContentTypeMapDefinition.cs | 3 +- .../Routing/DefaultUrlProvider.cs | 3 +- src/Umbraco.Core/Routing/DomainUtilities.cs | 7 ++-- .../Xml/UmbracoXPathPathSyntaxParser.cs | 3 +- .../RelateOnTrashNotificationHandler.cs | 5 ++- .../Packaging/PackageDataInstallation.cs | 9 +++-- .../Factories/ExternalLoginFactory.cs | 3 +- .../Persistence/Factories/MacroFactory.cs | 2 +- .../Implement/ContentRepositoryBase.cs | 3 +- .../Implement/ContentTypeRepositoryBase.cs | 2 +- .../Implement/DocumentRepository.cs | 3 +- .../Security/BackOfficeIdentityUser.cs | 3 +- .../Services/Implement/ContentService.cs | 3 +- .../Services/Implement/MediaService.cs | 2 +- .../Services/Implement/NotificationService.cs | 2 +- .../ContentCache.cs | 2 +- .../CoreThings/TryConvertToTests.cs | 23 ++++++++++- .../Controllers/DictionaryController.cs | 3 +- .../Controllers/EntityController.cs | 9 +++-- .../Controllers/MacrosController.cs | 3 +- .../Controllers/MemberGroupController.cs | 3 +- .../Controllers/TemplateQueryController.cs | 3 +- .../Trees/ContentBlueprintTreeController.cs | 3 +- .../Trees/ContentTypeTreeController.cs | 5 ++- .../Trees/DataTypeTreeController.cs | 5 ++- .../Trees/MacrosTreeController.cs | 3 +- .../Trees/MediaTypeTreeController.cs | 5 ++- .../Trees/RelationTypeTreeController.cs | 3 +- .../Trees/TemplatesTreeController.cs | 4 +- .../Security/MemberManager.cs | 7 ++-- 35 files changed, 123 insertions(+), 74 deletions(-) diff --git a/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs b/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs index 57c69ee9aa..1e492013b7 100644 --- a/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs +++ b/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Security.Principal; @@ -293,7 +294,7 @@ namespace Umbraco.Extensions /// /// /// User ID as integer - public static int GetId(this ClaimsIdentity identity) => int.Parse(identity.FindFirstValue(ClaimTypes.NameIdentifier)); + public static int GetId(this ClaimsIdentity identity) => int.Parse(identity.FindFirstValue(ClaimTypes.NameIdentifier), CultureInfo.InvariantCulture); /// /// Get the real name belonging to the user from a ClaimsIdentity diff --git a/src/Umbraco.Core/Extensions/ObjectExtensions.cs b/src/Umbraco.Core/Extensions/ObjectExtensions.cs index db2d63b643..bdde330c8f 100644 --- a/src/Umbraco.Core/Extensions/ObjectExtensions.cs +++ b/src/Umbraco.Core/Extensions/ObjectExtensions.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -94,8 +95,8 @@ namespace Umbraco.Extensions { // sure, null can be any object return Attempt.Succeed((T)input); - } - } + } + } // just try to cast try @@ -293,7 +294,7 @@ namespace Umbraco.Extensions { if (target == typeof(int)) { - if (int.TryParse(input, out var value)) + if (int.TryParse(input, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) { return Attempt.Succeed(value); } @@ -301,26 +302,26 @@ namespace Umbraco.Extensions // Because decimal 100.01m will happily convert to integer 100, it // makes sense that string "100.01" *also* converts to integer 100. var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2)); + return Attempt.If(decimal.TryParse(input2, NumberStyles.Number, CultureInfo.InvariantCulture, out var value2), Convert.ToInt32(value2, CultureInfo.InvariantCulture)); } if (target == typeof(long)) { - if (long.TryParse(input, out var value)) + if (long.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) { return Attempt.Succeed(value); } // Same as int var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2)); + return Attempt.If(decimal.TryParse(input2, NumberStyles.Number, CultureInfo.InvariantCulture, out var value2), Convert.ToInt64(value2)); } // TODO: Should we do the decimal trick for short, byte, unsigned? if (target == typeof(bool)) { - if (bool.TryParse(input, out var value)) + if (bool.TryParse(input, out var value)) { return Attempt.Succeed(value); } @@ -333,15 +334,15 @@ namespace Umbraco.Extensions switch (Type.GetTypeCode(target)) { case TypeCode.Int16: - return Attempt.If(short.TryParse(input, out var value), value); + return Attempt.If(short.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value), value); case TypeCode.Double: var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(double.TryParse(input2, out var valueD), valueD); + return Attempt.If(double.TryParse(input2, NumberStyles.Float, CultureInfo.InvariantCulture, out var valueD), valueD); case TypeCode.Single: var input3 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(float.TryParse(input3, out var valueF), valueF); + return Attempt.If(float.TryParse(input3, NumberStyles.Float, CultureInfo.InvariantCulture, out var valueF), valueF); case TypeCode.Char: return Attempt.If(char.TryParse(input, out var valueC), valueC); @@ -350,16 +351,16 @@ namespace Umbraco.Extensions return Attempt.If(byte.TryParse(input, out var valueB), valueB); case TypeCode.SByte: - return Attempt.If(sbyte.TryParse(input, out var valueSb), valueSb); + return Attempt.If(sbyte.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var valueSb), valueSb); case TypeCode.UInt32: - return Attempt.If(uint.TryParse(input, out var valueU), valueU); + return Attempt.If(uint.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var valueU), valueU); case TypeCode.UInt16: - return Attempt.If(ushort.TryParse(input, out var valueUs), valueUs); + return Attempt.If(ushort.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var valueUs), valueUs); case TypeCode.UInt64: - return Attempt.If(ulong.TryParse(input, out var valueUl), valueUl); + return Attempt.If(ulong.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var valueUl), valueUl); } } else if (target == typeof(Guid)) @@ -368,7 +369,7 @@ namespace Umbraco.Extensions } else if (target == typeof(DateTime)) { - if (DateTime.TryParse(input, out var value)) + if (DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.None, out var value)) { switch (value.Kind) { @@ -388,16 +389,16 @@ namespace Umbraco.Extensions } else if (target == typeof(DateTimeOffset)) { - return Attempt.If(DateTimeOffset.TryParse(input, out var value), value); + return Attempt.If(DateTimeOffset.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.None,out var value), value); } else if (target == typeof(TimeSpan)) { - return Attempt.If(TimeSpan.TryParse(input, out var value), value); + return Attempt.If(TimeSpan.TryParse(input, CultureInfo.InvariantCulture, out var value), value); } else if (target == typeof(decimal)) { var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(decimal.TryParse(input2, out var value), value); + return Attempt.If(decimal.TryParse(input2, NumberStyles.Number, CultureInfo.InvariantCulture, out var value), value); } else if (input != null && target == typeof(Version)) { @@ -676,7 +677,7 @@ namespace Umbraco.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] private static string NormalizeNumberDecimalSeparator(string s) { - var normalized = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator[0]; + var normalized = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator[0]; return s.ReplaceMany(NumberDecimalSeparatorsToNormalize, normalized); } diff --git a/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs b/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs index 900c9b1b43..74465a6684 100644 --- a/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs +++ b/src/Umbraco.Core/Media/Exif/ExifBitConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Text; namespace Umbraco.Cms.Core.Media.Exif @@ -65,12 +66,12 @@ namespace Umbraco.Cms.Core.Media.Exif // yyyy:MM:dd HH:mm:ss // This is the expected format though some cameras // can use single digits. See Issue 21. - return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]), int.Parse(parts[5])); + return new DateTime(int.Parse(parts[0], CultureInfo.InvariantCulture), int.Parse(parts[1], CultureInfo.InvariantCulture), int.Parse(parts[2], CultureInfo.InvariantCulture), int.Parse(parts[3], CultureInfo.InvariantCulture), int.Parse(parts[4], CultureInfo.InvariantCulture), int.Parse(parts[5], CultureInfo.InvariantCulture)); } else if (!hastime && parts.Length == 3) { // yyyy:MM:dd - return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2])); + return new DateTime(int.Parse(parts[0], CultureInfo.InvariantCulture), int.Parse(parts[1], CultureInfo.InvariantCulture), int.Parse(parts[2], CultureInfo.InvariantCulture)); } else { diff --git a/src/Umbraco.Core/Media/Exif/MathEx.cs b/src/Umbraco.Core/Media/Exif/MathEx.cs index dfad9ae7de..7334643bb3 100644 --- a/src/Umbraco.Core/Media/Exif/MathEx.cs +++ b/src/Umbraco.Core/Media/Exif/MathEx.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Text; namespace Umbraco.Cms.Core.Media.Exif @@ -714,8 +715,8 @@ namespace Umbraco.Cms.Core.Media.Exif } else if (sa.Length == 2) { - numerator = int.Parse(sa[0]); - denominator = int.Parse(sa[1]); + numerator = int.Parse(sa[0], CultureInfo.InvariantCulture); + denominator = int.Parse(sa[1], CultureInfo.InvariantCulture); } else throw new FormatException("The input string must be formatted as n/d where n and d are integers"); @@ -1342,8 +1343,8 @@ namespace Umbraco.Cms.Core.Media.Exif } else if (sa.Length == 2) { - numerator = uint.Parse(sa[0]); - denominator = uint.Parse(sa[1]); + numerator = uint.Parse(sa[0], CultureInfo.InvariantCulture); + denominator = uint.Parse(sa[1], CultureInfo.InvariantCulture); } else throw new FormatException("The input string must be formatted as n/d where n and d are integers"); diff --git a/src/Umbraco.Core/Media/Exif/SvgFile.cs b/src/Umbraco.Core/Media/Exif/SvgFile.cs index 00516eecb8..b83aebe1fb 100644 --- a/src/Umbraco.Core/Media/Exif/SvgFile.cs +++ b/src/Umbraco.Core/Media/Exif/SvgFile.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Globalization; +using System.IO; using System.Linq; using System.Xml.Linq; @@ -16,9 +17,9 @@ namespace Umbraco.Cms.Core.Media.Exif var height = document.Root?.Attributes().Where(x => x.Name == "height").Select(x => x.Value).FirstOrDefault(); Properties.Add(new ExifSInt(ExifTag.PixelYDimension, - height == null ? Constants.Conventions.Media.DefaultSize : int.Parse(height))); + height == null ? Constants.Conventions.Media.DefaultSize : int.Parse(height, CultureInfo.InvariantCulture))); Properties.Add(new ExifSInt(ExifTag.PixelXDimension, - width == null ? Constants.Conventions.Media.DefaultSize : int.Parse(width))); + width == null ? Constants.Conventions.Media.DefaultSize : int.Parse(width, CultureInfo.InvariantCulture))); Format = ImageFileFormat.SVG; } diff --git a/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs index 7449a6f778..d3269c2c0b 100644 --- a/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -601,7 +602,7 @@ namespace Umbraco.Cms.Core.Models.Mapping return Enumerable.Empty(); var aliases = new List(); - var ancestorIds = parent.Path.Split(Constants.CharArrays.Comma).Select(int.Parse); + var ancestorIds = parent.Path.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)); // loop through all content types and return ordered aliases of ancestors var allContentTypes = _contentTypeService.GetAll().ToArray(); foreach (var ancestorId in ancestorIds) diff --git a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs index 4e5d854250..16248854e5 100644 --- a/src/Umbraco.Core/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Core/Routing/DefaultUrlProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; @@ -56,7 +57,7 @@ namespace Umbraco.Cms.Core.Routing var path = pos == 0 ? route : route.Substring(pos); var domainUri = pos == 0 ? null - : DomainUtilities.DomainForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, int.Parse(route.Substring(0, pos)), current, culture); + : DomainUtilities.DomainForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainMapper, int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture), current, culture); // assemble the URL from domainUri (maybe null) and path var url = AssembleUrl(domainUri, path, current, mode).ToString(); diff --git a/src/Umbraco.Core/Routing/DomainUtilities.cs b/src/Umbraco.Core/Routing/DomainUtilities.cs index 035e57c43a..2e36e8c0ef 100644 --- a/src/Umbraco.Core/Routing/DomainUtilities.cs +++ b/src/Umbraco.Core/Routing/DomainUtilities.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Web; @@ -47,7 +48,7 @@ namespace Umbraco.Cms.Core.Routing var pos = route.IndexOf('/'); var domain = pos == 0 ? null - : DomainForNode(umbracoContext.Domains, siteDomainMapper, int.Parse(route.Substring(0, pos)), current); + : DomainForNode(umbracoContext.Domains, siteDomainMapper, int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture), current); var rootContentId = domain?.ContentId ?? -1; var wcDomain = FindWildcardDomainInPath(umbracoContext.Domains.GetAll(true), contentPath, rootContentId); @@ -329,7 +330,7 @@ namespace Umbraco.Cms.Core.Routing return path.Split(Constants.CharArrays.Comma) .Reverse() - .Select(int.Parse) + .Select(s => int.Parse(s, CultureInfo.InvariantCulture)) .TakeWhile(id => id != stopNodeId) .Select(id => domains.FirstOrDefault(d => d.ContentId == id && d.IsWildcard == false)) .SkipWhile(domain => domain == null) @@ -350,7 +351,7 @@ namespace Umbraco.Cms.Core.Routing return path.Split(Constants.CharArrays.Comma) .Reverse() - .Select(int.Parse) + .Select(s => int.Parse(s, CultureInfo.InvariantCulture)) .TakeWhile(id => id != stopNodeId) .Select(id => domains.FirstOrDefault(d => d.ContentId == id && d.IsWildcard)) .FirstOrDefault(domain => domain != null); diff --git a/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs b/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs index e92aa8e147..661d40be0c 100644 --- a/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs +++ b/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; namespace Umbraco.Cms.Core.Xml @@ -51,7 +52,7 @@ namespace Umbraco.Cms.Core.Xml int idAsInt; if (int.TryParse(i, out idAsInt)) { - var exists = publishedContentExists(int.Parse(i)); + var exists = publishedContentExists(int.Parse(i, CultureInfo.InvariantCulture)); if (exists) return idAsInt; } diff --git a/src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs b/src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs index df0f074ea3..4222ac800e 100644 --- a/src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs +++ b/src/Umbraco.Infrastructure/Events/RelateOnTrashNotificationHandler.cs @@ -1,6 +1,7 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using System.Globalization; using System.Linq; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; @@ -72,7 +73,7 @@ namespace Umbraco.Cms.Core.Events { var originalPath = item.OriginalPath.ToDelimitedList(); var originalParentId = originalPath.Count > 2 - ? int.Parse(originalPath[originalPath.Count - 2]) + ? int.Parse(originalPath[originalPath.Count - 2], CultureInfo.InvariantCulture) : Constants.System.Root; //before we can create this relation, we need to ensure that the original parent still exists which @@ -130,7 +131,7 @@ namespace Umbraco.Cms.Core.Events { var originalPath = item.OriginalPath.ToDelimitedList(); var originalParentId = originalPath.Count > 2 - ? int.Parse(originalPath[originalPath.Count - 2]) + ? int.Parse(originalPath[originalPath.Count - 2], CultureInfo.InvariantCulture) : Constants.System.Root; //before we can create this relation, we need to ensure that the original parent still exists which //may not be the case if the encompassing transaction also deleted it when this item was moved to the bin diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 05ceef6697..776af6531c 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net; using System.Text; @@ -323,8 +324,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging parentId, contentType, key, - int.Parse(level), - int.Parse(sortOrder), + int.Parse(level, CultureInfo.InvariantCulture), + int.Parse(sortOrder, CultureInfo.InvariantCulture), template?.Id); // Handle culture specific node names @@ -1323,7 +1324,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging var cacheDuration = 0; if (cacheDurationElement != null && string.IsNullOrEmpty((string)cacheDurationElement) == false) { - cacheDuration = int.Parse(cacheDurationElement.Value); + cacheDuration = int.Parse(cacheDurationElement.Value, CultureInfo.InvariantCulture); } var cacheByMemberElement = macroElement.Element("cacheByMember"); var cacheByMember = false; @@ -1364,7 +1365,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging XAttribute sortOrderAttribute = property.Attribute("sortOrder"); if (sortOrderAttribute != null) { - sortOrder = int.Parse(sortOrderAttribute.Value); + sortOrder = int.Parse(sortOrderAttribute.Value, CultureInfo.InvariantCulture); } if (macro.Properties.Values.Any(x => string.Equals(x.Alias, propertyAlias, StringComparison.OrdinalIgnoreCase))) diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs index 58819f306a..212973d49c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Infrastructure.Persistence.Dtos; @@ -35,7 +36,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories CreateDate = entity.CreateDate, LoginProvider = entity.LoginProvider, ProviderKey = entity.ProviderKey, - UserId = int.Parse(entity.UserId), // TODO: This is temp until we change the ext logins to use GUIDs + UserId = int.Parse(entity.UserId, CultureInfo.InvariantCulture), // TODO: This is temp until we change the ext logins to use GUIDs UserData = entity.UserData }; diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs index 960b809c74..ce871f8761 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories }; if (entity.HasIdentity) - dto.Id = int.Parse(entity.Id.ToString(CultureInfo.InvariantCulture)); + dto.Id = int.Parse(entity.Id.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); return dto; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs index c72e11f595..239f0a89ed 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; @@ -532,7 +533,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement currentParentIds.Add(node.NodeId); // paths parts without the roots - var pathParts = node.Path.Split(Constants.CharArrays.Comma).Where(x => !rootIds.Contains(int.Parse(x))).ToArray(); + var pathParts = node.Path.Split(Constants.CharArrays.Comma).Where(x => !rootIds.Contains(int.Parse(x, CultureInfo.InvariantCulture))).ToArray(); if (!prevParentIds.Contains(node.ParentId)) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index f9e8316f70..d93c2c8322 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -1344,7 +1344,7 @@ WHERE cmsContentType." + aliasColumn + @" LIKE @pattern", /// public bool HasContainerInPath(string contentPath) { - var ids = contentPath.Split(Constants.CharArrays.Comma).Select(int.Parse).ToArray(); + var ids = contentPath.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)).ToArray(); return HasContainerInPath(ids); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs index 0353106e17..1ed8404f78 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using NPoco; @@ -941,7 +942,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement if (content.ParentId == -1) return content.Published; - var ids = content.Path.Split(Constants.CharArrays.Comma).Skip(1).Select(int.Parse); + var ids = content.Path.Split(Constants.CharArrays.Comma).Skip(1).Select(s => int.Parse(s, CultureInfo.InvariantCulture)); var sql = SqlContext.Sql() .SelectCount(x => x.NodeId) diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs b/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs index e3ddc69e6f..ebd12719e1 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeIdentityUser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Identity; using Umbraco.Cms.Core.Configuration.Models; @@ -157,6 +158,6 @@ namespace Umbraco.Cms.Core.Security Roles = roles; } - private static string UserIdToString(int userId) => string.Intern(userId.ToString()); + private static string UserIdToString(int userId) => string.Intern(userId.ToString(CultureInfo.InvariantCulture)); } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs b/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs index dceae58446..15490bcd04 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ContentService.cs @@ -535,7 +535,8 @@ namespace Umbraco.Cms.Core.Services.Implement var rootId = Cms.Core.Constants.System.RootString; var ids = content.Path.Split(Constants.CharArrays.Comma) - .Where(x => x != rootId && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray(); + .Where(x => x != rootId && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(s => + int.Parse(s, CultureInfo.InvariantCulture)).ToArray(); if (ids.Any() == false) return new List(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs index 0239ad8e60..0aa49cde44 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/MediaService.cs @@ -485,7 +485,7 @@ namespace Umbraco.Cms.Core.Services.Implement var rootId = Cms.Core.Constants.System.RootString; var ids = media.Path.Split(Constants.CharArrays.Comma) .Where(x => x != rootId && x != media.Id.ToString(CultureInfo.InvariantCulture)) - .Select(int.Parse) + .Select(s => int.Parse(s, CultureInfo.InvariantCulture)) .ToArray(); if (ids.Any() == false) return new List(); diff --git a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs index dc45319d12..447143092a 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs @@ -83,7 +83,7 @@ namespace Umbraco.Cms.Core.Services.Implement if (entitiesL.Count == 0) return; //put all entity's paths into a list with the same indices - var paths = entitiesL.Select(x => x.Path.Split(Constants.CharArrays.Comma).Select(int.Parse).ToArray()).ToArray(); + var paths = entitiesL.Select(x => x.Path.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)).ToArray()).ToArray(); // lazily get versions var prevVersionDictionary = new Dictionary(); diff --git a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs index f26b53775f..875e6d2ffc 100644 --- a/src/Umbraco.PublishedCache.NuCache/ContentCache.cs +++ b/src/Umbraco.PublishedCache.NuCache/ContentCache.cs @@ -82,7 +82,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache var pos = route.IndexOf('/'); var path = pos == 0 ? route : route.Substring(pos); - var startNodeId = pos == 0 ? 0 : int.Parse(route.Substring(0, pos)); + var startNodeId = pos == 0 ? 0 : int.Parse(route.Substring(0, pos), CultureInfo.InvariantCulture); var parts = path.Split(Constants.CharArrays.ForwardSlash, StringSplitOptions.RemoveEmptyEntries); IPublishedContent content; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs index 0525a24173..5d1c0364b1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System; +using System.Globalization; using NUnit.Framework; using Umbraco.Extensions; @@ -46,10 +47,28 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.CoreThings Assert.AreEqual(false, conv.Result); } + [Test] - public void ConvertToIntegerTest() + [TestCase("en-US")] + [TestCase(null)] + [TestCase("sv-SE")] + [TestCase("da-DK")] + [TestCase("tr-TR")] + public void ConvertToIntegerTest(string culture) { - var conv = "100".TryConvertTo(); + if (culture is not null) + { + CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo(culture); + } + var conv = "-1".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(-1, conv.Result); + + conv = "−1".TryConvertTo(); + Assert.IsTrue(conv); + Assert.AreEqual(-1, conv.Result); + + conv = "100".TryConvertTo(); Assert.IsTrue(conv); Assert.AreEqual(100, conv.Result); diff --git a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs index 8ee4ee1182..4d0e2cfe14 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DictionaryController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net.Http; using Microsoft.AspNetCore.Authorization; @@ -202,7 +203,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers public ActionResult PostSave(DictionarySave dictionary) { var dictionaryItem = - _localizationService.GetDictionaryItemById(int.Parse(dictionary.Id.ToString())); + _localizationService.GetDictionaryItemById(int.Parse(dictionary.Id.ToString(), CultureInfo.InvariantCulture)); if (dictionaryItem == null) return ValidationProblem("Dictionary item does not exist"); diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 944f1946bf..4f380b1bcf 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Reflection; using Microsoft.AspNetCore.Http; @@ -218,7 +219,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers return foundContentResult; } - return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse)); + return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select( + s => int.Parse(s, CultureInfo.InvariantCulture))); } /// @@ -236,7 +238,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers return foundContentResult; } - return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse)); + return new ActionResult>(foundContent.Path.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select( + s => int.Parse(s, CultureInfo.InvariantCulture))); } /// @@ -859,7 +862,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers { // TODO: Need to check for Object types that support hierarchic here, some might not. - var ids = _entityService.Get(id).Path.Split(Constants.CharArrays.Comma).Select(int.Parse).Distinct().ToArray(); + var ids = _entityService.Get(id).Path.Split(Constants.CharArrays.Comma).Select(s => int.Parse(s, CultureInfo.InvariantCulture)).Distinct().ToArray(); var ignoreUserStartNodes = IsDataTypeIgnoringUserStartNodes(queryStrings?.GetValue("dataTypeId")); if (ignoreUserStartNodes == false) diff --git a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs index 84ff7565cc..834d8cc565 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; @@ -184,7 +185,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers return ValidationProblem("Name cannnot be more than 255 characters in length."); } - var macro = _macroService.GetById(int.Parse(macroDisplay.Id.ToString())); + var macro = _macroService.GetById(int.Parse(macroDisplay.Id.ToString(), CultureInfo.InvariantCulture)); if (macro == null) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs index 81303ba55e..fb5286505e 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberGroupController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -122,7 +123,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers public ActionResult PostSave(MemberGroupSave saveModel) { - var id = int.Parse(saveModel.Id.ToString()); + var id = int.Parse(saveModel.Id.ToString(), CultureInfo.InvariantCulture); IMemberGroup memberGroup = id > 0 ? _memberGroupService.GetById(id) : new MemberGroup(); if (memberGroup == null) { diff --git a/src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs b/src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs index 7f5298066a..d0aadac744 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TemplateQueryController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.Linq; using System.Text; using Umbraco.Cms.Core; @@ -189,7 +190,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers switch (condition.Property.Type) { case "int": - return int.Parse(condition.ConstraintValue); + return int.Parse(condition.ConstraintValue, CultureInfo.InvariantCulture); case "datetime": DateTime dt; return DateTime.TryParse(condition.ConstraintValue, out dt) ? dt : DateTime.Today; diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs index 9b6ccf91f6..abf3854f5b 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentBlueprintTreeController.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -130,7 +131,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees menu.Items.Add(new RefreshNode(LocalizedTextService, true)); return menu; } - var cte = _entityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentType); + var cte = _entityService.Get(int.Parse(id, CultureInfo.InvariantCulture), UmbracoObjectTypes.DocumentType); //only refresh & create if it's a content type if (cte != null) { diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs index 2ba9e5f6c7..024be6647e 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -125,7 +126,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var container = _entityService.Get(int.Parse(id), UmbracoObjectTypes.DocumentTypeContainer); + var container = _entityService.Get(int.Parse(id, CultureInfo.InvariantCulture), UmbracoObjectTypes.DocumentTypeContainer); if (container != null) { //set the default to create @@ -147,7 +148,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees } else { - var ct = _contentTypeService.Get(int.Parse(id)); + var ct = _contentTypeService.Get(int.Parse(id, CultureInfo.InvariantCulture)); var parent = ct == null ? null : _contentTypeService.Get(ct.ParentId); menu.Items.Add(LocalizedTextService, opensDialog: true); diff --git a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs index bddf823c43..d83a813de6 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -134,7 +135,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var container = _entityService.Get(int.Parse(id), UmbracoObjectTypes.DataTypeContainer); + var container = _entityService.Get(int.Parse(id, CultureInfo.InvariantCulture), UmbracoObjectTypes.DataTypeContainer); if (container != null) { //set the default to create @@ -158,7 +159,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { var nonDeletableSystemDataTypeIds = GetNonDeletableSystemDataTypeIds(); - if (nonDeletableSystemDataTypeIds.Contains(int.Parse(id)) == false) + if (nonDeletableSystemDataTypeIds.Contains(int.Parse(id, CultureInfo.InvariantCulture)) == false) menu.Items.Add(LocalizedTextService, opensDialog: true); menu.Items.Add(LocalizedTextService, hasSeparator: true, opensDialog: true); diff --git a/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs index c29518473d..d90a53c8e2 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MacrosTreeController.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -79,7 +80,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var macro = _macroService.GetById(int.Parse(id)); + var macro = _macroService.GetById(int.Parse(id, CultureInfo.InvariantCulture)); if (macro == null) return menu; //add delete option for all macros diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs index 2cda5802b8..7a6c70650a 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -97,7 +98,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var container = _entityService.Get(int.Parse(id), UmbracoObjectTypes.MediaTypeContainer); + var container = _entityService.Get(int.Parse(id, CultureInfo.InvariantCulture), UmbracoObjectTypes.MediaTypeContainer); if (container != null) { // set the default to create @@ -119,7 +120,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees } else { - var ct = _mediaTypeService.Get(int.Parse(id)); + var ct = _mediaTypeService.Get(int.Parse(id, CultureInfo.InvariantCulture)); var parent = ct == null ? null : _mediaTypeService.Get(ct.ParentId); menu.Items.Add(LocalizedTextService, opensDialog: true); diff --git a/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs index 6da2298e03..22f96fa7c8 100644 --- a/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/RelationTypeTreeController.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -51,7 +52,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var relationType = _relationService.GetRelationTypeById(int.Parse(id)); + var relationType = _relationService.GetRelationTypeById(int.Parse(id, CultureInfo.InvariantCulture)); if (relationType == null) return menu; if (relationType.IsSystemRelationType() == false) diff --git a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs index 4c91edbf45..e017f0e6d0 100644 --- a/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/TemplatesTreeController.cs @@ -76,7 +76,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees var found = id == Constants.System.RootString ? _fileService.GetTemplates(-1) - : _fileService.GetTemplates(int.Parse(id)); + : _fileService.GetTemplates(int.Parse(id, CultureInfo.InvariantCulture)); nodes.AddRange(found.Select(template => CreateTreeNode( template.Id.ToString(CultureInfo.InvariantCulture), @@ -115,7 +115,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - var template = _fileService.GetTemplate(int.Parse(id)); + var template = _fileService.GetTemplate(int.Parse(id, CultureInfo.InvariantCulture)); if (template == null) return menu; var entity = FromTemplate(template); diff --git a/src/Umbraco.Web.Common/Security/MemberManager.cs b/src/Umbraco.Web.Common/Security/MemberManager.cs index f7d0c8e43e..9a0f26aff4 100644 --- a/src/Umbraco.Web.Common/Security/MemberManager.cs +++ b/src/Umbraco.Web.Common/Security/MemberManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -82,7 +83,7 @@ namespace Umbraco.Cms.Web.Common.Security return false; } - int memberId = int.Parse(currentMember.Id); + int memberId = int.Parse(currentMember.Id, CultureInfo.InvariantCulture); username = currentMember.UserName; // If types defined, check member is of one of those types @@ -192,7 +193,7 @@ namespace Umbraco.Cms.Web.Common.Security if (currentMember == null || !currentMember.IsApproved || currentMember.IsLockedOut) { return false; - } + } return await _publicAccessService.HasAccessAsync( path, @@ -231,7 +232,7 @@ namespace Umbraco.Cms.Web.Common.Security async () => await getUserRolesAsync()); } return result; - } + } public IPublishedContent AsPublishedMember(MemberIdentityUser user) => _store.GetPublishedMember(user); } From 7e7e28f7c73b15c4cb6ae3542af278c8bd6a0841 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Tue, 14 Sep 2021 23:48:24 +0200 Subject: [PATCH 05/73] Use IFileService to save macro partial views --- .../Packaging/InstallationSummary.cs | 1 + .../Packaging/PackageDataInstallation.cs | 40 +++++++++++-------- .../Packaging/PackageDataInstallationTests.cs | 2 - 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Core/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Packaging/InstallationSummary.cs index 005d5859fb..705b32358a 100644 --- a/src/Umbraco.Core/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Packaging/InstallationSummary.cs @@ -23,6 +23,7 @@ namespace Umbraco.Cms.Core.Packaging public IEnumerable LanguagesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable DictionaryItemsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable MacrosInstalled { get; set; } = Enumerable.Empty(); + public IEnumerable MacroPartialViewsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable TemplatesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable DocumentTypesInstalled { get; set; } = Enumerable.Empty(); public IEnumerable MediaTypesInstalled { get; set; } = Enumerable.Empty(); diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 05ceef6697..9b7e28f80a 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; -using System.Text; using System.Xml.Linq; using System.Xml.XPath; using Microsoft.Extensions.Logging; @@ -94,19 +93,20 @@ namespace Umbraco.Cms.Infrastructure.Packaging DataTypesInstalled = ImportDataTypes(compiledPackage.DataTypes.ToList(), userId), LanguagesInstalled = ImportLanguages(compiledPackage.Languages, userId), DictionaryItemsInstalled = ImportDictionaryItems(compiledPackage.DictionaryItems, userId), - MacrosInstalled = ImportMacros(compiledPackage.Macros, compiledPackage.MacroPartialViews, userId), + MacrosInstalled = ImportMacros(compiledPackage.Macros, userId), + MacroPartialViewsInstalled = ImportMacroPartialViews(compiledPackage.MacroPartialViews, userId), TemplatesInstalled = ImportTemplates(compiledPackage.Templates.ToList(), userId), DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId), MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId), + StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId), + ScriptsInstalled = ImportScripts(compiledPackage.Scripts, userId), + PartialViewsInstalled = ImportPartialViews(compiledPackage.PartialViews, userId) }; - //we need a reference to the imported doc types to continue + // We need a reference to the imported doc types to continue var importedDocTypes = installationSummary.DocumentTypesInstalled.ToDictionary(x => x.Alias, x => x); var importedMediaTypes = installationSummary.MediaTypesInstalled.ToDictionary(x => x.Alias, x => x); - installationSummary.StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId); - installationSummary.PartialViewsInstalled = ImportPartialViews(compiledPackage.PartialViews, userId); - installationSummary.ScriptsInstalled = ImportScripts(compiledPackage.Scripts, userId); installationSummary.ContentInstalled = ImportContentBase(compiledPackage.Documents, importedDocTypes, userId, _contentTypeService, _contentService); installationSummary.MediaInstalled = ImportContentBase(compiledPackage.Media, importedMediaTypes, userId, _mediaTypeService, _mediaService); @@ -1270,7 +1270,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// public IReadOnlyList ImportMacros( IEnumerable macroElements, - IEnumerable macroPartialViewsElements, int userId) { var macros = macroElements.Select(ParseMacroElement).ToList(); @@ -1280,29 +1279,36 @@ namespace Umbraco.Cms.Infrastructure.Packaging _macroService.Save(macro, userId); } - ImportMacroPartialViews(macroPartialViewsElements); - return macros; } - private void ImportMacroPartialViews(IEnumerable viewElements) + public IReadOnlyList ImportMacroPartialViews(IEnumerable macroPartialViewsElements, int userId) { - foreach (XElement element in viewElements) + var result = new List(); + + foreach (XElement macroPartialViewXml in macroPartialViewsElements) { - var path = element.AttributeValue("path"); + var path = macroPartialViewXml.AttributeValue("path"); + if (path == null) { throw new InvalidOperationException("No path attribute found"); } - var contents = element.Value ?? string.Empty; - var physicalPath = _hostingEnvironment.MapPathContentRoot(path); - // TODO: Do we overwrite? IMO I don't think so since these will be views a user will change. - if (!System.IO.File.Exists(physicalPath)) + IPartialView macroPartialView = _fileService.GetPartialViewMacro(path); + + // only update if it doesn't exist + if (macroPartialView == null) { - System.IO.File.WriteAllText(physicalPath, contents, Encoding.UTF8); + var content = macroPartialViewXml.Value ?? string.Empty; + + macroPartialView = new PartialView(PartialViewType.PartialViewMacro, path) { Content = content }; + _fileService.SavePartialViewMacro(macroPartialView, userId); + result.Add(macroPartialView); } } + + return result; } private IMacro ParseMacroElement(XElement macroElement) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs index 14a52cead7..6e45d1708a 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Packaging/PackageDataInstallationTests.cs @@ -650,7 +650,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Packaging // Act var macros = PackageDataInstallation.ImportMacros( macrosElement.Elements("macro"), - Enumerable.Empty(), 0).ToList(); // Assert @@ -674,7 +673,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Packaging // Act var macros = PackageDataInstallation.ImportMacros( macrosElement.Elements("macro"), - Enumerable.Empty(), 0).ToList(); // Assert From 26b26a940da27279fa688730b2b63ef0a9c30f39 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Tue, 14 Sep 2021 23:50:25 +0200 Subject: [PATCH 06/73] Write all installation results to summary text --- .../Packaging/InstallationSummary.cs | 102 ++++++++---------- 1 file changed, 42 insertions(+), 60 deletions(-) diff --git a/src/Umbraco.Core/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Packaging/InstallationSummary.cs index 705b32358a..22818f352c 100644 --- a/src/Umbraco.Core/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Packaging/InstallationSummary.cs @@ -13,9 +13,9 @@ namespace Umbraco.Cms.Core.Packaging public class InstallationSummary { public InstallationSummary(string packageName) - { - PackageName = packageName; - } + => PackageName = packageName; + + public string PackageName { get; } public InstallWarnings Warnings { get; set; } = new InstallWarnings(); @@ -32,73 +32,55 @@ namespace Umbraco.Cms.Core.Packaging public IEnumerable PartialViewsInstalled { get; set; } = Enumerable.Empty(); public IEnumerable ContentInstalled { get; set; } = Enumerable.Empty(); public IEnumerable MediaInstalled { get; set; } = Enumerable.Empty(); - public string PackageName { get; } public override string ToString() { var sb = new StringBuilder(); - var macroConflicts = Warnings.ConflictingMacros.ToList(); - if (macroConflicts.Count > 0) + + void WriteConflicts(IEnumerable source, Func selector, string message, bool appendLine = true) { - sb.Append("Conflicting macros found, they will be overwritten:"); - foreach(IMacro m in macroConflicts) + var result = source.Select(selector).ToList(); + if (result.Count > 0) { - sb.Append(m.Alias); - sb.Append(','); + sb.Append(message); + sb.Append(string.Join(", ", result)); + + if (appendLine) + { + sb.AppendLine(); + } } - sb.AppendLine(". "); - } - var templateConflicts = Warnings.ConflictingTemplates.ToList(); - if (templateConflicts.Count > 0) - { - sb.Append("Conflicting templates found, they will be overwritten:"); - foreach (ITemplate m in templateConflicts) - { - sb.Append(m.Alias); - sb.Append(','); - } - sb.AppendLine(". "); - } - var stylesheetConflicts = Warnings.ConflictingStylesheets.ToList(); - if (stylesheetConflicts.Count > 0) - { - sb.Append("Conflicting stylesheets found, they will be overwritten:"); - foreach (IFile m in stylesheetConflicts) - { - sb.Append(m.Alias); - sb.Append(','); - } - sb.AppendLine(". "); } - sb.Append("Content items installed: "); - sb.Append(ContentInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Media items installed: "); - sb.Append(MediaInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Dictionary items installed: "); - sb.Append(DictionaryItemsInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Macros installed: "); - sb.Append(MacrosInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Stylesheets installed: "); - sb.Append(StylesheetsInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Templates installed: "); - sb.Append(TemplatesInstalled.Count()); - sb.AppendLine(); - sb.Append("Document types installed: "); - sb.Append(DocumentTypesInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Media types installed: "); - sb.Append(MediaTypesInstalled.Count()); - sb.AppendLine(". "); - sb.Append("Data types items installed: "); - sb.Append(DataTypesInstalled.Count()); + void WriteCount(string message, IEnumerable source, bool appendLine = true) + { + sb.Append(message); + sb.Append(source.Count()); + + if (appendLine) + { + sb.AppendLine(); + } + } + + WriteConflicts(Warnings.ConflictingMacros, x => x.Alias, "Conflicting macros found, they will be overwritten: "); + WriteConflicts(Warnings.ConflictingTemplates, x => x.Alias, "Conflicting templates found, they will be overwritten: "); + WriteConflicts(Warnings.ConflictingStylesheets, x => x.Alias, "Conflicting stylesheets found, they will be overwritten: "); + WriteCount("Data types installed: ", DataTypesInstalled); + WriteCount("Languages installed: ", LanguagesInstalled); + WriteCount("Dictionary items installed: ", DictionaryItemsInstalled); + WriteCount("Macros installed: ", MacrosInstalled); + WriteCount("Macro partial views installed: ", MacroPartialViewsInstalled); + WriteCount("Templates installed: ", TemplatesInstalled); + WriteCount("Document types installed: ", DocumentTypesInstalled); + WriteCount("Media types installed: ", MediaTypesInstalled); + WriteCount("Stylesheets installed: ", StylesheetsInstalled); + WriteCount("Scripts installed: ", ScriptsInstalled); + WriteCount("Partial views installed: ", PartialViewsInstalled); + WriteCount("Content items installed: ", ContentInstalled); + WriteCount("Media items installed: ", MediaInstalled, false); + return sb.ToString(); } } - } From af0f263e3cdbf311b14a5c98f868d3ee55ce3be4 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Tue, 14 Sep 2021 23:56:49 +0200 Subject: [PATCH 07/73] Fix code formatting --- .../Packaging/PackageDataInstallation.cs | 154 ++++++++---------- 1 file changed, 67 insertions(+), 87 deletions(-) diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 9b7e28f80a..70ce46164c 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -122,31 +122,21 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// Optional id of the User performing the operation. Default is zero (admin). /// An enumerable list of generated ContentTypes public IReadOnlyList ImportMediaTypes(IEnumerable docTypeElements, int userId) - { - return ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService); - } + => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService); #endregion #region Content - public IReadOnlyList ImportContentBase( + public IReadOnlyList ImportContentBase( IEnumerable docs, - IDictionary importedDocumentTypes, + IDictionary importedDocumentTypes, int userId, - IContentTypeBaseService typeService, - IContentServiceBase service) - where T : class, IContentBase - where S : IContentTypeComposition - { - return docs.SelectMany(x => ImportContentBase( - x.XmlData.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty), - -1, - importedDocumentTypes, - userId, - typeService, - service)).ToList(); - } + IContentTypeBaseService typeService, + IContentServiceBase service) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition + => docs.SelectMany(x => ImportContentBase(x.XmlData.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty), -1, importedDocumentTypes, userId, typeService, service)).ToList(); /// /// Imports and saves package xml as @@ -156,17 +146,16 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// A dictionary of already imported document types (basically used as a cache) /// Optional Id of the user performing the import /// An enumerable list of generated content - public IEnumerable ImportContentBase( + public IEnumerable ImportContentBase( IEnumerable roots, int parentId, - IDictionary importedDocumentTypes, + IDictionary importedDocumentTypes, int userId, - IContentTypeBaseService typeService, - IContentServiceBase service) - where T : class, IContentBase - where S : IContentTypeComposition + IContentTypeBaseService typeService, + IContentServiceBase service) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { - var contents = ParseContentBaseRootXml(roots, parentId, importedDocumentTypes, typeService, service).ToList(); if (contents.Any()) { @@ -213,74 +202,72 @@ namespace Umbraco.Cms.Infrastructure.Packaging { throw new InvalidOperationException("Could not find content type with alias " + contentTypeAlias); } + importedContentTypes.Add(contentTypeAlias, contentType); } - if (TryCreateContentFromXml(root, importedContentTypes[contentTypeAlias], default, parentId, service, - out TContentBase content)) + if (TryCreateContentFromXml(root, importedContentTypes[contentTypeAlias], default, parentId, service, out TContentBase content)) { contents.Add(content); } - var children = root.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty) - .ToList(); - + var children = root.Elements().Where(doc => (string)doc.Attribute("isDoc") == string.Empty).ToList(); if (children.Count > 0) { contents.AddRange(CreateContentFromXml(children, content, importedContentTypes, typeService, service).WhereNotNull()); } } + return contents; } - private IEnumerable CreateContentFromXml( + private IEnumerable CreateContentFromXml( IEnumerable children, - T parent, - IDictionary importedContentTypes, - IContentTypeBaseService typeService, - IContentServiceBase service) - where T : class, IContentBase - where S : IContentTypeComposition + TContentBase parent, + IDictionary importedContentTypes, + IContentTypeBaseService typeService, + IContentServiceBase service) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { - var list = new List(); + var list = new List(); + foreach (var child in children) { string contentTypeAlias = child.Name.LocalName; - if (importedContentTypes.ContainsKey(contentTypeAlias) == false) { var contentType = FindContentTypeByAlias(contentTypeAlias, typeService); + importedContentTypes.Add(contentTypeAlias, contentType); } - //Create and add the child to the list + // Create and add the child to the list if (TryCreateContentFromXml(child, importedContentTypes[contentTypeAlias], parent, default, service, out var content)) { list.Add(content); } - //Recursive call - var child1 = child; - var grandChildren = (from grand in child1.Elements() - where (string)grand.Attribute("isDoc") == "" - select grand).ToList(); - + // Recursive call + var grandChildren = child.Elements().Where(x => (string)x.Attribute("isDoc") == string.Empty).ToList(); if (grandChildren.Any()) + { list.AddRange(CreateContentFromXml(grandChildren, content, importedContentTypes, typeService, service)); + } } return list; } - private bool TryCreateContentFromXml( + private bool TryCreateContentFromXml( XElement element, - S contentType, - T parent, + TContentTypeComposition contentType, + TContentBase parent, int parentId, - IContentServiceBase service, - out T output) - where T : class, IContentBase - where S : IContentTypeComposition + IContentServiceBase service, + out TContentBase output) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { Guid key = element.RequiredAttributeValue("key"); @@ -317,7 +304,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging } } - T content = CreateContent( + TContentBase content = CreateContent( nodeName, parent, parentId, @@ -384,34 +371,34 @@ namespace Umbraco.Cms.Infrastructure.Packaging return true; } - private T CreateContent(string name, T parent, int parentId, S contentType, Guid key, int level, int sortOrder, int? templateId) - where T : class, IContentBase - where S : IContentTypeComposition + private TContentBase CreateContent(string name, TContentBase parent, int parentId, TContentTypeComposition contentType, Guid key, int level, int sortOrder, int? templateId) + where TContentBase : class, IContentBase + where TContentTypeComposition : IContentTypeComposition { switch (contentType) { case IContentType c: if (parent is null) { - return new Content(name, parentId, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as T; + return new Content(name, parentId, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as TContentBase; } else { - return new Content(name, (IContent)parent, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as T; + return new Content(name, (IContent)parent, c) { Key = key, Level = level, SortOrder = sortOrder, TemplateId = templateId, } as TContentBase; } case IMediaType m: if (parent is null) { - return new Core.Models.Media(name, parentId, m) { Key = key, Level = level, SortOrder = sortOrder, } as T; + return new Core.Models.Media(name, parentId, m) { Key = key, Level = level, SortOrder = sortOrder, } as TContentBase; } else { - return new Core.Models.Media(name, (IMedia)parent, m) { Key = key, Level = level, SortOrder = sortOrder, } as T; + return new Core.Models.Media(name, (IMedia)parent, m) { Key = key, Level = level, SortOrder = sortOrder, } as TContentBase; } default: - throw new NotSupportedException($"Type {typeof(S)} is not supported"); + throw new NotSupportedException($"Type {typeof(TContentTypeComposition)} is not supported"); } } @@ -420,9 +407,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging #region DocumentTypes public IReadOnlyList ImportDocumentType(XElement docTypeElement, int userId) - { - return ImportDocumentTypes(new[] { docTypeElement }, userId); - } + => ImportDocumentTypes(new[] { docTypeElement }, userId); /// /// Imports and saves package xml as @@ -431,9 +416,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// Optional id of the User performing the operation. Default is zero (admin). /// An enumerable list of generated ContentTypes public IReadOnlyList ImportDocumentTypes(IEnumerable docTypeElements, int userId) - { - return ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService); - } + => ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService); /// /// Imports and saves package xml as @@ -443,7 +426,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// Optional id of the User performing the operation. Default is zero (admin). /// An enumerable list of generated ContentTypes public IReadOnlyList ImportDocumentTypes(IReadOnlyCollection unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService service) - where T : class, IContentTypeComposition + where T : class, IContentTypeComposition { var importedContentTypes = new Dictionary(); @@ -768,8 +751,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging return contentType; } - private void UpdateContentTypesAllowedTemplates(IContentType contentType, - XElement allowedTemplatesElement, XElement defaultTemplateElement) + private void UpdateContentTypesAllowedTemplates(IContentType contentType, XElement allowedTemplatesElement, XElement defaultTemplateElement) { if (allowedTemplatesElement != null && allowedTemplatesElement.Elements("Template").Any()) { @@ -953,7 +935,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging } private T UpdateContentTypesStructure(T contentType, XElement structureElement, IReadOnlyDictionary importedContentTypes, IContentTypeBaseService service) - where T : IContentTypeComposition + where T : IContentTypeComposition { var allowedChildren = contentType.AllowedContentTypes.ToList(); int sortOrder = allowedChildren.Any() ? allowedChildren.Last().SortOrder : 0; @@ -986,8 +968,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging /// /// /// - private S FindContentTypeByAlias(string contentTypeAlias, IContentTypeBaseService typeService) - where S : IContentTypeComposition + private T FindContentTypeByAlias(string contentTypeAlias, IContentTypeBaseService typeService) + where T : IContentTypeComposition { var contentType = typeService.Get(contentTypeAlias); @@ -1207,12 +1189,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging } private static bool DictionaryValueIsNew(IEnumerable translations, XElement valueElement) - { - return translations.All(t => - string.Compare(t.Language.IsoCode, valueElement.Attribute("LanguageCultureAlias").Value, - StringComparison.InvariantCultureIgnoreCase) != 0 - ); - } + => translations.All(t => string.Compare(t.Language.IsoCode, valueElement.Attribute("LanguageCultureAlias").Value, StringComparison.InvariantCultureIgnoreCase) != 0); private static void AddDictionaryTranslation(ICollection translations, XElement valueElement, IEnumerable languages) { @@ -1231,7 +1208,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging #region Languages - /// /// Imports and saves the 'Languages' part of a package xml as a list of /// @@ -1289,7 +1265,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging foreach (XElement macroPartialViewXml in macroPartialViewsElements) { var path = macroPartialViewXml.AttributeValue("path"); - if (path == null) { throw new InvalidOperationException("No path attribute found"); @@ -1325,24 +1300,28 @@ namespace Umbraco.Cms.Infrastructure.Packaging { useInEditor = bool.Parse(useInEditorElement.Value); } + var cacheDurationElement = macroElement.Element("refreshRate"); var cacheDuration = 0; if (cacheDurationElement != null && string.IsNullOrEmpty((string)cacheDurationElement) == false) { cacheDuration = int.Parse(cacheDurationElement.Value); } + var cacheByMemberElement = macroElement.Element("cacheByMember"); var cacheByMember = false; if (cacheByMemberElement != null && string.IsNullOrEmpty((string)cacheByMemberElement) == false) { cacheByMember = bool.Parse(cacheByMemberElement.Value); } + var cacheByPageElement = macroElement.Element("cacheByPage"); var cacheByPage = false; if (cacheByPageElement != null && string.IsNullOrEmpty((string)cacheByPageElement) == false) { cacheByPage = bool.Parse(cacheByPageElement.Value); } + var dontRenderElement = macroElement.Element("dontRender"); var dontRender = true; if (dontRenderElement != null && string.IsNullOrEmpty((string)dontRenderElement) == false) @@ -1386,6 +1365,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging sortOrder++; } } + return macro; } @@ -1398,7 +1378,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging foreach (XElement scriptXml in scriptElements) { var path = scriptXml.AttributeValue("path"); - if (path.IsNullOrWhiteSpace()) { continue; @@ -1462,7 +1441,6 @@ namespace Umbraco.Cms.Infrastructure.Packaging foreach (XElement n in stylesheetElements) { var stylesheetPath = n.Element("FileName")?.Value; - if (stylesheetPath.IsNullOrWhiteSpace()) { continue; @@ -1503,9 +1481,11 @@ namespace Umbraco.Cms.Infrastructure.Packaging sp = newProp; } } + sp.Alias = alias; sp.Value = prop.Element("Value")?.Value; } + _fileService.SaveStylesheet(s, userId); result.Add(s); } @@ -1518,9 +1498,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging #region Templates public IEnumerable ImportTemplate(XElement templateElement, int userId) - { - return ImportTemplates(new[] { templateElement }, userId); - } + => ImportTemplates(new[] { templateElement }, userId); /// /// Imports and saves package xml as @@ -1570,6 +1548,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging var existingTemplate = _fileService.GetTemplate(alias) as Template; var template = existingTemplate ?? new Template(_shortStringHelper, templateName, alias); template.Content = design; + if (masterElement != null && string.IsNullOrEmpty((string)masterElement) == false) { template.MasterTemplateAlias = masterElement.Value; @@ -1577,6 +1556,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging if (masterTemplate != null) template.MasterTemplateId = new Lazy(() => masterTemplate.Id); } + templates.Add(template); } From ee42a7ebace6787d4e6fb9684b3d76e98017d242 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 15 Sep 2021 09:57:03 +0200 Subject: [PATCH 08/73] Add the correct year of open sourcing Umbraco on the license --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index fa83dba963..b8bda9d7a3 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # The MIT License (MIT) # -Copyright (c) 2013-present Umbraco +Copyright (c) 2005-present Umbraco Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: From 00bd5bd6eee2619d666e675589f8985ec03b5a8b Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Wed, 15 Sep 2021 09:57:56 +0200 Subject: [PATCH 09/73] Fixing the IIS Express maxAllowedContentLength --- src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs index 22d958377c..949a2b6419 100644 --- a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs +++ b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Web.Common.Security public void Configure(IISServerOptions options) { // convert from KB to bytes - options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength * 1024; + options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : int.MaxValue; } } } From fc29a2ccd74b8c15d3271f3a799bf62a94d6e02e Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Wed, 15 Sep 2021 10:00:01 +0200 Subject: [PATCH 10/73] Cherry-picking the https://github.com/umbraco/Umbraco-CMS/pull/11061 UI fix --- .../upload/umbfiledropzone.directive.js | 16 ++++++++++++---- .../components/upload/umb-file-dropzone.html | 10 +++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js index e926ca23d7..8e2af44883 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js @@ -65,7 +65,6 @@ angular.module("umbraco.directives") function _filesQueued(files, event) { //Push into the queue Utilities.forEach(files, file => { - if (_filterFile(file) === true) { if (file.$error) { @@ -173,6 +172,8 @@ angular.module("umbraco.directives") } } else if (evt.Message) { file.serverErrorMessage = evt.Message; + } else if (evt && typeof evt === 'string') { + file.serverErrorMessage = evt; } // If file not found, server will return a 404 and display this message if (status === 404) { @@ -247,11 +248,18 @@ angular.module("umbraco.directives") return true;// yes, we did open the choose-media dialog, therefor we return true. } - scope.handleFiles = function(files, event) { + scope.handleFiles = function(files, event, invalidFiles) { + const allFiles = [...files, ...invalidFiles]; + + // add unique key for each files to use in ng-repeats + allFiles.forEach(file => { + file.key = String.CreateGuid(); + }); + if (scope.filesQueued) { - scope.filesQueued(files, event); + scope.filesQueued(allFiles, event); } - _filesQueued(files, event); + _filesQueued(allFiles, event); }; } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html b/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html index e5466d1da0..ff0e8970a4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/upload/umb-file-dropzone.html @@ -6,7 +6,7 @@
@@ -43,7 +43,7 @@
    -
  • +
  • {{ file.name }}
    @@ -68,13 +68,13 @@
  • -
  • +
  • {{queued.name}}
  • -
  • +
  • From 45a9a94ababf5b0917fe1bf3deb27ddf52c17e33 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska Date: Wed, 15 Sep 2021 10:41:58 +0200 Subject: [PATCH 11/73] Change from int.MaxValue to long.MaxValue --- src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs | 2 +- src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs index a05ac5b3c6..25427461d5 100644 --- a/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs +++ b/src/Umbraco.Web.Common/Security/ConfigureFormOptions.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Web.Common.Security public void Configure(FormOptions options) { // convert from KB to bytes - options.MultipartBodyLengthLimit = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : int.MaxValue; + options.MultipartBodyLengthLimit = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : long.MaxValue; } } } diff --git a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs index 949a2b6419..dd4ea4d970 100644 --- a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs +++ b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Web.Common.Security public void Configure(IISServerOptions options) { // convert from KB to bytes - options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : int.MaxValue; + options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : long.MaxValue; } } } From c2a184482c3556640bebb9c5d744d4dd51622dcd Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 15 Sep 2021 11:03:28 +0200 Subject: [PATCH 12/73] Add null checks when writing summary text --- src/Umbraco.Core/Packaging/InstallationSummary.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Core/Packaging/InstallationSummary.cs b/src/Umbraco.Core/Packaging/InstallationSummary.cs index 22818f352c..2aa74474d1 100644 --- a/src/Umbraco.Core/Packaging/InstallationSummary.cs +++ b/src/Umbraco.Core/Packaging/InstallationSummary.cs @@ -39,8 +39,8 @@ namespace Umbraco.Cms.Core.Packaging void WriteConflicts(IEnumerable source, Func selector, string message, bool appendLine = true) { - var result = source.Select(selector).ToList(); - if (result.Count > 0) + var result = source?.Select(selector).ToList(); + if (result?.Count > 0) { sb.Append(message); sb.Append(string.Join(", ", result)); @@ -55,7 +55,7 @@ namespace Umbraco.Cms.Core.Packaging void WriteCount(string message, IEnumerable source, bool appendLine = true) { sb.Append(message); - sb.Append(source.Count()); + sb.Append(source?.Count() ?? 0); if (appendLine) { @@ -63,9 +63,9 @@ namespace Umbraco.Cms.Core.Packaging } } - WriteConflicts(Warnings.ConflictingMacros, x => x.Alias, "Conflicting macros found, they will be overwritten: "); - WriteConflicts(Warnings.ConflictingTemplates, x => x.Alias, "Conflicting templates found, they will be overwritten: "); - WriteConflicts(Warnings.ConflictingStylesheets, x => x.Alias, "Conflicting stylesheets found, they will be overwritten: "); + WriteConflicts(Warnings?.ConflictingMacros, x => x.Alias, "Conflicting macros found, they will be overwritten: "); + WriteConflicts(Warnings?.ConflictingTemplates, x => x.Alias, "Conflicting templates found, they will be overwritten: "); + WriteConflicts(Warnings?.ConflictingStylesheets, x => x.Alias, "Conflicting stylesheets found, they will be overwritten: "); WriteCount("Data types installed: ", DataTypesInstalled); WriteCount("Languages installed: ", LanguagesInstalled); WriteCount("Dictionary items installed: ", DictionaryItemsInstalled); From 39faf63f9c9fc8d5c6dba089cc6676937b150d85 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 15 Sep 2021 13:40:08 +0200 Subject: [PATCH 13/73] Fixed tryParse --- .../Configuration/Models/RuntimeSettings.cs | 2 +- .../Extensions/ClaimsIdentityExtensions.cs | 4 +- .../Extensions/ObjectExtensions.cs | 2 +- .../Extensions/VersionExtensions.cs | 3 +- src/Umbraco.Core/Media/Exif/MathEx.cs | 4 +- .../Packaging/PackagesRepository.cs | 17 +- .../ValueConverters/LabelValueConverter.cs | 2 +- .../Routing/ContentFinderByIdPath.cs | 3 +- .../Routing/ContentFinderByPageIdQuery.cs | 3 +- .../Security/ClaimsPrincipalExtensions.cs | 1 + .../Templates/HtmlLocalLinkParser.cs | 3 +- .../Xml/UmbracoXPathPathSyntaxParser.cs | 2 +- .../Xml/XPath/NavigableNavigator.cs | 4 +- .../BackOfficeExamineSearcher.cs | 3 +- .../Examine/ExamineExtensions.cs | 5 +- .../Examine/ExamineUmbracoIndexingHandler.cs | 4 +- .../ConvertRelatedLinksToMultiUrlPicker.cs | 3 +- .../DataTypes/ListViewPreValueMigrator.cs | 3 +- .../NestedContentPreValueMigrator.cs | 5 +- .../V_8_0_0/PropertyEditorsMigrationBase.cs | 3 +- .../V_8_0_0/UpdatePickerIntegerValuesToUdi.cs | 5 +- .../Models/Mapping/EntityMapDefinition.cs | 3 +- .../Packaging/PackageDataInstallation.cs | 4 +- .../Persistence/Factories/PropertyFactory.cs | 3 +- .../FaultHandling/ThrottlingCondition.cs | 2 +- .../Repositories/Implement/SimilarNodeName.cs | 3 +- .../RteMacroRenderingValueConverter.cs | 3 +- .../PublishedContentQuery.cs | 3 +- .../Security/MemberRoleStore.cs | 7 +- .../Services/Implement/PublicAccessService.cs | 3 +- .../Sync/LastSyncedFileManager.cs | 2 +- .../Authorization/AdminUsersHandler.cs | 3 +- .../PermissionsQueryStringHandler.cs | 3 +- .../Controllers/AuthenticationController.cs | 2 +- .../Controllers/EntityController.cs | 2 +- .../Controllers/MediaController.cs | 3 +- .../CheckIfUserTicketDataIsStaleAttribute.cs | 2 +- .../Mapping/ContentMapDefinition.cs | 3 +- .../Security/BackOfficeUserManagerAuditer.cs | 7 +- .../ConfigureBackOfficeCookieOptions.cs | 3 +- .../Trees/ContentTreeController.cs | 3 +- .../Trees/ContentTreeControllerBase.cs | 11 +- .../Trees/MediaTreeController.cs | 3 +- .../Filters/UmbracoMemberAuthorizeFilter.cs | 3 +- src/Umbraco.Web.UI.Client/package-lock.json | 756 +++++++++--------- 45 files changed, 474 insertions(+), 444 deletions(-) diff --git a/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs b/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs index 64625f153b..ef67d40102 100644 --- a/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/RuntimeSettings.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.Configuration.Models public int? MaxQueryStringLength { get; set; } /// - /// Gets or sets a value for the maximum request length. + /// Gets or sets a value for the maximum request length in kb. /// public int? MaxRequestLength { get; set; } } diff --git a/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs b/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs index 1e492013b7..9b3674b07b 100644 --- a/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs +++ b/src/Umbraco.Core/Extensions/ClaimsIdentityExtensions.cs @@ -268,7 +268,7 @@ namespace Umbraco.Extensions /// Array of start content nodes public static int[] GetStartContentNodes(this ClaimsIdentity identity) => identity.FindAll(x => x.Type == Constants.Security.StartContentNodeIdClaimType) - .Select(node => int.TryParse(node.Value, out var i) ? i : default) + .Select(node => int.TryParse(node.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : default) .Where(x => x != default).ToArray(); /// @@ -278,7 +278,7 @@ namespace Umbraco.Extensions /// Array of start media nodes public static int[] GetStartMediaNodes(this ClaimsIdentity identity) => identity.FindAll(x => x.Type == Constants.Security.StartMediaNodeIdClaimType) - .Select(node => int.TryParse(node.Value, out var i) ? i : default) + .Select(node => int.TryParse(node.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : default) .Where(x => x != default).ToArray(); /// diff --git a/src/Umbraco.Core/Extensions/ObjectExtensions.cs b/src/Umbraco.Core/Extensions/ObjectExtensions.cs index bdde330c8f..4c0b01d9d5 100644 --- a/src/Umbraco.Core/Extensions/ObjectExtensions.cs +++ b/src/Umbraco.Core/Extensions/ObjectExtensions.cs @@ -294,7 +294,7 @@ namespace Umbraco.Extensions { if (target == typeof(int)) { - if (int.TryParse(input, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) + if (int.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) { return Attempt.Succeed(value); } diff --git a/src/Umbraco.Core/Extensions/VersionExtensions.cs b/src/Umbraco.Core/Extensions/VersionExtensions.cs index 06451ce8a0..24326ef327 100644 --- a/src/Umbraco.Core/Extensions/VersionExtensions.cs +++ b/src/Umbraco.Core/Extensions/VersionExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using Umbraco.Cms.Core.Semver; namespace Umbraco.Extensions @@ -12,7 +13,7 @@ namespace Umbraco.Extensions public static Version GetVersion(this SemVersion semVersion, int maxParts = 4) { int build = 0; - int.TryParse(semVersion.Build, out build); + int.TryParse(semVersion.Build, NumberStyles.Integer, CultureInfo.InvariantCulture, out build); if (maxParts >= 4) { diff --git a/src/Umbraco.Core/Media/Exif/MathEx.cs b/src/Umbraco.Core/Media/Exif/MathEx.cs index 7334643bb3..5262aa18a8 100644 --- a/src/Umbraco.Core/Media/Exif/MathEx.cs +++ b/src/Umbraco.Core/Media/Exif/MathEx.cs @@ -702,7 +702,7 @@ namespace Umbraco.Cms.Core.Media.Exif if (sa.Length == 1) { // Try to parse as int - if (int.TryParse(sa[0], out numerator)) + if (int.TryParse(sa[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out numerator)) { denominator = 1; } @@ -1330,7 +1330,7 @@ namespace Umbraco.Cms.Core.Media.Exif if (sa.Length == 1) { // Try to parse as uint - if (uint.TryParse(sa[0], out numerator)) + if (uint.TryParse(sa[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out numerator)) { denominator = 1; } diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index a24890d5f2..79f9aba722 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; @@ -294,7 +295,7 @@ namespace Umbraco.Cms.Core.Packaging var dataTypes = new XElement("DataTypes"); foreach (var dtId in definition.DataTypes) { - if (!int.TryParse(dtId, out var outInt)) + if (!int.TryParse(dtId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var dataType = _dataTypeService.GetDataType(outInt); if (dataType == null) @@ -309,7 +310,7 @@ namespace Umbraco.Cms.Core.Packaging var languages = new XElement("Languages"); foreach (var langId in definition.Languages) { - if (!int.TryParse(langId, out var outInt)) + if (!int.TryParse(langId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var lang = _languageService.GetLanguageById(outInt); if (lang == null) @@ -326,7 +327,7 @@ namespace Umbraco.Cms.Core.Packaging foreach (var dictionaryId in definition.DictionaryItems) { - if (!int.TryParse(dictionaryId, out var outInt)) + if (!int.TryParse(dictionaryId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) { continue; } @@ -397,7 +398,7 @@ namespace Umbraco.Cms.Core.Packaging var macros = new XElement("Macros"); foreach (var macroId in definition.Macros) { - if (!int.TryParse(macroId, out int outInt)) + if (!int.TryParse(macroId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int outInt)) { continue; } @@ -477,7 +478,7 @@ namespace Umbraco.Cms.Core.Packaging var templatesXml = new XElement("Templates"); foreach (var templateId in definition.Templates) { - if (!int.TryParse(templateId, out var outInt)) + if (!int.TryParse(templateId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var template = _fileService.GetTemplate(outInt); if (template == null) @@ -520,7 +521,7 @@ namespace Umbraco.Cms.Core.Packaging var docTypesXml = new XElement("DocumentTypes"); foreach (var dtId in definition.DocumentTypes) { - if (!int.TryParse(dtId, out var outInt)) + if (!int.TryParse(dtId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var contentType = _contentTypeService.Get(outInt); if (contentType == null) @@ -539,7 +540,7 @@ namespace Umbraco.Cms.Core.Packaging var mediaTypesXml = new XElement("MediaTypes"); foreach (var mediaTypeId in definition.MediaTypes) { - if (!int.TryParse(mediaTypeId, out var outInt)) + if (!int.TryParse(mediaTypeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var outInt)) continue; var mediaType = _mediaTypeService.Get(outInt); if (mediaType == null) @@ -555,7 +556,7 @@ namespace Umbraco.Cms.Core.Packaging private void PackageDocumentsAndTags(PackageDefinition definition, XContainer root) { //Documents and tags - if (string.IsNullOrEmpty(definition.ContentNodeId) == false && int.TryParse(definition.ContentNodeId, out var contentNodeId)) + if (string.IsNullOrEmpty(definition.ContentNodeId) == false && int.TryParse(definition.ContentNodeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var contentNodeId)) { if (contentNodeId > 0) { diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs index 637039faa9..c873b29b98 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs @@ -71,7 +71,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters case ValueTypes.Integer: if (source is int sourceInt) return sourceInt; if (source is string sourceIntString) - return int.TryParse(sourceIntString, out var i) ? i : 0; + return int.TryParse(sourceIntString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : 0; return 0; case ValueTypes.Bigint: if (source is string sourceLongString) diff --git a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs index 13a3d8c973..d8093aed1b 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByIdPath.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; @@ -60,7 +61,7 @@ namespace Umbraco.Cms.Core.Routing { var noSlashPath = path.Substring(1); - if (int.TryParse(noSlashPath, out nodeId) == false) + if (int.TryParse(noSlashPath, NumberStyles.Integer, CultureInfo.InvariantCulture, out nodeId) == false) { nodeId = -1; } diff --git a/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs b/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs index b5b80d7b9e..7a71cfc5cd 100644 --- a/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs +++ b/src/Umbraco.Core/Routing/ContentFinderByPageIdQuery.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Web; using Umbraco.Extensions; @@ -32,7 +33,7 @@ namespace Umbraco.Cms.Core.Routing { return false; } - if (int.TryParse(_requestAccessor.GetRequestValue("umbPageID"), out int pageId)) + if (int.TryParse(_requestAccessor.GetRequestValue("umbPageID"), NumberStyles.Integer, CultureInfo.InvariantCulture, out int pageId)) { IPublishedContent doc = umbracoContext.Content.GetById(pageId); diff --git a/src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs b/src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs index 1ee5699868..585d9c73f1 100644 --- a/src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs +++ b/src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System; +using System.Diagnostics; using System.Globalization; using System.Linq; using System.Security.Claims; diff --git a/src/Umbraco.Core/Templates/HtmlLocalLinkParser.cs b/src/Umbraco.Core/Templates/HtmlLocalLinkParser.cs index a92548ea18..a75fd3dee9 100644 --- a/src/Umbraco.Core/Templates/HtmlLocalLinkParser.cs +++ b/src/Umbraco.Core/Templates/HtmlLocalLinkParser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Text.RegularExpressions; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Web; @@ -114,7 +115,7 @@ namespace Umbraco.Cms.Core.Templates yield return (null, guidUdi, tag.Value); } - if (int.TryParse(id, out var intId)) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) { yield return (intId, null, tag.Value); } diff --git a/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs b/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs index 661d40be0c..5d72221391 100644 --- a/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs +++ b/src/Umbraco.Core/Xml/UmbracoXPathPathSyntaxParser.cs @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Core.Xml foreach (var i in path) { int idAsInt; - if (int.TryParse(i, out idAsInt)) + if (int.TryParse(i, NumberStyles.Integer, CultureInfo.InvariantCulture, out idAsInt)) { var exists = publishedContentExists(int.Parse(i, CultureInfo.InvariantCulture)); if (exists) diff --git a/src/Umbraco.Core/Xml/XPath/NavigableNavigator.cs b/src/Umbraco.Core/Xml/XPath/NavigableNavigator.cs index 68dfb9bb67..5ebc575243 100644 --- a/src/Umbraco.Core/Xml/XPath/NavigableNavigator.cs +++ b/src/Umbraco.Core/Xml/XPath/NavigableNavigator.cs @@ -300,7 +300,7 @@ namespace Umbraco.Cms.Core.Xml.XPath public XPathNavigator CloneWithNewRoot(string id, int maxDepth = int.MaxValue) { int i; - if (int.TryParse(id, out i) == false) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out i) == false) throw new ArgumentException("Not a valid identifier.", nameof(id)); return CloneWithNewRoot(id); } @@ -679,7 +679,7 @@ namespace Umbraco.Cms.Core.Xml.XPath var navRootId = state.Content.Id; int contentId; - if (int.TryParse(id, out contentId)) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out contentId)) { if (contentId == navRootId) { diff --git a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs index 27fdf1f2f7..5e2b66c720 100644 --- a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs +++ b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -335,7 +336,7 @@ namespace Umbraco.Cms.Infrastructure.Examine UdiParser.TryParse(searchFrom, true, out var udi); searchFrom = udi == null ? searchFrom : entityService.GetId(udi).Result.ToString(); - var entityPath = int.TryParse(searchFrom, out var searchFromId) && searchFromId > 0 + var entityPath = int.TryParse(searchFrom, NumberStyles.Integer, CultureInfo.InvariantCulture, out var searchFromId) && searchFromId > 0 ? entityService.GetAllPaths(objectType, searchFromId).FirstOrDefault() : null; if (entityPath != null) diff --git a/src/Umbraco.Infrastructure/Examine/ExamineExtensions.cs b/src/Umbraco.Infrastructure/Examine/ExamineExtensions.cs index d0f65fe6a4..b2b025b5a6 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineExtensions.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using Examine; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; @@ -32,7 +33,7 @@ namespace Umbraco.Extensions foreach (var result in results) { - if (int.TryParse(result.Id, out var contentId) && + if (int.TryParse(result.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var contentId) && cache.GetById(contentId) is IPublishedContent content) { publishedSearchResults.Add(new PublishedSearchResult(content, result.Score)); @@ -62,7 +63,7 @@ namespace Umbraco.Extensions foreach (var result in results) { - if (int.TryParse(result.Id, out var contentId) && + if (int.TryParse(result.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var contentId) && result.Values.TryGetValue(ExamineFieldNames.CategoryFieldName, out var indexType)) { IPublishedContent content; diff --git a/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs b/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs index 5afe010b82..4fbbb35a6d 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs @@ -198,7 +198,7 @@ namespace Umbraco.Cms.Infrastructure.Examine foreach (ISearchResult item in paged) { - if (int.TryParse(item.Id, out int contentId)) + if (int.TryParse(item.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out int contentId)) { DeleteIndexForEntity(contentId, false); } @@ -411,7 +411,7 @@ namespace Umbraco.Cms.Infrastructure.Examine else { Execute(_examineUmbracoIndexingHandler, _ids, _keepIfUnpublished); - } + } } public static void Execute(ExamineUmbracoIndexingHandler examineUmbracoIndexingHandler, int id, bool keepIfUnpublished) diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs index 4e277262a7..70f5b6f0bf 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/ConvertRelatedLinksToMultiUrlPicker.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Runtime.Serialization; using Newtonsoft.Json; @@ -68,7 +69,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0 if (linkIsUdi == false) { // oh no.. probably an integer, yikes! - if (int.TryParse(relatedLink.Link, out var intId)) + if (int.TryParse(relatedLink.Link, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) { var sqlNodeData = Sql() .Select() diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs index 01cd171b6b..0b9bb4519c 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using Newtonsoft.Json; using Umbraco.Extensions; @@ -18,7 +19,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes protected override object GetPreValueValue(PreValueDto preValue) { if (preValue.Alias == "pageSize") - return int.TryParse(preValue.Value, out var i) ? (int?)i : null; + return int.TryParse(preValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? (int?)i : null; return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value; } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs index aba3e3f407..98eac62f15 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System.Globalization; +using Newtonsoft.Json; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes @@ -25,7 +26,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes if (preValue.Alias == "minItems" || preValue.Alias == "maxItems") - return int.TryParse(preValue.Value, out var i) ? (int?)i : null; + return int.TryParse(preValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? (int?)i : null; return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value; } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs index b5e50d2248..f24cfc1142 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -35,7 +36,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0 var splitVals = val.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries); var intVals = splitVals - .Select(x => int.TryParse(x, out var i) ? i : int.MinValue) + .Select(x => int.TryParse(x, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : int.MinValue) .Where(x => x != int.MinValue) .ToArray(); diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs index cea0fbdd23..3cbc7357e5 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -33,7 +34,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0 { var config = JsonConvert.DeserializeObject(datatype.Configuration); var startNodeId = config.Value("startNodeId"); - if (!startNodeId.IsNullOrWhiteSpace() && int.TryParse(startNodeId, out var intStartNode)) + if (!startNodeId.IsNullOrWhiteSpace() && int.TryParse(startNodeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intStartNode)) { var guid = intStartNode <= 0 ? null @@ -65,7 +66,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0 var objectType = startNodeConfig.Value("type"); if (!objectType.IsNullOrWhiteSpace() && !startNodeId.IsNullOrWhiteSpace() - && int.TryParse(startNodeId, out var intStartNode)) + && int.TryParse(startNodeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intStartNode)) { var guid = intStartNode <= 0 ? null diff --git a/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs index e96e96f521..2b52a93741 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs +++ b/src/Umbraco.Infrastructure/Models/Mapping/EntityMapDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using Examine; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models.ContentEditing; @@ -224,7 +225,7 @@ namespace Umbraco.Cms.Core.Models.Mapping if (source.Values.ContainsKey("parentID")) { - if (int.TryParse(source.Values["parentID"], out var parentId)) + if (int.TryParse(source.Values["parentID"], NumberStyles.Integer, CultureInfo.InvariantCulture,out var parentId)) { target.ParentId = parentId; } diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 776af6531c..8f016ada7f 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -838,7 +838,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging propertyGroup.Type = type; } - if (int.TryParse(propertyGroupElement.Element("SortOrder")?.Value, out var sortOrder)) + if (int.TryParse(propertyGroupElement.Element("SortOrder")?.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var sortOrder)) { // Override the sort order with the imported value propertyGroup.SortOrder = sortOrder; @@ -902,7 +902,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging var sortOrderElement = property.Element("SortOrder"); if (sortOrderElement != null) { - int.TryParse(sortOrderElement.Value, out sortOrder); + int.TryParse(sortOrderElement.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out sortOrder); } var propertyType = new PropertyType(_shortStringHelper, dataTypeDefinition, property.Element("Alias").Value) diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs index 730c24f2f2..8df6d654b0 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/PropertyFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; @@ -53,7 +54,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories { dto.IntegerValue = value != null && string.IsNullOrEmpty(value.ToString()) ? 0 : Convert.ToInt32(value); } - else if (value != null && string.IsNullOrWhiteSpace(value.ToString()) == false && int.TryParse(value.ToString(), out var val)) + else if (value != null && string.IsNullOrWhiteSpace(value.ToString()) == false && int.TryParse(value.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var val)) { dto.IntegerValue = val; } diff --git a/src/Umbraco.Infrastructure/Persistence/FaultHandling/ThrottlingCondition.cs b/src/Umbraco.Infrastructure/Persistence/FaultHandling/ThrottlingCondition.cs index 9905a35696..9155937fe0 100644 --- a/src/Umbraco.Infrastructure/Persistence/FaultHandling/ThrottlingCondition.cs +++ b/src/Umbraco.Infrastructure/Persistence/FaultHandling/ThrottlingCondition.cs @@ -263,7 +263,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.FaultHandling var match = sqlErrorCodeRegEx.Match(error.Message); int reasonCode; - if (match.Success && int.TryParse(match.Groups[1].Value, out reasonCode)) + if (match.Success && int.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out reasonCode)) { return FromReasonCode(reasonCode); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs index 8dc8a7783d..116ec356b7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using Umbraco.Extensions; @@ -188,7 +189,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement { var match = matches[0]; Text = match.Groups[1].Value; - int number = int.TryParse(match.Groups[2].Value, out number) ? number : 0; + int number = int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out number) ? number : 0; Suffix = (uint?)(number); return; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs index 82b1305fe4..4c85277781 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System; +using System.Globalization; using System.Linq; using System.Text; using HtmlAgilityPack; @@ -110,7 +111,7 @@ namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters foreach (var img in imgNodes) { var nodeId = img.GetAttributeValue("rel", string.Empty); - if (int.TryParse(nodeId, out _)) + if (int.TryParse(nodeId, NumberStyles.Integer, CultureInfo.InvariantCulture, out _)) { img.Attributes.Remove("rel"); modified = true; diff --git a/src/Umbraco.Infrastructure/PublishedContentQuery.cs b/src/Umbraco.Infrastructure/PublishedContentQuery.cs index 14298cbb4e..946f501b1f 100644 --- a/src/Umbraco.Infrastructure/PublishedContentQuery.cs +++ b/src/Umbraco.Infrastructure/PublishedContentQuery.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Xml.XPath; using Examine; @@ -43,7 +44,7 @@ namespace Umbraco.Cms.Infrastructure switch (id) { case string s: - return int.TryParse(s, out intId); + return int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out intId); case int i: intId = i; diff --git a/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs b/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs index 685a21d175..03339fbd33 100644 --- a/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberRoleStore.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -71,7 +72,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(role)); } - if (!int.TryParse(role.Id, out int roleId)) + if (!int.TryParse(role.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out int roleId)) { return Task.FromResult(IdentityResult.Failed(_intParseError)); } @@ -103,7 +104,7 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(role)); } - if (!int.TryParse(role.Id, out int roleId)) + if (!int.TryParse(role.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out int roleId)) { throw new ArgumentException("The Id of the role is not an integer"); } @@ -184,7 +185,7 @@ namespace Umbraco.Cms.Core.Security IMemberGroup memberGroup; // member group can be found by int or Guid, so try both - if (!int.TryParse(roleId, out int id)) + if (!int.TryParse(roleId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int id)) { if (!Guid.TryParse(roleId, out Guid guid)) { diff --git a/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs b/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs index 419881fe1c..90184cd258 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/PublicAccessService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Events; @@ -57,7 +58,7 @@ namespace Umbraco.Cms.Core.Services.Implement //Get all ids in the path for the content item and ensure they all // parse to ints that are not -1. var ids = contentPath.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries) - .Select(x => int.TryParse(x, out int val) ? val : -1) + .Select(x => int.TryParse(x, NumberStyles.Integer, CultureInfo.InvariantCulture, out int val) ? val : -1) .Where(x => x != -1) .ToList(); diff --git a/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs b/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs index 3b3351fd93..462eb88239 100644 --- a/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs +++ b/src/Umbraco.Infrastructure/Sync/LastSyncedFileManager.cs @@ -52,7 +52,7 @@ namespace Umbraco.Cms.Infrastructure.Sync if (File.Exists(distCacheFilePath)) { var content = File.ReadAllText(distCacheFilePath); - if (int.TryParse(content, out var last)) + if (int.TryParse(content, NumberStyles.Integer, CultureInfo.InvariantCulture, out var last)) { return last; } diff --git a/src/Umbraco.Web.BackOffice/Authorization/AdminUsersHandler.cs b/src/Umbraco.Web.BackOffice/Authorization/AdminUsersHandler.cs index 64649ac274..1f760de4fd 100644 --- a/src/Umbraco.Web.BackOffice/Authorization/AdminUsersHandler.cs +++ b/src/Umbraco.Web.BackOffice/Authorization/AdminUsersHandler.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -55,7 +56,7 @@ namespace Umbraco.Cms.Web.BackOffice.Authorization } int[] userIds; - if (int.TryParse(queryString, out var userId)) + if (int.TryParse(queryString, NumberStyles.Integer, CultureInfo.InvariantCulture, out var userId)) { userIds = new[] { userId }; } diff --git a/src/Umbraco.Web.BackOffice/Authorization/PermissionsQueryStringHandler.cs b/src/Umbraco.Web.BackOffice/Authorization/PermissionsQueryStringHandler.cs index 531b92a7e9..e8433dd1a8 100644 --- a/src/Umbraco.Web.BackOffice/Authorization/PermissionsQueryStringHandler.cs +++ b/src/Umbraco.Web.BackOffice/Authorization/PermissionsQueryStringHandler.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System; +using System.Globalization; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Umbraco.Cms.Core; @@ -61,7 +62,7 @@ namespace Umbraco.Cms.Web.BackOffice.Authorization // It might be a udi, so check that next. // Otherwise treat it as a guid - unlikely we ever get here. // Failing that, we can't parse it. - if (int.TryParse(argument, out int parsedId)) + if (int.TryParse(argument, NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsedId)) { nodeId = parsedId; return true; diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index e79b49ace3..bc0929487a 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -272,7 +272,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers var result = _umbracoMapper.Map(user); //set their remaining seconds - result.SecondsUntilTimeout = HttpContext.User.GetRemainingAuthSeconds(); + result.SecondsUntilTimeout = 100+ HttpContext.User.GetRemainingAuthSeconds(); return result; } diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 4f380b1bcf..2eaeee3d12 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -579,7 +579,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers string filter = "", Guid? dataTypeKey = null) { - if (int.TryParse(id, out var intId)) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) { return GetPagedChildren(intId, type, pageNumber, pageSize, orderBy, orderDirection, filter); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index e8947dbf17..d54bd7a093 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Net.Mime; @@ -898,7 +899,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers } //if it's not an INT then we'll check for GUID - if (int.TryParse(parentId, out intParentId) == false) + if (int.TryParse(parentId, NumberStyles.Integer, CultureInfo.InvariantCulture, out intParentId) == false) { // if a guid then try to look up the entity Guid idGuid; diff --git a/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs index 39432703a7..8527355597 100644 --- a/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs @@ -169,7 +169,7 @@ namespace Umbraco.Cms.Web.BackOffice.Filters await _backOfficeSignInManager.SignInAsync(backOfficeIdentityUser, isPersistent: true); // ensure the remainder of the request has the correct principal set - actionContext.HttpContext.SetPrincipalForRequest(ClaimsPrincipal.Current); + //actionContext.HttpContext.SetPrincipalForRequest(ClaimsPrincipal.Current); // flag that we've made changes _requestCache.Set(nameof(CheckIfUserTicketDataIsStaleFilter), true); diff --git a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs index 0dd19d7db9..e234fa1115 100644 --- a/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs +++ b/src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; @@ -330,7 +331,7 @@ namespace Umbraco.Cms.Web.BackOffice.Mapping if (parent == null) return false; - var pathParts = parent.Path.Split(Constants.CharArrays.Comma).Select(x => int.TryParse(x, out var i) ? i : 0).ToList(); + var pathParts = parent.Path.Split(Constants.CharArrays.Comma).Select(x => int.TryParse(x, NumberStyles.Integer, CultureInfo.InvariantCulture, out var i) ? i : 0).ToList(); // reduce the path parts so we exclude top level content items that // are higher up than a user's start nodes diff --git a/src/Umbraco.Web.BackOffice/Security/BackOfficeUserManagerAuditer.cs b/src/Umbraco.Web.BackOffice/Security/BackOfficeUserManagerAuditer.cs index a47987667f..75cd5ab5a1 100644 --- a/src/Umbraco.Web.BackOffice/Security/BackOfficeUserManagerAuditer.cs +++ b/src/Umbraco.Web.BackOffice/Security/BackOfficeUserManagerAuditer.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Notifications; @@ -55,7 +56,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security private void WriteAudit(string performingId, string affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null) { IUser performingUser = null; - if (int.TryParse(performingId, out int asInt)) + if (int.TryParse(performingId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int asInt)) { performingUser = _userService.GetUserById(asInt); } @@ -64,12 +65,12 @@ namespace Umbraco.Cms.Web.BackOffice.Security ? $"User UNKNOWN:{performingId}" : $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}"; - if (!int.TryParse(performingId, out int performingIdAsInt)) + if (!int.TryParse(performingId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int performingIdAsInt)) { performingIdAsInt = 0; } - if (!int.TryParse(affectedId, out int affectedIdAsInt)) + if (!int.TryParse(affectedId, NumberStyles.Integer, CultureInfo.InvariantCulture, out int affectedIdAsInt)) { affectedIdAsInt = 0; } diff --git a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs index 1457732c53..1767386088 100644 --- a/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs +++ b/src/Umbraco.Web.BackOffice/Security/ConfigureBackOfficeCookieOptions.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; @@ -190,7 +191,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security // occurs when sign in is successful and after the ticket is written to the outbound cookie // When we are signed in with the cookie, assign the principal to the current HttpContext - ctx.HttpContext.User = ctx.Principal; + ctx.HttpContext.SetPrincipalForRequest(ctx.Principal); return Task.CompletedTask; }, diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs index 011cbe74e6..74c456026d 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -187,7 +188,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees //return a normal node menu: int iid; - if (int.TryParse(id, out iid) == false) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out iid) == false) { return NotFound(); } diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs index e84338fc9b..2f27f8adac 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -71,7 +72,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { int asInt; Guid asGuid = Guid.Empty; - if (int.TryParse(id, out asInt) == false) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out asInt) == false) { if (Guid.TryParse(id, out asGuid) == false) { @@ -264,7 +265,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { int id; var parts = entity.Path.Split(Comma, StringSplitOptions.RemoveEmptyEntries); - return parts.Length >= 2 && int.TryParse(parts[1], out id) ? id : 0; + return parts.Length >= 2 && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out id) ? id : 0; } protected abstract ActionResult PerformGetMenuForNode(string id, FormCollection queryStrings); @@ -275,7 +276,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { // try to parse id as an integer else use GetEntityFromId // which will grok Guids, Udis, etc and let use obtain the id - if (!int.TryParse(id, out var entityId)) + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var entityId)) { var entity = GetEntityFromId(id); if (entity == null) @@ -544,7 +545,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { return new Tuple(idGuid, null); } - if (int.TryParse(id, out idInt)) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out idInt)) { return new Tuple(null, idInt); } @@ -576,7 +577,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees { entity = _entityService.Get(idGuid, UmbracoObjectType); } - else if (int.TryParse(s, out var idInt)) + else if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var idInt)) { entity = _entityService.Get(idInt, UmbracoObjectType); } diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs index 2ff354410c..a1a83bc5f3 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -122,7 +123,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees return menu; } - if (int.TryParse(id, out var iid) == false) + if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var iid) == false) { return NotFound(); } diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs index b0a640b230..6cc81fd724 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; @@ -71,7 +72,7 @@ namespace Umbraco.Cms.Web.Common.Filters var members = new List(); foreach (var s in AllowMembers.Split(Core.Constants.CharArrays.Comma)) { - if (int.TryParse(s, out var id)) + if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var id)) { members.Add(id); } diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index ad00c5b8b6..260a58a035 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -20,7 +20,7 @@ "@babel/core": { "version": "7.6.4", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", - "integrity": "sha1-br2f4Akl9sPhd7tyahiLX1eAiP8=", + "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", "dev": true, "requires": { "@babel/code-frame": "^7.5.5", @@ -831,7 +831,7 @@ "@babel/preset-env": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.3.tgz", - "integrity": "sha1-nhvwWi4taHA20kxA5GOdxGzvInE=", + "integrity": "sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.0.0", @@ -957,7 +957,7 @@ "@gulp-sourcemaps/identity-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", - "integrity": "sha1-Hm/l2AJ7HyhdwNMXYvVmvM1z1ak=", + "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", "dev": true, "requires": { "acorn": "^5.0.3", @@ -976,7 +976,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -1086,7 +1086,7 @@ "accepts": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "dev": true, "requires": { "mime-types": "~2.1.24", @@ -1096,7 +1096,7 @@ "accord": { "version": "0.29.0", "resolved": "https://registry.npmjs.org/accord/-/accord-0.29.0.tgz", - "integrity": "sha1-t0HBdtAENcWSnUZt/oz2vukzseQ=", + "integrity": "sha512-3OOR92FTc2p5/EcOzPcXp+Cbo+3C15nV9RXHlOUBCBpHhcB+0frbSNR9ehED/o7sTcyGVtqGJpguToEdlXhD0w==", "dev": true, "requires": { "convert-source-map": "^1.5.0", @@ -1143,7 +1143,7 @@ "ace-builds": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.2.tgz", - "integrity": "sha1-avwuQ6e17/3ETYQHQ2EShSVo6A0=" + "integrity": "sha512-M1JtZctO2Zg+1qeGUFZXtYKsyaRptqQtqpVzlj80I0NzGW9MF3um0DBuizIvQlrPYUlTdm+wcOPZpZoerkxQdA==" }, "acorn": { "version": "7.1.0", @@ -1240,12 +1240,12 @@ "angular-animate": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.7.5.tgz", - "integrity": "sha1-H/xsKpze4ieiunnMbNj3HsRNtdw=" + "integrity": "sha512-kU/fHIGf2a4a3bH7E1tzALTHk+QfoUSCK9fEcMFisd6ZWvNDwPzXWAilItqOC3EDiAXPmGHaNc9/aXiD9xrAxQ==" }, "angular-aria": { "version": "1.7.9", "resolved": "https://registry.npmjs.org/angular-aria/-/angular-aria-1.7.9.tgz", - "integrity": "sha1-kMYYlf+9h26VkVIisyp70AcK9+M=" + "integrity": "sha512-luI3Jemd1AbOQW0krdzfEG3fM0IFtLY0bSSqIDEx3POE0XjKIC1MkrO8Csyq9PPgueLphyAPofzUwZ8YeZ88SA==" }, "angular-chart.js": { "version": "1.1.1", @@ -1270,12 +1270,12 @@ "angular-cookies": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-cookies/-/angular-cookies-1.7.5.tgz", - "integrity": "sha1-HFqzwFzcQ/F3e+lQbmRYfLNUNjQ=" + "integrity": "sha512-/8xvvSl/Z9Vwu8ChRm+OQE3vmli8Icwl8uTYkHqD7j7cknJP9kNaf7SgsENlsLVtOqLE/I7TCFYrSx3bmSeNQA==" }, "angular-dynamic-locale": { "version": "0.1.37", "resolved": "https://registry.npmjs.org/angular-dynamic-locale/-/angular-dynamic-locale-0.1.37.tgz", - "integrity": "sha1-fon70uxFvdaryJ82zaiJODjkk1Q=", + "integrity": "sha512-m5Kyk8W8/mOZSqRxuByOwHBjv8labLBAgvl0Z3iQx2xT/tWCqb94imKUPwumudszdPDjxeopwyucQvm8Sw7ogw==", "requires": { "@types/angular": "^1.6.25" } @@ -1283,7 +1283,7 @@ "angular-i18n": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-i18n/-/angular-i18n-1.7.5.tgz", - "integrity": "sha1-Lie2Thl3qMa2sFHFHQF1xtTcglI=" + "integrity": "sha512-52+Jpt8HRJV2bqSbSU6fWkwOvGzj/DxbNpKXxnTuCS9heuJrlm77BS/lhrF4BA8+Uudnh7npr5/yRELobP+8Yw==" }, "angular-local-storage": { "version": "0.7.1", @@ -1293,32 +1293,32 @@ "angular-messages": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-messages/-/angular-messages-1.7.5.tgz", - "integrity": "sha1-fC/XgTFaQ6GYOLEX2gFCqYhFThQ=" + "integrity": "sha512-YDpJpFLyrIgZjE/sIAjgww1y6r3QqXBJbNDI0QjftD37vHXLkwvAOo3A4bxPw8BikyGLcJrFrgf6hRAzntJIWA==" }, "angular-mocks": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.7.5.tgz", - "integrity": "sha1-yLq6WgbtYLk0aXAmtJIWliavOEs=" + "integrity": "sha512-I+Ue2Bkx6R9W5178DYrNvzjIdGh4wKKoCWsgz8dc7ysH4mA70Q3M9v5xRF0RUu7r+2CZj+nDeUecvh2paxcYvg==" }, "angular-route": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-route/-/angular-route-1.7.5.tgz", - "integrity": "sha1-NKNkjEB6FKAw0HXPSFMY4zuiPw4=" + "integrity": "sha512-7KfyEVVOWTI+jTY/j5rUNCIHGRyeCOx7YqZI/Ci3IbDK7GIsy6xH+hS5ai0Xi0sLjzDZ0PUDO4gBn+K0dVtlOg==" }, "angular-sanitize": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-sanitize/-/angular-sanitize-1.7.5.tgz", - "integrity": "sha1-ddSeFQccqccFgedtIJQPJjcuJNI=" + "integrity": "sha512-wjKCJOIwrkEvfD0keTnKGi6We13gtoCAQIHcdoqyoo3gwvcgNfYymVQIS3+iCGVcjfWz0jHuS3KgB4ysRWsTTA==" }, "angular-touch": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/angular-touch/-/angular-touch-1.7.5.tgz", - "integrity": "sha1-7SYyKmhfApmyPLauqYNMEZQk2kY=" + "integrity": "sha512-XNAZNG0RA1mtdwBJheViCF1H/7wOygp4MLIfs5y1K+rne6AeaYKZcV6EJs9fvgfLKLO6ecm1+3J8hoCkdhhxQw==" }, "angular-ui-sortable": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/angular-ui-sortable/-/angular-ui-sortable-0.19.0.tgz", - "integrity": "sha1-SsQ5H8TU3lcRDbS10xp8GY0xT9A=", + "integrity": "sha512-u/uc981Nzg4XN1bMU9qKleMTSt7F1XjMWnyGw6gxPLIeQeLZm8jWNy7tj8y2r2HmvzXFbQVq2z6rObznFKAekQ==", "requires": { "angular": ">=1.2.x", "jquery": ">=3.1.x", @@ -1333,7 +1333,7 @@ "ansi-colors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha1-Y3S03V1HGP884npnGjscrQdxMqk=", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { "ansi-wrap": "^0.1.0" @@ -1381,7 +1381,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -1561,7 +1561,7 @@ "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" @@ -1585,7 +1585,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "arr-map": { @@ -1635,7 +1635,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true } } @@ -1643,7 +1643,7 @@ "array-last": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha1-eqdwc/7FZd2rJJP1+IGF9ASp0zY=", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", "dev": true, "requires": { "is-number": "^4.0.0" @@ -1652,7 +1652,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true } } @@ -1660,13 +1660,13 @@ "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "array-sort": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha1-5MBTVkU/VvU1EqfR1hI/LFTAqIo=", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", "dev": true, "requires": { "default-compare": "^1.0.0", @@ -1677,7 +1677,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -1703,7 +1703,7 @@ "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", "dev": true }, "asap": { @@ -1716,7 +1716,7 @@ "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha1-jSR136tVO7M+d7VOWeiAu4ziMTY=", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { "safer-buffer": "~2.1.0" } @@ -1735,13 +1735,13 @@ "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha1-bIw/uCfdQ+45GPJ7gngqt2WKb9k=", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8=", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { "lodash": "^4.17.14" @@ -1758,7 +1758,7 @@ "async-done": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha1-XhWqcplipLB0FPUoqIzfGOCykKI=", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -1770,13 +1770,13 @@ "async-each": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha1-tyfb+H12UWAvBvTUrDh/R9kbDL8=", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "dev": true }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=" + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, "async-settle": { "version": "1.0.0", @@ -1795,13 +1795,13 @@ "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha1-bZUX654DDSQ2ZmZR6GvZ9vE1M8k=", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, "autoprefixer": { "version": "9.6.5", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.5.tgz", - "integrity": "sha1-mPSv5+k8zPMjKHUV1CYBlhl3Xl4=", + "integrity": "sha512-rGd50YV8LgwFQ2WQp4XzOTG69u1qQsXn0amww7tjqV5jJuNazgFKYEVItEBngyyvVITKOg20zr2V+9VsrXJQ2g==", "dev": true, "requires": { "browserslist": "^4.7.0", @@ -1834,7 +1834,7 @@ "babel-plugin-dynamic-import-node": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha1-8A9Qe9qjw+P/bn5emNkKesq5b38=", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", "dev": true, "requires": { "object.assign": "^4.1.0" @@ -1872,7 +1872,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -1896,7 +1896,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1905,7 +1905,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1914,7 +1914,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -2257,7 +2257,7 @@ "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha1-WYr+VHVbKGilMw0q/51Ou1Mgm2U=", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "bl": { @@ -2309,7 +2309,7 @@ "blob": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha1-1oDu7yX4zZGtUz9bAe7UjmTK9oM=", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", "dev": true }, "bluebird": { @@ -2321,7 +2321,7 @@ "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "dev": true, "requires": { "bytes": "3.1.0", @@ -2339,7 +2339,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -2354,7 +2354,7 @@ "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", "dev": true } } @@ -2368,7 +2368,7 @@ "bootstrap": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", - "integrity": "sha1-w6NH1Bniia0R9AM+PEEyuHwIHXI=" + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" }, "bootstrap-social": { "version": "5.1.1", @@ -2382,7 +2382,7 @@ "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -2392,7 +2392,7 @@ "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { "arr-flatten": "^1.1.0", @@ -2449,7 +2449,7 @@ "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", @@ -2459,7 +2459,7 @@ "buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", "dev": true }, "buffer-crc32": { @@ -2484,7 +2484,7 @@ "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha1-MnE7wCj3XAL9txDXx7zsHyxgcO8=", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, "bufferstreams": { @@ -2499,13 +2499,13 @@ "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", "dev": true }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -2606,7 +2606,7 @@ }, "callsites": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true }, @@ -2639,7 +2639,7 @@ "caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -2685,7 +2685,7 @@ "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -2696,7 +2696,7 @@ "chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha1-kAlISfCTfy7twkJdDSip5fDLrZ4=", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, "chart.js": { @@ -2720,7 +2720,7 @@ "chartjs-color-string": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", - "integrity": "sha1-HfCWYhwOcHIKZPQTXqFx0FFAL3E=", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", "requires": { "color-name": "^1.0.0" } @@ -2728,7 +2728,7 @@ "chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha1-gEs6e2qZNYw8XGHnHYco8EHP+Rc=", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -2778,7 +2778,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true } } @@ -2786,7 +2786,7 @@ "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -2809,7 +2809,7 @@ "clean-css": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", - "integrity": "sha1-LUEe92uFabbQyEBo2r6FsKpeXBc=", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", "dev": true, "requires": { "source-map": "~0.6.0" @@ -2818,7 +2818,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -2826,7 +2826,7 @@ "cli-color": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha1-fRBzj0hSaCT4/n2lGFfLD1cv4B8=", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", "dev": true, "requires": { "ansi-regex": "^2.1.1", @@ -2855,7 +2855,7 @@ "clipboard": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", - "integrity": "sha1-g22v1mzw/qXXHOXVsL9ulYAJES0=", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", "requires": { "good-listener": "^1.2.2", "select": "^1.1.2", @@ -2904,7 +2904,7 @@ "cloneable-readable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha1-EgoAywU7+2OiIucJ+Wg+ouEdjOw=", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -2947,7 +2947,7 @@ "coa": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha1-Q/bCEVG07yv1cYfbDXPeIp4+fsM=", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", "dev": true, "requires": { "@types/q": "^1.5.1", @@ -2985,7 +2985,7 @@ "color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", - "integrity": "sha1-aBSOf4XUGtdknF+oyBBvCY0inhA=", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", "dev": true, "requires": { "color-convert": "^1.9.1", @@ -3017,12 +3017,12 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "color-string": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", - "integrity": "sha1-ybvF8BtYtUkvPWhXRZy2WQziBMw=", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", "dev": true, "requires": { "color-name": "^1.0.0", @@ -3032,7 +3032,7 @@ "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true }, "colorette": { @@ -3050,13 +3050,13 @@ "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha1-xQSRR51MG9rtLJztMs98fcI2D3g=", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "colorspace": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", - "integrity": "sha1-4BKJUNCCuGohaFgHlqCqXWxo2MU=", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", "dev": true, "requires": { "color": "3.0.x", @@ -3066,7 +3066,7 @@ "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha1-2SC0Mo1TSjrIKV1o971LpsQnvpo=", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", "dev": true, "requires": { "color-convert": "^1.9.1", @@ -3093,7 +3093,7 @@ "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { "delayed-stream": "~1.0.0" } @@ -3113,7 +3113,7 @@ "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "component-inherit": { @@ -3131,7 +3131,7 @@ "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -3164,7 +3164,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -3175,7 +3175,7 @@ "concat-with-sourcemaps": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", - "integrity": "sha1-1OqT8FriV5CVG5nns7CeOQikCC4=", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", "dev": true, "requires": { "source-map": "^0.6.1" @@ -3184,7 +3184,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -3203,7 +3203,7 @@ "connect": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha1-XUk0iRDKpeB6AYALAw0MNfIEhPg=", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "requires": { "debug": "2.6.9", @@ -3215,7 +3215,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -3239,7 +3239,7 @@ "consolidate": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha1-IasEMjXHGgfUXZqtmFk7DbpWurc=", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", "dev": true, "requires": { "bluebird": "^3.1.1" @@ -3258,7 +3258,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "convert-source-map": { @@ -3285,7 +3285,7 @@ "copy-props": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", - "integrity": "sha1-k7scrfr9MdpbuKnUtB9HHsOnLf4=", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", "dev": true, "requires": { "each-props": "^1.3.0", @@ -3344,7 +3344,7 @@ "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha1-BA9yaAnFked6F8CjYmykW08Wixo=", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "dev": true, "requires": { "import-fresh": "^2.0.0", @@ -3356,7 +3356,7 @@ "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha1-Sl7Hxk364iw6FBJNus3uhG2Ay8Q=", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { "nice-try": "^1.0.4", @@ -3369,7 +3369,7 @@ "css": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha1-xkZ1XHOXHyu6amAeLPL9cbEpiSk=", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -3381,7 +3381,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -3395,7 +3395,7 @@ "css-declaration-sorter": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha1-wZiUD2OnbX42wecQGLABchBUyyI=", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", "dev": true, "requires": { "postcss": "^7.0.1", @@ -3417,7 +3417,7 @@ "css-select-base-adapter": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha1-Oy/0lyzDYquIVhUHqVQIoUMhNdc=", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", "dev": true }, "css-tree": { @@ -3451,7 +3451,7 @@ "cssnano": { "version": "4.1.10", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz", - "integrity": "sha1-CsQfCxPRPUZUh+ERt3jULaYxuLI=", + "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==", "dev": true, "requires": { "cosmiconfig": "^5.0.0", @@ -3463,7 +3463,7 @@ "cssnano-preset-default": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz", - "integrity": "sha1-UexmLM/KD4izltzZZ5zbkxvhf3Y=", + "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==", "dev": true, "requires": { "css-declaration-sorter": "^4.0.1", @@ -3513,7 +3513,7 @@ "cssnano-util-raw-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha1-sm1f1fcqEd/np4RvtMZyYPlr8oI=", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -3522,7 +3522,7 @@ "cssnano-util-same-parent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha1-V0CC+yhZ0ttDOFWDXZqEVuoYu/M=", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", "dev": true }, "csso": { @@ -3594,7 +3594,7 @@ "d": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha1-hpgJU3LVjb7jRv/Qxwk/mfj561o=", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", "dev": true, "requires": { "es5-ext": "^0.10.50", @@ -3635,7 +3635,7 @@ "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" @@ -3644,7 +3644,7 @@ "debug-fabulous": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", - "integrity": "sha1-r4oIYyRlIk70F0qfBjCMPCoevI4=", + "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", "dev": true, "requires": { "debug": "3.X", @@ -3849,7 +3849,7 @@ "default-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha1-y2ETGESthNhHiPto/QFoHKd4Gi8=", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", "dev": true, "requires": { "kind-of": "^5.0.2" @@ -3858,7 +3858,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -3872,7 +3872,7 @@ "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha1-z4jabL7ib+bbcJT2HYcMvYTO6fE=", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { "object-keys": "^1.0.12" @@ -3881,7 +3881,7 @@ "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "requires": { "is-descriptor": "^1.0.2", @@ -3891,7 +3891,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3900,7 +3900,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3909,7 +3909,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -3927,7 +3927,7 @@ "delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha1-tmtxwxWFIuirV0T3INjKDCr1kWY=" + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" }, "depd": { "version": "1.1.2", @@ -3956,7 +3956,7 @@ "diagnostics": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha1-yrasM99wydmnJ0kK5DrJladpsio=", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", "dev": true, "requires": { "colorspace": "1.1.x", @@ -3967,7 +3967,7 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=" + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, "dir-glob": { "version": "3.0.1", @@ -3989,7 +3989,7 @@ "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -4020,7 +4020,7 @@ "domelementtype": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", - "integrity": "sha1-H4vf6R9aeAYydOgDtL3O326U+U0=", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", "dev": true } } @@ -4028,7 +4028,7 @@ "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha1-0EjESzew0Qp/Kj1f7j9DM9eQSB8=", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, "domexception": { @@ -4051,7 +4051,7 @@ "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "dev": true, "requires": { "domelementtype": "1" @@ -4060,7 +4060,7 @@ "domutils": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha1-Vuo0HoNOBuZ0ivehyyXaZ+qfjCo=", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "dev": true, "requires": { "dom-serializer": "0", @@ -4148,7 +4148,7 @@ "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -4192,7 +4192,7 @@ "each-props": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha1-6kWkFNFt1c+kGbGoFyDVygaJIzM=", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", "dev": true, "requires": { "is-plain-object": "^2.0.1", @@ -4250,7 +4250,7 @@ "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" @@ -4362,7 +4362,7 @@ "entities": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha1-aNYITKsbB5dnVA2A5Wo5tCPkq/Q=", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", "dev": true }, "env-variable": { @@ -4374,7 +4374,7 @@ "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "dev": true, "optional": true, "requires": { @@ -4384,7 +4384,7 @@ "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { "is-arrayish": "^0.2.1" @@ -4444,7 +4444,7 @@ "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha1-TrIVlMlyvEBVPSduUQU5FD21Pgo=", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true }, "es6-symbol": { @@ -4460,7 +4460,7 @@ "es6-weak-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha1-ttofFswswNm+Q+a9v8Xn383zHVM=", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", "dev": true, "requires": { "d": "1", @@ -4509,7 +4509,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -4563,7 +4563,7 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "glob-parent": { @@ -4597,19 +4597,19 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" @@ -4630,7 +4630,7 @@ "eslint-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha1-dP7HxU0Hdrb2fgJRBAtYBlZOmB8=", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" @@ -4656,7 +4656,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "esquery": { @@ -4698,13 +4698,13 @@ "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "event-emitter": { @@ -4833,7 +4833,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -4877,7 +4877,7 @@ "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", "dev": true, "requires": { "is-number": "^2.1.0", @@ -4955,7 +4955,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -4970,7 +4970,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -4981,7 +4981,7 @@ "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha1-ywP3QL764D6k0oPK7SdBqD8zVJU=", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, "requires": { "chardet": "^0.7.0", @@ -4992,7 +4992,7 @@ "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, "requires": { "array-unique": "^0.3.2", @@ -5026,7 +5026,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -5035,7 +5035,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -5044,7 +5044,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -5062,7 +5062,7 @@ "fancy-log": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha1-28GRVPVYaQFQojlToK29A1vkX8c=", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", "dev": true, "requires": { "ansi-gray": "^0.1.1", @@ -5201,7 +5201,7 @@ "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha1-yg9u+m3T1WEzP7FFFQZcL6/fQ5w=", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { "flat-cache": "^2.0.1" @@ -5264,7 +5264,7 @@ "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "requires": { "debug": "2.6.9", @@ -5279,7 +5279,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -5339,7 +5339,7 @@ "fined": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha1-0AvszxqitHXRbUI7Aji3E6LEo3s=", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -5393,13 +5393,13 @@ "flagged-respawn": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha1-595vEnnd2cqarIpZcdYYYGs6q0E=", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha1-XSltbwS9pEpGMKMBQTvbwuwIXsA=", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { "flatted": "^2.0.0", @@ -5415,13 +5415,13 @@ "flatted": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", - "integrity": "sha1-aeV8qo8OrLwoHS4stFjUb9tEngg=", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha1-jdfYc6G6vCB9lOrQwuDkQnbr8ug=", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -5508,7 +5508,7 @@ "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha1-3M5SwF9kTymManq5Nr1yTO/786Y=", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -5596,7 +5596,7 @@ "fs-readfile-promise": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/fs-readfile-promise/-/fs-readfile-promise-3.0.1.tgz", - "integrity": "sha1-0NMHt/au38kgwx+m5XEu+qKXyVg=", + "integrity": "sha512-LsSxMeaJdYH27XrW7Dmq0Gx63mioULCRel63B5VeELYLavi1wF5s0XfsIdKDFdCL9hsfQ2qBvXJszQtQJ9h17A==", "dev": true, "requires": { "graceful-fs": "^4.1.11" @@ -6159,7 +6159,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "functional-red-black-tree": { @@ -6171,7 +6171,7 @@ "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, "get-proxy": { @@ -6475,7 +6475,7 @@ "glob-watcher": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", - "integrity": "sha1-iKir8cTRMeuTkomUvEpZPC5d1iY=", + "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -6501,7 +6501,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -6525,7 +6525,7 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "globby": { @@ -6561,7 +6561,7 @@ "glogg": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha1-LX3XAr7aIus7/634gGltpthGMT8=", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", "dev": true, "requires": { "sparkles": "^1.0.0" @@ -6622,7 +6622,7 @@ "gulp": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha1-VDZRBw/Q9qsKBlDGo+b/WnywnKo=", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, "requires": { "glob-watcher": "^5.0.3", @@ -6655,7 +6655,7 @@ "gulp-babel": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0.tgz", - "integrity": "sha1-4NqW9PLsSojdOjAw9HbjirISbYc=", + "integrity": "sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ==", "dev": true, "requires": { "plugin-error": "^1.0.1", @@ -6675,7 +6675,7 @@ "gulp-clean-css": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.2.0.tgz", - "integrity": "sha1-kV7CWNxtPmpQBD9hAGbVwurE9U4=", + "integrity": "sha512-r4zQsSOAK2UYUL/ipkAVCTRg/2CLZ2A+oPVORopBximRksJ6qy3EX1KGrIWT4ZrHxz3Hlobb1yyJtqiut7DNjA==", "dev": true, "requires": { "clean-css": "4.2.1", @@ -6713,7 +6713,7 @@ "through2": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha1-OSducTwzAu3544jdnIEt07glvVo=", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", "dev": true, "requires": { "readable-stream": "2 || 3" @@ -6795,7 +6795,7 @@ "gulp-eslint": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", - "integrity": "sha1-fUArtF+KZ2UrhoJ3ARgSBXNwqDI=", + "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", "dev": true, "requires": { "eslint": "^6.0.0", @@ -6870,7 +6870,7 @@ "gulp-less": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-4.0.1.tgz", - "integrity": "sha1-NIwzpd3nogfFdxsdgmHRrBAhzu0=", + "integrity": "sha512-hmM2k0FfQp7Ptm3ZaqO2CkMX3hqpiIOn4OHtuSsCeFym63F7oWlEua5v6u1cIjVUKYsVIs9zPg9vbqTEb/udpA==", "dev": true, "requires": { "accord": "^0.29.0", @@ -6915,7 +6915,7 @@ }, "kind-of": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", "dev": true }, @@ -7047,7 +7047,7 @@ "gulp-notify": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/gulp-notify/-/gulp-notify-3.2.0.tgz", - "integrity": "sha1-KugiUAnfiB7vWb5d1aLxM3OHdk4=", + "integrity": "sha512-qEocs1UVoDKKUjfsxJNMNwkRla0PbsyJwsqNNXpzYWsLQ29LhxRMY3wnTGZcc4hMHtalnvah/Dwlwb4NijH/0A==", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -7099,7 +7099,7 @@ "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha1-+XYZXPPzR9DV9SSDVp/oAxzM6Ks=", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0", @@ -7109,7 +7109,7 @@ "lodash.templatesettings": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha1-5IExDwSdPPbUfpEq0JMTsVTw+zM=", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0" @@ -7133,7 +7133,7 @@ "gulp-postcss": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/gulp-postcss/-/gulp-postcss-8.0.0.tgz", - "integrity": "sha1-jTdyzU0nvKVeyMtMjlduO95NxVA=", + "integrity": "sha512-Wtl6vH7a+8IS/fU5W9IbOpcaLqKxd5L1DUOzaPmlnCbX1CrG0aWdwVnC3Spn8th0m8D59YbysV5zPUe1n/GJYg==", "dev": true, "requires": { "fancy-log": "^1.3.2", @@ -7146,7 +7146,7 @@ "gulp-rename": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz", - "integrity": "sha1-3hxxjnxAla6GH3KW708ySGSCQL0=", + "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==", "dev": true }, "gulp-sort": { @@ -7161,7 +7161,7 @@ "gulp-sourcemaps": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", - "integrity": "sha1-o/AC2HNG0sDzrsNq9+uHPyPeiuY=", + "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", "dev": true, "requires": { "@gulp-sourcemaps/identity-map": "1.X", @@ -7186,7 +7186,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -7225,7 +7225,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -7247,7 +7247,7 @@ "gulp-watch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz", - "integrity": "sha1-g9N4dS9b+0baAj5zwX7R2nBmIV0=", + "integrity": "sha512-HnTSBdzAOFIT4wmXYPDUn783TaYAq9bpaN05vuZNP5eni3z3aRx0NAKbjhhMYtcq76x4R1wf4oORDGdlrEjuog==", "dev": true, "requires": { "ansi-colors": "1.1.0", @@ -7348,7 +7348,7 @@ "gulp-wrap": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/gulp-wrap/-/gulp-wrap-0.15.0.tgz", - "integrity": "sha1-6QFMm7hkOrMQ6TjURpuFaFUaVS8=", + "integrity": "sha512-f17zkGObA+hE/FThlg55gfA0nsXbdmHK1WqzjjB2Ytq1TuhLR7JiCBJ3K4AlMzCyoFaCjfowos+VkToUNE0WTQ==", "dev": true, "requires": { "consolidate": "^0.15.1", @@ -7392,7 +7392,7 @@ "through2": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha1-OSducTwzAu3544jdnIEt07glvVo=", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", "dev": true, "requires": { "readable-stream": "2 || 3" @@ -7457,7 +7457,7 @@ "har-validator": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha1-HvievT5JllV2de7ZiTEQ3DUPoIA=", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" @@ -7466,7 +7466,7 @@ "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { "function-bind": "^1.1.1" @@ -7484,7 +7484,7 @@ "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "dev": true, "requires": { "isarray": "2.0.1" @@ -7577,13 +7577,13 @@ "hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha1-TAb8y0YC/iYCs8k9+C1+fb8aio4=", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", "dev": true }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha1-dDKYzvTlrz4ZQWH7rcwhUdOgWOg=", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { "parse-passwd": "^1.0.0" @@ -7610,7 +7610,7 @@ "html-comment-regex": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", - "integrity": "sha1-l9RoiutcgYhqNk+qDK0d2hTUM6c=", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", "dev": true }, "html-encoding-sniffer": { @@ -7639,7 +7639,7 @@ "entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha1-vfpzUplmTfr9NFKe1PhSKidf6lY=", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true }, "isarray": { @@ -7684,7 +7684,7 @@ "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "dev": true, "requires": { "depd": "~1.1.2", @@ -7733,7 +7733,7 @@ "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -7749,7 +7749,7 @@ "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "image-size": { @@ -7993,13 +7993,13 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true }, "inquirer": { @@ -8095,7 +8095,7 @@ "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "dev": true, "requires": { "loose-envify": "^1.0.0" @@ -8122,13 +8122,13 @@ "is": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha1-Yc/23TxBk9uUo9YlggcrROVkXXk=", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==", "dev": true }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { "is-relative": "^1.0.0", @@ -8179,13 +8179,13 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "integrity": "sha1-HhrfIZ4e62hNaR+dagX/DTCiTXU=", "dev": true }, "is-color-stop": { @@ -8231,7 +8231,7 @@ "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", @@ -8242,7 +8242,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", "dev": true } } @@ -8387,7 +8387,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { "isobject": "^3.0.1" @@ -8436,7 +8436,7 @@ "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { "is-unc-path": "^1.0.0" @@ -8445,7 +8445,7 @@ "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-retry-allowed": { @@ -8465,7 +8465,7 @@ "is-svg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", - "integrity": "sha1-kyHb0pwhLlypnE+peUxxS8r6L3U=", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", "dev": true, "requires": { "html-comment-regex": "^1.1.0" @@ -8488,7 +8488,7 @@ "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -8509,7 +8509,7 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "is-wsl": { @@ -8564,7 +8564,7 @@ "jasmine-core": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", - "integrity": "sha1-Eywj5kWvlthci8oTyHWLGEKfweQ=", + "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", "dev": true }, "jquery": { @@ -8585,19 +8585,19 @@ "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha1-xs7ljrNVA3LfjeuF+tXOZs4B1Z0=", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", "dev": true }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha1-r/FRswv9+o5J4F2iLnQV6d+jeEc=", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -8731,7 +8731,7 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, "json-buffer": { @@ -8744,7 +8744,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "json-schema": { @@ -8755,7 +8755,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -8771,7 +8771,7 @@ "json5": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha1-gbbLBOm6SW8ccAXQe0NoomOPkLY=", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -8837,7 +8837,7 @@ "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha1-xV7PAhheJGklk5kxDBc84xIzsUI=", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -8853,7 +8853,7 @@ "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { "fill-range": "^7.0.1" @@ -8878,7 +8878,7 @@ "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -8903,7 +8903,7 @@ "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "requires": { "binary-extensions": "^2.0.0" @@ -8921,7 +8921,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "mime": { @@ -8933,7 +8933,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, "readdirp": { @@ -8954,7 +8954,7 @@ "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { "is-number": "^7.0.0" @@ -8965,7 +8965,7 @@ "karma-jasmine": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", - "integrity": "sha1-JuPjHy+vJy3YDrsOGJiRTMOhl2M=", + "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", "dev": true, "requires": { "jasmine-core": "^3.3" @@ -8980,7 +8980,7 @@ "karma-junit-reporter": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/karma-junit-reporter/-/karma-junit-reporter-2.0.1.tgz", - "integrity": "sha1-007vfwsv0GTgiWlU6IUakM8UyPM=", + "integrity": "sha512-VtcGfE0JE4OE1wn0LK8xxDKaTP7slN8DO3I+4xg6gAi1IoAHAXOJ1V9G/y45Xg6sxdxPOR3THCFtDlAfBo9Afw==", "dev": true, "requires": { "path-is-absolute": "^1.0.0", @@ -9009,13 +9009,13 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha1-73x4TzbJ+24W3TFQ0VJneysCKKY=", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "dev": true, "requires": { "colornames": "^1.1.1" @@ -9104,7 +9104,7 @@ "less": { "version": "3.10.3", "resolved": "https://registry.npmjs.org/less/-/less-3.10.3.tgz", - "integrity": "sha1-QXoJddXu7MUs/0vPo8CdNXgeZ5I=", + "integrity": "sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow==", "dev": true, "requires": { "clone": "^2.1.2", @@ -9127,7 +9127,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -9317,7 +9317,7 @@ "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "lodash.partialright": { @@ -9430,7 +9430,7 @@ "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -9470,7 +9470,7 @@ "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { "pseudomap": "^1.0.2", @@ -9506,7 +9506,7 @@ "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { "kind-of": "^6.0.2" @@ -9537,7 +9537,7 @@ "marked": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", - "integrity": "sha1-tkIB8FHScbHtwQoE0a6bdLuOXA4=", + "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==", "dev": true }, "matchdep": { @@ -9569,13 +9569,13 @@ "math-random": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha1-XdaUPJOFSCZwFtTjTwV1gwgMUUw=", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", "dev": true }, "mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha1-aZs8OKxvHXKAkaZGULZdOIUC/Vs=", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", "dev": true }, "media-typer": { @@ -9587,7 +9587,7 @@ "memoizee": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha1-B6APIEaZ+alcLZ53IYJxx81hDVc=", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", "dev": true, "requires": { "d": "1", @@ -9631,7 +9631,7 @@ "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, "merge2": { @@ -9643,7 +9643,7 @@ "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -9664,7 +9664,7 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, "optional": true }, @@ -9697,7 +9697,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -9705,14 +9705,14 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "minimize": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/minimize/-/minimize-2.2.0.tgz", - "integrity": "sha1-ixZ28wBR2FmNdDZGvRJpCwdNpMM=", + "integrity": "sha512-IxR2XMbw9pXCxApkdD9BTcH2U4XlXhbeySUrv71rmMS9XDA8BVXEsIuFu24LtwCfBgfbL7Fuh8/ZzkO5DaTLlQ==", "dev": true, "requires": { "argh": "^0.1.4", @@ -9727,7 +9727,7 @@ "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha1-ESC0PcNZp4Xc5ltVuC4lfM9HlWY=", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -9737,7 +9737,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -9756,7 +9756,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true } @@ -9782,7 +9782,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "multipipe": { @@ -9797,7 +9797,7 @@ "mute-stdout": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha1-rLAwDrTeI6fd7sAU4+lgRLNHIzE=", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", "dev": true }, "mute-stream": { @@ -9816,7 +9816,7 @@ "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -9841,12 +9841,12 @@ "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", "dev": true }, "next-tick": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, @@ -9858,13 +9858,13 @@ "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "node-notifier": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha1-y3La+UyTkECY4oucWQ/YZuRkvVA=", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", "dev": true, "requires": { "growly": "^1.3.0", @@ -9886,7 +9886,7 @@ "node.extend": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz", - "integrity": "sha1-tEBFJUlKzJl0DzcDxJa31Rgsxsw=", + "integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==", "dev": true, "requires": { "has": "^1.0.3", @@ -9896,7 +9896,7 @@ "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha1-5m2xg4sgDB38IzIl0SyzZSDiNKg=", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -9923,7 +9923,7 @@ "normalize-url": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", "dev": true }, "nouislider": { @@ -9934,7 +9934,7 @@ "now-and-later": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha1-jlechoV2SnzALLaAOA6U9DzLH3w=", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", "dev": true, "requires": { "once": "^1.3.2" @@ -13067,7 +13067,7 @@ "nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha1-sr0pXDfj3VijvwcAN2Zjuk2c8Fw=", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "dev": true, "requires": { "boolbase": "~1.0.0" @@ -13094,7 +13094,7 @@ "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha1-R6ewFrqmi1+g7PPe4IqFxnmsZFU=" + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "3.0.0", @@ -13148,7 +13148,7 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha1-HEfyct8nfzsdrwYWd9nILiMixg4=", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object-visit": { @@ -13163,7 +13163,7 @@ "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha1-lovxEA15Vrs8oIbwBvhGs7xACNo=", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { "define-properties": "^1.1.2", @@ -13394,7 +13394,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -13474,7 +13474,7 @@ "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "requires": { "callsites": "^3.0.0" @@ -13483,7 +13483,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true } } @@ -13541,7 +13541,7 @@ "parse-node-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha1-4rXb7eAOf6m8NjYH9TMn6LBzGJs=", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true }, "parse-passwd": { @@ -13577,7 +13577,7 @@ "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, "pascalcase": { @@ -13616,7 +13616,7 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, "path-root": { @@ -13673,7 +13673,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -13695,7 +13695,7 @@ "plugin-error": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha1-dwFr2JGdCsN3/c3QMiMolTyleBw=", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", "dev": true, "requires": { "ansi-colors": "^1.0.1", @@ -13733,13 +13733,13 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha1-B2Srxpxj1ayELdSGfo0CXogN+PM=", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -13762,7 +13762,7 @@ "postcss-colormin": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha1-rgYLzpPteUrHEmTwgTLVUJVr04E=", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -13775,7 +13775,7 @@ "postcss-convert-values": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha1-yjgT7U2g+BL51DcDWE5Enr4Ymn8=", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", "dev": true, "requires": { "postcss": "^7.0.0", @@ -13785,7 +13785,7 @@ "postcss-discard-comments": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha1-H7q9LCRr/2qq15l7KwkY9NevQDM=", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13794,7 +13794,7 @@ "postcss-discard-duplicates": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha1-P+EzzTyCKC5VD8myORdqkge3hOs=", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13803,7 +13803,7 @@ "postcss-discard-empty": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha1-yMlR6fc+2UKAGUWERKAq2Qu592U=", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13812,7 +13812,7 @@ "postcss-discard-overridden": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha1-ZSrvipZybwKfXj4AFG7npOdV/1c=", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13821,7 +13821,7 @@ "postcss-load-config": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", - "integrity": "sha1-yE1pK3u3tB3c7ZTuYuirMbQXsAM=", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", "dev": true, "requires": { "cosmiconfig": "^5.0.0", @@ -13831,7 +13831,7 @@ "postcss-merge-longhand": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha1-YvSaE+Sg7gTnuY9CuxYGLKJUniQ=", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", "dev": true, "requires": { "css-color-names": "0.0.4", @@ -13843,7 +13843,7 @@ "postcss-merge-rules": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha1-NivqT/Wh+Y5AdacTxsslrv75plA=", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -13870,7 +13870,7 @@ "postcss-minify-font-values": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha1-zUw0TM5HQ0P6xdgiBqssvLiv1aY=", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", "dev": true, "requires": { "postcss": "^7.0.0", @@ -13880,7 +13880,7 @@ "postcss-minify-gradients": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha1-k7KcL/UJnFNe7NpWxKpuZlpmNHE=", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13892,7 +13892,7 @@ "postcss-minify-params": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha1-a5zvAwwR41Jh+V9hjJADbWgNuHQ=", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -13906,7 +13906,7 @@ "postcss-minify-selectors": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha1-4uXrQL/uUA0M2SQ1APX46kJi+9g=", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -13931,7 +13931,7 @@ "postcss-normalize-charset": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha1-izWt067oOhNrBHHg1ZvlilAoXdQ=", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", "dev": true, "requires": { "postcss": "^7.0.0" @@ -13940,7 +13940,7 @@ "postcss-normalize-display-values": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha1-Db4EpM6QY9RmftK+R2u4MMglk1o=", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -13951,7 +13951,7 @@ "postcss-normalize-positions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha1-BfdX+E8mBDc3g2ipH4ky1LECkX8=", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13963,7 +13963,7 @@ "postcss-normalize-repeat-style": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha1-xOu8KJ85kaAo1EdRy90RkYsXkQw=", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -13975,7 +13975,7 @@ "postcss-normalize-string": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha1-zUTECrB6DHo23F6Zqs4eyk7CaQw=", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", "dev": true, "requires": { "has": "^1.0.0", @@ -13986,7 +13986,7 @@ "postcss-normalize-timing-functions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha1-jgCcoqOUnNr4rSPmtquZy159KNk=", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -13997,7 +13997,7 @@ "postcss-normalize-unicode": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha1-hBvUj9zzAZrUuqdJOj02O1KuHPs=", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -14008,7 +14008,7 @@ "postcss-normalize-url": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha1-EOQ3+GvHx+WPe5ZS7YeNqqlfquE=", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", "dev": true, "requires": { "is-absolute-url": "^2.0.0", @@ -14020,7 +14020,7 @@ "postcss-normalize-whitespace": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha1-vx1AcP5Pzqh9E0joJdjMDF+qfYI=", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", "dev": true, "requires": { "postcss": "^7.0.0", @@ -14030,7 +14030,7 @@ "postcss-ordered-values": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha1-DPdcgg7H1cTSgBiVWeC1ceusDu4=", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", "dev": true, "requires": { "cssnano-util-get-arguments": "^4.0.0", @@ -14041,7 +14041,7 @@ "postcss-reduce-initial": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha1-f9QuvqXpyBRgljniwuhK4nC6SN8=", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -14053,7 +14053,7 @@ "postcss-reduce-transforms": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha1-F++kBerMbge+NBSlyi0QdGgdTik=", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", "dev": true, "requires": { "cssnano-util-get-match": "^4.0.0", @@ -14076,7 +14076,7 @@ "postcss-svgo": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz", - "integrity": "sha1-F7mXvHEbMzurFDqu07jT1uPTglg=", + "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==", "dev": true, "requires": { "is-svg": "^3.0.0", @@ -14088,7 +14088,7 @@ "postcss-unique-selectors": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha1-lEaRHzKJv9ZMbWgPBzwDsfnuS6w=", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", "dev": true, "requires": { "alphanum-sort": "^1.0.0", @@ -14129,32 +14129,32 @@ }, "pretty-hrtime": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", "dev": true }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "dev": true, "optional": true, "requires": { @@ -14189,7 +14189,7 @@ "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "requires": { "end-of-stream": "^1.1.0", @@ -14199,7 +14199,7 @@ "pumpify": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, "requires": { "duplexify": "^3.6.0", @@ -14210,7 +14210,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "q": { "version": "1.5.1", @@ -14221,13 +14221,13 @@ "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=" + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { "version": "5.1.1", @@ -14258,7 +14258,7 @@ "randomatic": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha1-t3bvxZN1mE42xTey9RofCv8Noe0=", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", "dev": true, "requires": { "is-number": "^4.0.0", @@ -14269,7 +14269,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", "dev": true } } @@ -14277,13 +14277,13 @@ "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true }, "raw-body": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", "dev": true, "requires": { "bytes": "3.1.0", @@ -14328,7 +14328,7 @@ "readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha1-DodiKjMlqjPokihcr4tOhGUppSU=", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -14366,7 +14366,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14397,7 +14397,7 @@ "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha1-SoVuxLVuQHfFV1icroXnpMiGmhE=", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", "dev": true }, "regenerate-unicode-properties": { @@ -14421,7 +14421,7 @@ "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { "is-equal-shallow": "^0.1.3" @@ -14430,7 +14430,7 @@ "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, "requires": { "extend-shallow": "^3.0.2", @@ -14440,7 +14440,7 @@ "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha1-jRnTHPYySCtYkEn4KB+T28uk0H8=", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, "regexpu-core": { @@ -14460,7 +14460,7 @@ "regjsgen": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha1-SPC/Gl6iBRlpKcDZeYtC0e2YRDw=", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", "dev": true }, "regjsparser": { @@ -14483,7 +14483,7 @@ "remove-bom-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha1-wr8eN3Ug0yT2I4kuM8EMrCwlK1M=", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", "dev": true, "requires": { "is-buffer": "^1.1.5", @@ -14510,7 +14510,7 @@ "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha1-eC4NglwMWjuzlzH4Tv7mt0Lmsc4=", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -14683,7 +14683,7 @@ "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, "reusify": { @@ -14695,7 +14695,7 @@ "rfdc": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", - "integrity": "sha1-unLME2egzNnPgahws7WL060H+MI=", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", "dev": true }, "rgb-regex": { @@ -14722,7 +14722,7 @@ "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha1-stEE/g2Psnz54KHNqCYt04M8bKs=", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { "glob": "^7.1.3" @@ -14746,7 +14746,7 @@ "run-sequence": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-2.2.1.tgz", - "integrity": "sha1-HOZD2jb9jH6n4akynaM/wriJhJU=", + "integrity": "sha512-qkzZnQWMZjcKbh3CNly2srtrkaO/2H/SI5f2eliMCapdRD3UhMrwjfOAZJAnZ2H8Ju4aBzFZkBGXUqFs9V0yxw==", "dev": true, "requires": { "chalk": "^1.1.3", @@ -14784,7 +14784,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -14806,7 +14806,7 @@ }, "kind-of": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", "dev": true }, @@ -14843,7 +14843,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -14857,12 +14857,12 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, "saxes": { @@ -14892,7 +14892,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "semver-greatest-satisfied-range": { @@ -14930,7 +14930,7 @@ "set-value": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha1-oY1AUw5vB95CKMfe/kInr4ytAFs=", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -14953,7 +14953,7 @@ "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", "dev": true }, "shebang-command": { @@ -14974,7 +14974,7 @@ "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha1-1rkYHBpI05cyTISHHvvPxz/AZUs=", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, "signal-exit": { @@ -14995,7 +14995,7 @@ "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha1-RXSirlb3qyBolvtDHq7tBm/fjwM=", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "dev": true } } @@ -15009,7 +15009,7 @@ "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha1-ys12k0YaY3pXiNkqfdT7oGjoFjY=", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { "ansi-styles": "^3.2.0", @@ -15028,7 +15028,7 @@ "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "dev": true, "requires": { "base": "^0.11.1", @@ -15044,7 +15044,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -15079,7 +15079,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "dev": true, "requires": { "define-property": "^1.0.0", @@ -15099,7 +15099,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -15108,7 +15108,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -15117,7 +15117,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -15130,7 +15130,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -15335,13 +15335,13 @@ "sparkles": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha1-AI22XtzmxQ7sDF4ijhlFBh3QQ3w=", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", "dev": true }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha1-+4PlBERSaPFUsHTiGMh8ADzTHfQ=", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -15351,7 +15351,7 @@ "spdx-exceptions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha1-LqRQrudPKom/uUUZwH/Nb0EyKXc=", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, "spdx-expression-parse": { @@ -15367,7 +15367,7 @@ "spdx-license-ids": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha1-NpS1gEVnpFjTyARYQqY1hjL2JlQ=", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "spectrum-colorpicker2": { @@ -15378,7 +15378,7 @@ "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "dev": true, "requires": { "extend-shallow": "^3.0.0" @@ -15411,7 +15411,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "optional": true, @@ -15435,7 +15435,7 @@ "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha1-+2YcC+8ps520B2nuOfpwCT1vaHc=", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -15451,7 +15451,7 @@ "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", "dev": true }, "stack-trace": { @@ -15496,7 +15496,7 @@ "stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha1-rNrI2lnvK8HheiwMz2wyDRIOVV0=", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", "dev": true }, "stream-shift": { @@ -15680,7 +15680,7 @@ "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha1-Zxj8r00eB9ihMYaQiB6NlnJqcdU=", + "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", "dev": true, "requires": { "browserslist": "^4.0.0", @@ -15704,7 +15704,7 @@ "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -15750,7 +15750,7 @@ "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha1-EpLRlQDOP4YFOwXw6Ofko7shB54=", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -15762,7 +15762,7 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "is-fullwidth-code-point": { @@ -15774,7 +15774,7 @@ "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { "emoji-regex": "^7.0.1", @@ -15785,7 +15785,7 @@ "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" @@ -15884,7 +15884,7 @@ "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha1-adycGxdEbueakr9biEu0uRJ1BvU=", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "dev": true }, "text-table": { @@ -15902,7 +15902,7 @@ "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha1-AcHjnrMdB8t9A6lqcIIyYLIxMs0=", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, "requires": { "readable-stream": "~2.3.6", @@ -15953,7 +15953,7 @@ "through2-filter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha1-cA54bfI2fCyIzYqlvkz5weeDElQ=", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", "dev": true, "requires": { "through2": "~2.0.0", @@ -15976,7 +15976,7 @@ "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha1-b1ethXjgej+5+R2Th9ZWR1VeJcY=", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", "dev": true, "requires": { "es5-ext": "~0.10.46", @@ -15992,7 +15992,7 @@ "tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha1-HRpW7fxRxD6GPLtTgqcjMONVVCM=" + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" }, "tinymce": { "version": "4.9.11", @@ -16002,7 +16002,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -16060,7 +16060,7 @@ "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, "requires": { "define-property": "^2.0.2", @@ -16091,7 +16091,7 @@ "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "dev": true }, "tough-cookie": { @@ -16165,7 +16165,7 @@ "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha1-hI3XaY2vo+VKbEeedZxLw/GIR6A=", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", "dev": true }, "type-check": { @@ -16180,7 +16180,7 @@ "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, "requires": { "media-typer": "0.3.0", @@ -16287,7 +16287,7 @@ "undertaker": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", - "integrity": "sha1-cBZi/4zjWHFTJN/UkqTwNgVd/ks=", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", "dev": true, "requires": { "arr-flatten": "^1.0.1", @@ -16310,13 +16310,13 @@ "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha1-JhmADEyCWADv3YNDr33Zkzy+KBg=", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", "dev": true }, "unicode-match-property-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha1-jtKjJWmWG86SJ9Cc0/+7j+1fAgw=", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", "dev": true, "requires": { "unicode-canonical-property-names-ecmascript": "^1.0.4", @@ -16338,7 +16338,7 @@ "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha1-C2/nuDWuzaYcbqTU8CwUIh4QmEc=", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -16362,7 +16362,7 @@ "unique-stream": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha1-xl0RDppK35psWUiygFPZqNBMvqw=", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", "dev": true, "requires": { "json-stable-stringify-without-jsonify": "^1.0.1", @@ -16372,7 +16372,7 @@ "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, "unpipe": { @@ -16436,13 +16436,13 @@ "upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha1-j2bbzVWog6za5ECK+LA1pQRMGJQ=", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { "punycode": "^2.1.0" } @@ -16482,7 +16482,7 @@ "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, "useragent": { @@ -16504,7 +16504,7 @@ "util.promisify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", "dev": true, "requires": { "define-properties": "^1.1.2", @@ -16540,7 +16540,7 @@ "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha1-/JH2uce6FchX9MssXe/uw51PQQo=", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -16619,7 +16619,7 @@ "vinyl-fs": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha1-yFhJQF9nQo/qu71cXb3WT0fTG8c=", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", "dev": true, "requires": { "fs-mkdirp-stream": "^1.0.0", @@ -16828,7 +16828,7 @@ "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -16859,7 +16859,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -16876,7 +16876,7 @@ "write": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha1-CADhRSO5I6OH5BUSPIZWFqrg9cM=", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" @@ -16902,7 +16902,7 @@ "xmlbuilder": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-12.0.0.tgz", - "integrity": "sha1-4u1nXgaDSgid37hNuW4sKwP3jBo=", + "integrity": "sha512-lMo8DJ8u6JRWp0/Y4XLa/atVDr75H9litKlb2E5j3V3MesoL50EBgZDWoLT3F/LztVnG67GjPXLZpqcky/UMnQ==", "dev": true }, "xmlchars": { @@ -16920,7 +16920,7 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true }, "y18n": { From dd8b1d27effdda729bc82c9459aad181d5b3dd6d Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 15 Sep 2021 13:59:01 +0200 Subject: [PATCH 14/73] Do not handle date time as invariant --- src/Umbraco.Core/Extensions/ObjectExtensions.cs | 2 +- .../Umbraco.Core/CoreThings/TryConvertToTests.cs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Core/Extensions/ObjectExtensions.cs b/src/Umbraco.Core/Extensions/ObjectExtensions.cs index 4c0b01d9d5..15ecf9340c 100644 --- a/src/Umbraco.Core/Extensions/ObjectExtensions.cs +++ b/src/Umbraco.Core/Extensions/ObjectExtensions.cs @@ -369,7 +369,7 @@ namespace Umbraco.Extensions } else if (target == typeof(DateTime)) { - if (DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.None, out var value)) + if (DateTime.TryParse(input, out var value)) { switch (value.Kind) { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs index 5d1c0364b1..6373155603 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Umbraco. +// Copyright (c) Umbraco. // See LICENSE for more details. using System; @@ -64,10 +64,6 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.CoreThings Assert.IsTrue(conv); Assert.AreEqual(-1, conv.Result); - conv = "−1".TryConvertTo(); - Assert.IsTrue(conv); - Assert.AreEqual(-1, conv.Result); - conv = "100".TryConvertTo(); Assert.IsTrue(conv); Assert.AreEqual(100, conv.Result); From 27043bec591e481c712e4ed7bac1906122f7d33b Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 15 Sep 2021 15:30:21 +0200 Subject: [PATCH 15/73] Remove custom SQL CE checks from IsConnectionStringConfigured --- .../ConfigConnectionStringExtensions.cs | 37 ++----------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Core/Extensions/ConfigConnectionStringExtensions.cs b/src/Umbraco.Core/Extensions/ConfigConnectionStringExtensions.cs index c1b788c0b9..329c9e8202 100644 --- a/src/Umbraco.Core/Extensions/ConfigConnectionStringExtensions.cs +++ b/src/Umbraco.Core/Extensions/ConfigConnectionStringExtensions.cs @@ -1,10 +1,6 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System; -using System.IO; -using System.Linq; -using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; namespace Umbraco.Extensions @@ -12,35 +8,8 @@ namespace Umbraco.Extensions public static class ConfigConnectionStringExtensions { public static bool IsConnectionStringConfigured(this ConfigConnectionString databaseSettings) - { - var dbIsSqlCe = false; - if (databaseSettings?.ProviderName != null) - { - dbIsSqlCe = databaseSettings.ProviderName == Constants.DbProviderNames.SqlCe; - } - - var sqlCeDatabaseExists = false; - if (dbIsSqlCe) - { - var parts = databaseSettings.ConnectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - var dataSourcePart = parts.FirstOrDefault(x => x.InvariantStartsWith("Data Source=")); - if (dataSourcePart != null) - { - var datasource = dataSourcePart.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString()); - var filePath = datasource.Replace("Data Source=", string.Empty); - sqlCeDatabaseExists = File.Exists(filePath); - } - } - - // Either the connection details are not fully specified or it's a SQL CE database that doesn't exist yet - if (databaseSettings == null - || string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) || string.IsNullOrWhiteSpace(databaseSettings.ProviderName) - || (dbIsSqlCe && sqlCeDatabaseExists == false)) - { - return false; - } - - return true; - } + => databaseSettings != null && + !string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) && + !string.IsNullOrWhiteSpace(databaseSettings.ProviderName); } } From aa15b0d244612fc44bf7e81cb1c146a8b4a5cebd Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 15 Sep 2021 15:41:20 +0200 Subject: [PATCH 16/73] Simplify parsing provider name from connection string --- .../Configuration/ConfigConnectionString.cs | 72 +++++++------------ .../Migrations/Install/DatabaseBuilder.cs | 2 +- .../Persistence/DbConnectionExtensions.cs | 39 ++++------ 3 files changed, 39 insertions(+), 74 deletions(-) diff --git a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs index e88d1f4d01..d0dec2548c 100644 --- a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs +++ b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs @@ -5,69 +5,45 @@ namespace Umbraco.Cms.Core.Configuration { public class ConfigConnectionString { + public string Name { get; } + + public string ConnectionString { get; } + + public string ProviderName { get; } + public ConfigConnectionString(string name, string connectionString, string providerName = null) { Name = name ?? throw new ArgumentNullException(nameof(name)); ConnectionString = connectionString; - - ProviderName = string.IsNullOrEmpty(providerName) ? ParseProvider(connectionString) : providerName; + ProviderName = string.IsNullOrEmpty(providerName) ? ParseProviderName(connectionString) : providerName; } - public string ConnectionString { get; } - public string ProviderName { get; } - public string Name { get; } - - private static bool IsSqlCe(DbConnectionStringBuilder builder) => (builder.TryGetValue("Data Source", out var ds) - || builder.TryGetValue("DataSource", out ds)) && - ds is string dataSource && - dataSource.EndsWith(".sdf"); - - private static bool IsSqlServer(DbConnectionStringBuilder builder) => - !string.IsNullOrEmpty(GetServer(builder)) && - ((builder.TryGetValue("Database", out var db) && db is string database && - !string.IsNullOrEmpty(database)) || - (builder.TryGetValue("AttachDbFileName", out var a) && a is string attachDbFileName && - !string.IsNullOrEmpty(attachDbFileName)) || - (builder.TryGetValue("Initial Catalog", out var i) && i is string initialCatalog && - !string.IsNullOrEmpty(initialCatalog))); - - private static string GetServer(DbConnectionStringBuilder builder) - { - if(builder.TryGetValue("Server", out var s) && s is string server) - { - return server; - } - - if ((builder.TryGetValue("Data Source", out var ds) - || builder.TryGetValue("DataSource", out ds)) && ds is string dataSource) - { - return dataSource; - } - - return ""; - } - - private static string ParseProvider(string connectionString) + /// + /// Parses the connection string to get the provider name. + /// + /// The connection string. + /// + /// The provider name or null is the connection string is empty. + /// + public static string ParseProviderName(string connectionString) { if (string.IsNullOrEmpty(connectionString)) { return null; } - var builder = new DbConnectionStringBuilder {ConnectionString = connectionString}; - if (IsSqlCe(builder)) + var builder = new DbConnectionStringBuilder { - return Constants.DbProviderNames.SqlCe; + ConnectionString = connectionString + }; + + if ((builder.TryGetValue("Data Source", out var dataSource) || builder.TryGetValue("DataSource", out dataSource)) && + dataSource?.ToString().EndsWith(".sdf", StringComparison.OrdinalIgnoreCase) == true) + { + return Cms.Core.Constants.DbProviderNames.SqlCe; } - - if (IsSqlServer(builder)) - { - return Constants.DbProviderNames.SqlServer; - } - - throw new ArgumentException("Cannot determine provider name from connection string", - nameof(connectionString)); + return Cms.Core.Constants.DbProviderNames.SqlServer; } } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index b7437f4c2d..e4b8353e02 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -92,7 +92,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install if (string.IsNullOrWhiteSpace(connectionString) == false) { - providerName = DbConnectionExtensions.DetectProviderNameFromConnectionString(connectionString); + providerName = ConfigConnectionString.ParseProviderName(connectionString); } else if (integratedAuth) { diff --git a/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs b/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs index c4876aef7c..fb5d00abfd 100644 --- a/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/DbConnectionExtensions.cs @@ -1,35 +1,17 @@ -using System; +using System; using System.Data; using System.Data.Common; -using System.Linq; using Microsoft.Extensions.Logging; using StackExchange.Profiling.Data; using Umbraco.Cms.Core; using Umbraco.Cms.Infrastructure.Persistence.FaultHandling; -using Umbraco.Extensions; namespace Umbraco.Extensions { public static class DbConnectionExtensions { - public static string DetectProviderNameFromConnectionString(string connectionString) + public static bool IsConnectionAvailable(string connectionString, DbProviderFactory factory) { - var builder = new DbConnectionStringBuilder { ConnectionString = connectionString }; - var allKeys = builder.Keys.Cast(); - - if (allKeys.InvariantContains("Data Source") - //this dictionary is case insensitive - && builder["Data source"].ToString().InvariantContains(".sdf")) - { - return Cms.Core.Constants.DbProviderNames.SqlCe; - } - - return Cms.Core.Constants.DbProviderNames.SqlServer; - } - - public static bool IsConnectionAvailable(string connectionString, DbProviderFactory factory) - { - var connection = factory?.CreateConnection(); if (connection == null) @@ -42,7 +24,6 @@ namespace Umbraco.Extensions } } - public static bool IsAvailable(this IDbConnection connection) { try @@ -68,17 +49,25 @@ namespace Umbraco.Extensions internal static IDbConnection UnwrapUmbraco(this IDbConnection connection) { var unwrapped = connection; + IDbConnection c; do { c = unwrapped; - if (unwrapped is ProfiledDbConnection profiled) unwrapped = profiled.WrappedConnection; - if (unwrapped is RetryDbConnection retrying) unwrapped = retrying.Inner; - } while (c != unwrapped); + if (unwrapped is ProfiledDbConnection profiled) + { + unwrapped = profiled.WrappedConnection; + } + + if (unwrapped is RetryDbConnection retrying) + { + unwrapped = retrying.Inner; + } + } + while (c != unwrapped); return unwrapped; } - } } From e056918e4f95a92d8aae323124f0ea486bc36216 Mon Sep 17 00:00:00 2001 From: BatJan <1932158+BatJan@users.noreply.github.com> Date: Wed, 15 Sep 2021 18:44:04 +0200 Subject: [PATCH 17/73] Ensure the expression is interpolated so the aria-selected attribute has a proper true/false value --- .../src/views/components/tabs/umb-tabs-nav.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/tabs/umb-tabs-nav.html b/src/Umbraco.Web.UI.Client/src/views/components/tabs/umb-tabs-nav.html index b55555339b..df649a9e4a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/tabs/umb-tabs-nav.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/tabs/umb-tabs-nav.html @@ -1,6 +1,6 @@
    • - @@ -23,7 +23,7 @@ ng-class="{'dropdown-menu--active': tab.active}" ng-click="vm.clickTab($event, tab)" role="tab" - aria-selected="{tab.active}" > + aria-selected="{{tab.active}}" > {{ tab.label }}
      !
      From 138ef428849dca952833fe278995e3974477ee66 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 16 Sep 2021 12:39:56 +0100 Subject: [PATCH 18/73] Adds new dotnet new template arg --use-https-redirect (#11115) --- .../.template.config/dotnetcli.host.json | 4 ++++ .../.template.config/ide.host.json | 7 +++++++ .../.template.config/template.json | 6 ++++++ .../templates/UmbracoProject/appsettings.json | 9 ++++++++- src/Umbraco.Web.UI/Startup.cs | 19 ++++++++++++------- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/build/templates/UmbracoProject/.template.config/dotnetcli.host.json b/build/templates/UmbracoProject/.template.config/dotnetcli.host.json index d0548110fd..d357188ed7 100644 --- a/build/templates/UmbracoProject/.template.config/dotnetcli.host.json +++ b/build/templates/UmbracoProject/.template.config/dotnetcli.host.json @@ -32,6 +32,10 @@ "NoNodesViewPath":{ "longName": "no-nodes-view-path", "shortName": "" + }, + "UseHttpsRedirect": { + "longName": "use-https-redirect", + "shortName": "" } }, "usageExamples": [ diff --git a/build/templates/UmbracoProject/.template.config/ide.host.json b/build/templates/UmbracoProject/.template.config/ide.host.json index 8b8d2608cd..1ee7a492aa 100644 --- a/build/templates/UmbracoProject/.template.config/ide.host.json +++ b/build/templates/UmbracoProject/.template.config/ide.host.json @@ -62,6 +62,13 @@ "text": "Optional: Path to a custom view presented with the Umbraco installation contains no published content" }, "isVisible": "true" + }, + { + "id": "UseHttpsRedirect", + "name": { + "text": "Optional: Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting." + }, + "isVisible": "true" } ] } diff --git a/build/templates/UmbracoProject/.template.config/template.json b/build/templates/UmbracoProject/.template.config/template.json index 3d4f197164..3cf7485ab2 100644 --- a/build/templates/UmbracoProject/.template.config/template.json +++ b/build/templates/UmbracoProject/.template.config/template.json @@ -293,6 +293,12 @@ "UsingUnattenedInstall":{ "type": "computed", "value": "(FriendlyName != \"\" && Email != \"\" && Password != \"\" && ConnectionString != \"\")" + }, + "UseHttpsRedirect":{ + "type": "parameter", + "datatype":"bool", + "defaultValue": "false", + "description": "Adds code to Startup.cs to redirect HTTP to HTTPS and enables the UseHttps setting (Default: false)" } } } diff --git a/build/templates/UmbracoProject/appsettings.json b/build/templates/UmbracoProject/appsettings.json index 915671ce4b..feb6b07d95 100644 --- a/build/templates/UmbracoProject/appsettings.json +++ b/build/templates/UmbracoProject/appsettings.json @@ -15,9 +15,16 @@ }, "Umbraco": { "CMS": { - //#if (HasNoNodesViewPath) + //#if (HasNoNodesViewPath || UseHttpsRedirect) "Global": { + //#if (!HasNoNodesViewPath && UseHttpsRedirect) + "UseHttps": true + //#elseif (UseHttpsRedirect) + "UseHttps": true, + //#endif + //#if (HasNoNodesViewPath) "NoNodesViewPath": "NO_NODES_VIEW_PATH_FROM_TEMPLATE" + //#endif }, //#endif "Hosting": { diff --git a/src/Umbraco.Web.UI/Startup.cs b/src/Umbraco.Web.UI/Startup.cs index 0d263c7b6b..71c3dd008c 100644 --- a/src/Umbraco.Web.UI/Startup.cs +++ b/src/Umbraco.Web.UI/Startup.cs @@ -15,10 +15,10 @@ namespace Umbraco.Cms.Web.UI private readonly IConfiguration _config; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The Web Host Environment - /// The Configuration + /// The web hosting environment. + /// The configuration. /// /// Only a few services are possible to be injected here https://github.com/dotnet/aspnetcore/issues/9337 /// @@ -28,11 +28,10 @@ namespace Umbraco.Cms.Web.UI _config = config ?? throw new ArgumentNullException(nameof(config)); } - - /// - /// Configures the services + /// Configures the services. /// + /// The services. /// /// This method gets called by the runtime. Use this method to add services to the container. /// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 @@ -50,8 +49,10 @@ namespace Umbraco.Cms.Web.UI } /// - /// Configures the application + /// Configures the application. /// + /// The application builder. + /// The web hosting environment. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) @@ -59,6 +60,10 @@ namespace Umbraco.Cms.Web.UI app.UseDeveloperExceptionPage(); } +#if (UseHttpsRedirect) + app.UseHttpsRedirection(); + +#endif app.UseUmbraco() .WithMiddleware(u => { From 42987b21287c8591f3d16057d72e320617e8110a Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 16 Sep 2021 14:07:00 +0200 Subject: [PATCH 19/73] clean up --- .../Filters/CheckIfUserTicketDataIsStaleAttribute.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs index 8527355597..178d9d50f0 100644 --- a/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs +++ b/src/Umbraco.Web.BackOffice/Filters/CheckIfUserTicketDataIsStaleAttribute.cs @@ -168,9 +168,6 @@ namespace Umbraco.Cms.Web.BackOffice.Filters BackOfficeIdentityUser backOfficeIdentityUser = _umbracoMapper.Map(user); await _backOfficeSignInManager.SignInAsync(backOfficeIdentityUser, isPersistent: true); - // ensure the remainder of the request has the correct principal set - //actionContext.HttpContext.SetPrincipalForRequest(ClaimsPrincipal.Current); - // flag that we've made changes _requestCache.Set(nameof(CheckIfUserTicketDataIsStaleFilter), true); } From 1baa4cf653839baa60021dd8824a95eb8e1e5d6b Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 16 Sep 2021 14:07:31 +0200 Subject: [PATCH 20/73] Add property group key to save model --- .../src/common/services/umbdataformatter.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index eeb5a59aef..226fabeae4 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -75,7 +75,7 @@ }); saveModel.groups = _.map(realGroups, function (g) { - var saveGroup = _.pick(g, 'inherited', 'id', 'sortOrder', 'name', 'alias', 'type'); + var saveGroup = _.pick(g, 'inherited', 'id', 'sortOrder', 'name', 'key', 'alias', 'type'); var realProperties = _.reject(g.properties, function (p) { //do not include these properties From 4a1820b80d0ff5b86feadb6da9c3b9c7ffb5bd96 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 16 Sep 2021 14:07:31 +0200 Subject: [PATCH 21/73] Add property group key to save model --- .../src/common/services/umbdataformatter.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index e72900cacd..f6b24dd12b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -75,7 +75,7 @@ }); saveModel.groups = _.map(realGroups, function (g) { - var saveGroup = _.pick(g, 'inherited', 'id', 'sortOrder', 'name', 'alias', 'type'); + var saveGroup = _.pick(g, 'inherited', 'id', 'sortOrder', 'name', 'key', 'alias', 'type'); var realProperties = _.reject(g.properties, function (p) { //do not include these properties From c799d9e45c38b4bc1203d1f0a047290d035816e7 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 16 Sep 2021 21:59:52 +0200 Subject: [PATCH 22/73] https://github.com/umbraco/Umbraco-CMS/issues/11123 initializing the IVariationContextAccessor if the UmbracoRequestMiddleware --- .../Middleware/UmbracoRequestMiddleware.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index fe0029bd80..539c1c844f 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -13,10 +13,11 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.PublishedCache; @@ -50,6 +51,8 @@ namespace Umbraco.Cms.Web.Common.Middleware private readonly UmbracoRequestPaths _umbracoRequestPaths; private readonly BackOfficeWebAssets _backOfficeWebAssets; private readonly IRuntimeState _runtimeState; + private readonly IVariationContextAccessor _variationContextAccessor; + private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly SmidgeOptions _smidgeOptions; private readonly WebProfiler _profiler; @@ -77,7 +80,9 @@ namespace Umbraco.Cms.Web.Common.Middleware UmbracoRequestPaths umbracoRequestPaths, BackOfficeWebAssets backOfficeWebAssets, IOptions smidgeOptions, - IRuntimeState runtimeState) + IRuntimeState runtimeState, + IVariationContextAccessor variationContextAccessor, + IDefaultCultureAccessor defaultCultureAccessor) { _logger = logger; _umbracoContextFactory = umbracoContextFactory; @@ -88,6 +93,8 @@ namespace Umbraco.Cms.Web.Common.Middleware _umbracoRequestPaths = umbracoRequestPaths; _backOfficeWebAssets = backOfficeWebAssets; _runtimeState = runtimeState; + _variationContextAccessor = variationContextAccessor; + _defaultCultureAccessor = defaultCultureAccessor; _smidgeOptions = smidgeOptions.Value; _profiler = profiler as WebProfiler; // Ignore if not a WebProfiler } @@ -110,6 +117,7 @@ namespace Umbraco.Cms.Web.Common.Middleware EnsureContentCacheInitialized(); + _variationContextAccessor.VariationContext ??= new VariationContext(_defaultCultureAccessor.DefaultCulture); UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); Uri currentApplicationUrl = GetApplicationUrlFromCurrentRequest(context.Request); From e2ab9a2285880713c768b851f45d518819de9ed8 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 17 Sep 2021 08:29:34 +0200 Subject: [PATCH 23/73] Clean up --- src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs | 1 - .../Controllers/AuthenticationController.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs b/src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs index 585d9c73f1..1ee5699868 100644 --- a/src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs +++ b/src/Umbraco.Core/Security/ClaimsPrincipalExtensions.cs @@ -2,7 +2,6 @@ // See LICENSE for more details. using System; -using System.Diagnostics; using System.Globalization; using System.Linq; using System.Security.Claims; diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index bc0929487a..e79b49ace3 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -272,7 +272,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers var result = _umbracoMapper.Map(user); //set their remaining seconds - result.SecondsUntilTimeout = 100+ HttpContext.User.GetRemainingAuthSeconds(); + result.SecondsUntilTimeout = HttpContext.User.GetRemainingAuthSeconds(); return result; } From e6413aad0a3ad2cf5d242251afbf652711808055 Mon Sep 17 00:00:00 2001 From: An0d Date: Fri, 17 Sep 2021 11:22:09 +0200 Subject: [PATCH 24/73] Fix: AllowAnonymous attribute on Action is ignored when UmbracoMemberAuthorize is set on Controller Ref: https://github.com/umbraco/Umbraco-CMS/issues/11125 --- .../Filters/UmbracoMemberAuthorizeFilter.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs index b0a640b230..249dd6a1d2 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs @@ -1,6 +1,10 @@ using System.Collections.Generic; using System.Threading.Tasks; + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Security; @@ -42,6 +46,12 @@ namespace Umbraco.Cms.Web.Common.Filters public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { + // Allow Anonymous skips all authorization + if (HasAllowAnonymous(context)) + { + return; + } + IMemberManager memberManager = context.HttpContext.RequestServices.GetRequiredService(); if (!await IsAuthorizedAsync(memberManager)) @@ -51,6 +61,32 @@ namespace Umbraco.Cms.Web.Common.Filters } } + /// + /// Copied from https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/Authorization/AuthorizeFilter.cs + /// + private bool HasAllowAnonymous(AuthorizationFilterContext context) + { + var filters = context.Filters; + for (var i = 0; i < filters.Count; i++) + { + if (filters[i] is IAllowAnonymousFilter) + { + return true; + } + } + + // When doing endpoint routing, MVC does not add AllowAnonymousFilters for AllowAnonymousAttributes that + // were discovered on controllers and actions. To maintain compat with 2.x, + // we'll check for the presence of IAllowAnonymous in endpoint metadata. + var endpoint = context.HttpContext.GetEndpoint(); + if (endpoint?.Metadata?.GetMetadata() != null) + { + return true; + } + + return false; + } + private async Task IsAuthorizedAsync(IMemberManager memberManager) { if (AllowMembers.IsNullOrWhiteSpace()) From 57610c96b937046405baea99950874442547e6b2 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 11:57:20 +0200 Subject: [PATCH 25/73] Detect as brand new install if we can't connect and InstallMissingDatabase is enabled --- .../Install/InstallHelper.cs | 68 ++++++------------- 1 file changed, 19 insertions(+), 49 deletions(-) diff --git a/src/Umbraco.Infrastructure/Install/InstallHelper.cs b/src/Umbraco.Infrastructure/Install/InstallHelper.cs index 944ebbb586..6b5e882134 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -10,7 +7,6 @@ using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Core.Net; -using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Migrations.Install; @@ -30,6 +26,7 @@ namespace Umbraco.Cms.Infrastructure.Install private readonly ICookieManager _cookieManager; private readonly IUserAgentProvider _userAgentProvider; private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory; + private readonly IOptionsMonitor _globalSettings; private InstallationType? _installationType; public InstallHelper(DatabaseBuilder databaseBuilder, @@ -39,7 +36,8 @@ namespace Umbraco.Cms.Infrastructure.Install IInstallationService installationService, ICookieManager cookieManager, IUserAgentProvider userAgentProvider, - IUmbracoDatabaseFactory umbracoDatabaseFactory) + IUmbracoDatabaseFactory umbracoDatabaseFactory, + IOptionsMonitor globalSettings) { _logger = logger; _umbracoVersion = umbracoVersion; @@ -49,15 +47,13 @@ namespace Umbraco.Cms.Infrastructure.Install _cookieManager = cookieManager; _userAgentProvider = userAgentProvider; _umbracoDatabaseFactory = umbracoDatabaseFactory; + _globalSettings = globalSettings; - //We need to initialize the type already, as we can't detect later, if the connection string is added on the fly. + // We need to initialize the type already, as we can't detect later, if the connection string is added on the fly. GetInstallationType(); } - public InstallationType GetInstallationType() - { - return _installationType ?? (_installationType = IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade).Value; - } + public InstallationType GetInstallationType() => _installationType ??= IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade; public async Task SetInstallStatusAsync(bool isCompleted, string errorMsg) { @@ -65,25 +61,14 @@ namespace Umbraco.Cms.Infrastructure.Install { var userAgent = _userAgentProvider.GetUserAgent(); - // Check for current install Id - var installId = Guid.NewGuid(); - + // Check for current install ID var installCookie = _cookieManager.GetCookieValue(Constants.Web.InstallerCookieName); - if (string.IsNullOrEmpty(installCookie) == false) + if (!Guid.TryParse(installCookie, out var installId)) { - if (Guid.TryParse(installCookie, out installId)) - { - // check that it's a valid Guid - if (installId == Guid.Empty) - installId = Guid.NewGuid(); - } - else - { - installId = Guid.NewGuid(); // Guid.TryParse will have reset installId to Guid.Empty - } - } + installId = Guid.NewGuid(); - _cookieManager.SetCookieValue(Constants.Web.InstallerCookieName, installId.ToString()); + _cookieManager.SetCookieValue(Constants.Web.InstallerCookieName, installId.ToString()); + } var dbProvider = string.Empty; if (IsBrandNewInstall == false) @@ -108,29 +93,14 @@ namespace Umbraco.Cms.Infrastructure.Install } /// - /// Checks if this is a brand new install meaning that there is no configured version and there is no configured database connection + /// Checks if this is a brand new install, meaning that there is no configured database connection or the database is empty. /// - private bool IsBrandNewInstall - { - get - { - var databaseSettings = _connectionStrings.CurrentValue.UmbracoConnectionString; - if (databaseSettings.IsConnectionStringConfigured() == false) - { - //no version or conn string configured, must be a brand new install - return true; - } - - //now we have to check if this is really a new install, the db might be configured and might contain data - - if (databaseSettings.IsConnectionStringConfigured() == false - || _databaseBuilder.IsDatabaseConfigured == false) - { - return true; - } - - return _databaseBuilder.IsUmbracoInstalled() == false; - } - } + /// + /// true if this is a brand new install; otherwise, false. + /// + private bool IsBrandNewInstall => _connectionStrings.CurrentValue.UmbracoConnectionString?.IsConnectionStringConfigured() != true || + _databaseBuilder.IsDatabaseConfigured == false || + (_globalSettings.CurrentValue.InstallMissingDatabase && _databaseBuilder.CanConnectToDatabase == false) || + _databaseBuilder.IsUmbracoInstalled() == false; } } From b82fc3350fcf4b0bd2d730d310d2638927e38db9 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 11:57:49 +0200 Subject: [PATCH 26/73] Set default UmbracoConnectionString value --- src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs b/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs index bfcb41d992..c0421be7e3 100644 --- a/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs +++ b/src/Umbraco.Core/Configuration/Models/ConnectionStrings.cs @@ -26,6 +26,6 @@ namespace Umbraco.Cms.Core.Configuration.Models /// /// Gets or sets a value for the Umbraco database connection string.. /// - public ConfigConnectionString UmbracoConnectionString { get; set; } + public ConfigConnectionString UmbracoConnectionString { get; set; } = new ConfigConnectionString(Constants.System.UmbracoConnectionName, null); } } From 785630922e6c58e5b7409a098548487b40109a19 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 12:02:41 +0200 Subject: [PATCH 27/73] Rename IEmbeddedDatabaseCreator to IDatabaseCreator and refactor implementations --- .../Persistence/DbProviderFactoryCreator.cs | 13 ++-- .../Persistence/IDatabaseCreator.cs | 9 +++ .../Persistence/IDbProviderFactoryCreator.cs | 2 +- .../Persistence/IEmbeddedDatabaseCreator.cs | 9 --- .../NoopEmbeddedDatabaseCreator.cs | 14 ----- .../Persistence/SqlServerDatabaseCreator.cs | 63 +++++++++++++++++++ .../SqlServerDbProviderFactoryCreator.cs | 26 +++----- .../SqlCeDatabaseCreator.cs | 16 +++++ .../SqlCeEmbeddedDatabaseCreator.cs | 18 ------ .../Persistence/DatabaseBuilderTests.cs | 8 +-- .../UmbracoBuilderExtensions.cs | 10 +-- 11 files changed, 114 insertions(+), 74 deletions(-) create mode 100644 src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs delete mode 100644 src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs delete mode 100644 src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs create mode 100644 src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs create mode 100644 src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs delete mode 100644 src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs diff --git a/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs index 942368f5cb..e54c1f5fbc 100644 --- a/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Data.Common; using System.Linq; using NPoco; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; namespace Umbraco.Cms.Infrastructure.Persistence @@ -11,7 +10,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence public class DbProviderFactoryCreator : IDbProviderFactoryCreator { private readonly Func _getFactory; - private readonly IDictionary _embeddedDatabaseCreators; + private readonly IDictionary _databaseCreators; private readonly IDictionary _syntaxProviders; private readonly IDictionary _bulkSqlInsertProviders; private readonly IDictionary _providerSpecificMapperFactories; @@ -20,11 +19,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence Func getFactory, IEnumerable syntaxProviders, IEnumerable bulkSqlInsertProviders, - IEnumerable embeddedDatabaseCreators, + IEnumerable databaseCreators, IEnumerable providerSpecificMapperFactories) { _getFactory = getFactory; - _embeddedDatabaseCreators = embeddedDatabaseCreators.ToDictionary(x => x.ProviderName); + _databaseCreators = databaseCreators.ToDictionary(x => x.ProviderName); _syntaxProviders = syntaxProviders.ToDictionary(x => x.ProviderName); _bulkSqlInsertProviders = bulkSqlInsertProviders.ToDictionary(x => x.ProviderName); _providerSpecificMapperFactories = providerSpecificMapperFactories.ToDictionary(x => x.ProviderName); @@ -60,11 +59,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence return result; } - public void CreateDatabase(string providerName) + public void CreateDatabase(string providerName, string connectionString) { - if (_embeddedDatabaseCreators.TryGetValue(providerName, out var creator)) + if (_databaseCreators.TryGetValue(providerName, out var creator)) { - creator.Create(); + creator.Create(connectionString); } } diff --git a/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs new file mode 100644 index 0000000000..2d97cfbcd3 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Cms.Infrastructure.Persistence +{ + public interface IDatabaseCreator + { + string ProviderName { get; } + + void Create(string connectionString); + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs index 99b7469085..6a38dc3c06 100644 --- a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence DbProviderFactory CreateFactory(string providerName); ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName); IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName); - void CreateDatabase(string providerName); + void CreateDatabase(string providerName, string connectionString); NPocoMapperCollection ProviderSpecificMappers(string providerName); } } diff --git a/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs deleted file mode 100644 index 2461644d0a..0000000000 --- a/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Umbraco.Cms.Infrastructure.Persistence -{ - public interface IEmbeddedDatabaseCreator - { - string ProviderName { get; } - string ConnectionString { get; set; } - void Create(); - } -} diff --git a/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs deleted file mode 100644 index fd378d44bc..0000000000 --- a/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Umbraco.Cms.Infrastructure.Persistence -{ - public class NoopEmbeddedDatabaseCreator : IEmbeddedDatabaseCreator - { - public string ProviderName => Cms.Core.Constants.DatabaseProviders.SqlServer; - - public string ConnectionString { get; set; } - - public void Create() - { - - } - } -} diff --git a/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs new file mode 100644 index 0000000000..e7f5934e78 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs @@ -0,0 +1,63 @@ +using System; +using System.Data.SqlClient; +using System.IO; +using Umbraco.Cms.Core; + +namespace Umbraco.Cms.Infrastructure.Persistence +{ + public class SqlServerDatabaseCreator : IDatabaseCreator + { + public string ProviderName => Constants.DatabaseProviders.SqlServer; + + public void Create(string connectionString) + { + var builder = new SqlConnectionStringBuilder(connectionString); + + // Get connection string without database specific information + var masterBuilder = new SqlConnectionStringBuilder(builder.ConnectionString) + { + AttachDBFilename = string.Empty, + InitialCatalog = string.Empty + }; + var masterConnectionString = masterBuilder.ConnectionString; + + string fileName = builder.AttachDBFilename, + database = builder.InitialCatalog; + + // Create database + if (!string.IsNullOrEmpty(fileName) && !File.Exists(fileName)) + { + if (string.IsNullOrWhiteSpace(database)) + { + // Use a temporary database name + database = "Umbraco-" + Guid.NewGuid(); + } + + using var connection = new SqlConnection(masterConnectionString); + connection.Open(); + + using var command = new SqlCommand( + $"CREATE DATABASE [{database}] ON (NAME='{database}', FILENAME='{fileName}');" + + $"ALTER DATABASE [{database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;" + + $"EXEC sp_detach_db @dbname='{database}';", + connection); + command.ExecuteNonQuery(); + + connection.Close(); + } + else if (!string.IsNullOrEmpty(database)) + { + using var connection = new SqlConnection(masterConnectionString); + connection.Open(); + + using var command = new SqlCommand( + $"IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = '{database}') " + + $"CREATE DATABASE [{database}];", + connection); + command.ExecuteNonQuery(); + + connection.Close(); + } + } + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs index 756490c531..c16e5a75ab 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs @@ -3,12 +3,12 @@ using System.Data.Common; using System.Linq; using Microsoft.Extensions.Options; using NPoco; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; namespace Umbraco.Cms.Infrastructure.Persistence { + [Obsolete("This is only used for integration tests and should be moved into a test project.")] public class SqlServerDbProviderFactoryCreator : IDbProviderFactoryCreator { private readonly Func _getFactory; @@ -23,35 +23,29 @@ namespace Umbraco.Cms.Infrastructure.Persistence public DbProviderFactory CreateFactory(string providerName) { if (string.IsNullOrEmpty(providerName)) return null; + return _getFactory(providerName); } // gets the sql syntax provider that corresponds, from attribute public ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName) - { - return providerName switch + => providerName switch { Cms.Core.Constants.DbProviderNames.SqlCe => throw new NotSupportedException("SqlCe is not supported"), Cms.Core.Constants.DbProviderNames.SqlServer => new SqlServerSyntaxProvider(_globalSettings), _ => throw new InvalidOperationException($"Unknown provider name \"{providerName}\""), }; - } public IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName) - { - switch (providerName) + => providerName switch { - case Cms.Core.Constants.DbProviderNames.SqlCe: - throw new NotSupportedException("SqlCe is not supported"); - case Cms.Core.Constants.DbProviderNames.SqlServer: - return new SqlServerBulkSqlInsertProvider(); - default: - return new BasicBulkSqlInsertProvider(); - } - } + Cms.Core.Constants.DbProviderNames.SqlCe => throw new NotSupportedException("SqlCe is not supported"), + Cms.Core.Constants.DbProviderNames.SqlServer => new SqlServerBulkSqlInsertProvider(), + _ => new BasicBulkSqlInsertProvider(), + }; - public void CreateDatabase(string providerName) - => throw new NotSupportedException("Embedded databases are not supported"); + public void CreateDatabase(string providerName, string connectionString) + => throw new NotSupportedException("Embedded databases are not supported"); // TODO But LocalDB is? public NPocoMapperCollection ProviderSpecificMappers(string providerName) => new NPocoMapperCollection(() => Enumerable.Empty()); diff --git a/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs b/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs new file mode 100644 index 0000000000..fd360be13a --- /dev/null +++ b/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs @@ -0,0 +1,16 @@ +using Umbraco.Cms.Infrastructure.Persistence; +using Constants = Umbraco.Cms.Core.Constants; + +namespace Umbraco.Cms.Persistence.SqlCe +{ + public class SqlCeDatabaseCreator : IDatabaseCreator + { + public string ProviderName => Constants.DatabaseProviders.SqlCe; + + public void Create(string connectionString) + { + using var engine = new System.Data.SqlServerCe.SqlCeEngine(connectionString); + engine.CreateDatabase(); + } + } +} diff --git a/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs b/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs deleted file mode 100644 index ee2d888109..0000000000 --- a/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Persistence; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Cms.Persistence.SqlCe -{ - public class SqlCeEmbeddedDatabaseCreator : IEmbeddedDatabaseCreator - { - public string ProviderName => Constants.DatabaseProviders.SqlCe; - - public string ConnectionString { get; set; } = DatabaseBuilder.EmbeddedDatabaseConnectionString; - public void Create() - { - var engine = new System.Data.SqlServerCe.SqlCeEngine(ConnectionString); - engine.CreateDatabase(); - } - } -} diff --git a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs index e8269fafa9..500d71dddc 100644 --- a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs +++ b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence { private IDbProviderFactoryCreator DbProviderFactoryCreator => GetRequiredService(); private IUmbracoDatabaseFactory UmbracoDatabaseFactory => GetRequiredService(); - private IEmbeddedDatabaseCreator EmbeddedDatabaseCreator => GetRequiredService(); + private IDatabaseCreator EmbeddedDatabaseCreator => GetRequiredService(); public DatabaseBuilderTests() { @@ -42,10 +42,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence if (File.Exists(filePath)) File.Delete(filePath); - EmbeddedDatabaseCreator.ConnectionString = $"Datasource=|DataDirectory|{dbFile};Flush Interval=1"; + var connectionString = $"Datasource=|DataDirectory|{dbFile};Flush Interval=1"; - UmbracoDatabaseFactory.Configure(EmbeddedDatabaseCreator.ConnectionString, Constants.DbProviderNames.SqlCe); - DbProviderFactoryCreator.CreateDatabase(Constants.DbProviderNames.SqlCe); + UmbracoDatabaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlCe); + DbProviderFactoryCreator.CreateDatabase(Constants.DbProviderNames.SqlCe, connectionString); UmbracoDatabaseFactory.CreateDatabase(); // test get database type (requires an actual database) diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 5073eefe2f..4319bc3544 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -150,7 +150,7 @@ namespace Umbraco.Extensions DbProviderFactories.GetFactory, factory.GetServices(), factory.GetServices(), - factory.GetServices(), + factory.GetServices(), factory.GetServices() )); @@ -357,17 +357,17 @@ namespace Umbraco.Extensions Type sqlCeSyntaxProviderType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSyntaxProvider"); Type sqlCeBulkSqlInsertProviderType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeBulkSqlInsertProvider"); - Type sqlCeEmbeddedDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeEmbeddedDatabaseCreator"); + Type sqlCeDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeDatabaseCreator"); Type sqlCeSpecificMapperFactory = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSpecificMapperFactory"); if (!(sqlCeSyntaxProviderType is null || sqlCeBulkSqlInsertProviderType is null - || sqlCeEmbeddedDatabaseCreatorType is null + || sqlCeDatabaseCreatorType is null || sqlCeSpecificMapperFactory is null)) { builder.Services.AddSingleton(typeof(ISqlSyntaxProvider), sqlCeSyntaxProviderType); builder.Services.AddSingleton(typeof(IBulkSqlInsertProvider), sqlCeBulkSqlInsertProviderType); - builder.Services.AddSingleton(typeof(IEmbeddedDatabaseCreator), sqlCeEmbeddedDatabaseCreatorType); + builder.Services.AddSingleton(typeof(IDatabaseCreator), sqlCeDatabaseCreatorType); builder.Services.AddSingleton(typeof(IProviderSpecificMapperFactory), sqlCeSpecificMapperFactory); } @@ -397,7 +397,7 @@ namespace Umbraco.Extensions builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); return builder; } From 81cbbd861455e25e2a52237c59a2f64d52edb204 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 12:50:25 +0200 Subject: [PATCH 28/73] Add LocalDB database option to installer --- .../Install/Models/DatabaseModel.cs | 4 +- .../Install/Models/DatabaseType.cs | 3 +- .../InstallSteps/DatabaseConfigureStep.cs | 33 +++++++---- .../InstallSteps/DatabaseInstallStep.cs | 14 ++++- .../Migrations/Install/DatabaseBuilder.cs | 56 ++++++++++-------- .../Persistence/UmbracoDatabaseFactory.cs | 20 ++----- .../src/installer/steps/database.html | 58 +++++++++++-------- 7 files changed, 107 insertions(+), 81 deletions(-) diff --git a/src/Umbraco.Core/Install/Models/DatabaseModel.cs b/src/Umbraco.Core/Install/Models/DatabaseModel.cs index c7f4ce0aab..514500f445 100644 --- a/src/Umbraco.Core/Install/Models/DatabaseModel.cs +++ b/src/Umbraco.Core/Install/Models/DatabaseModel.cs @@ -1,4 +1,4 @@ -using System.Runtime.Serialization; +using System.Runtime.Serialization; namespace Umbraco.Cms.Core.Install.Models { @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Core.Install.Models public DatabaseModel() { //defaults - DatabaseType = DatabaseType.SqlCe; + DatabaseType = DatabaseType.SqlLocalDb; } [DataMember(Name = "dbType")] diff --git a/src/Umbraco.Core/Install/Models/DatabaseType.cs b/src/Umbraco.Core/Install/Models/DatabaseType.cs index 5eef471562..bc0616620f 100644 --- a/src/Umbraco.Core/Install/Models/DatabaseType.cs +++ b/src/Umbraco.Core/Install/Models/DatabaseType.cs @@ -1,7 +1,8 @@ -namespace Umbraco.Cms.Core.Install.Models +namespace Umbraco.Cms.Core.Install.Models { public enum DatabaseType { + SqlLocalDb, SqlCe, SqlServer, SqlAzure, diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs index 7b02ea786e..a14b0f3a1c 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs @@ -7,6 +7,7 @@ using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Install; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Infrastructure.Migrations.Install; +using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Install.InstallSteps @@ -39,7 +40,9 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { throw new InstallException("Could not connect to the database"); } + ConfigureConnection(database); + return Task.FromResult(null); } @@ -49,6 +52,10 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { _databaseBuilder.ConfigureDatabaseConnection(database.ConnectionString); } + else if (database.DatabaseType == DatabaseType.SqlLocalDb) + { + _databaseBuilder.ConfigureSqlLocalDbDatabaseConnection(); + } else if (database.DatabaseType == DatabaseType.SqlCe) { _databaseBuilder.ConfigureEmbeddedDatabaseConnection(); @@ -62,9 +69,7 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps var password = database.Password.Replace("'", "''"); password = string.Format("'{0}'", password); - _databaseBuilder.ConfigureDatabaseConnection( - database.Server, database.DatabaseName, database.Login, password, - database.DatabaseType.ToString()); + _databaseBuilder.ConfigureDatabaseConnection(database.Server, database.DatabaseName, database.Login, password, database.DatabaseType.ToString()); } } @@ -84,28 +89,31 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps databases.Insert(0, new { name = "Microsoft SQL Server Compact (SQL CE)", id = DatabaseType.SqlCe.ToString() }); } + if (IsLocalDbAvailable()) + { + // Ensure this is always inserted as first when available + databases.Insert(0, new { name = "Microsoft SQL Server Express (LocalDB)", id = DatabaseType.SqlLocalDb.ToString() }); + } + return new { - databases = databases + databases }; } } - public static bool IsSqlCeAvailable() - { + public static bool IsLocalDbAvailable() => new LocalDb().IsAvailable; + + public static bool IsSqlCeAvailable() => // NOTE: Type.GetType will only return types that are currently loaded into the appdomain. In this case // that is ok because we know if this is availalbe we will have manually loaded it into the appdomain. // Else we'd have to use Assembly.LoadFrom and need to know the DLL location here which we don't need to do. - return !(Type.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSyntaxProvider, Umbraco.Persistence.SqlCe") is null); - } + !(Type.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSyntaxProvider, Umbraco.Persistence.SqlCe") is null); public override string View => ShouldDisplayView() ? base.View : ""; - public override bool RequiresExecution(DatabaseModel model) - { - return ShouldDisplayView(); - } + public override bool RequiresExecution(DatabaseModel model) => ShouldDisplayView(); private bool ShouldDisplayView() { @@ -118,6 +126,7 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { //Since a connection string was present we verify the db can connect and query _ = _databaseBuilder.ValidateSchema(); + return false; } catch (Exception ex) diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs index 61d78173fa..1c58d04810 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs @@ -1,11 +1,14 @@ -using System; +using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Install; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Migrations.Install; +using Umbraco.Cms.Infrastructure.Persistence; namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { @@ -15,11 +18,13 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { private readonly DatabaseBuilder _databaseBuilder; private readonly IRuntimeState _runtime; + private readonly IOptionsMonitor _globalSettings; - public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime) + public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime, IOptionsMonitor globalSettings) { _databaseBuilder = databaseBuilder; _runtime = runtime; + _globalSettings = globalSettings; } public override Task ExecuteAsync(object model) @@ -27,6 +32,11 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); + if (_globalSettings.CurrentValue.InstallMissingDatabase) + { + _databaseBuilder.CreateDatabase(); + } + var result = _databaseBuilder.CreateSchemaAndData(); if (result.Success == false) diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index e4b8353e02..8b9b2b07cd 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -1,6 +1,4 @@ using System; -using System.IO; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; @@ -85,7 +83,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install public bool CanConnect(string databaseType, string connectionString, string server, string database, string login, string password, bool integratedAuth) { // we do not test SqlCE connection - if (databaseType.InvariantContains("sqlce")) + if (databaseType.InvariantContains("sqlce") || databaseType.InvariantContains("localdb")) return true; string providerName; @@ -153,23 +151,32 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// public void ConfigureEmbeddedDatabaseConnection() { - ConfigureEmbeddedDatabaseConnection(_databaseFactory); + const string connectionString = EmbeddedDatabaseConnectionString; + const string providerName = Constants.DbProviderNames.SqlCe; + + _configManipulator.SaveConnectionString(connectionString, providerName); + _databaseFactory.Configure(connectionString, providerName); + + // Always create embedded database + CreateDatabase(); } - private void ConfigureEmbeddedDatabaseConnection(IUmbracoDatabaseFactory factory) + public const string LocalDbConnectionString = @"Server=(localdb)\MSSQLLocalDB;Integrated Security=true;AttachDbFileName=|DataDirectory|\Umbraco.mdf"; + + public void ConfigureSqlLocalDbDatabaseConnection() { - _configManipulator.SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe); + string connectionString = LocalDbConnectionString; + const string providerName = Constants.DbProviderNames.SqlServer; - var path = _hostingEnvironment.MapPathContentRoot(Path.Combine(Constants.SystemDirectories.Data, "Umbraco.sdf")); - if (File.Exists(path) == false) - { - // this should probably be in a "using (new SqlCeEngine)" clause but not sure - // of the side effects and it's been like this for quite some time now + // Replace data directory placeholder (this is not supported by LocalDB) + var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString(); + connectionString = connectionString.Replace("|DataDirectory|", dataDirectory); - _dbProviderFactoryCreator.CreateDatabase(Constants.DbProviderNames.SqlCe); - } + _configManipulator.SaveConnectionString(connectionString, providerName); + _databaseFactory.Configure(connectionString, providerName); - factory.Configure(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe); + // Always create LocalDB database + CreateDatabase(); } /// @@ -214,9 +221,10 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install public static string GetDatabaseConnectionString(string server, string databaseName, string user, string password, string databaseProvider, out string providerName) { providerName = Constants.DbProviderNames.SqlServer; - var provider = databaseProvider.ToLower(); - if (provider.InvariantContains("azure")) + + if (databaseProvider.InvariantContains("Azure")) return GetAzureConnectionString(server, databaseName, user, password); + return $"server={server};database={databaseName};user id={user};password={password}"; } @@ -228,8 +236,10 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName) { var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName); - _configManipulator.SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer); - _databaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlServer); + const string providerName = Constants.DbProviderNames.SqlServer; + + _configManipulator.SaveConnectionString(connectionString, providerName); + _databaseFactory.Configure(connectionString, providerName); } /// @@ -292,18 +302,14 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install return $"Server={server};Database={databaseName};User ID={user};Password={password}"; } - private static bool ServerStartsWithTcp(string server) - { - return server.ToLower().StartsWith("tcp:".ToLower()); - } - - - + private static bool ServerStartsWithTcp(string server) => server.InvariantStartsWith("tcp:"); #endregion #region Database Schema + public void CreateDatabase() => _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName, _databaseFactory.ConnectionString); + /// /// Validates the database schema. /// diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs index 6dfe2ada6b..299aff2caa 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs @@ -96,7 +96,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence _loggerFactory = loggerFactory; var settings = connectionStrings.CurrentValue.UmbracoConnectionString; - if (settings == null) { logger.LogDebug("Missing connection string, defer configuration."); @@ -105,9 +104,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence // could as well be // so need to test the values too - var connectionString = settings.ConnectionString; - var providerName = settings.ProviderName; - if (string.IsNullOrWhiteSpace(connectionString) || string.IsNullOrWhiteSpace(providerName)) + if (settings.IsConnectionStringConfigured() == false) { logger.LogDebug("Empty connection string or provider name, defer configuration."); return; // not configured @@ -148,7 +145,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence private void UpdateSqlServerDatabaseType() { // replace NPoco database type by a more efficient one - var setting = _globalSettings.Value.DatabaseFactoryServerVersion; var fromSettings = false; @@ -188,6 +184,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { // must be initialized to have a context EnsureInitialized(); + return _sqlContext; } } @@ -199,15 +196,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence { // must be initialized to have a bulk insert provider EnsureInitialized(); + return _bulkSqlInsertProvider; } } /// - public void ConfigureForUpgrade() - { - _upgrading = true; - } + public void ConfigureForUpgrade() => _upgrading = true; /// public void Configure(string connectionString, string providerName) @@ -248,13 +243,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\"."); } - // cannot initialize without being able to talk to the database - // TODO: Why not? - if (!DbConnectionExtensions.IsConnectionAvailable(ConnectionString, DbProviderFactory)) - { - throw new Exception("Cannot connect to the database."); - } - _connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(ConnectionString); _commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(ConnectionString); diff --git a/src/Umbraco.Web.UI.Client/src/installer/steps/database.html b/src/Umbraco.Web.UI.Client/src/installer/steps/database.html index eee933b561..cf367b2ff2 100644 --- a/src/Umbraco.Web.UI.Client/src/installer/steps/database.html +++ b/src/Umbraco.Web.UI.Client/src/installer/steps/database.html @@ -10,38 +10,48 @@ What type of database do you use?
      -
      -
      +

      Great! No need to configure anything, you can simply click the continue button below to continue to the next step

      -
      +
      +

      Great! No need to configure anything, you can simply click the continue button below to continue to the next step

      +
      + +
      What is the exact connection string we should use?
      - +
      - + Enter a valid database connection string.
      -
      +
      Where do we find your database?
      - +
      - + Enter server domain or IP
      @@ -49,11 +59,12 @@
      - +
      - + required + ng-model="installer.current.model.databaseName" /> Enter the name of the database
      @@ -64,11 +75,12 @@ What credentials are used to access the database?
      - +
      - + required + ng-model="installer.current.model.login" /> Enter the database user name
      @@ -76,21 +88,21 @@
      - +
      - + required + ng-model="installer.current.model.password" /> Enter the database password
      -
      +
      From 074bbb045bd30bb06c972f9e727f457e89358428 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 12:52:05 +0200 Subject: [PATCH 29/73] Install missing database during unattended install --- .../Install/UnattendedInstaller.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs b/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs index babf882e1b..24e55c90f5 100644 --- a/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs +++ b/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs @@ -20,6 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Install private readonly DatabaseSchemaCreatorFactory _databaseSchemaCreatorFactory; private readonly IEventAggregator _eventAggregator; private readonly IUmbracoDatabaseFactory _databaseFactory; + private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; private readonly IOptions _globalSettings; private readonly ILogger _logger; private readonly IRuntimeState _runtimeState; @@ -29,6 +30,7 @@ namespace Umbraco.Cms.Infrastructure.Install IEventAggregator eventAggregator, IOptions unattendedSettings, IUmbracoDatabaseFactory databaseFactory, + IDbProviderFactoryCreator dbProviderFactoryCreator, IOptions globalSettings, ILogger logger, IRuntimeState runtimeState) @@ -37,6 +39,7 @@ namespace Umbraco.Cms.Infrastructure.Install _eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator)); _unattendedSettings = unattendedSettings; _databaseFactory = databaseFactory; + _dbProviderFactoryCreator = dbProviderFactoryCreator; _globalSettings = globalSettings; _logger = logger; _runtimeState = runtimeState; @@ -70,6 +73,14 @@ namespace Umbraco.Cms.Infrastructure.Install } _logger.LogDebug("Could not immediately connect to database, trying again."); + + if (_globalSettings.Value.InstallMissingDatabase) + { + _logger.LogDebug("Install missing database is enabled, creating database before trying again."); + + _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName, _databaseFactory.ConnectionString); + } + Thread.Sleep(1000); } } From 51002ba7a4d4fd615931136f99b63886cef8cf86 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 12:52:23 +0200 Subject: [PATCH 30/73] Minor code cleanup --- .../Persistence/UmbracoDatabase.cs | 49 ++++++++++--------- .../Runtime/CoreRuntime.cs | 2 - 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs index 529144953d..80970ec637 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs @@ -7,7 +7,6 @@ using System.Text; using Microsoft.Extensions.Logging; using NPoco; using StackExchange.Profiling; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Persistence.FaultHandling; using Umbraco.Extensions; @@ -62,6 +61,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence _connectionRetryPolicy = connectionRetryPolicy; _commandRetryPolicy = commandRetryPolicy; _mapperCollection = mapperCollection; + Init(); } @@ -79,6 +79,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence SqlContext = sqlContext; _logger = logger; _bulkSqlInsertProvider = bulkSqlInsertProvider; + Init(); } @@ -86,6 +87,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { EnableSqlTrace = EnableSqlTraceDefault; NPocoDatabaseExtensions.ConfigureNPocoBulkExtensions(); + if (_mapperCollection != null) { Mappers.AddRange(_mapperCollection); @@ -104,11 +106,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence { var command = base.CreateCommand(connection, commandType, sql, args); - if (!DatabaseType.IsSqlCe()) return command; + if (!DatabaseType.IsSqlCe()) + return command; foreach (DbParameter parameter in command.Parameters) + { if (parameter.Value == DBNull.Value) parameter.DbType = DbType.String; + } return command; } @@ -128,17 +133,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence #endif /// - public string InstanceId - { - get - { + public string InstanceId => #if DEBUG_DATABASES - return _instanceGuid.ToString("N").Substring(0, 8) + ':' + _spid; + _instanceGuid.ToString("N").Substring(0, 8) + ':' + _spid; #else - return _instanceId ?? (_instanceId = _instanceGuid.ToString("N").Substring(0, 8)); + _instanceId ??= _instanceGuid.ToString("N").Substring(0, 8); #endif - } - } /// public bool InTransaction { get; private set; } @@ -175,8 +175,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence set { _enableCount = value; + if (_enableCount == false) + { SqlCount = 0; + } } } @@ -193,11 +196,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence internal IEnumerable Commands => _commands; - public int BulkInsertRecords(IEnumerable records) - { - return _bulkSqlInsertProvider.BulkInsertRecords(this, records); - - } + public int BulkInsertRecords(IEnumerable records) => _bulkSqlInsertProvider.BulkInsertRecords(this, records); /// /// Returns the for the database @@ -206,6 +205,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence { var dbSchema = _databaseSchemaCreatorFactory.Create(this); var databaseSchemaValidationResult = dbSchema.ValidateSchema(); + return databaseSchemaValidationResult; } @@ -263,8 +263,10 @@ namespace Umbraco.Cms.Infrastructure.Persistence { _logger.LogError(ex, "Exception ({InstanceId}).", InstanceId); _logger.LogDebug("At:\r\n{StackTrace}", Environment.StackTrace); + if (EnableSqlTrace == false) _logger.LogDebug("Sql:\r\n{Sql}", CommandToString(LastSQL, LastArgs)); + base.OnException(ex); } @@ -287,22 +289,22 @@ namespace Umbraco.Cms.Infrastructure.Persistence #endif _cmd = cmd; + base.OnExecutingCommand(cmd); } - private string CommandToString(DbCommand cmd) - { - return CommandToString(cmd.CommandText, cmd.Parameters.Cast().Select(x => x.Value).ToArray()); - } + private string CommandToString(DbCommand cmd) => CommandToString(cmd.CommandText, cmd.Parameters.Cast().Select(x => x.Value).ToArray()); private string CommandToString(string sql, object[] args) { var text = new StringBuilder(); #if DEBUG_DATABASES - text.Append(InstanceId); - text.Append(": "); + text.Append(InstanceId); + text.Append(": "); #endif + NPocoSqlExtensions.ToText(sql, args, text); + return text.ToString(); } @@ -325,11 +327,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence { Text = cmd.CommandText; var parameters = new List(); - foreach (IDbDataParameter parameter in cmd.Parameters) parameters.Add(new ParameterInfo(parameter)); + foreach (IDbDataParameter parameter in cmd.Parameters) + parameters.Add(new ParameterInfo(parameter)); + Parameters = parameters.ToArray(); } public string Text { get; } + public ParameterInfo[] Parameters { get; } } diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index 597a8901da..f9a8578dc3 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -12,8 +12,6 @@ using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Migrations.Upgrade; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Extensions; From d702b2f616dddbd064673bae293825fa77434c2f Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 13:10:21 +0200 Subject: [PATCH 31/73] Fix non-Windows database configuration install step --- src/Umbraco.Core/Install/Models/DatabaseModel.cs | 8 +------- .../Install/InstallSteps/DatabaseConfigureStep.cs | 11 +++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/Install/Models/DatabaseModel.cs b/src/Umbraco.Core/Install/Models/DatabaseModel.cs index 514500f445..b87941e590 100644 --- a/src/Umbraco.Core/Install/Models/DatabaseModel.cs +++ b/src/Umbraco.Core/Install/Models/DatabaseModel.cs @@ -5,14 +5,8 @@ namespace Umbraco.Cms.Core.Install.Models [DataContract(Name = "database", Namespace = "")] public class DatabaseModel { - public DatabaseModel() - { - //defaults - DatabaseType = DatabaseType.SqlLocalDb; - } - [DataMember(Name = "dbType")] - public DatabaseType DatabaseType { get; set; } + public DatabaseType DatabaseType { get; set; } = DatabaseType.SqlServer; [DataMember(Name = "server")] public string Server { get; set; } diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs index a14b0f3a1c..a25151bda2 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseConfigureStep.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -34,6 +35,15 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps if (database == null) { database = new DatabaseModel(); + + if (IsLocalDbAvailable()) + { + database.DatabaseType = DatabaseType.SqlLocalDb; + } + else if (IsSqlCeAvailable()) + { + database.DatabaseType = DatabaseType.SqlCe; + } } if (_databaseBuilder.CanConnect(database.DatabaseType.ToString(), database.ConnectionString, database.Server, database.DatabaseName, database.Login, database.Password, database.IntegratedAuth) == false) @@ -108,6 +118,7 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps // NOTE: Type.GetType will only return types that are currently loaded into the appdomain. In this case // that is ok because we know if this is availalbe we will have manually loaded it into the appdomain. // Else we'd have to use Assembly.LoadFrom and need to know the DLL location here which we don't need to do. + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !(Type.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSyntaxProvider, Umbraco.Persistence.SqlCe") is null); public override string View => ShouldDisplayView() ? base.View : ""; From ab28251558cf7307579dad64a919b95d7bd39a87 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 16:30:46 +0200 Subject: [PATCH 32/73] Use RuntimeState to determine whether to install missing database --- .../Install/InstallHelper.cs | 8 ++--- .../InstallSteps/DatabaseInstallStep.cs | 11 ++----- .../Install/UnattendedInstaller.cs | 19 +++++------- .../Migrations/Install/DatabaseBuilder.cs | 16 +++------- .../Runtime/RuntimeState.cs | 30 ++++++++++--------- 5 files changed, 34 insertions(+), 50 deletions(-) diff --git a/src/Umbraco.Infrastructure/Install/InstallHelper.cs b/src/Umbraco.Infrastructure/Install/InstallHelper.cs index 6b5e882134..056d1c1b8c 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -26,7 +26,7 @@ namespace Umbraco.Cms.Infrastructure.Install private readonly ICookieManager _cookieManager; private readonly IUserAgentProvider _userAgentProvider; private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory; - private readonly IOptionsMonitor _globalSettings; + private readonly IRuntimeState _runtimeState; private InstallationType? _installationType; public InstallHelper(DatabaseBuilder databaseBuilder, @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Infrastructure.Install ICookieManager cookieManager, IUserAgentProvider userAgentProvider, IUmbracoDatabaseFactory umbracoDatabaseFactory, - IOptionsMonitor globalSettings) + IRuntimeState runtimeState) { _logger = logger; _umbracoVersion = umbracoVersion; @@ -47,7 +47,7 @@ namespace Umbraco.Cms.Infrastructure.Install _cookieManager = cookieManager; _userAgentProvider = userAgentProvider; _umbracoDatabaseFactory = umbracoDatabaseFactory; - _globalSettings = globalSettings; + _runtimeState = runtimeState; // We need to initialize the type already, as we can't detect later, if the connection string is added on the fly. GetInstallationType(); @@ -100,7 +100,7 @@ namespace Umbraco.Cms.Infrastructure.Install /// private bool IsBrandNewInstall => _connectionStrings.CurrentValue.UmbracoConnectionString?.IsConnectionStringConfigured() != true || _databaseBuilder.IsDatabaseConfigured == false || - (_globalSettings.CurrentValue.InstallMissingDatabase && _databaseBuilder.CanConnectToDatabase == false) || + (_runtimeState.Level == RuntimeLevel.Install && _runtimeState.Reason == RuntimeLevelReason.InstallMissingDatabase) || _databaseBuilder.IsUmbracoInstalled() == false; } } diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs index 1c58d04810..0976e14112 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs @@ -18,13 +18,11 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { private readonly DatabaseBuilder _databaseBuilder; private readonly IRuntimeState _runtime; - private readonly IOptionsMonitor _globalSettings; - public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime, IOptionsMonitor globalSettings) + public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime) { _databaseBuilder = databaseBuilder; _runtime = runtime; - _globalSettings = globalSettings; } public override Task ExecuteAsync(object model) @@ -32,7 +30,7 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); - if (_globalSettings.CurrentValue.InstallMissingDatabase) + if (_runtime.Reason == RuntimeLevelReason.InstallMissingDatabase) { _databaseBuilder.CreateDatabase(); } @@ -56,9 +54,6 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps })); } - public override bool RequiresExecution(object model) - { - return true; - } + public override bool RequiresExecution(object model) => true; } } diff --git a/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs b/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs index 24e55c90f5..94a6646086 100644 --- a/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs +++ b/src/Umbraco.Infrastructure/Install/UnattendedInstaller.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Exceptions; @@ -21,7 +22,6 @@ namespace Umbraco.Cms.Infrastructure.Install private readonly IEventAggregator _eventAggregator; private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; - private readonly IOptions _globalSettings; private readonly ILogger _logger; private readonly IRuntimeState _runtimeState; @@ -31,7 +31,6 @@ namespace Umbraco.Cms.Infrastructure.Install IOptions unattendedSettings, IUmbracoDatabaseFactory databaseFactory, IDbProviderFactoryCreator dbProviderFactoryCreator, - IOptions globalSettings, ILogger logger, IRuntimeState runtimeState) { @@ -40,7 +39,6 @@ namespace Umbraco.Cms.Infrastructure.Install _unattendedSettings = unattendedSettings; _databaseFactory = databaseFactory; _dbProviderFactoryCreator = dbProviderFactoryCreator; - _globalSettings = globalSettings; _logger = logger; _runtimeState = runtimeState; } @@ -59,7 +57,11 @@ namespace Umbraco.Cms.Infrastructure.Install return Task.CompletedTask; } - var tries = _globalSettings.Value.InstallMissingDatabase ? 2 : 5; + _runtimeState.DetermineRuntimeLevel(); + if (_runtimeState.Reason == RuntimeLevelReason.InstallMissingDatabase) + { + _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName, _databaseFactory.ConnectionString); + } bool connect; try @@ -67,20 +69,13 @@ namespace Umbraco.Cms.Infrastructure.Install for (var i = 0; ;) { connect = _databaseFactory.CanConnect; - if (connect || ++i == tries) + if (connect || ++i == 5) { break; } _logger.LogDebug("Could not immediately connect to database, trying again."); - if (_globalSettings.Value.InstallMissingDatabase) - { - _logger.LogDebug("Install missing database is enabled, creating database before trying again."); - - _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName, _databaseFactory.ConnectionString); - } - Thread.Sleep(1000); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index 8b9b2b07cd..a4efa29e00 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -20,12 +20,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install { private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IScopeProvider _scopeProvider; - private readonly IRuntimeState _runtime; - private readonly IMigrationBuilder _migrationBuilder; + private readonly IRuntimeState _runtimeState; private readonly IKeyValueService _keyValueService; - private readonly IHostingEnvironment _hostingEnvironment; private readonly ILogger _logger; - private readonly ILoggerFactory _loggerFactory; private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; private readonly IConfigManipulator _configManipulator; private readonly IMigrationPlanExecutor _migrationPlanExecutor; @@ -39,11 +36,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install public DatabaseBuilder( IScopeProvider scopeProvider, IUmbracoDatabaseFactory databaseFactory, - IRuntimeState runtime, + IRuntimeState runtimeState, ILoggerFactory loggerFactory, - IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, - IHostingEnvironment hostingEnvironment, IDbProviderFactoryCreator dbProviderFactoryCreator, IConfigManipulator configManipulator, IMigrationPlanExecutor migrationPlanExecutor, @@ -51,12 +46,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install { _scopeProvider = scopeProvider; _databaseFactory = databaseFactory; - _runtime = runtime; + _runtimeState = runtimeState; _logger = loggerFactory.CreateLogger(); - _loggerFactory = loggerFactory; - _migrationBuilder = migrationBuilder; _keyValueService = keyValueService; - _hostingEnvironment = hostingEnvironment; _dbProviderFactoryCreator = dbProviderFactoryCreator; _configManipulator = configManipulator; _migrationPlanExecutor = migrationPlanExecutor; @@ -381,7 +373,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install //If the determined version is "empty" its a new install - otherwise upgrade the existing if (!hasInstalledVersion) { - if (_runtime.Level == RuntimeLevel.Run) + if (_runtimeState.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); var creator = _databaseSchemaCreatorFactory.Create(database); diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs index d91a3de4bf..8eab08bfee 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -13,6 +12,7 @@ using Umbraco.Cms.Core.Semver; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Migrations.Upgrade; using Umbraco.Cms.Infrastructure.Persistence; +using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Runtime { @@ -110,7 +110,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime // cannot connect to configured database, this is bad, fail _logger.LogDebug("Could not connect to database."); - if (_globalSettings.Value.InstallMissingDatabase) + if (_globalSettings.Value.InstallMissingDatabase || CanAutoInstallMissingDatabase(_databaseFactory)) { // ok to install on a configured but missing database Level = RuntimeLevel.Install; @@ -173,6 +173,17 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } + public void Configure(RuntimeLevel level, RuntimeLevelReason reason, Exception bootFailedException = null) + { + Level = level; + Reason = reason; + + if (bootFailedException != null) + { + BootFailedException = new BootFailedException(bootFailedException.Message, bootFailedException); + } + } + private enum UmbracoDatabaseState { Ok, @@ -233,17 +244,6 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } - public void Configure(RuntimeLevel level, RuntimeLevelReason reason, Exception bootFailedException = null) - { - Level = level; - Reason = reason; - - if (bootFailedException != null) - { - BootFailedException = new BootFailedException(bootFailedException.Message, bootFailedException); - } - } - private bool DoesUmbracoRequireUpgrade(IReadOnlyDictionary keyValues) { var upgrader = new Upgrader(new UmbracoPlan(_umbracoVersion)); @@ -277,6 +277,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime return canConnect; } - + private bool CanAutoInstallMissingDatabase(IUmbracoDatabaseFactory databaseFactory) + => databaseFactory.ProviderName == Constants.DatabaseProviders.SqlCe || + databaseFactory.ConnectionString?.InvariantContains("(localdb)") == true; } } From 494c9f1b42d2eb9103a17374238230d6334596e7 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 17 Sep 2021 10:29:24 -0600 Subject: [PATCH 33/73] UmbracoRouteValueTransformer fixes --- .../UmbracoBuilderExtensions.cs | 2 +- .../Routing/UmbracoRouteValueTransformer.cs | 56 +++++++++++++------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index 62ec5a9921..744bd13388 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -38,7 +38,7 @@ namespace Umbraco.Extensions builder.Services.AddDataProtection(); builder.Services.AddAntiforgery(); - builder.Services.AddScoped(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs index 41fd20a69b..9e0b71b61e 100644 --- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -92,31 +92,41 @@ namespace Umbraco.Cms.Web.Website.Routing // If we aren't running, then we have nothing to route if (_runtime.Level != RuntimeLevel.Run) { - return values; + return null; } // will be null for any client side requests like JS, etc... - if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext)) + if (!_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext umbracoContext)) { - return values; + return null; } if (!_routableDocumentFilter.IsDocumentRequest(httpContext.Request.Path)) { - return values; + return null; + } + + // Don't execute if there are already UmbracoRouteValues assigned. + // This can occur if someone else is dynamically routing and in which case we don't want to overwrite + // the routing work being done there. + UmbracoRouteValues umbracoRouteValues = httpContext.Features.Get(); + if (umbracoRouteValues != null) + { + return null; } // Check if there is no existing content and return the no content controller if (!umbracoContext.Content.HasContent()) { - values[ControllerToken] = ControllerExtensions.GetControllerName(); - values[ActionToken] = nameof(RenderNoContentController.Index); - - return values; + return new RouteValueDictionary + { + [ControllerToken] = ControllerExtensions.GetControllerName(), + [ActionToken] = nameof(RenderNoContentController.Index) + }; } IPublishedRequest publishedRequest = await RouteRequestAsync(httpContext, umbracoContext); - UmbracoRouteValues umbracoRouteValues = await _routeValuesFactory.CreateAsync(httpContext, publishedRequest); + umbracoRouteValues = await _routeValuesFactory.CreateAsync(httpContext, publishedRequest); // Store the route values as a httpcontext feature httpContext.Features.Set(umbracoRouteValues); @@ -125,16 +135,27 @@ namespace Umbraco.Cms.Web.Website.Routing PostedDataProxyInfo postedInfo = GetFormInfo(httpContext, values); if (postedInfo != null) { - return HandlePostedValues(postedInfo, httpContext, values); + return HandlePostedValues(postedInfo, httpContext); } - values[ControllerToken] = umbracoRouteValues.ControllerName; + // See https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.routing.dynamicroutevaluetransformer.transformasync?view=aspnetcore-5.0#Microsoft_AspNetCore_Mvc_Routing_DynamicRouteValueTransformer_TransformAsync_Microsoft_AspNetCore_Http_HttpContext_Microsoft_AspNetCore_Routing_RouteValueDictionary_ + // We should apparenlty not be modified these values. + // So we create new ones. + var newValues = new RouteValueDictionary + { + [ControllerToken] = umbracoRouteValues.ControllerName + }; if (string.IsNullOrWhiteSpace(umbracoRouteValues.ActionName) == false) { - values[ActionToken] = umbracoRouteValues.ActionName; + newValues[ActionToken] = umbracoRouteValues.ActionName; } - return values; + // NOTE: If we are never returning null it means that it is not possible for another + // DynamicRouteValueTransformer to execute to set the route values. This one will + // always win even if it is a 404 because we manage all 404s via Umbraco and 404 + // handlers. + + return newValues; } private async Task RouteRequestAsync(HttpContext httpContext, IUmbracoContext umbracoContext) @@ -196,11 +217,14 @@ namespace Umbraco.Cms.Web.Website.Routing }; } - private RouteValueDictionary HandlePostedValues(PostedDataProxyInfo postedInfo, HttpContext httpContext, RouteValueDictionary values) + private RouteValueDictionary HandlePostedValues(PostedDataProxyInfo postedInfo, HttpContext httpContext) { // set the standard route values/tokens - values[ControllerToken] = postedInfo.ControllerName; - values[ActionToken] = postedInfo.ActionName; + var values = new RouteValueDictionary + { + [ControllerToken] = postedInfo.ControllerName, + [ActionToken] = postedInfo.ActionName + }; ControllerActionDescriptor surfaceControllerDescriptor = _controllerActionSearcher.Find(httpContext, postedInfo.ControllerName, postedInfo.ActionName); From 4ad34270dda2d590e7c15755658a24e1c18013a6 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 19:59:54 +0200 Subject: [PATCH 34/73] Remove runtime state dependency in InstallHelper --- src/Umbraco.Infrastructure/Install/InstallHelper.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Infrastructure/Install/InstallHelper.cs b/src/Umbraco.Infrastructure/Install/InstallHelper.cs index 056d1c1b8c..cd7dfcbf0c 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -26,7 +26,6 @@ namespace Umbraco.Cms.Infrastructure.Install private readonly ICookieManager _cookieManager; private readonly IUserAgentProvider _userAgentProvider; private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory; - private readonly IRuntimeState _runtimeState; private InstallationType? _installationType; public InstallHelper(DatabaseBuilder databaseBuilder, @@ -36,8 +35,7 @@ namespace Umbraco.Cms.Infrastructure.Install IInstallationService installationService, ICookieManager cookieManager, IUserAgentProvider userAgentProvider, - IUmbracoDatabaseFactory umbracoDatabaseFactory, - IRuntimeState runtimeState) + IUmbracoDatabaseFactory umbracoDatabaseFactory) { _logger = logger; _umbracoVersion = umbracoVersion; @@ -47,7 +45,6 @@ namespace Umbraco.Cms.Infrastructure.Install _cookieManager = cookieManager; _userAgentProvider = userAgentProvider; _umbracoDatabaseFactory = umbracoDatabaseFactory; - _runtimeState = runtimeState; // We need to initialize the type already, as we can't detect later, if the connection string is added on the fly. GetInstallationType(); @@ -100,7 +97,7 @@ namespace Umbraco.Cms.Infrastructure.Install /// private bool IsBrandNewInstall => _connectionStrings.CurrentValue.UmbracoConnectionString?.IsConnectionStringConfigured() != true || _databaseBuilder.IsDatabaseConfigured == false || - (_runtimeState.Level == RuntimeLevel.Install && _runtimeState.Reason == RuntimeLevelReason.InstallMissingDatabase) || + _databaseBuilder.CanConnectToDatabase == false || _databaseBuilder.IsUmbracoInstalled() == false; } } From d27dc05f328c20f13fa3ff09e9850f6950e2ebb3 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 17 Sep 2021 12:02:04 -0600 Subject: [PATCH 35/73] Return null from UmbracoRouteValueTransformer when there is no matches, use a custom IEndpointSelectorPolicy to deal with 404s. --- .../UmbracoBuilderExtensions.cs | 4 + .../Routing/NotFoundSelectorPolicy.cs | 79 +++++++++++++++++++ .../Routing/UmbracoRouteValueTransformer.cs | 16 ++-- 3 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index 744bd13388..72d8ec58ce 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -1,5 +1,7 @@ using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Infrastructure.DependencyInjection; @@ -11,6 +13,7 @@ using Umbraco.Cms.Web.Website.Middleware; using Umbraco.Cms.Web.Website.Models; using Umbraco.Cms.Web.Website.Routing; using Umbraco.Cms.Web.Website.ViewEngines; +using static Microsoft.Extensions.DependencyInjection.ServiceDescriptor; namespace Umbraco.Extensions { @@ -40,6 +43,7 @@ namespace Umbraco.Extensions builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.TryAddEnumerable(Singleton()); builder.Services.AddSingleton(); builder.Services.AddSingleton(); diff --git a/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs new file mode 100644 index 0000000000..589c424629 --- /dev/null +++ b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Matching; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Web.Common.Controllers; +using Umbraco.Cms.Web.Common.Routing; + +namespace Umbraco.Cms.Web.Website.Routing +{ + /// + /// Used to handle 404 routes that haven't been handled by the end user + /// + internal class NotFoundSelectorPolicy : MatcherPolicy, IEndpointSelectorPolicy + { + private readonly Lazy _notFound; + private readonly EndpointDataSource _endpointDataSource; + + public NotFoundSelectorPolicy(EndpointDataSource endpointDataSource) + { + _notFound = new Lazy(GetNotFoundEndpoint); + _endpointDataSource = endpointDataSource; + } + + // return the endpoint for the RenderController.Index action. + private Endpoint GetNotFoundEndpoint() + { + Endpoint e = _endpointDataSource.Endpoints.First(x => + { + // return the endpoint for the RenderController.Index action. + ControllerActionDescriptor descriptor = x.Metadata?.GetMetadata(); + return descriptor.ControllerTypeInfo == typeof(RenderController) + && descriptor.ActionName == nameof(RenderController.Index); + }); + return e; + } + + public override int Order => 0; + + public bool AppliesToEndpoints(IReadOnlyList endpoints) + { + // Don't apply this filter to any endpoint group that is a controller route + // i.e. only dynamic routes. + foreach(Endpoint endpoint in endpoints) + { + ControllerAttribute controller = endpoint.Metadata?.GetMetadata(); + if (controller != null) + { + return false; + } + } + + // then ensure this is only applied if all endpoints are IDynamicEndpointMetadata + return endpoints.All(x => x.Metadata?.GetMetadata() != null); + } + + public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates) + { + if (candidates.Count == 1 && candidates[0].Values == null) + { + UmbracoRouteValues umbracoRouteValues = httpContext.Features.Get(); + if (umbracoRouteValues?.PublishedRequest != null + && !umbracoRouteValues.PublishedRequest.HasPublishedContent() + && umbracoRouteValues.PublishedRequest.ResponseStatusCode == StatusCodes.Status404NotFound) + { + // not found/404 + httpContext.SetEndpoint(_notFound.Value); + } + } + + return Task.CompletedTask; + } + } +} diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs index 9e0b71b61e..fc54350097 100644 --- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -28,6 +28,7 @@ using RouteDirection = Umbraco.Cms.Core.Routing.RouteDirection; namespace Umbraco.Cms.Web.Website.Routing { + /// /// The route value transformer for Umbraco front-end routes /// @@ -138,6 +139,16 @@ namespace Umbraco.Cms.Web.Website.Routing return HandlePostedValues(postedInfo, httpContext); } + if (!umbracoRouteValues?.PublishedRequest?.HasPublishedContent() ?? false) + { + // No content was found, not by any registered 404 handlers and + // not by the IContentLastChanceFinder. In this case we want to return + // our default 404 page but we cannot return route values now because + // it's possible that a developer is handling dynamic routes too. + // Our 404 page will be handled with the NotFoundSelectorPolicy + return null; + } + // See https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.routing.dynamicroutevaluetransformer.transformasync?view=aspnetcore-5.0#Microsoft_AspNetCore_Mvc_Routing_DynamicRouteValueTransformer_TransformAsync_Microsoft_AspNetCore_Http_HttpContext_Microsoft_AspNetCore_Routing_RouteValueDictionary_ // We should apparenlty not be modified these values. // So we create new ones. @@ -150,11 +161,6 @@ namespace Umbraco.Cms.Web.Website.Routing newValues[ActionToken] = umbracoRouteValues.ActionName; } - // NOTE: If we are never returning null it means that it is not possible for another - // DynamicRouteValueTransformer to execute to set the route values. This one will - // always win even if it is a 404 because we manage all 404s via Umbraco and 404 - // handlers. - return newValues; } From fd5cef6b429a8676e5e2523cf7c942331939b5e0 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 20:20:36 +0200 Subject: [PATCH 36/73] Support DataDirectory placeholder in LocalDB connection string --- .../Configuration/ConfigConnectionString.cs | 48 +++++++++++++++++-- .../Migrations/Install/DatabaseBuilder.cs | 4 -- .../Runtime/CoreRuntime.cs | 2 - .../UmbracoBuilderExtensions.cs | 3 ++ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs index d0dec2548c..18bdace632 100644 --- a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs +++ b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs @@ -14,8 +14,43 @@ namespace Umbraco.Cms.Core.Configuration public ConfigConnectionString(string name, string connectionString, string providerName = null) { Name = name ?? throw new ArgumentNullException(nameof(name)); - ConnectionString = connectionString; - ProviderName = string.IsNullOrEmpty(providerName) ? ParseProviderName(connectionString) : providerName; + ConnectionString = ParseConnectionString(connectionString, ref providerName); + ProviderName = providerName; + } + + private static string ParseConnectionString(string connectionString, ref string providerName) + { + if (string.IsNullOrEmpty(connectionString)) + { + return null; + } + + var builder = new DbConnectionStringBuilder + { + ConnectionString = connectionString + }; + + // Replace data directory placeholder + const string attachDbFileNameKey = "AttachDbFileName"; + const string dataDirectoryPlaceholder = "|DataDirectory|"; + if (builder.TryGetValue(attachDbFileNameKey, out var attachDbFileNameValue) && + attachDbFileNameValue is string attachDbFileName && + attachDbFileName.Contains(dataDirectoryPlaceholder)) + { + var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString(); + if (!string.IsNullOrEmpty(dataDirectory)) + { + builder[attachDbFileNameKey] = attachDbFileName.Replace(dataDirectoryPlaceholder, dataDirectory); + } + } + + // Also parse provider name now we already have a builder + if (string.IsNullOrEmpty(providerName)) + { + providerName = ParseProviderName(builder); + } + + return builder.ToString(); } /// @@ -37,13 +72,18 @@ namespace Umbraco.Cms.Core.Configuration ConnectionString = connectionString }; + return ParseProviderName(builder); + } + + private static string ParseProviderName(DbConnectionStringBuilder builder) + { if ((builder.TryGetValue("Data Source", out var dataSource) || builder.TryGetValue("DataSource", out dataSource)) && dataSource?.ToString().EndsWith(".sdf", StringComparison.OrdinalIgnoreCase) == true) { - return Cms.Core.Constants.DbProviderNames.SqlCe; + return Constants.DbProviderNames.SqlCe; } - return Cms.Core.Constants.DbProviderNames.SqlServer; + return Constants.DbProviderNames.SqlServer; } } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index a4efa29e00..0a1def06ef 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -160,10 +160,6 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install string connectionString = LocalDbConnectionString; const string providerName = Constants.DbProviderNames.SqlServer; - // Replace data directory placeholder (this is not supported by LocalDB) - var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString(); - connectionString = connectionString.Replace("|DataDirectory|", dataDirectory); - _configManipulator.SaveConnectionString(connectionString, providerName); _databaseFactory.Configure(connectionString, providerName); diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs index f9a8578dc3..86f4e070c2 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs @@ -94,8 +94,6 @@ namespace Umbraco.Cms.Infrastructure.Runtime _logger.LogError(exception, msg); }; - AppDomain.CurrentDomain.SetData("DataDirectory", _hostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data)); - // acquire the main domain - if this fails then anything that should be registered with MainDom will not operate AcquireMainDom(); diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 4319bc3544..90307cf746 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -94,6 +94,9 @@ namespace Umbraco.Extensions services.AddLogger(tempHostingEnvironment, loggingConfig, config); + // The DataDirectory is used to resolve database file paths (directly supported by SQL CE and manually replaced for LocalDB) + AppDomain.CurrentDomain.SetData("DataDirectory", tempHostingEnvironment?.MapPathContentRoot(Constants.SystemDirectories.Data)); + // Manually create and register the HttpContextAccessor. In theory this should not be registered // again by the user but if that is the case it's not the end of the world since HttpContextAccessor // is just based on AsyncLocal, see https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/HttpContextAccessor.cs From 2ede06485cde6b28d06b66b377f5408bd3aae6ae Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 17 Sep 2021 12:47:41 -0600 Subject: [PATCH 37/73] fix/add tests --- .../UmbracoRouteValueTransformerTests.cs | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs index 47fcbd010c..d00f85fd0a 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs @@ -14,6 +14,7 @@ using NUnit.Framework; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; @@ -92,28 +93,28 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing => Mock.Of(x => x.RouteRequestAsync(It.IsAny(), It.IsAny()) == Task.FromResult(request)); [Test] - public async Task Noop_When_Runtime_Level_Not_Run() + public async Task Null_When_Runtime_Level_Not_Run() { UmbracoRouteValueTransformer transformer = GetTransformer( Mock.Of(), Mock.Of()); RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); - Assert.AreEqual(0, result.Count); + Assert.IsNull(result); } [Test] - public async Task Noop_When_No_Umbraco_Context() + public async Task Null_When_No_Umbraco_Context() { UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( Mock.Of()); RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); - Assert.AreEqual(0, result.Count); + Assert.IsNull(result); } [Test] - public async Task Noop_When_Not_Document_Request() + public async Task Null_When_Not_Document_Request() { var umbracoContext = Mock.Of(); UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( @@ -121,7 +122,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == false)); RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); - Assert.AreEqual(0, result.Count); + Assert.IsNull(result); } [Test] @@ -173,10 +174,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing } [Test] - public async Task Assigns_Values_To_RouteValueDictionary() + public async Task Assigns_Values_To_RouteValueDictionary_When_Content() { IUmbracoContext umbracoContext = GetUmbracoContext(true); - IPublishedRequest request = Mock.Of(); + IPublishedRequest request = Mock.Of(x => x.PublishedContent == Mock.Of()); UmbracoRouteValues routeValues = GetRouteValues(request); UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( @@ -190,6 +191,23 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing Assert.AreEqual(routeValues.ActionName, result[ActionToken]); } + [Test] + public async Task Returns_Null_RouteValueDictionary_When_No_Content() + { + IUmbracoContext umbracoContext = GetUmbracoContext(true); + IPublishedRequest request = Mock.Of(x => x.PublishedContent == null); + UmbracoRouteValues routeValues = GetRouteValues(request); + + UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( + Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), + router: GetRouter(request), + routeValuesFactory: GetRouteValuesFactory(request)); + + RouteValueDictionary result = await transformer.TransformAsync(new DefaultHttpContext(), new RouteValueDictionary()); + + Assert.IsNull(result); + } + private class TestController : RenderController { public TestController(ILogger logger, ICompositeViewEngine compositeViewEngine, IUmbracoContextAccessor umbracoContextAccessor) From 57bbbfa7d3104b46bb48d403147d8b26bc3fe34e Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 17 Sep 2021 13:35:43 -0600 Subject: [PATCH 38/73] better null checks --- src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs index 589c424629..e9370c94ce 100644 --- a/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs +++ b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -34,8 +34,8 @@ namespace Umbraco.Cms.Web.Website.Routing { // return the endpoint for the RenderController.Index action. ControllerActionDescriptor descriptor = x.Metadata?.GetMetadata(); - return descriptor.ControllerTypeInfo == typeof(RenderController) - && descriptor.ActionName == nameof(RenderController.Index); + return descriptor?.ControllerTypeInfo == typeof(RenderController) + && descriptor?.ActionName == nameof(RenderController.Index); }); return e; } From 9306861d76a393801fe42a2f6cb0ed6b4dc81737 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 17 Sep 2021 13:49:12 -0600 Subject: [PATCH 39/73] Better candidate checking. --- .../Routing/NotFoundSelectorPolicy.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs index e9370c94ce..dbc06175fd 100644 --- a/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs +++ b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs @@ -24,7 +24,7 @@ namespace Umbraco.Cms.Web.Website.Routing public NotFoundSelectorPolicy(EndpointDataSource endpointDataSource) { _notFound = new Lazy(GetNotFoundEndpoint); - _endpointDataSource = endpointDataSource; + _endpointDataSource = endpointDataSource; } // return the endpoint for the RenderController.Index action. @@ -46,7 +46,7 @@ namespace Umbraco.Cms.Web.Website.Routing { // Don't apply this filter to any endpoint group that is a controller route // i.e. only dynamic routes. - foreach(Endpoint endpoint in endpoints) + foreach (Endpoint endpoint in endpoints) { ControllerAttribute controller = endpoint.Metadata?.GetMetadata(); if (controller != null) @@ -61,7 +61,7 @@ namespace Umbraco.Cms.Web.Website.Routing public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates) { - if (candidates.Count == 1 && candidates[0].Values == null) + if (AllInvalid(candidates)) { UmbracoRouteValues umbracoRouteValues = httpContext.Features.Get(); if (umbracoRouteValues?.PublishedRequest != null @@ -72,8 +72,20 @@ namespace Umbraco.Cms.Web.Website.Routing httpContext.SetEndpoint(_notFound.Value); } } - - return Task.CompletedTask; + + return Task.CompletedTask; + } + + private static bool AllInvalid(CandidateSet candidates) + { + for (int i = 0; i < candidates.Count; i++) + { + if (candidates.IsValidCandidate(i)) + { + return false; + } + } + return true; } } } From bc291550326a5fe174a158bc9104e420fddd224a Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Sat, 18 Sep 2021 00:23:47 +0200 Subject: [PATCH 40/73] Fix parsing of connection string during setup --- .../InstallSteps/DatabaseInstallStep.cs | 16 +++---- .../Migrations/Install/DatabaseBuilder.cs | 44 ++++++++++++------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs index 0976e14112..96d2a7c996 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/DatabaseInstallStep.cs @@ -1,28 +1,24 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.Extensions.Options; using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Install; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Persistence; namespace Umbraco.Cms.Infrastructure.Install.InstallSteps { - [InstallSetupStep(InstallationType.NewInstall | InstallationType.Upgrade, - "DatabaseInstall", 11, "")] + [InstallSetupStep(InstallationType.NewInstall | InstallationType.Upgrade, "DatabaseInstall", 11, "")] public class DatabaseInstallStep : InstallSetupStep { - private readonly DatabaseBuilder _databaseBuilder; private readonly IRuntimeState _runtime; + private readonly DatabaseBuilder _databaseBuilder; - public DatabaseInstallStep(DatabaseBuilder databaseBuilder, IRuntimeState runtime) + public DatabaseInstallStep(IRuntimeState runtime, DatabaseBuilder databaseBuilder) { - _databaseBuilder = databaseBuilder; _runtime = runtime; + _databaseBuilder = databaseBuilder; } public override Task ExecuteAsync(object model) @@ -47,10 +43,10 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps return Task.FromResult(null); } - //upgrade is required so set the flag for the next step + // Upgrade is required, so set the flag for the next step return Task.FromResult(new InstallSetupResult(new Dictionary { - {"upgrade", true} + { "upgrade", true} })); } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index 0a1def06ef..f9e36d8d12 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -1,7 +1,9 @@ using System; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; +using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Migrations; using Umbraco.Cms.Core.Scoping; @@ -25,6 +27,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install private readonly ILogger _logger; private readonly IDbProviderFactoryCreator _dbProviderFactoryCreator; private readonly IConfigManipulator _configManipulator; + private readonly IOptionsMonitor _globalSettings; + private readonly IOptionsMonitor _connectionStrings; private readonly IMigrationPlanExecutor _migrationPlanExecutor; private readonly DatabaseSchemaCreatorFactory _databaseSchemaCreatorFactory; @@ -41,6 +45,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install IKeyValueService keyValueService, IDbProviderFactoryCreator dbProviderFactoryCreator, IConfigManipulator configManipulator, + IOptionsMonitor globalSettings, + IOptionsMonitor connectionStrings, IMigrationPlanExecutor migrationPlanExecutor, DatabaseSchemaCreatorFactory databaseSchemaCreatorFactory) { @@ -51,6 +57,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install _keyValueService = keyValueService; _dbProviderFactoryCreator = dbProviderFactoryCreator; _configManipulator = configManipulator; + _globalSettings = globalSettings; + _connectionStrings = connectionStrings; _migrationPlanExecutor = migrationPlanExecutor; _databaseSchemaCreatorFactory = databaseSchemaCreatorFactory; } @@ -74,8 +82,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// public bool CanConnect(string databaseType, string connectionString, string server, string database, string login, string password, bool integratedAuth) { - // we do not test SqlCE connection - if (databaseType.InvariantContains("sqlce") || databaseType.InvariantContains("localdb")) + // we do not test SqlCE or LocalDB connections + if (databaseType.InvariantContains("SqlCe") || databaseType.InvariantContains("SqlLocalDb")) return true; string providerName; @@ -147,10 +155,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install const string providerName = Constants.DbProviderNames.SqlCe; _configManipulator.SaveConnectionString(connectionString, providerName); - _databaseFactory.Configure(connectionString, providerName); - - // Always create embedded database - CreateDatabase(); + Configure(connectionString, providerName, true); } public const string LocalDbConnectionString = @"Server=(localdb)\MSSQLLocalDB;Integrated Security=true;AttachDbFileName=|DataDirectory|\Umbraco.mdf"; @@ -161,10 +166,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install const string providerName = Constants.DbProviderNames.SqlServer; _configManipulator.SaveConnectionString(connectionString, providerName); - _databaseFactory.Configure(connectionString, providerName); - - // Always create LocalDB database - CreateDatabase(); + Configure(connectionString, providerName, true); } /// @@ -174,10 +176,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install /// Has to be SQL Server public void ConfigureDatabaseConnection(string connectionString) { - const string providerName = Constants.DbProviderNames.SqlServer; - - _configManipulator.SaveConnectionString(connectionString, providerName); - _databaseFactory.Configure(connectionString, providerName); + _configManipulator.SaveConnectionString(connectionString, null); + Configure(connectionString, null, _globalSettings.CurrentValue.InstallMissingDatabase); } /// @@ -193,7 +193,21 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out var providerName); _configManipulator.SaveConnectionString(connectionString, providerName); - _databaseFactory.Configure(connectionString, providerName); + Configure(connectionString, providerName, _globalSettings.CurrentValue.InstallMissingDatabase); + } + + private void Configure(string connectionString, string providerName, bool installMissingDatabase) + { + // Update existing connection string + var umbracoConnectionString = new ConfigConnectionString(Constants.System.UmbracoConnectionName, connectionString, providerName); + _connectionStrings.CurrentValue.UmbracoConnectionString = umbracoConnectionString; + + _databaseFactory.Configure(umbracoConnectionString.ConnectionString, umbracoConnectionString.ProviderName); + + if (installMissingDatabase) + { + CreateDatabase(); + } } /// From e960ca6fdbda6a57db0e32fe521ec7fcedefa584 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 07:56:22 +0200 Subject: [PATCH 41/73] Handle null in ConfigureKestrelServerOptions.cs --- .../Security/ConfigureKestrelServerOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs index 2483981b7f..c11e0d8814 100644 --- a/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs +++ b/src/Umbraco.Web.Common/Security/ConfigureKestrelServerOptions.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Web.Common.Security public void Configure(KestrelServerOptions options) { // convert from KB to bytes - options.Limits.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength * 1024; + options.Limits.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : long.MaxValue; } } } From 0a042b2c37d622fc0f5b90398c1e8a628051869a Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 08:39:59 +0200 Subject: [PATCH 42/73] IIS can only handle ~4GB uploads. No good documentation, but found a couple of places documenting this. E.g. https://newbedev.com/how-to-set-the-maxallowedcontentlength-to-500mb-while-running-on-iis7 --- src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs index dd4ea4d970..f5ac2ac4a6 100644 --- a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs +++ b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs @@ -12,7 +12,8 @@ namespace Umbraco.Cms.Web.Common.Security public void Configure(IISServerOptions options) { // convert from KB to bytes - options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : long.MaxValue; + options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : uint.MaxValue; // ~4GB is the max supported value for IIS and IIS express. + //options.IisMaxRequestSizeLimit } } } From 3ffbbf64e5d78c501442fe22abfd597b1c15827f Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 08:40:23 +0200 Subject: [PATCH 43/73] Clean up --- src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs index f5ac2ac4a6..4141669c1c 100644 --- a/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs +++ b/src/Umbraco.Web.Common/Security/ConfigureIISServerOptions.cs @@ -13,7 +13,6 @@ namespace Umbraco.Cms.Web.Common.Security { // convert from KB to bytes options.MaxRequestBodySize = _runtimeSettings.Value.MaxRequestLength.HasValue ? _runtimeSettings.Value.MaxRequestLength.Value * 1024 : uint.MaxValue; // ~4GB is the max supported value for IIS and IIS express. - //options.IisMaxRequestSizeLimit } } } From 3b9593614cf8fb8cc3eceddeca41695a0114aeab Mon Sep 17 00:00:00 2001 From: Zeegaan <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 20 Sep 2021 10:29:03 +0200 Subject: [PATCH 44/73] Fixed cultures to now both seperately in the backoffice and frontend check for both region culture and UI culture --- .../UmbracoBackOfficeIdentityCultureProvider.cs | 9 ++++++++- .../UmbracoPublishedContentCultureProvider.cs | 11 ++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs b/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs index d7d10fe67f..96022cdcc7 100644 --- a/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs +++ b/src/Umbraco.Web.Common/Localization/UmbracoBackOfficeIdentityCultureProvider.cs @@ -36,13 +36,20 @@ namespace Umbraco.Cms.Web.Common.Localization lock (_locker) { // We need to dynamically change the supported cultures since we won't ever know what languages are used since - // they are dynamic within Umbraco. + // they are dynamic within Umbraco. We have to handle this for both UI and Region cultures, in case people run different region and UI languages var cultureExists = _localizationOptions.SupportedCultures.Contains(culture); if (!cultureExists) { // add this as a supporting culture _localizationOptions.SupportedCultures.Add(culture); + } + + var uiCultureExists = _localizationOptions.SupportedCultures.Contains(culture); + + if (!uiCultureExists) + { + // add this as a supporting culture _localizationOptions.SupportedUICultures.Add(culture); } diff --git a/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs b/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs index ab3f4ccc77..50e8d859ea 100644 --- a/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs +++ b/src/Umbraco.Web.Common/Localization/UmbracoPublishedContentCultureProvider.cs @@ -36,7 +36,7 @@ namespace Umbraco.Cms.Web.Common.Localization lock (_locker) { // We need to dynamically change the supported cultures since we won't ever know what languages are used since - // they are dynamic within Umbraco. + // they are dynamic within Umbraco. We have to handle this for both UI and Region cultures, in case people run different region and UI languages // This code to check existence is borrowed from aspnetcore to avoid creating a CultureInfo // https://github.com/dotnet/aspnetcore/blob/b795ac3546eb3e2f47a01a64feb3020794ca33bb/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs#L165 CultureInfo existingCulture = _localizationOptions.SupportedCultures.FirstOrDefault(supportedCulture => @@ -47,6 +47,15 @@ namespace Umbraco.Cms.Web.Common.Localization // add this as a supporting culture var ci = CultureInfo.GetCultureInfo(culture); _localizationOptions.SupportedCultures.Add(ci); + } + + CultureInfo existingUICulture = _localizationOptions.SupportedUICultures.FirstOrDefault(supportedCulture => + StringSegment.Equals(supportedCulture.Name, culture, StringComparison.OrdinalIgnoreCase)); + + if (existingUICulture == null) + { + // add this as a supporting culture + var ci = CultureInfo.GetCultureInfo(culture); _localizationOptions.SupportedUICultures.Add(ci); } } From 981e096a19d3a5579adb90a4e337c726438cf644 Mon Sep 17 00:00:00 2001 From: Jeavon Date: Mon, 20 Sep 2021 09:37:58 +0100 Subject: [PATCH 45/73] Rename server roles, master = SchedulingPublisher and replica = Subscriber (#10480) --- src/Umbraco.Core/Models/IServerRegistration.cs | 6 +++--- src/Umbraco.Core/Models/ServerRegistration.cs | 18 +++++++++--------- .../Sync/ElectedServerRoleAccessor.cs | 2 +- src/Umbraco.Core/Sync/ServerRole.cs | 10 +++++----- .../Sync/SingleServerRoleAccessor.cs | 2 +- .../HostedServices/HealthCheckNotifier.cs | 4 ++-- .../HostedServices/KeepAlive.cs | 4 ++-- .../HostedServices/LogScrubber.cs | 4 ++-- .../HostedServices/ScheduledPublishing.cs | 4 ++-- .../HostedServices/TempFileCleanup.cs | 4 ++-- .../Persistence/Dtos/ServerRegistrationDto.cs | 4 ++-- .../Factories/ServerRegistrationFactory.cs | 6 +++--- .../Mappers/ServerRegistrationMapper.cs | 4 ++-- .../Implement/CacheInstructionService.cs | 2 +- .../Implement/ServerRegistrationService.cs | 14 ++++++-------- .../NPocoTests/NPocoBulkInsertTests.cs | 2 +- .../HostedServices/HealthCheckNotifierTests.cs | 4 ++-- .../HostedServices/KeepAliveTests.cs | 4 ++-- .../HostedServices/LogScrubberTests.cs | 4 ++-- .../HostedServices/ScheduledPublishingTests.cs | 4 ++-- 20 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/Umbraco.Core/Models/IServerRegistration.cs b/src/Umbraco.Core/Models/IServerRegistration.cs index 4aba9b10c0..12319da6c8 100644 --- a/src/Umbraco.Core/Models/IServerRegistration.cs +++ b/src/Umbraco.Core/Models/IServerRegistration.cs @@ -1,4 +1,4 @@ -using System; +using System; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Sync; @@ -19,9 +19,9 @@ namespace Umbraco.Cms.Core.Models bool IsActive { get; set; } /// - /// Gets or sets a value indicating whether the server is master. + /// Gets or sets a value indicating whether the server is has the SchedulingPublisher role. /// - bool IsMaster { get; set; } + bool IsSchedulingPublisher { get; set; } /// /// Gets the date and time the registration was created. diff --git a/src/Umbraco.Core/Models/ServerRegistration.cs b/src/Umbraco.Core/Models/ServerRegistration.cs index 5aa926bdaa..dae691812b 100644 --- a/src/Umbraco.Core/Models/ServerRegistration.cs +++ b/src/Umbraco.Core/Models/ServerRegistration.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Extensions; @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Models private string _serverAddress; private string _serverIdentity; private bool _isActive; - private bool _isMaster; + private bool _isSchedulingPublisher; /// /// Initializes a new instance of the class. @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Core.Models /// The date and time the registration was last accessed. /// A value indicating whether the registration is active. /// A value indicating whether the registration is master. - public ServerRegistration(int id, string serverAddress, string serverIdentity, DateTime registered, DateTime accessed, bool isActive, bool isMaster) + public ServerRegistration(int id, string serverAddress, string serverIdentity, DateTime registered, DateTime accessed, bool isActive, bool isSchedulingPublisher) { UpdateDate = accessed; CreateDate = registered; @@ -40,7 +40,7 @@ namespace Umbraco.Cms.Core.Models ServerAddress = serverAddress; ServerIdentity = serverIdentity; IsActive = isActive; - IsMaster = isMaster; + IsSchedulingPublisher = isSchedulingPublisher; } /// @@ -86,12 +86,12 @@ namespace Umbraco.Cms.Core.Models } /// - /// Gets or sets a value indicating whether the server is master. + /// Gets or sets a value indicating whether the server has the SchedulingPublisher role /// - public bool IsMaster + public bool IsSchedulingPublisher { - get => _isMaster; - set => SetPropertyValueAndDetectChanges(value, ref _isMaster, nameof(IsMaster)); + get => _isSchedulingPublisher; + set => SetPropertyValueAndDetectChanges(value, ref _isSchedulingPublisher, nameof(IsSchedulingPublisher)); } /// @@ -118,7 +118,7 @@ namespace Umbraco.Cms.Core.Models /// public override string ToString() { - return string.Format("{{\"{0}\", \"{1}\", {2}active, {3}master}}", ServerAddress, ServerIdentity, IsActive ? "" : "!", IsMaster ? "" : "!"); + return string.Format("{{\"{0}\", \"{1}\", {2}active, {3}master}}", ServerAddress, ServerIdentity, IsActive ? "" : "!", IsSchedulingPublisher ? "" : "!"); } } } diff --git a/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs b/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs index 3c4d8a2b47..340de80c96 100644 --- a/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs +++ b/src/Umbraco.Core/Sync/ElectedServerRoleAccessor.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Core.Sync /// /// /// This is the default service which determines a server's role by using a master election process. - /// The master election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase. + /// The scheduling publisher election process doesn't occur until just after startup so this election process doesn't really affect the primary startup phase. /// public sealed class ElectedServerRoleAccessor : IServerRoleAccessor { diff --git a/src/Umbraco.Core/Sync/ServerRole.cs b/src/Umbraco.Core/Sync/ServerRole.cs index 27358608a4..9bfd4469b3 100644 --- a/src/Umbraco.Core/Sync/ServerRole.cs +++ b/src/Umbraco.Core/Sync/ServerRole.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Cms.Core.Sync +namespace Umbraco.Cms.Core.Sync { /// /// The role of a server in an application environment. @@ -16,13 +16,13 @@ Single = 1, /// - /// In a multi-servers environment, the server is a replica server. + /// In a multi-servers environment, the server is a Subscriber server. /// - Replica = 2, + Subscriber = 2, /// - /// In a multi-servers environment, the server is the master server. + /// In a multi-servers environment, the server is the Scheduling Publisher. /// - Master = 3 + SchedulingPublisher = 3 } } diff --git a/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs b/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs index 43fd421ac5..2f4e85c5b1 100644 --- a/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs +++ b/src/Umbraco.Core/Sync/SingleServerRoleAccessor.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Core.Sync /// /// /// The micro optimization is specifically to avoid a DB query just after the app starts up to determine the - /// which by default is done with master election by a database query. The master election process doesn't occur until just after startup + /// which by default is done with scheduling publisher election by a database query. The master election process doesn't occur until just after startup /// so this micro optimization doesn't really affect the primary startup phase. /// public class SingleServerRoleAccessor : IServerRoleAccessor diff --git a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs index 78dc3f533b..6a0828fad3 100644 --- a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs +++ b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs @@ -89,8 +89,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices switch (_serverRegistrar.CurrentServerRole) { - case ServerRole.Replica: - _logger.LogDebug("Does not run on replica servers."); + case ServerRole.Subscriber: + _logger.LogDebug("Does not run on subscriber servers."); return; case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs index 644b2c278f..b564e7948d 100644 --- a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs +++ b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs @@ -69,8 +69,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices // Don't run on replicas nor unknown role servers switch (_serverRegistrar.CurrentServerRole) { - case ServerRole.Replica: - _logger.LogDebug("Does not run on replica servers."); + case ServerRole.Subscriber: + _logger.LogDebug("Does not run on subscriber servers."); return; case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs index 39f638000a..27d9c29e8d 100644 --- a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs +++ b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs @@ -63,8 +63,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices { switch (_serverRegistrar.CurrentServerRole) { - case ServerRole.Replica: - _logger.LogDebug("Does not run on replica servers."); + case ServerRole.Subscriber: + _logger.LogDebug("Does not run on subscriber servers."); return Task.CompletedTask; case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs index 089afa4e07..d59ea4fad3 100644 --- a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs +++ b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs @@ -69,8 +69,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices switch (_serverRegistrar.CurrentServerRole) { - case ServerRole.Replica: - _logger.LogDebug("Does not run on replica servers."); + case ServerRole.Subscriber: + _logger.LogDebug("Does not run on subscriber servers."); return Task.CompletedTask; case ServerRole.Unknown: _logger.LogDebug("Does not run on servers with unknown role."); diff --git a/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs b/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs index b126de9467..e59cca5fbd 100644 --- a/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs +++ b/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs @@ -14,8 +14,8 @@ namespace Umbraco.Cms.Infrastructure.HostedServices /// Used to cleanup temporary file locations. /// /// - /// Will run on all servers - even though file upload should only be handled on the master, this will - /// ensure that in the case it happes on replicas that they are cleaned up too. + /// Will run on all servers - even though file upload should only be handled on the scheduling publisher, this will + /// ensure that in the case it happens on subscribers that they are cleaned up too. /// public class TempFileCleanup : RecurringHostedServiceBase { diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs index 26e371dbaf..a82a5ca748 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs @@ -1,4 +1,4 @@ -using System; +using System; using NPoco; using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; using Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions; @@ -35,6 +35,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos public bool IsActive { get; set; } [Column("isMaster")] - public bool IsMaster { get; set; } + public bool IsSchedulingPublisher { get; set; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/ServerRegistrationFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/ServerRegistrationFactory.cs index 6a1aa48162..f662faf561 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/ServerRegistrationFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/ServerRegistrationFactory.cs @@ -1,4 +1,4 @@ -using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Infrastructure.Persistence.Dtos; namespace Umbraco.Cms.Infrastructure.Persistence.Factories @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories { public static ServerRegistration BuildEntity(ServerRegistrationDto dto) { - var model = new ServerRegistration(dto.Id, dto.ServerAddress, dto.ServerIdentity, dto.DateRegistered, dto.DateAccessed, dto.IsActive, dto.IsMaster); + var model = new ServerRegistration(dto.Id, dto.ServerAddress, dto.ServerIdentity, dto.DateRegistered, dto.DateAccessed, dto.IsActive, dto.IsSchedulingPublisher); // reset dirty initial properties (U4-1946) model.ResetDirtyProperties(false); return model; @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories ServerAddress = entity.ServerAddress, DateRegistered = entity.CreateDate, IsActive = entity.IsActive, - IsMaster = ((ServerRegistration) entity).IsMaster, + IsSchedulingPublisher = ((ServerRegistration) entity).IsSchedulingPublisher, DateAccessed = entity.UpdateDate, ServerIdentity = entity.ServerIdentity }; diff --git a/src/Umbraco.Infrastructure/Persistence/Mappers/ServerRegistrationMapper.cs b/src/Umbraco.Infrastructure/Persistence/Mappers/ServerRegistrationMapper.cs index f35116ee81..61b597be46 100644 --- a/src/Umbraco.Infrastructure/Persistence/Mappers/ServerRegistrationMapper.cs +++ b/src/Umbraco.Infrastructure/Persistence/Mappers/ServerRegistrationMapper.cs @@ -1,4 +1,4 @@ -using System; +using System; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Infrastructure.Persistence.Dtos; @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Mappers { DefineMap(nameof(ServerRegistration.Id), nameof(ServerRegistrationDto.Id)); DefineMap(nameof(ServerRegistration.IsActive), nameof(ServerRegistrationDto.IsActive)); - DefineMap(nameof(ServerRegistration.IsMaster), nameof(ServerRegistrationDto.IsMaster)); + DefineMap(nameof(ServerRegistration.IsSchedulingPublisher), nameof(ServerRegistrationDto.IsSchedulingPublisher)); DefineMap(nameof(ServerRegistration.ServerAddress), nameof(ServerRegistrationDto.ServerAddress)); DefineMap(nameof(ServerRegistration.CreateDate), nameof(ServerRegistrationDto.DateRegistered)); DefineMap(nameof(ServerRegistration.UpdateDate), nameof(ServerRegistrationDto.DateAccessed)); diff --git a/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs b/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs index e0c0f56244..a037cd1095 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/CacheInstructionService.cs @@ -151,7 +151,7 @@ namespace Umbraco.Cms.Core.Services.Implement switch (serverRole) { case ServerRole.Single: - case ServerRole.Master: + case ServerRole.SchedulingPublisher: PruneOldInstructions(); instructionsWerePruned = true; break; diff --git a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs index 248de428a8..92968510fa 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ServerRegistrationService.cs @@ -53,7 +53,7 @@ namespace Umbraco.Cms.Core.Services.Implement ((ServerRegistrationRepository) _serverRegistrationRepository).ClearCache(); // ensure we have up-to-date cache var regs = _serverRegistrationRepository.GetMany().ToArray(); - var hasMaster = regs.Any(x => ((ServerRegistration) x).IsMaster); + var hasSchedulingPublisher = regs.Any(x => ((ServerRegistration) x).IsSchedulingPublisher); var server = regs.FirstOrDefault(x => x.ServerIdentity.InvariantEquals(serverIdentity)); if (server == null) @@ -67,22 +67,20 @@ namespace Umbraco.Cms.Core.Services.Implement } server.IsActive = true; - if (hasMaster == false) - server.IsMaster = true; + if (hasSchedulingPublisher == false) + server.IsSchedulingPublisher = true; _serverRegistrationRepository.Save(server); _serverRegistrationRepository.DeactiveStaleServers(staleTimeout); // triggers a cache reload // reload - cheap, cached - // default role is single server, but if registrations contain more - // than one active server, then role is master or replica regs = _serverRegistrationRepository.GetMany().ToArray(); // default role is single server, but if registrations contain more - // than one active server, then role is master or replica + // than one active server, then role is scheduling publisher or subscriber _currentServerRole = regs.Count(x => x.IsActive) > 1 - ? (server.IsMaster ? ServerRole.Master : ServerRole.Replica) + ? (server.IsSchedulingPublisher ? ServerRole.SchedulingPublisher : ServerRole.Subscriber) : ServerRole.Single; scope.Complete(); @@ -105,7 +103,7 @@ namespace Umbraco.Cms.Core.Services.Implement var server = _serverRegistrationRepository.GetMany().FirstOrDefault(x => x.ServerIdentity.InvariantEquals(serverIdentity)); if (server == null) return; - server.IsActive = server.IsMaster = false; + server.IsActive = server.IsSchedulingPublisher = false; _serverRegistrationRepository.Save(server); // will trigger a cache reload // will trigger a cache reload scope.Complete(); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoBulkInsertTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoBulkInsertTests.cs index 471586c715..290d018df9 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoBulkInsertTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/NPocoTests/NPocoBulkInsertTests.cs @@ -191,7 +191,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.NPoco DateRegistered = DateTime.Now, IsActive = true, DateAccessed = DateTime.Now, - IsMaster = true + IsSchedulingPublisher = true }); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs index f128d49128..be581122a1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs @@ -53,9 +53,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices } [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Replica() + public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() { - HealthCheckNotifier sut = CreateHealthCheckNotifier(serverRole: ServerRole.Replica); + HealthCheckNotifier sut = CreateHealthCheckNotifier(serverRole: ServerRole.Subscriber); await sut.PerformExecuteAsync(null); VerifyNotificationsNotSent(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs index 557e87fb0c..3cc23cfb45 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs @@ -37,9 +37,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices } [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Replica() + public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() { - KeepAlive sut = CreateKeepAlive(serverRole: ServerRole.Replica); + KeepAlive sut = CreateKeepAlive(serverRole: ServerRole.Subscriber); await sut.PerformExecuteAsync(null); VerifyKeepAliveRequestNotSent(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs index a3a7b95210..2057167653 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs @@ -27,9 +27,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices private const int MaxLogAgeInMinutes = 60; [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Replica() + public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() { - LogScrubber sut = CreateLogScrubber(serverRole: ServerRole.Replica); + LogScrubber sut = CreateLogScrubber(serverRole: ServerRole.Subscriber); await sut.PerformExecuteAsync(null); VerifyLogsNotScrubbed(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs index efbd0c9e98..2a8f006ab6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs @@ -44,9 +44,9 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices } [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Replica() + public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() { - ScheduledPublishing sut = CreateScheduledPublishing(serverRole: ServerRole.Replica); + ScheduledPublishing sut = CreateScheduledPublishing(serverRole: ServerRole.Subscriber); await sut.PerformExecuteAsync(null); VerifyScheduledPublishingNotPerformed(); } From c08c9c9160042224f0f00f8d6ec3ef84e53eaf82 Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Mon, 20 Sep 2021 10:39:34 +0200 Subject: [PATCH 46/73] Don't ToString int only to parse it back This seems to be a fix for a VERY old issue (U4-5223), when ID was seemingly saved as int16, so we parsed it back to int32, this doesn't make sense anymore since the ID is int32 to begin with. --- .../Persistence/Factories/MacroFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs index ce871f8761..7f73abacaa 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/MacroFactory.cs @@ -50,7 +50,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories }; if (entity.HasIdentity) - dto.Id = int.Parse(entity.Id.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); + dto.Id = entity.Id; return dto; } From ef39f36d638a408054ff4aff52bfdc8aaad22da4 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 11:15:32 +0200 Subject: [PATCH 47/73] Rollback changes to TryConvertTo (now it is always current culture) and uses int.tryParse directly where we know it do not come from user input --- .../Extensions/ObjectExtensions.cs | 30 +++++++++---------- .../Security/UmbracoUserStore.cs | 8 ++--- .../Trees/DictionaryTreeController.cs | 8 +++-- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Core/Extensions/ObjectExtensions.cs b/src/Umbraco.Core/Extensions/ObjectExtensions.cs index 15ecf9340c..fa43ae3595 100644 --- a/src/Umbraco.Core/Extensions/ObjectExtensions.cs +++ b/src/Umbraco.Core/Extensions/ObjectExtensions.cs @@ -294,7 +294,7 @@ namespace Umbraco.Extensions { if (target == typeof(int)) { - if (int.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) + if (int.TryParse(input, out var value)) { return Attempt.Succeed(value); } @@ -302,19 +302,19 @@ namespace Umbraco.Extensions // Because decimal 100.01m will happily convert to integer 100, it // makes sense that string "100.01" *also* converts to integer 100. var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(decimal.TryParse(input2, NumberStyles.Number, CultureInfo.InvariantCulture, out var value2), Convert.ToInt32(value2, CultureInfo.InvariantCulture)); + return Attempt.If(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2, CultureInfo.InvariantCulture)); } if (target == typeof(long)) { - if (long.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) + if (long.TryParse(input, out var value)) { return Attempt.Succeed(value); } // Same as int var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(decimal.TryParse(input2, NumberStyles.Number, CultureInfo.InvariantCulture, out var value2), Convert.ToInt64(value2)); + return Attempt.If(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2)); } // TODO: Should we do the decimal trick for short, byte, unsigned? @@ -334,15 +334,15 @@ namespace Umbraco.Extensions switch (Type.GetTypeCode(target)) { case TypeCode.Int16: - return Attempt.If(short.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value), value); + return Attempt.If(short.TryParse(input, out var value), value); case TypeCode.Double: var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(double.TryParse(input2, NumberStyles.Float, CultureInfo.InvariantCulture, out var valueD), valueD); + return Attempt.If(double.TryParse(input2, out var valueD), valueD); case TypeCode.Single: var input3 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(float.TryParse(input3, NumberStyles.Float, CultureInfo.InvariantCulture, out var valueF), valueF); + return Attempt.If(float.TryParse(input3, out var valueF), valueF); case TypeCode.Char: return Attempt.If(char.TryParse(input, out var valueC), valueC); @@ -351,16 +351,16 @@ namespace Umbraco.Extensions return Attempt.If(byte.TryParse(input, out var valueB), valueB); case TypeCode.SByte: - return Attempt.If(sbyte.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var valueSb), valueSb); + return Attempt.If(sbyte.TryParse(input, out var valueSb), valueSb); case TypeCode.UInt32: - return Attempt.If(uint.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var valueU), valueU); + return Attempt.If(uint.TryParse(input, out var valueU), valueU); case TypeCode.UInt16: - return Attempt.If(ushort.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var valueUs), valueUs); + return Attempt.If(ushort.TryParse(input, out var valueUs), valueUs); case TypeCode.UInt64: - return Attempt.If(ulong.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var valueUl), valueUl); + return Attempt.If(ulong.TryParse(input, out var valueUl), valueUl); } } else if (target == typeof(Guid)) @@ -389,16 +389,16 @@ namespace Umbraco.Extensions } else if (target == typeof(DateTimeOffset)) { - return Attempt.If(DateTimeOffset.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.None,out var value), value); + return Attempt.If(DateTimeOffset.TryParse(input, out var value), value); } else if (target == typeof(TimeSpan)) { - return Attempt.If(TimeSpan.TryParse(input, CultureInfo.InvariantCulture, out var value), value); + return Attempt.If(TimeSpan.TryParse(input, out var value), value); } else if (target == typeof(decimal)) { var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(decimal.TryParse(input2, NumberStyles.Number, CultureInfo.InvariantCulture, out var value), value); + return Attempt.If(decimal.TryParse(input2, out var value), value); } else if (input != null && target == typeof(Version)) { @@ -677,7 +677,7 @@ namespace Umbraco.Extensions [MethodImpl(MethodImplOptions.AggressiveInlining)] private static string NormalizeNumberDecimalSeparator(string s) { - var normalized = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator[0]; + var normalized = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator[0]; return s.ReplaceMany(NumberDecimalSeparatorsToNormalize, normalized); } diff --git a/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs b/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs index 3884ee31a1..e3fb1cfd85 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading; @@ -28,13 +29,12 @@ namespace Umbraco.Cms.Core.Security protected static int UserIdToInt(string userId) { - Attempt attempt = userId.TryConvertTo(); - if (attempt.Success) + if(int.TryParse(userId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { - return attempt.Result; + return result; } - throw new InvalidOperationException("Unable to convert user ID to int", attempt.Exception); + throw new InvalidOperationException($"Unable to convert user ID ({userId})to int using InvariantCulture"); } protected static string UserIdToString(int userId) => string.Intern(userId.ToString()); diff --git a/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs index 0722a095b3..c61fabfa7b 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DictionaryTreeController.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -69,9 +70,10 @@ namespace Umbraco.Cms.Web.BackOffice.Trees /// protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) { - var intId = id.TryConvertTo(); - if (intId == false) + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + { throw new InvalidOperationException("Id must be an integer"); + } var nodes = new TreeNodeCollection(); @@ -92,7 +94,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees else { // maybe we should use the guid as URL param to avoid the extra call for getting dictionary item - var parentDictionary = _localizationService.GetDictionaryItemById(intId.Result); + var parentDictionary = _localizationService.GetDictionaryItemById(intId); if (parentDictionary == null) return nodes; From 8060d41dba5bd69bfe8c59cf50446e17cdd893cd Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 11:17:38 +0200 Subject: [PATCH 48/73] More rollback --- src/Umbraco.Core/Extensions/ObjectExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Extensions/ObjectExtensions.cs b/src/Umbraco.Core/Extensions/ObjectExtensions.cs index fa43ae3595..d666046e4b 100644 --- a/src/Umbraco.Core/Extensions/ObjectExtensions.cs +++ b/src/Umbraco.Core/Extensions/ObjectExtensions.cs @@ -302,7 +302,7 @@ namespace Umbraco.Extensions // Because decimal 100.01m will happily convert to integer 100, it // makes sense that string "100.01" *also* converts to integer 100. var input2 = NormalizeNumberDecimalSeparator(input); - return Attempt.If(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2, CultureInfo.InvariantCulture)); + return Attempt.If(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2)); } if (target == typeof(long)) From 25aae38a25802a1b430357a62ce3f93df655e30c Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 11:22:51 +0200 Subject: [PATCH 49/73] Explictly uses int.TryParse Invariant when the input is not from a user --- .../Security/BackOfficeUserStore.cs | 8 ++++---- src/Umbraco.Infrastructure/Security/MemberUserStore.cs | 9 ++++----- .../Trees/ContentTypeTreeController.cs | 10 ++++++---- .../Trees/DataTypeTreeController.cs | 10 ++++++---- .../Trees/MediaTypeTreeController.cs | 10 ++++++---- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs index deb85ff496..0930b510f3 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading; @@ -133,15 +134,14 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(user)); } - Attempt asInt = user.Id.TryConvertTo(); - if (asInt == false) + if (!int.TryParse(user.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var asInt)) { throw new InvalidOperationException("The user id must be an integer to work with the Umbraco"); } using (IScope scope = _scopeProvider.CreateScope()) { - IUser found = _userService.GetUserById(asInt.Result); + IUser found = _userService.GetUserById(asInt); if (found != null) { // we have to remember whether Logins property is dirty, since the UpdateMemberProperties will reset it. @@ -441,7 +441,7 @@ namespace Umbraco.Cms.Core.Security if (identityUser.IsPropertyDirty(nameof(BackOfficeIdentityUser.InviteDateUtc)) || (user.InvitedDate?.ToUniversalTime() != identityUser.InviteDateUtc)) { - anythingChanged = true; + anythingChanged = true; user.InvitedDate = identityUser.InviteDateUtc?.ToLocalTime(); } diff --git a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs index 70cfcc3bfb..086ff6a66c 100644 --- a/src/Umbraco.Infrastructure/Security/MemberUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/MemberUserStore.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -116,16 +117,14 @@ namespace Umbraco.Cms.Core.Security throw new ArgumentNullException(nameof(user)); } - Attempt asInt = user.Id.TryConvertTo(); - if (asInt == false) + if (!int.TryParse(user.Id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var asInt)) { //TODO: should this be thrown, or an identity result? - throw new InvalidOperationException("The user id must be an integer to work with Umbraco"); + throw new InvalidOperationException("The user id must be an integer to work with the Umbraco"); } - using IScope scope = _scopeProvider.CreateScope(autoComplete: true); - IMember found = _memberService.GetById(asInt.Result); + IMember found = _memberService.GetById(asInt); if (found != null) { // we have to remember whether Logins property is dirty, since the UpdateMemberProperties will reset it. diff --git a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs index 024be6647e..2be23f69e2 100644 --- a/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/ContentTypeTreeController.cs @@ -55,13 +55,15 @@ namespace Umbraco.Cms.Web.BackOffice.Trees protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) { - var intId = id.TryConvertTo(); - if (intId == false) throw new InvalidOperationException("Id must be an integer"); + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + { + throw new InvalidOperationException("Id must be an integer"); + } var nodes = new TreeNodeCollection(); nodes.AddRange( - _entityService.GetChildren(intId.Result, UmbracoObjectTypes.DocumentTypeContainer) + _entityService.GetChildren(intId, UmbracoObjectTypes.DocumentTypeContainer) .OrderBy(entity => entity.Name) .Select(dt => { @@ -76,7 +78,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees //if the request is for folders only then just return if (queryStrings["foldersonly"].ToString().IsNullOrWhiteSpace() == false && queryStrings["foldersonly"] == "1") return nodes; - var children = _entityService.GetChildren(intId.Result, UmbracoObjectTypes.DocumentType).ToArray(); + var children = _entityService.GetChildren(intId, UmbracoObjectTypes.DocumentType).ToArray(); var contentTypes = _contentTypeService.GetAll(children.Select(c => c.Id).ToArray()).ToDictionary(c => c.Id); nodes.AddRange( children diff --git a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs index d83a813de6..2a2c4bed0c 100644 --- a/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/DataTypeTreeController.cs @@ -43,14 +43,16 @@ namespace Umbraco.Cms.Web.BackOffice.Trees protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) { - var intId = id.TryConvertTo(); - if (intId == false) throw new InvalidOperationException("Id must be an integer"); + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + { + throw new InvalidOperationException("Id must be an integer"); + } var nodes = new TreeNodeCollection(); //Folders first nodes.AddRange( - _entityService.GetChildren(intId.Result, UmbracoObjectTypes.DataTypeContainer) + _entityService.GetChildren(intId, UmbracoObjectTypes.DataTypeContainer) .OrderBy(entity => entity.Name) .Select(dt => { @@ -68,7 +70,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees //System ListView nodes var systemListViewDataTypeIds = GetNonDeletableSystemListViewDataTypeIds(); - var children = _entityService.GetChildren(intId.Result, UmbracoObjectTypes.DataType).ToArray(); + var children = _entityService.GetChildren(intId, UmbracoObjectTypes.DataType).ToArray(); var dataTypes = Enumerable.ToDictionary(_dataTypeService.GetAll(children.Select(c => c.Id).ToArray()), dt => dt.Id); nodes.AddRange( diff --git a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs index 7a6c70650a..c19c9a800a 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MediaTypeTreeController.cs @@ -42,13 +42,15 @@ namespace Umbraco.Cms.Web.BackOffice.Trees protected override ActionResult GetTreeNodes(string id, FormCollection queryStrings) { - var intId = id.TryConvertTo(); - if (intId == false) throw new InvalidOperationException("Id must be an integer"); + if (!int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) + { + throw new InvalidOperationException("Id must be an integer"); + } var nodes = new TreeNodeCollection(); nodes.AddRange( - _entityService.GetChildren(intId.Result, UmbracoObjectTypes.MediaTypeContainer) + _entityService.GetChildren(intId, UmbracoObjectTypes.MediaTypeContainer) .OrderBy(entity => entity.Name) .Select(dt => { @@ -66,7 +68,7 @@ namespace Umbraco.Cms.Web.BackOffice.Trees var mediaTypes = _mediaTypeService.GetAll(); nodes.AddRange( - _entityService.GetChildren(intId.Result, UmbracoObjectTypes.MediaType) + _entityService.GetChildren(intId, UmbracoObjectTypes.MediaType) .OrderBy(entity => entity.Name) .Select(dt => { From 68d4d76da2c7dd5a9fd9c043f2d859c4a4bae34f Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 11:30:09 +0200 Subject: [PATCH 50/73] Use Invariant when toString userIds --- .../Install/InstallSteps/NewInstallStep.cs | 4 ++-- .../Persistence/Factories/ExternalLoginFactory.cs | 4 ++-- src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs | 5 +++-- src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs | 2 +- .../Services/Implement/ExternalLoginService.cs | 5 +++-- .../Authorization/AdminUsersHandlerTests.cs | 7 ++++--- .../Controllers/AuthenticationController.cs | 5 +++-- .../Controllers/BackOfficeController.cs | 2 +- .../Controllers/CurrentUserController.cs | 2 +- .../Install/CreateUnattendedUserNotificationHandler.cs | 4 ++-- 10 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs index fdcef20943..73b9d702b7 100644 --- a/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs @@ -73,11 +73,11 @@ namespace Umbraco.Cms.Infrastructure.Install.InstallSteps _userService.Save(admin); - var membershipUser = await _userManager.FindByIdAsync(Constants.Security.SuperUserId.ToString()); + var membershipUser = await _userManager.FindByIdAsync(Constants.Security.SuperUserIdAsString); if (membershipUser == null) { throw new InvalidOperationException( - $"No user found in membership provider with id of {Constants.Security.SuperUserId}."); + $"No user found in membership provider with id of {Constants.Security.SuperUserIdAsString}."); } //To change the password here we actually need to reset it since we don't have an old one to use to change diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs index 212973d49c..82bbb4a40a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/ExternalLoginFactory.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories { public static IIdentityUserToken BuildEntity(ExternalLoginTokenDto dto) { - var entity = new IdentityUserToken(dto.Id, dto.ExternalLoginDto.LoginProvider, dto.Name, dto.Value, dto.ExternalLoginDto.UserId.ToString(), dto.CreateDate); + var entity = new IdentityUserToken(dto.Id, dto.ExternalLoginDto.LoginProvider, dto.Name, dto.Value, dto.ExternalLoginDto.UserId.ToString(CultureInfo.InvariantCulture), dto.CreateDate); // reset dirty initial properties (U4-1946) entity.ResetDirtyProperties(false); @@ -18,7 +18,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Factories public static IIdentityUserLogin BuildEntity(ExternalLoginDto dto) { - var entity = new IdentityUserLogin(dto.Id, dto.LoginProvider, dto.ProviderKey, dto.UserId.ToString(), dto.CreateDate) + var entity = new IdentityUserLogin(dto.Id, dto.LoginProvider, dto.ProviderKey, dto.UserId.ToString(CultureInfo.InvariantCulture), dto.CreateDate) { UserData = dto.UserData }; diff --git a/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs b/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs index 724eb77030..9e29316056 100644 --- a/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/MemberIdentityUser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Extensions; @@ -11,7 +12,7 @@ namespace Umbraco.Cms.Core.Security /// public class MemberIdentityUser : UmbracoIdentityUser { - private string _comments; + private string _comments; // Custom comparer for enumerables private static readonly DelegateEqualityComparer> s_groupsComparer = new DelegateEqualityComparer>( @@ -77,7 +78,7 @@ namespace Umbraco.Cms.Core.Security /// public string MemberTypeAlias { get; set; } - private static string UserIdToString(int userId) => string.Intern(userId.ToString()); + private static string UserIdToString(int userId) => string.Intern(userId.ToString(CultureInfo.InvariantCulture)); // TODO: Should we support custom member properties for persistence/retrieval? } diff --git a/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs b/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs index e3fb1cfd85..6a2325c316 100644 --- a/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs @@ -37,7 +37,7 @@ namespace Umbraco.Cms.Core.Security throw new InvalidOperationException($"Unable to convert user ID ({userId})to int using InvariantCulture"); } - protected static string UserIdToString(int userId) => string.Intern(userId.ToString()); + protected static string UserIdToString(int userId) => string.Intern(userId.ToString(CultureInfo.InvariantCulture)); /// /// Not supported in Umbraco diff --git a/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs b/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs index 259d6e8739..079971be24 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/ExternalLoginService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Events; @@ -25,7 +26,7 @@ namespace Umbraco.Cms.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // TODO: This is temp until we update the external service to support guids for both users and members - var asString = userId.ToString(); + var asString = userId.ToString(CultureInfo.InvariantCulture); return _externalLoginRepository.Get(Query().Where(x => x.UserId == asString)) .ToList(); } @@ -36,7 +37,7 @@ namespace Umbraco.Cms.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // TODO: This is temp until we update the external service to support guids for both users and members - var asString = userId.ToString(); + var asString = userId.ToString(CultureInfo.InvariantCulture); return _externalLoginRepository.Get(Query().Where(x => x.UserId == asString)) .ToList(); } diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/AdminUsersHandlerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/AdminUsersHandlerTests.cs index 191381d8c5..7b638c29d1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/AdminUsersHandlerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Authorization/AdminUsersHandlerTests.cs @@ -2,6 +2,7 @@ // See LICENSE for more details. using System.Collections.Generic; +using System.Globalization; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -59,7 +60,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization public async Task Editing_Single_Admin_User_By_Admin_User_Is_Authorized() { AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(); - AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString(), editingWithAdmin: true); + AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString(CultureInfo.InvariantCulture), editingWithAdmin: true); await sut.HandleAsync(authHandlerContext); @@ -70,7 +71,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization public async Task Editing_Single_Admin_User_By_Non_Admin_User_Is_Not_Authorized() { AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(); - AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString()); + AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString(CultureInfo.InvariantCulture)); await sut.HandleAsync(authHandlerContext); @@ -81,7 +82,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization public async Task Editing_Single_Non_Admin_User_By_Non_Admin_User_Is_Authorized() { AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(); - AdminUsersHandler sut = CreateHandler(queryStringValue: NonAdmin2UserId.ToString()); + AdminUsersHandler sut = CreateHandler(queryStringValue: NonAdmin2UserId.ToString(CultureInfo.InvariantCulture)); await sut.HandleAsync(authHandlerContext); diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index e79b49ace3..f159011d80 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; @@ -510,7 +511,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [AllowAnonymous] public async Task PostSetPassword(SetPasswordModel model) { - var identityUser = await _userManager.FindByIdAsync(model.UserId.ToString()); + var identityUser = await _userManager.FindByIdAsync(model.UserId.ToString(CultureInfo.InvariantCulture)); var result = await _userManager.ResetPasswordAsync(identityUser, model.ResetCode, model.Password); if (result.Succeeded) @@ -560,7 +561,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers } } - _userManager.NotifyForgotPasswordChanged(User, model.UserId.ToString()); + _userManager.NotifyForgotPasswordChanged(User, model.UserId.ToString(CultureInfo.InvariantCulture)); return Ok(); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs index 237aad6bd3..b6df2ebf4a 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/BackOfficeController.cs @@ -348,7 +348,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [AllowAnonymous] public async Task ValidatePasswordResetCode([Bind(Prefix = "u")]int userId, [Bind(Prefix = "r")]string resetCode) { - var user = await _userManager.FindByIdAsync(userId.ToString()); + var user = await _userManager.FindByIdAsync(userId.ToString(CultureInfo.InvariantCulture)); if (user != null) { var result = await _userManager.VerifyUserTokenAsync(user, "Default", "ResetPassword", resetCode); diff --git a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs index 1435eb6c52..ba6ca36085 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/CurrentUserController.cs @@ -250,7 +250,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers [ValidateAngularAntiForgeryToken] public async Task> GetCurrentUserLinkedLogins() { - var identityUser = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0).ToString()); + var identityUser = await _backOfficeUserManager.FindByIdAsync(_backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0).ToString(CultureInfo.InvariantCulture)); // deduplicate in case there are duplicates (there shouldn't be now since we have a unique constraint on the external logins // but there didn't used to be) diff --git a/src/Umbraco.Web.BackOffice/Install/CreateUnattendedUserNotificationHandler.cs b/src/Umbraco.Web.BackOffice/Install/CreateUnattendedUserNotificationHandler.cs index 3990f42aa7..6eaed2f42d 100644 --- a/src/Umbraco.Web.BackOffice/Install/CreateUnattendedUserNotificationHandler.cs +++ b/src/Umbraco.Web.BackOffice/Install/CreateUnattendedUserNotificationHandler.cs @@ -76,10 +76,10 @@ namespace Umbraco.Cms.Web.BackOffice.Install // Uses same approach as NewInstall Step using IServiceScope scope = _serviceScopeFactory.CreateScope(); IBackOfficeUserManager backOfficeUserManager = scope.ServiceProvider.GetRequiredService(); - BackOfficeIdentityUser membershipUser = await backOfficeUserManager.FindByIdAsync(Core.Constants.Security.SuperUserId.ToString()); + BackOfficeIdentityUser membershipUser = await backOfficeUserManager.FindByIdAsync(Core.Constants.Security.SuperUserIdAsString); if (membershipUser == null) { - throw new InvalidOperationException($"No user found in membership provider with id of {Core.Constants.Security.SuperUserId}."); + throw new InvalidOperationException($"No user found in membership provider with id of {Core.Constants.Security.SuperUserIdAsString}."); } //To change the password here we actually need to reset it since we don't have an old one to use to change From fed720042cddd404a49e040abb511ac112cbb060 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Mon, 20 Sep 2021 11:38:54 +0200 Subject: [PATCH 51/73] Fix ParseConnectionString to pass tests --- src/Umbraco.Core/Configuration/ConfigConnectionString.cs | 7 +++++-- .../Migrations/Install/DatabaseBuilder.cs | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs index 18bdace632..116b96df9c 100644 --- a/src/Umbraco.Core/Configuration/ConfigConnectionString.cs +++ b/src/Umbraco.Core/Configuration/ConfigConnectionString.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Core.Configuration { if (string.IsNullOrEmpty(connectionString)) { - return null; + return connectionString; } var builder = new DbConnectionStringBuilder @@ -41,6 +41,9 @@ namespace Umbraco.Cms.Core.Configuration if (!string.IsNullOrEmpty(dataDirectory)) { builder[attachDbFileNameKey] = attachDbFileName.Replace(dataDirectoryPlaceholder, dataDirectory); + + // Mutate the existing connection string (note: the builder also lowercases the properties) + connectionString = builder.ToString(); } } @@ -50,7 +53,7 @@ namespace Umbraco.Cms.Core.Configuration providerName = ParseProviderName(builder); } - return builder.ToString(); + return connectionString; } /// diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index f9e36d8d12..55fdd24f77 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -4,7 +4,6 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Migrations; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; @@ -144,7 +143,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install #region Configure Connection String - public const string EmbeddedDatabaseConnectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;"; + public const string EmbeddedDatabaseConnectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1"; /// /// Configures a connection string for the embedded database. From f638636c10ecf3355a691b4c3800f0144a6a7b5c Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Mon, 20 Sep 2021 11:45:08 +0200 Subject: [PATCH 52/73] Update default LocalDB connection string to equal parsed value --- .../Migrations/Install/DatabaseBuilder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs index 55fdd24f77..78dbdddc84 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs @@ -157,7 +157,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install Configure(connectionString, providerName, true); } - public const string LocalDbConnectionString = @"Server=(localdb)\MSSQLLocalDB;Integrated Security=true;AttachDbFileName=|DataDirectory|\Umbraco.mdf"; + public const string LocalDbConnectionString = @"Data Source=(localdb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Umbraco.mdf;Integrated Security=True"; public void ConfigureSqlLocalDbDatabaseConnection() { From fb24e4eca58546ab5ca8611023c1b3db1233d75f Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 11:49:51 +0200 Subject: [PATCH 53/73] Removes the sv-SE test, as it is expected to fail for "-1" --- .../Umbraco.Core/CoreThings/TryConvertToTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs index 6373155603..2c399d0e93 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/TryConvertToTests.cs @@ -51,7 +51,6 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.CoreThings [Test] [TestCase("en-US")] [TestCase(null)] - [TestCase("sv-SE")] [TestCase("da-DK")] [TestCase("tr-TR")] public void ConvertToIntegerTest(string culture) From e95a759181886bcbc53879a0e1dfb758a0157313 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 20 Sep 2021 12:59:14 +0200 Subject: [PATCH 54/73] Updated nuget package dependencies --- src/Umbraco.Core/Umbraco.Core.csproj | 4 ++-- .../Umbraco.Examine.Lucene.csproj | 2 +- .../Umbraco.Infrastructure.csproj | 14 +++++++------- .../Umbraco.Persistence.SqlCe.csproj | 2 +- .../Umbraco.PublishedCache.NuCache.csproj | 2 +- src/Umbraco.TestData/Umbraco.TestData.csproj | 2 +- .../Umbraco.Tests.Integration.SqlCe.csproj | 4 ++-- .../Umbraco.Tests.Integration.csproj | 4 ++-- .../Umbraco.Web.BackOffice.csproj | 4 ++-- src/Umbraco.Web.Common/Umbraco.Web.Common.csproj | 6 +++--- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- src/Umbraco.Web.Website/Umbraco.Web.Website.csproj | 2 +- 12 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 9055030875..734ed2261d 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -16,7 +16,7 @@ - + @@ -29,7 +29,7 @@ - + all diff --git a/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj index baa843247d..8a3c0cbc73 100644 --- a/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj +++ b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj @@ -26,7 +26,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj index 67adb9907c..bb619d0f09 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -19,16 +19,16 @@ - - + + - + - + @@ -46,12 +46,12 @@ - + - - + + all diff --git a/src/Umbraco.Persistence.SqlCe/Umbraco.Persistence.SqlCe.csproj b/src/Umbraco.Persistence.SqlCe/Umbraco.Persistence.SqlCe.csproj index 508bcf3ccb..70366707e7 100644 --- a/src/Umbraco.Persistence.SqlCe/Umbraco.Persistence.SqlCe.csproj +++ b/src/Umbraco.Persistence.SqlCe/Umbraco.Persistence.SqlCe.csproj @@ -19,7 +19,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj b/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj index 7d6ff54c25..2115eab398 100644 --- a/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj +++ b/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj @@ -22,7 +22,7 @@ - + all diff --git a/src/Umbraco.TestData/Umbraco.TestData.csproj b/src/Umbraco.TestData/Umbraco.TestData.csproj index 22c9ca9131..eedf6e5668 100644 --- a/src/Umbraco.TestData/Umbraco.TestData.csproj +++ b/src/Umbraco.TestData/Umbraco.TestData.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj index 2eff2802a4..486e816c3f 100644 --- a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj +++ b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj @@ -8,7 +8,7 @@ - + @@ -17,7 +17,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index 1bd0fbd7f2..2ca6d78c84 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -76,7 +76,7 @@ - + @@ -85,7 +85,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj index 8de2b2e248..56c1eb5492 100644 --- a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj +++ b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj @@ -18,14 +18,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj index 3a04ed1b22..ea4194431f 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -25,8 +25,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -38,7 +38,7 @@ - + all diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 7e2d51b12c..a050d22a16 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -66,12 +66,12 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj index d1bd53e5fe..7dab73b100 100644 --- a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj +++ b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj @@ -32,7 +32,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all From 63807bc65f4fb3689b06c33716cfc9727d3fbbcc Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 21 Sep 2021 10:51:43 +0200 Subject: [PATCH 55/73] Bump version to RC4 --- build/templates/UmbracoPackage/.template.config/template.json | 2 +- build/templates/UmbracoProject/.template.config/template.json | 2 +- src/Directory.Build.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/templates/UmbracoPackage/.template.config/template.json b/build/templates/UmbracoPackage/.template.config/template.json index 3758621968..b650e59a49 100644 --- a/build/templates/UmbracoPackage/.template.config/template.json +++ b/build/templates/UmbracoPackage/.template.config/template.json @@ -24,7 +24,7 @@ "version": { "type": "parameter", "datatype": "string", - "defaultValue": "9.0.0-rc003", + "defaultValue": "9.0.0-rc004", "description": "The version of Umbraco to load using NuGet", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, diff --git a/build/templates/UmbracoProject/.template.config/template.json b/build/templates/UmbracoProject/.template.config/template.json index 3cf7485ab2..8a07e29d2e 100644 --- a/build/templates/UmbracoProject/.template.config/template.json +++ b/build/templates/UmbracoProject/.template.config/template.json @@ -57,7 +57,7 @@ "version": { "type": "parameter", "datatype": "string", - "defaultValue": "9.0.0-rc003", + "defaultValue": "9.0.0-rc004", "description": "The version of Umbraco to load using NuGet", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 6f5eb39964..6445e6ea5f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ 9.0.0 9.0.0 - 9.0.0-rc003 + 9.0.0-rc004 9.0.0 9.0 en-US From 8b853b17ac6b63a8e55b93f865224eae6877702d Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Tue, 21 Sep 2021 11:11:40 +0200 Subject: [PATCH 56/73] Include installed media to package definition on install --- src/Umbraco.Core/Packaging/PackageDefinition.cs | 7 ++----- .../Packaging/PackageInstallation.cs | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Core/Packaging/PackageDefinition.cs b/src/Umbraco.Core/Packaging/PackageDefinition.cs index 345d669b15..ae12a914b3 100644 --- a/src/Umbraco.Core/Packaging/PackageDefinition.cs +++ b/src/Umbraco.Core/Packaging/PackageDefinition.cs @@ -28,7 +28,7 @@ namespace Umbraco.Cms.Core.Packaging public string Name { get; set; } = string.Empty; /// - /// The full path to the package's xml file + /// The full path to the package's XML file. /// [ReadOnly(true)] [DataMember(Name = "packagePath")] @@ -71,12 +71,9 @@ namespace Umbraco.Cms.Core.Packaging public IList DataTypes { get; set; } = new List(); [DataMember(Name = "mediaUdis")] - public IList MediaUdis { get; set; } = Array.Empty(); + public IList MediaUdis { get; set; } = new List(); [DataMember(Name = "mediaLoadChildNodes")] public bool MediaLoadChildNodes { get; set; } - - } - } diff --git a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs index 5138a4c630..e09bdf3e18 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs @@ -44,20 +44,29 @@ namespace Umbraco.Cms.Infrastructure.Packaging //make sure the definition is up to date with everything foreach (var x in installationSummary.DataTypesInstalled) packageDefinition.DataTypes.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.LanguagesInstalled) packageDefinition.Languages.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.DictionaryItemsInstalled) packageDefinition.DictionaryItems.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.MacrosInstalled) packageDefinition.Macros.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.TemplatesInstalled) packageDefinition.Templates.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.DocumentTypesInstalled) packageDefinition.DocumentTypes.Add(x.Id.ToInvariantString()); - foreach (var x in installationSummary.StylesheetsInstalled) - packageDefinition.Stylesheets.Add(x.Id.ToInvariantString()); - var contentInstalled = installationSummary.ContentInstalled.ToList(); - packageDefinition.ContentNodeId = contentInstalled.Count > 0 ? contentInstalled[0].Id.ToInvariantString() : null; + + foreach (var x in installationSummary.MediaTypesInstalled) + packageDefinition.MediaTypes.Add(x.Id.ToInvariantString()); + + packageDefinition.ContentNodeId = installationSummary.ContentInstalled.FirstOrDefault()?.Id.ToInvariantString(); + + foreach (var x in installationSummary.MediaInstalled) + packageDefinition.MediaUdis.Add(x.GetUdi()); return installationSummary; } From a9d8f5fa5b60cd8e5460bdd689ecc1c83a606732 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Tue, 21 Sep 2021 11:22:40 +0200 Subject: [PATCH 57/73] Fix exporting/importing macro partial views using a virtual file path --- .../Packaging/PackagesRepository.cs | 34 +++---------------- .../Packaging/PackageDataInstallation.cs | 11 ++++++ 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/src/Umbraco.Core/Packaging/PackagesRepository.cs b/src/Umbraco.Core/Packaging/PackagesRepository.cs index a24890d5f2..90cd7433b7 100644 --- a/src/Umbraco.Core/Packaging/PackagesRepository.cs +++ b/src/Umbraco.Core/Packaging/PackagesRepository.cs @@ -414,9 +414,10 @@ namespace Umbraco.Cms.Core.Packaging root.Add(macros); - // get the partial views for macros and package those - IEnumerable views = packagedMacros.Select(x => x.MacroSource).Where(x => x.EndsWith(".cshtml")); - PackageMacroPartialViews(views, root); + // Get the partial views for macros and package those (exclude views outside of the default directory, e.g. App_Plugins\*\Views) + IEnumerable views = packagedMacros.Where(x => x.MacroSource.StartsWith(Constants.SystemDirectories.MacroPartials)) + .Select(x => x.MacroSource.Substring(Constants.SystemDirectories.MacroPartials.Length).Replace('/', '\\')); + PackageStaticFiles(views, root, "MacroPartialViews", "View", _fileSystems.MacroPartialsFileSystem); } private void PackageStylesheets(PackageDefinition definition, XContainer root) @@ -487,33 +488,6 @@ namespace Umbraco.Cms.Core.Packaging root.Add(templatesXml); } - private void PackageMacroPartialViews(IEnumerable viewPaths, XContainer root) - { - var viewsXml = new XElement("MacroPartialViews"); - foreach (var viewPath in viewPaths) - { - // TODO: See TODO note in MacrosController about the inconsistencies of usages of partial views - // and how paths are saved. We have no choice currently but to assume that all views are 100% always - // on the content path. - - var physicalPath = _hostingEnvironment.MapPathContentRoot(viewPath); - if (!File.Exists(physicalPath)) - { - throw new InvalidOperationException("Could not find partial view at path " + viewPath); - } - - var fileContents = File.ReadAllText(physicalPath, Encoding.UTF8); - - viewsXml.Add( - new XElement( - "View", - new XAttribute("path", viewPath), - new XCData(fileContents))); - } - - root.Add(viewsXml); - } - private void PackageDocumentTypes(PackageDefinition definition, XContainer root) { var contentTypes = new HashSet(); diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 70ce46164c..7a63701559 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -1270,6 +1270,17 @@ namespace Umbraco.Cms.Infrastructure.Packaging throw new InvalidOperationException("No path attribute found"); } + // Remove prefix to maintain backwards compatibility + if (path.StartsWith(Constants.SystemDirectories.MacroPartials)) + { + path = path.Substring(Constants.SystemDirectories.MacroPartials.Length); + } + else if (path.StartsWith("~")) + { + _logger.LogWarning("Importing macro partial views outside of the Views/MacroPartials directory is not supported: {Path}", path); + continue; + } + IPartialView macroPartialView = _fileService.GetPartialViewMacro(path); // only update if it doesn't exist From 8d74efb6358d594e12b800a1d70cf97d7a8415cd Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 21 Sep 2021 12:28:49 +0200 Subject: [PATCH 58/73] Handle maindom was acquired doing install, so we do not have our lock Id in the database.. --- .../Runtime/SqlMainDomLock.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index 5e4597903a..5be1d13a7b 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -40,7 +40,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime private bool _errorDuringAcquiring; private readonly object _locker = new object(); private bool _hasTable = false; - + private bool _acquireWhenTablesNotAvailable = false; public SqlMainDomLock( ILogger logger, ILoggerFactory loggerFactory, @@ -99,7 +99,8 @@ namespace Umbraco.Cms.Infrastructure.Runtime _hasTable = db.HasTable(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue); if (!_hasTable) { - // the Db does not contain the required table, we must be in an install state we have no choice but to assume we can acquire + _logger.LogDebug("The DB does not contain the required table, we must be in an install state we have no choice but to assume we can acquire"); + _acquireWhenTablesNotAvailable = true; return true; } @@ -225,6 +226,13 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } + // In case we acquired the main dom doing install, there was no database. We therefore has to insert our lockId now, but only handle this once. + if (_acquireWhenTablesNotAvailable) + { + _acquireWhenTablesNotAvailable = false; + InsertLockRecord(_lockId, db); + } + db.BeginTransaction(IsolationLevel.ReadCommitted); // get a read lock _sqlServerSyntax.ReadLock(db, Cms.Core.Constants.Locks.MainDom); @@ -434,7 +442,10 @@ namespace Umbraco.Cms.Infrastructure.Runtime private bool IsMainDomValue(string val, IUmbracoDatabase db) { return db.ExecuteScalar("SELECT COUNT(*) FROM umbracoKeyValue WHERE [key] = @key AND [value] = @val", - new { key = MainDomKey, val = val }) == 1; + new { key = MainDomKey, val = val }) == 1; + + + } /// @@ -447,6 +458,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime #region IDisposable Support private bool _disposedValue = false; // To detect redundant calls + protected virtual void Dispose(bool disposing) { if (!_disposedValue) From b9ec06555f610d41983c184c6a6b1ce49ac66913 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 21 Sep 2021 12:37:23 +0200 Subject: [PATCH 59/73] Update src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs Co-authored-by: Andy Butland --- src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index 5be1d13a7b..c04328c83b 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -226,7 +226,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime } } - // In case we acquired the main dom doing install, there was no database. We therefore has to insert our lockId now, but only handle this once. + // In case we acquired the main dom doing install when there was no database. We therefore have to insert our lockId now, but only handle this once. if (_acquireWhenTablesNotAvailable) { _acquireWhenTablesNotAvailable = false; From 199c8b768128f6dcadf20dabb42b4a88d1b90116 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 21 Sep 2021 12:39:45 +0200 Subject: [PATCH 60/73] Update src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs Co-authored-by: Andy Butland --- src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index c04328c83b..90e5b54785 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -99,7 +99,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime _hasTable = db.HasTable(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue); if (!_hasTable) { - _logger.LogDebug("The DB does not contain the required table, we must be in an install state we have no choice but to assume we can acquire"); + _logger.LogDebug("The DB does not contain the required table so we must be in an install state. We have no choice but to assume we can acquire."); _acquireWhenTablesNotAvailable = true; return true; } From dd85ca6fade611bb6b33411e7e1d8ea9fda26624 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 21 Sep 2021 12:47:02 +0200 Subject: [PATCH 61/73] Update src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs Co-authored-by: Andy Butland --- src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs index 90e5b54785..845a0f506e 100644 --- a/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs @@ -41,6 +41,7 @@ namespace Umbraco.Cms.Infrastructure.Runtime private readonly object _locker = new object(); private bool _hasTable = false; private bool _acquireWhenTablesNotAvailable = false; + public SqlMainDomLock( ILogger logger, ILoggerFactory loggerFactory, From a6afe2bdf3b00dc19a69dff69f7e91bf16ce99ad Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 21 Sep 2021 11:18:34 +0200 Subject: [PATCH 62/73] cherry picked f7b485a --- .../NestedContentController.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/Umbraco.Web/PropertyEditors/NestedContentController.cs diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentController.cs b/src/Umbraco.Web/PropertyEditors/NestedContentController.cs new file mode 100644 index 0000000000..23ca91841c --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/NestedContentController.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Services; +using Umbraco.Web.Editors; +using Umbraco.Web.Mvc; + +namespace Umbraco.Web.PropertyEditors +{ + [PluginController("UmbracoApi")] + public class NestedContentController : UmbracoAuthorizedJsonController + { + [System.Web.Http.HttpGet] + public IEnumerable GetContentTypes() + { + return Services.ContentTypeService + .GetAllElementTypes() + .OrderBy(x => x.SortOrder) + .Select(x => new + { + id = x.Id, + guid = x.Key, + name = x.Name, + alias = x.Alias, + icon = x.Icon, + tabs = x.CompositionPropertyGroups.Where(y => y.Type == Core.Models.PropertyGroupType.Group && !y.Alias.Contains("/")).Select(y => y.Name).Distinct() + }); + } + } +} From de47f95c4fc1e2b692edcb08da75f2be9b9c5784 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 21 Sep 2021 11:19:04 +0200 Subject: [PATCH 63/73] alias is changed. We need to compare with label instead --- .../propertyeditors/nestedcontent/nestedcontent.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js index 64fc40d84d..3510da73a6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/nestedcontent/nestedcontent.controller.js @@ -535,7 +535,7 @@ // remove all tabs except the specified tab var tabs = scaffold.variants[0].tabs; var tab = _.find(tabs, function (tab) { - return tab.id !== 0 && (tab.alias.toLowerCase() === contentType.ncTabAlias.toLowerCase() || contentType.ncTabAlias === ""); + return tab.id !== 0 && (tab.label.toLowerCase() === contentType.ncTabAlias.toLowerCase() || contentType.ncTabAlias === ""); }); scaffold.variants[0].tabs = []; if (tab) { From ae85c959d47fd9839495a5d93fe84688885c16b0 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Tue, 21 Sep 2021 12:01:02 +0200 Subject: [PATCH 64/73] Updated predicate to use GetParentAlias() --- src/Umbraco.Web/PropertyEditors/NestedContentController.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentController.cs b/src/Umbraco.Web/PropertyEditors/NestedContentController.cs index 23ca91841c..71c2217709 100644 --- a/src/Umbraco.Web/PropertyEditors/NestedContentController.cs +++ b/src/Umbraco.Web/PropertyEditors/NestedContentController.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; +using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Web.Editors; using Umbraco.Web.Mvc; @@ -22,7 +23,7 @@ namespace Umbraco.Web.PropertyEditors name = x.Name, alias = x.Alias, icon = x.Icon, - tabs = x.CompositionPropertyGroups.Where(y => y.Type == Core.Models.PropertyGroupType.Group && !y.Alias.Contains("/")).Select(y => y.Name).Distinct() + tabs = x.CompositionPropertyGroups.Where(x => x.Type == PropertyGroupType.Group && x.GetParentAlias() == null).Select(y => y.Name).Distinct() }); } } From a7d60badd3e675fbb31a0de33e8b7fa353cea765 Mon Sep 17 00:00:00 2001 From: Zeegaan <70372949+Zeegaan@users.noreply.github.com> Date: Tue, 21 Sep 2021 13:25:11 +0200 Subject: [PATCH 65/73] fixed NestedContentController to use pattern matching instead of equals operator --- .../NestedContentController.cs | 8 ++--- .../NestedContentController.cs | 30 ------------------- 2 files changed, 3 insertions(+), 35 deletions(-) delete mode 100644 src/Umbraco.Web/PropertyEditors/NestedContentController.cs diff --git a/src/Umbraco.Web.BackOffice/PropertyEditors/NestedContentController.cs b/src/Umbraco.Web.BackOffice/PropertyEditors/NestedContentController.cs index 25d120d807..b975a0114b 100644 --- a/src/Umbraco.Web.BackOffice/PropertyEditors/NestedContentController.cs +++ b/src/Umbraco.Web.BackOffice/PropertyEditors/NestedContentController.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Web.BackOffice.Controllers; using Umbraco.Cms.Web.Common.Attributes; @@ -23,9 +24,7 @@ namespace Umbraco.Cms.Web.BackOffice.PropertyEditors } [HttpGet] - public IEnumerable GetContentTypes() - { - return _contentTypeService + public IEnumerable GetContentTypes() => _contentTypeService .GetAllElementTypes() .OrderBy(x => x.SortOrder) .Select(x => new @@ -35,8 +34,7 @@ namespace Umbraco.Cms.Web.BackOffice.PropertyEditors name = x.Name, alias = x.Alias, icon = x.Icon, - tabs = x.CompositionPropertyGroups.Select(y => y.Name).Distinct() + tabs = x.CompositionPropertyGroups.Where(x => x.Type == PropertyGroupType.Group && x.GetParentAlias() is null).Select(y => y.Name).Distinct() }); - } } } diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentController.cs b/src/Umbraco.Web/PropertyEditors/NestedContentController.cs deleted file mode 100644 index 71c2217709..0000000000 --- a/src/Umbraco.Web/PropertyEditors/NestedContentController.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Models; -using Umbraco.Core.Services; -using Umbraco.Web.Editors; -using Umbraco.Web.Mvc; - -namespace Umbraco.Web.PropertyEditors -{ - [PluginController("UmbracoApi")] - public class NestedContentController : UmbracoAuthorizedJsonController - { - [System.Web.Http.HttpGet] - public IEnumerable GetContentTypes() - { - return Services.ContentTypeService - .GetAllElementTypes() - .OrderBy(x => x.SortOrder) - .Select(x => new - { - id = x.Id, - guid = x.Key, - name = x.Name, - alias = x.Alias, - icon = x.Icon, - tabs = x.CompositionPropertyGroups.Where(x => x.Type == PropertyGroupType.Group && x.GetParentAlias() == null).Select(y => y.Name).Distinct() - }); - } - } -} From 43a33cc1c4808e389e72bb9c362a7276d772fbb9 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 21 Sep 2021 13:27:36 +0200 Subject: [PATCH 66/73] Update Examine dependencies to 2.0.0 --- src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj | 2 +- src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj | 2 +- .../Umbraco.Tests.Integration.SqlCe.csproj | 2 +- .../Umbraco.Tests.Integration.csproj | 2 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj index 8a3c0cbc73..118a895073 100644 --- a/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj +++ b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj @@ -21,7 +21,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj index bb619d0f09..1d2f8bc505 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -50,7 +50,7 @@ - + all diff --git a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj index 486e816c3f..a1f6ecd78d 100644 --- a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj +++ b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Tests.Integration.SqlCe.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj index 2ca6d78c84..89012e7d6c 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj +++ b/src/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj @@ -74,7 +74,7 @@ - + diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 53f42555a4..1daa6c2395 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -83,10 +83,10 @@ - 2.0.0-alpha.20200128.15 + 2.0.0 - + 1.11.31 From d1207148a84a12a2a7dc131a020e454b4781458a Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Tue, 21 Sep 2021 13:29:00 +0200 Subject: [PATCH 67/73] Update package definition with all installed file paths (stylesheets, scripts, partial views) --- .../Packaging/PackageInstallation.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs index e09bdf3e18..0af21b7eb2 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageInstallation.cs @@ -41,7 +41,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging InstallationSummary installationSummary = _packageDataInstallation.InstallPackageData(compiledPackage, userId); - //make sure the definition is up to date with everything + // Make sure the definition is up to date with everything (note: macro partial views are embedded in macros) foreach (var x in installationSummary.DataTypesInstalled) packageDefinition.DataTypes.Add(x.Id.ToInvariantString()); @@ -63,6 +63,15 @@ namespace Umbraco.Cms.Infrastructure.Packaging foreach (var x in installationSummary.MediaTypesInstalled) packageDefinition.MediaTypes.Add(x.Id.ToInvariantString()); + foreach (var x in installationSummary.StylesheetsInstalled) + packageDefinition.Stylesheets.Add(x.Path); + + foreach (var x in installationSummary.ScriptsInstalled) + packageDefinition.Scripts.Add(x.Path); + + foreach (var x in installationSummary.PartialViewsInstalled) + packageDefinition.PartialViews.Add(x.Path); + packageDefinition.ContentNodeId = installationSummary.ContentInstalled.FirstOrDefault()?.Id.ToInvariantString(); foreach (var x in installationSummary.MediaInstalled) From fd67e19bc8c58f5439ee7435a3de9170a737a56d Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Tue, 21 Sep 2021 13:56:37 +0200 Subject: [PATCH 68/73] Fix ambiguous reference in IPublishedContentQuery --- .../IPublishedContentQuery.cs | 22 ------------------- .../PublishedContentQuery.cs | 5 ----- 2 files changed, 27 deletions(-) diff --git a/src/Umbraco.Infrastructure/IPublishedContentQuery.cs b/src/Umbraco.Infrastructure/IPublishedContentQuery.cs index 24bd7ba44c..77ca873638 100644 --- a/src/Umbraco.Infrastructure/IPublishedContentQuery.cs +++ b/src/Umbraco.Infrastructure/IPublishedContentQuery.cs @@ -77,28 +77,6 @@ namespace Umbraco.Cms.Core /// IEnumerable Search(string term, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName); - /// - /// Searches content. - /// - /// The term to search. - /// The amount of results to skip. - /// The amount of results to take/return. - /// The total amount of records. - /// The culture (defaults to a culture insensitive search). - /// The name of the index to search (defaults to ). - /// - /// The search results. - /// - /// - /// - /// When the is not specified or is *, all cultures are searched. - /// To search for only invariant documents and fields use null. - /// When searching on a specific culture, all culture specific fields are searched for the provided culture and all invariant fields for all documents. - /// - /// While enumerating results, the ambient culture is changed to be the searched culture. - /// - IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName); - /// /// Executes the query and converts the results to . /// diff --git a/src/Umbraco.Infrastructure/PublishedContentQuery.cs b/src/Umbraco.Infrastructure/PublishedContentQuery.cs index 946f501b1f..e149e092d8 100644 --- a/src/Umbraco.Infrastructure/PublishedContentQuery.cs +++ b/src/Umbraco.Infrastructure/PublishedContentQuery.cs @@ -234,11 +234,6 @@ namespace Umbraco.Cms.Infrastructure string indexName = Constants.UmbracoIndexes.ExternalIndexName) => Search(term, 0, 0, out _, culture, indexName); - /// - public IEnumerable Search(string term, int skip, int take, out long totalRecords, - string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName) - => Search(term, skip, take, out totalRecords, culture, indexName, null); - /// public IEnumerable Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = Constants.UmbracoIndexes.ExternalIndexName, ISet loadedFields = null) { From 4a1dffcd24bfa5a5f8b87fd4db3634673c4d4d9d Mon Sep 17 00:00:00 2001 From: Zeegaan <70372949+Zeegaan@users.noreply.github.com> Date: Tue, 21 Sep 2021 15:37:46 +0200 Subject: [PATCH 69/73] Update tabs.ts --- .../cypress/integration/Tabs/tabs.ts | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts index 3daf907c99..77729912a6 100644 --- a/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts +++ b/src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tabs/tabs.ts @@ -379,7 +379,12 @@ context('Tabs', () => { cy.saveDocumentType(tabsDocType); OpenDocTypeFolder(); cy.get('[alias="reorder"]').click(); - cy.get('.umb-group-builder__tabs-overflow--right > .caret').click().click(); + cy.get('body') + .then(($body) => { + while($body.find('.umb-group-builder__tabs-overflow--right > .caret').hasClass('active')){ + cy.click(); + } + }); cy.get('.umb-group-builder__tab').last().click(); cy.get('.umb-group-builder__group-title-icon').last().trigger('mousedown', { which: 1 }) cy.get('.umb-group-builder__tab').eq(1).trigger('mousemove', {which: 1, force: true}); @@ -426,7 +431,12 @@ context('Tabs', () => { OpenDocTypeFolder(); cy.get('[alias="reorder"]').click(); //Scroll right so we can see tab 2 - cy.get('.umb-group-builder__tabs-overflow--right > .caret').click().click(); + cy.get('body') + .then(($body) => { + while($body.find('.umb-group-builder__tabs-overflow--right > .caret').hasClass('active')){ + cy.click(); + } + }); cy.get('.umb-group-builder__tab-title-icon').eq(1).trigger('mousedown', { which: 1 }) cy.get('.umb-group-builder__tab').eq(1).trigger('mousemove', {which: 1, force: true}); cy.get('.umb-group-builder__tab').eq(1).should('have.class', 'is-active').trigger('mouseup', {force:true}); @@ -473,7 +483,12 @@ context('Tabs', () => { OpenDocTypeFolder(); cy.get('[alias="reorder"]').click(); //Scroll so we are sure we see tab 2 - cy.get('.umb-group-builder__tabs-overflow--right > .caret').click().click(); + cy.get('body') + .then(($body) => { + while($body.find('.umb-group-builder__tabs-overflow--right > .caret').hasClass('active')){ + cy.click(); + } + }); //Navigate to tab 2 cy.get('.umb-group-builder__tab').last().click(); cy.get('.umb-group-builder__property-meta > .flex > .icon').eq(1).trigger('mousedown', {which: 1}) From 65cfc14cdbc63a11597836cde17ba0acb1b5d029 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 21 Sep 2021 08:56:10 -0600 Subject: [PATCH 70/73] Fixes persisting the IsApproved for users --- src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs index 0930b510f3..e656e68193 100644 --- a/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs @@ -482,6 +482,12 @@ namespace Umbraco.Cms.Core.Security user.FailedPasswordAttempts = identityUser.AccessFailedCount; } + if (user.IsApproved != identityUser.IsApproved) + { + anythingChanged = true; + user.IsApproved = identityUser.IsApproved; + } + if (user.IsLockedOut != identityUser.IsLockedOut) { anythingChanged = true; From cbafef2f03d9a5e0be081bd61f879aac18e7171f Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 21 Sep 2021 09:21:28 -0600 Subject: [PATCH 71/73] Adds user store test --- .../Security/BackOfficeUserStoreTests.cs | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Security/BackOfficeUserStoreTests.cs diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Security/BackOfficeUserStoreTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Security/BackOfficeUserStoreTests.cs new file mode 100644 index 0000000000..665bb2f079 --- /dev/null +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Security/BackOfficeUserStoreTests.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Mapping; +using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Security; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Security +{ + [TestFixture] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] + public class BackOfficeUserStoreTests : UmbracoIntegrationTest + { + private IUserService UserService => GetRequiredService(); + private IEntityService EntityService => GetRequiredService(); + private IExternalLoginService ExternalLoginService => GetRequiredService(); + private IUmbracoMapper UmbracoMapper => GetRequiredService(); + private ILocalizedTextService TextService => GetRequiredService(); + + private BackOfficeUserStore GetUserStore() + => new BackOfficeUserStore( + ScopeProvider, + UserService, + EntityService, + ExternalLoginService, + Options.Create(GlobalSettings), + UmbracoMapper, + new BackOfficeErrorDescriber(TextService), + AppCaches); + + [Test] + public async Task Can_Persist_Is_Approved() + { + var userStore = GetUserStore(); + var user = new BackOfficeIdentityUser(GlobalSettings, 1, new List()) + { + Name = "Test", + Email = "test@test.com", + UserName = "test@test.com" + }; + IdentityResult createResult = await userStore.CreateAsync(user); + Assert.IsTrue(createResult.Succeeded); + Assert.IsFalse(user.IsApproved); + + // update + user.IsApproved = true; + var saveResult = await userStore.UpdateAsync(user); + Assert.IsTrue(saveResult.Succeeded); + Assert.IsTrue(user.IsApproved); + + // get get + user = await userStore.FindByIdAsync(user.Id); + Assert.IsTrue(user.IsApproved); + } + } +} From 80386db368182b055bff8973d897ab73c537cbaf Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 21 Sep 2021 17:47:16 +0200 Subject: [PATCH 72/73] Fixes #11150 V9: MediaPicker3 casing incorrect --- src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs b/src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs index 7fa2753be9..87e097883f 100644 --- a/src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs +++ b/src/Umbraco.Core/PropertyEditors/MediaPicker3Configuration.cs @@ -39,7 +39,7 @@ namespace Umbraco.Cms.Core.PropertyEditors [ConfigurationField("enableLocalFocalPoint", "Enable Focal Point", "boolean")] public bool EnableLocalFocalPoint { get; set; } - [ConfigurationField("crops", "Image Crops", "views/propertyeditors/MediaPicker3/prevalue/mediapicker3.crops.html", Description = "Local crops, stored on document")] + [ConfigurationField("crops", "Image Crops", "views/propertyeditors/mediapicker3/prevalue/mediapicker3.crops.html", Description = "Local crops, stored on document")] public CropConfiguration[] Crops { get; set; } [DataContract] From c4fdf808d362d2face254e9982de36eec0de117a Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 21 Sep 2021 10:49:45 -0600 Subject: [PATCH 73/73] Fixes 10730 - Route hijacking with public access --- .../UmbracoRouteValueTransformerTests.cs | 27 ++++++++++- .../UmbracoBuilderExtensions.cs | 4 +- .../UmbracoApplicationBuilder.Website.cs | 2 - .../Routing/IPublicAccessRequestHandler.cs | 18 ++++++++ .../PublicAccessRequestHandler.cs} | 46 ++++++------------- .../Routing/UmbracoRouteValueTransformer.cs | 32 +++++++------ 6 files changed, 76 insertions(+), 53 deletions(-) create mode 100644 src/Umbraco.Web.Website/Routing/IPublicAccessRequestHandler.cs rename src/Umbraco.Web.Website/{Middleware/PublicAccessMiddleware.cs => Routing/PublicAccessRequestHandler.cs} (77%) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs index d00f85fd0a..11a2423051 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformerTests.cs @@ -48,6 +48,10 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing IPublishedRouter router = null, IUmbracoRouteValuesFactory routeValuesFactory = null) { + var publicAccessRequestHandler = new Mock(); + publicAccessRequestHandler.Setup(x => x.RewriteForPublishedContentAccessAsync(It.IsAny(), It.IsAny())) + .Returns((HttpContext ctx, UmbracoRouteValues routeVals) => Task.FromResult(routeVals)); + var transformer = new UmbracoRouteValueTransformer( new NullLogger(), ctx, @@ -59,7 +63,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing filter ?? Mock.Of(x => x.IsDocumentRequest(It.IsAny()) == true), Mock.Of(), Mock.Of(), - Mock.Of()); + Mock.Of(), + publicAccessRequestHandler.Object); return transformer; } @@ -155,7 +160,7 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing } [Test] - public async Task Assigns_UmbracoRouteValues_To_HttpContext_Feature() + public async Task Null_When_No_Content_On_PublishedRequest() { IUmbracoContext umbracoContext = GetUmbracoContext(true); IPublishedRequest request = Mock.Of(); @@ -168,6 +173,24 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Website.Routing var httpContext = new DefaultHttpContext(); RouteValueDictionary result = await transformer.TransformAsync(httpContext, new RouteValueDictionary()); + UmbracoRouteValues routeVals = httpContext.Features.Get(); + Assert.IsNull(routeVals); + } + + [Test] + public async Task Assigns_UmbracoRouteValues_To_HttpContext_Feature() + { + IUmbracoContext umbracoContext = GetUmbracoContext(true); + IPublishedRequest request = Mock.Of(x => x.PublishedContent == Mock.Of()); + + UmbracoRouteValueTransformer transformer = GetTransformerWithRunState( + Mock.Of(x => x.TryGetUmbracoContext(out umbracoContext)), + router: GetRouter(request), + routeValuesFactory: GetRouteValuesFactory(request)); + + var httpContext = new DefaultHttpContext(); + RouteValueDictionary result = await transformer.TransformAsync(httpContext, new RouteValueDictionary()); + UmbracoRouteValues routeVals = httpContext.Features.Get(); Assert.IsNotNull(routeVals); Assert.AreEqual(routeVals.PublishedRequest, umbracoContext.PublishedRequest); diff --git a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs index 72d8ec58ce..797a4b2202 100644 --- a/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Website/DependencyInjection/UmbracoBuilderExtensions.cs @@ -8,8 +8,6 @@ using Umbraco.Cms.Infrastructure.DependencyInjection; using Umbraco.Cms.Web.Common.Middleware; using Umbraco.Cms.Web.Common.Routing; using Umbraco.Cms.Web.Website.Collections; -using Umbraco.Cms.Web.Website.Controllers; -using Umbraco.Cms.Web.Website.Middleware; using Umbraco.Cms.Web.Website.Models; using Umbraco.Cms.Web.Website.Routing; using Umbraco.Cms.Web.Website.ViewEngines; @@ -51,7 +49,7 @@ namespace Umbraco.Extensions builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoApplicationBuilder.Website.cs b/src/Umbraco.Web.Website/Extensions/UmbracoApplicationBuilder.Website.cs index c549609397..33d42e07c9 100644 --- a/src/Umbraco.Web.Website/Extensions/UmbracoApplicationBuilder.Website.cs +++ b/src/Umbraco.Web.Website/Extensions/UmbracoApplicationBuilder.Website.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Web.Common.ApplicationBuilder; using Umbraco.Cms.Web.Common.Middleware; -using Umbraco.Cms.Web.Website.Middleware; using Umbraco.Cms.Web.Website.Routing; namespace Umbraco.Extensions @@ -20,7 +19,6 @@ namespace Umbraco.Extensions /// public static IUmbracoApplicationBuilderContext UseWebsite(this IUmbracoApplicationBuilderContext builder) { - builder.AppBuilder.UseMiddleware(); builder.AppBuilder.UseMiddleware(); return builder; } diff --git a/src/Umbraco.Web.Website/Routing/IPublicAccessRequestHandler.cs b/src/Umbraco.Web.Website/Routing/IPublicAccessRequestHandler.cs new file mode 100644 index 0000000000..0ce3ddad92 --- /dev/null +++ b/src/Umbraco.Web.Website/Routing/IPublicAccessRequestHandler.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Umbraco.Cms.Web.Common.Routing; + +namespace Umbraco.Cms.Web.Website.Routing +{ + public interface IPublicAccessRequestHandler + { + /// + /// Ensures that access to current node is permitted. + /// + /// + /// The current route values + /// Updated route values if public access changes the rendered content, else the original route values. + /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. + Task RewriteForPublishedContentAccessAsync(HttpContext httpContext, UmbracoRouteValues routeValues); + } +} diff --git a/src/Umbraco.Web.Website/Middleware/PublicAccessMiddleware.cs b/src/Umbraco.Web.Website/Routing/PublicAccessRequestHandler.cs similarity index 77% rename from src/Umbraco.Web.Website/Middleware/PublicAccessMiddleware.cs rename to src/Umbraco.Web.Website/Routing/PublicAccessRequestHandler.cs index 8bbb4e13e4..88bb6622bd 100644 --- a/src/Umbraco.Web.Website/Middleware/PublicAccessMiddleware.cs +++ b/src/Umbraco.Web.Website/Routing/PublicAccessRequestHandler.cs @@ -10,22 +10,21 @@ using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Web.Common.Routing; -using Umbraco.Cms.Web.Website.Routing; using Umbraco.Extensions; -namespace Umbraco.Cms.Web.Website.Middleware +namespace Umbraco.Cms.Web.Website.Routing { - public class PublicAccessMiddleware : IMiddleware + public class PublicAccessRequestHandler : IPublicAccessRequestHandler { - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IPublicAccessService _publicAccessService; private readonly IPublicAccessChecker _publicAccessChecker; private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IUmbracoRouteValuesFactory _umbracoRouteValuesFactory; private readonly IPublishedRouter _publishedRouter; - public PublicAccessMiddleware( - ILogger logger, + public PublicAccessRequestHandler( + ILogger logger, IPublicAccessService publicAccessService, IPublicAccessChecker publicAccessChecker, IUmbracoContextAccessor umbracoContextAccessor, @@ -40,23 +39,8 @@ namespace Umbraco.Cms.Web.Website.Middleware _publishedRouter = publishedRouter; } - public async Task InvokeAsync(HttpContext context, RequestDelegate next) - { - UmbracoRouteValues umbracoRouteValues = context.Features.Get(); - - if (umbracoRouteValues != null) - { - await EnsurePublishedContentAccess(context, umbracoRouteValues); - } - - await next(context); - } - - /// - /// Ensures that access to current node is permitted. - /// - /// Redirecting to a different site root and/or culture will not pick the new site root nor the new culture. - private async Task EnsurePublishedContentAccess(HttpContext httpContext, UmbracoRouteValues routeValues) + /// + public async Task RewriteForPublishedContentAccessAsync(HttpContext httpContext, UmbracoRouteValues routeValues) { // because these might loop, we have to have some sort of infinite loop detection int i = 0; @@ -64,13 +48,13 @@ namespace Umbraco.Cms.Web.Website.Middleware PublicAccessStatus publicAccessStatus = PublicAccessStatus.AccessAccepted; do { - _logger.LogDebug(nameof(EnsurePublishedContentAccess) + ": Loop {LoopCounter}", i); + _logger.LogDebug(nameof(RewriteForPublishedContentAccessAsync) + ": Loop {LoopCounter}", i); IPublishedContent publishedContent = routeValues.PublishedRequest?.PublishedContent; if (publishedContent == null) { - return; + return routeValues; } var path = publishedContent.Path; @@ -117,8 +101,10 @@ namespace Umbraco.Cms.Web.Website.Middleware if (i == maxLoop) { - _logger.LogDebug(nameof(EnsurePublishedContentAccess) + ": Looks like we are running into an infinite loop, abort"); + _logger.LogDebug(nameof(RewriteForPublishedContentAccessAsync) + ": Looks like we are running into an infinite loop, abort"); } + + return routeValues; } @@ -139,17 +125,11 @@ namespace Umbraco.Cms.Web.Website.Middleware // we need to change the content item that is getting rendered so we have to re-create UmbracoRouteValues. UmbracoRouteValues updatedRouteValues = await _umbracoRouteValuesFactory.CreateAsync(httpContext, reRouted); - // Update the feature - httpContext.Features.Set(updatedRouteValues); - return updatedRouteValues; } else { - _logger.LogWarning("Public Access rule has a redirect node set to itself, nothing can be routed."); - // Update the feature to nothing - cannot continue - httpContext.Features.Set(null); - return null; + throw new InvalidOperationException("Public Access rule has a redirect node set to itself, nothing can be routed."); } } } diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs index fc54350097..0bca8d7215 100644 --- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -52,6 +52,7 @@ namespace Umbraco.Cms.Web.Website.Routing private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IControllerActionSearcher _controllerActionSearcher; private readonly IEventAggregator _eventAggregator; + private readonly IPublicAccessRequestHandler _publicAccessRequestHandler; /// /// Initializes a new instance of the class. @@ -67,7 +68,8 @@ namespace Umbraco.Cms.Web.Website.Routing IRoutableDocumentFilter routableDocumentFilter, IDataProtectionProvider dataProtectionProvider, IControllerActionSearcher controllerActionSearcher, - IEventAggregator eventAggregator) + IEventAggregator eventAggregator, + IPublicAccessRequestHandler publicAccessRequestHandler) { if (globalSettings is null) { @@ -85,6 +87,7 @@ namespace Umbraco.Cms.Web.Website.Routing _dataProtectionProvider = dataProtectionProvider; _controllerActionSearcher = controllerActionSearcher; _eventAggregator = eventAggregator; + _publicAccessRequestHandler = publicAccessRequestHandler; } /// @@ -125,20 +128,10 @@ namespace Umbraco.Cms.Web.Website.Routing }; } - IPublishedRequest publishedRequest = await RouteRequestAsync(httpContext, umbracoContext); + IPublishedRequest publishedRequest = await RouteRequestAsync(umbracoContext); umbracoRouteValues = await _routeValuesFactory.CreateAsync(httpContext, publishedRequest); - // Store the route values as a httpcontext feature - httpContext.Features.Set(umbracoRouteValues); - - // Need to check if there is form data being posted back to an Umbraco URL - PostedDataProxyInfo postedInfo = GetFormInfo(httpContext, values); - if (postedInfo != null) - { - return HandlePostedValues(postedInfo, httpContext); - } - if (!umbracoRouteValues?.PublishedRequest?.HasPublishedContent() ?? false) { // No content was found, not by any registered 404 handlers and @@ -149,6 +142,19 @@ namespace Umbraco.Cms.Web.Website.Routing return null; } + // now we need to do some public access checks + umbracoRouteValues = await _publicAccessRequestHandler.RewriteForPublishedContentAccessAsync(httpContext, umbracoRouteValues); + + // Store the route values as a httpcontext feature + httpContext.Features.Set(umbracoRouteValues); + + // Need to check if there is form data being posted back to an Umbraco URL + PostedDataProxyInfo postedInfo = GetFormInfo(httpContext, values); + if (postedInfo != null) + { + return HandlePostedValues(postedInfo, httpContext); + } + // See https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.routing.dynamicroutevaluetransformer.transformasync?view=aspnetcore-5.0#Microsoft_AspNetCore_Mvc_Routing_DynamicRouteValueTransformer_TransformAsync_Microsoft_AspNetCore_Http_HttpContext_Microsoft_AspNetCore_Routing_RouteValueDictionary_ // We should apparenlty not be modified these values. // So we create new ones. @@ -164,7 +170,7 @@ namespace Umbraco.Cms.Web.Website.Routing return newValues; } - private async Task RouteRequestAsync(HttpContext httpContext, IUmbracoContext umbracoContext) + private async Task RouteRequestAsync(IUmbracoContext umbracoContext) { // ok, process