diff --git a/src/Umbraco.Core/Deploy/IFileSource.cs b/src/Umbraco.Core/Deploy/IFileSource.cs index ed169b9df5..e56f9a715e 100644 --- a/src/Umbraco.Core/Deploy/IFileSource.cs +++ b/src/Umbraco.Core/Deploy/IFileSource.cs @@ -68,18 +68,24 @@ public interface IFileSource /// A collection of file types which can store the files. void GetFiles(IEnumerable udis, IFileTypeCollection fileTypes); + // TODO (V14): Remove obsolete method and default implementation for GetFilesAsync overloads. + /// /// Gets files and store them using a file store. /// /// The udis of the files to get. /// A collection of file types which can store the files. /// A cancellation token. + [Obsolete("Please use the method overload taking all parameters. This method overload will be removed in Umbraco 14.")] Task GetFilesAsync(IEnumerable udis, IFileTypeCollection fileTypes, CancellationToken token); - ///// - ///// Gets the content of a file as a bytes array. - ///// - ///// A file entity identifier. - ///// A byte array containing the file content. - // byte[] GetFileBytes(StringUdi Udi); + /// + /// Gets files and store them using a file store. + /// + /// The udis of the files to get. + /// A collection of file types which can store the files. + /// A flag indicating whether to continue if a file isn't found or to stop and throw a FileNotFoundException. + /// A cancellation token. + Task GetFilesAsync(IEnumerable udis, IFileTypeCollection fileTypes, bool continueOnFileNotFound, CancellationToken token) + => GetFilesAsync(udis, fileTypes, token); } diff --git a/src/Umbraco.Core/Routing/IRedirectTracker.cs b/src/Umbraco.Core/Routing/IRedirectTracker.cs new file mode 100644 index 0000000000..2b0c8649a9 --- /dev/null +++ b/src/Umbraco.Core/Routing/IRedirectTracker.cs @@ -0,0 +1,23 @@ +using Umbraco.Cms.Core.Models; + +namespace Umbraco.Cms.Core.Routing +{ + /// + /// Determines and records redirects for a content item following an update that may change it's public URL. + /// + public interface IRedirectTracker + { + /// + /// Stores the existing routes for a content item before update. + /// + /// The content entity updated. + /// The dictionary of routes for population. + void StoreOldRoute(IContent entity, Dictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)> oldRoutes); + + /// + /// Creates appropriate redirects for the content item following an update. + /// + /// The populated dictionary of old routes; + void CreateRedirects(IDictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)> oldRoutes); + } +} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index 3e12664f03..1c21352af2 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -52,6 +52,7 @@ using Umbraco.Cms.Infrastructure.Migrations.PostMigrations; using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_0_0.DataTypes; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Persistence.Mappers; +using Umbraco.Cms.Infrastructure.Routing; using Umbraco.Cms.Infrastructure.Runtime; using Umbraco.Cms.Infrastructure.Runtime.RuntimeModeValidators; using Umbraco.Cms.Infrastructure.Scoping; @@ -216,6 +217,9 @@ public static partial class UmbracoBuilderExtensions builder.Services.AddSingleton(); builder.Services.AddTransient(); + + builder.Services.AddSingleton(); + builder.AddInstaller(); // Services required to run background jobs (with out the handler) diff --git a/src/Umbraco.Infrastructure/Routing/RedirectTracker.cs b/src/Umbraco.Infrastructure/Routing/RedirectTracker.cs new file mode 100644 index 0000000000..a1247313d2 --- /dev/null +++ b/src/Umbraco.Infrastructure/Routing/RedirectTracker.cs @@ -0,0 +1,125 @@ +using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Infrastructure.Routing +{ + internal class RedirectTracker : IRedirectTracker + { + private readonly IUmbracoContextFactory _umbracoContextFactory; + private readonly IVariationContextAccessor _variationContextAccessor; + private readonly ILocalizationService _localizationService; + private readonly IRedirectUrlService _redirectUrlService; + private readonly ILogger _logger; + + public RedirectTracker( + IUmbracoContextFactory umbracoContextFactory, + IVariationContextAccessor variationContextAccessor, + ILocalizationService localizationService, + IRedirectUrlService redirectUrlService, + ILogger logger) + { + _umbracoContextFactory = umbracoContextFactory; + _variationContextAccessor = variationContextAccessor; + _localizationService = localizationService; + _redirectUrlService = redirectUrlService; + _logger = logger; + } + + /// + public void StoreOldRoute(IContent entity, Dictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)> oldRoutes) + { + using UmbracoContextReference reference = _umbracoContextFactory.EnsureUmbracoContext(); + IPublishedContentCache? contentCache = reference.UmbracoContext.Content; + IPublishedContent? entityContent = contentCache?.GetById(entity.Id); + if (entityContent is null) + { + return; + } + + // Get the default affected cultures by going up the tree until we find the first culture variant entity (default to no cultures) + var defaultCultures = new Lazy(() => entityContent.AncestorsOrSelf().FirstOrDefault(a => a.Cultures.Any())?.Cultures.Keys.ToArray() ?? Array.Empty()); + + // Get all language ISO codes (in case we're dealing with invariant content with variant ancestors) + var languageIsoCodes = new Lazy(() => _localizationService.GetAllLanguages().Select(x => x.IsoCode).ToArray()); + + foreach (IPublishedContent publishedContent in entityContent.DescendantsOrSelf(_variationContextAccessor)) + { + // If this entity defines specific cultures, use those instead of the default ones + IEnumerable cultures = publishedContent.Cultures.Any() ? publishedContent.Cultures.Keys : defaultCultures.Value; + + foreach (var culture in cultures) + { + try + { + var route = contentCache?.GetRouteById(publishedContent.Id, culture); + if (IsValidRoute(route)) + { + oldRoutes[(publishedContent.Id, culture)] = (publishedContent.Key, route); + } + else if (string.IsNullOrEmpty(culture)) + { + // Retry using all languages, if this is invariant but has a variant ancestor. + foreach (string languageIsoCode in languageIsoCodes.Value) + { + route = contentCache?.GetRouteById(publishedContent.Id, languageIsoCode); + if (IsValidRoute(route)) + { + oldRoutes[(publishedContent.Id, languageIsoCode)] = (publishedContent.Key, route); + } + } + } + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Could not register redirects because the old route couldn't be retrieved for content ID {ContentId} and culture '{Culture}'.", publishedContent.Id, culture); + } + } + } + } + + /// + public void CreateRedirects(IDictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)> oldRoutes) + { + if (!oldRoutes.Any()) + { + return; + } + + using UmbracoContextReference reference = _umbracoContextFactory.EnsureUmbracoContext(); + IPublishedContentCache? contentCache = reference.UmbracoContext.Content; + if (contentCache == null) + { + _logger.LogWarning("Could not track redirects because there is no published content cache available on the current published snapshot."); + return; + } + + foreach (((int contentId, string culture), (Guid contentKey, string oldRoute)) in oldRoutes) + { + try + { + var newRoute = contentCache.GetRouteById(contentId, culture); + if (!IsValidRoute(newRoute) || oldRoute == newRoute) + { + continue; + } + + _redirectUrlService.Register(oldRoute, contentKey, culture); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Could not track redirects because the new route couldn't be retrieved for content ID {ContentId} and culture '{Culture}'.", contentId, culture); + } + } + } + + private static bool IsValidRoute([NotNullWhen(true)] string? route) => route is not null && !route.StartsWith("err/"); + } +} diff --git a/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs b/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs index 0e4ad2e9c6..c2bb444e2c 100644 --- a/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs +++ b/src/Umbraco.Infrastructure/Routing/RedirectTrackingHandler.cs @@ -1,17 +1,11 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Notifications; -using Umbraco.Cms.Core.PublishedCache; -using Umbraco.Cms.Core.Services; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Routing; @@ -30,44 +24,17 @@ public sealed class RedirectTrackingHandler : INotificationHandler { private const string NotificationStateKey = "Umbraco.Cms.Core.Routing.RedirectTrackingHandler"; - private readonly ILogger _logger; - private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - private readonly IRedirectUrlService _redirectUrlService; - private readonly IVariationContextAccessor _variationContextAccessor;private readonly ILocalizationService _localizationService; + private readonly IOptionsMonitor _webRoutingSettings; + private readonly IRedirectTracker _redirectTracker; public RedirectTrackingHandler( - ILogger logger, IOptionsMonitor webRoutingSettings, - IPublishedSnapshotAccessor publishedSnapshotAccessor, - IRedirectUrlService redirectUrlService, - IVariationContextAccessor variationContextAccessor, - ILocalizationService localizationService){ - _logger = logger; + IRedirectTracker redirectTracker) + { _webRoutingSettings = webRoutingSettings; - _publishedSnapshotAccessor = publishedSnapshotAccessor; - _redirectUrlService = redirectUrlService; - _variationContextAccessor = variationContextAccessor; - _localizationService = localizationService; - } - - [Obsolete("Use ctor with all params")] - public RedirectTrackingHandler( - ILogger logger, - IOptionsMonitor webRoutingSettings, - IPublishedSnapshotAccessor publishedSnapshotAccessor, - IRedirectUrlService redirectUrlService, - IVariationContextAccessor variationContextAccessor) - :this( - logger, - webRoutingSettings, - publishedSnapshotAccessor, - redirectUrlService, - variationContextAccessor, - StaticServiceProvider.Instance.GetRequiredService()) - { - - } + _redirectTracker = redirectTracker; + } public void Handle(ContentMovedNotification notification) => CreateRedirectsForOldRoutes(notification); @@ -79,150 +46,40 @@ public sealed class RedirectTrackingHandler : public void Handle(ContentPublishingNotification notification) => StoreOldRoutes(notification.PublishedEntities, notification); - private static bool IsNotRoute(string? route) => - - // null if content not found - // err/- if collision or anomaly or ... - route == null || route.StartsWith("err/"); - private void StoreOldRoutes(IEnumerable entities, IStatefulNotification notification) { - // don't let the notification handlers kick in if Redirect Tracking is turned off in the config + // Don't let the notification handlers kick in if redirect tracking is turned off in the config. if (_webRoutingSettings.CurrentValue.DisableRedirectUrlTracking) { return; } - OldRoutesDictionary oldRoutes = GetOldRoutes(notification); + Dictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)> oldRoutes = GetOldRoutes(notification); foreach (IContent entity in entities) { - StoreOldRoute(entity, oldRoutes); + _redirectTracker.StoreOldRoute(entity, oldRoutes); } } private void CreateRedirectsForOldRoutes(IStatefulNotification notification) { - // don't let the notification handlers kick in if Redirect Tracking is turned off in the config + // Don't let the notification handlers kick in if redirect tracking is turned off in the config. if (_webRoutingSettings.CurrentValue.DisableRedirectUrlTracking) { return; } - OldRoutesDictionary oldRoutes = GetOldRoutes(notification); - CreateRedirects(oldRoutes); + Dictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)> oldRoutes = GetOldRoutes(notification); + _redirectTracker.CreateRedirects(oldRoutes); } - private OldRoutesDictionary GetOldRoutes(IStatefulNotification notification) + private Dictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)> GetOldRoutes(IStatefulNotification notification) { if (notification.State.ContainsKey(NotificationStateKey) == false) { - notification.State[NotificationStateKey] = new OldRoutesDictionary(); + notification.State[NotificationStateKey] = new Dictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)>(); } - return (OldRoutesDictionary?)notification.State[NotificationStateKey] ?? new OldRoutesDictionary(); - } - - private void StoreOldRoute(IContent entity, OldRoutesDictionary oldRoutes) - { - if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot)) - { - return; - } - - IPublishedContentCache? contentCache = publishedSnapshot?.Content; - IPublishedContent? entityContent = contentCache?.GetById(entity.Id); - if (entityContent is null) - { - return; - } - - // get the default affected cultures by going up the tree until we find the first culture variant entity (default to no cultures) - var defaultCultures = entityContent.AncestorsOrSelf().FirstOrDefault(a => a.Cultures.Any())?.Cultures.Keys - .ToArray() - ?? Array.Empty(); - - foreach (IPublishedContent publishedContent in entityContent.DescendantsOrSelf(_variationContextAccessor)) - { - // if this entity defines specific cultures, use those instead of the default ones - IEnumerable cultures = - publishedContent.Cultures.Any() ? publishedContent.Cultures.Keys : defaultCultures; - - foreach (var culture in cultures) - { - var route = contentCache?.GetRouteById(publishedContent.Id, culture); - if (!IsNotRoute(route)) - { - oldRoutes[new ContentIdAndCulture(publishedContent.Id, culture)] = new ContentKeyAndOldRoute(publishedContent.Key, route!); - } - else if (string.IsNullOrEmpty(culture)) - { - // Retry using all languages, if this is invariant but has a variant ancestor - var languages = _localizationService.GetAllLanguages(); - foreach (var language in languages) - { - route = contentCache?.GetRouteById(publishedContent.Id, language.IsoCode); - if (!IsNotRoute(route)) - { - oldRoutes[new ContentIdAndCulture(publishedContent.Id, language.IsoCode)] = - new ContentKeyAndOldRoute(publishedContent.Key, route!); - } - } - }} - } - } - - private void CreateRedirects(OldRoutesDictionary oldRoutes) - { - if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot)) - { - return; - } - - IPublishedContentCache? contentCache = publishedSnapshot?.Content; - - if (contentCache == null) - { - _logger.LogWarning("Could not track redirects because there is no current published snapshot available."); - return; - } - - foreach (KeyValuePair oldRoute in oldRoutes) - { - var newRoute = contentCache.GetRouteById(oldRoute.Key.ContentId, oldRoute.Key.Culture); - if (IsNotRoute(newRoute) || oldRoute.Value.OldRoute == newRoute) - { - continue; - } - - _redirectUrlService.Register(oldRoute.Value.OldRoute, oldRoute.Value.ContentKey, oldRoute.Key.Culture); - } - } - - private class ContentIdAndCulture : Tuple - { - public ContentIdAndCulture(int contentId, string culture) - : base(contentId, culture) - { - } - - public int ContentId => Item1; - - public string Culture => Item2; - } - - private class ContentKeyAndOldRoute : Tuple - { - public ContentKeyAndOldRoute(Guid contentKey, string oldRoute) - : base(contentKey, oldRoute) - { - } - - public Guid ContentKey => Item1; - - public string OldRoute => Item2; - } - - private class OldRoutesDictionary : Dictionary - { + return (Dictionary<(int ContentId, string Culture), (Guid ContentKey, string OldRoute)>?)notification.State[NotificationStateKey]!; } } diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index aa65c3e335..ddcc167622 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -7,7 +7,7 @@ "name": "ui", "dependencies": { "@microsoft/signalr": "7.0.12", - "ace-builds": "1.30.0", + "ace-builds": "1.31.0", "angular": "1.8.3", "angular-animate": "1.8.3", "angular-aria": "1.8.3", @@ -47,7 +47,7 @@ "@babel/preset-env": "7.21.5", "autoprefixer": "10.4.16", "cssnano": "6.0.1", - "eslint": "8.51.0", + "eslint": "8.52.0", "gulp": "4.0.2", "gulp-angular-embed-templates": "2.3.0", "gulp-babel": "8.0.0", @@ -296,9 +296,9 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -1875,9 +1875,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1991,12 +1991,12 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -2018,9 +2018,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@jridgewell/gen-mapping": { @@ -2170,10 +2170,13 @@ "dev": true }, "node_modules/@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true + "version": "2.8.15", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.15.tgz", + "integrity": "sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/eslint": { "version": "8.44.5", @@ -2226,6 +2229,12 @@ "dev": true, "optional": true }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -2257,9 +2266,9 @@ } }, "node_modules/ace-builds": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.30.0.tgz", - "integrity": "sha512-ZC+G1ozrrVCVL/KPkeU9R7TEwYeNJUYRrjnEvNhF8r2+WR2tkcCjmduL8M6D3abIdf/16ccEXHtpoRBhAnTyCw==" + "version": "1.31.0", + "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.31.0.tgz", + "integrity": "sha512-nitIhcUYA6wyO3lo2WZBPX5fcjllW6XFt4EFyHwcN2Fp70/IZwz8tdw6a0+8udDEwDj/ebt3aWEClIyCs/6qYA==" }, "node_modules/acorn": { "version": "8.9.0", @@ -2340,7 +2349,7 @@ "node_modules/angular-chart.js": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/angular-chart.js/-/angular-chart.js-1.1.1.tgz", - "integrity": "sha1-SfDhjQgXYrbUyXkeSHr/L7sw9a4=", + "integrity": "sha512-6lqkeQvoEOMqtIzHLeOC68fdeqjdgeQ4b3bUG3Lm6X1Y6IBM0m91G6VuVA3EV0puwPuIWz4VYkzjd0DPHhIcpA==", "dependencies": { "angular": "1.x", "chart.js": "2.3.x" @@ -2349,7 +2358,7 @@ "node_modules/angular-chart.js/node_modules/chart.js": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.3.0.tgz", - "integrity": "sha1-QEYOSOLEF8BfwzJc2E97AA3H19Y=", + "integrity": "sha512-LwJ6j1FNneojxFYewnz9QDQyjV++KN2s/Lgm0eipDUaKV3Fj5jOA3xtJg7AUGFcbhsYB4+Kn16c1bXwRxbOXow==", "dependencies": { "chartjs-color": "^2.0.0", "moment": "^2.10.6" @@ -3656,7 +3665,7 @@ "node_modules/cacheable-request": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", - "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "integrity": "sha512-vag0O2LKZ/najSoUwDbVlnlCFvhBE/7mGTY2B5FgCBDcRD+oVV1HYTOwM6JZfMg/hIcM6IwnTZ1uQQL5/X3xIQ==", "dev": true, "optional": true, "dependencies": { @@ -5528,9 +5537,9 @@ } }, "node_modules/engine.io": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz", - "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.3.tgz", + "integrity": "sha512-IML/R4eG/pUS5w7OfcDE0jKrljWS9nwnEfsxWCIJF5eO6AHo6+Hlv+lQbdlAYsiJPHzUthLm1RUjnBzWOs45cw==", "dev": true, "dependencies": { "@types/cookie": "^0.4.1", @@ -5541,26 +5550,26 @@ "cookie": "~0.4.1", "cors": "~2.8.5", "debug": "~4.3.1", - "engine.io-parser": "~5.0.3", - "ws": "~8.2.3" + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" }, "engines": { - "node": ">=10.0.0" + "node": ">=10.2.0" } }, "node_modules/engine.io-parser": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", - "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", "dev": true, "engines": { "node": ">=10.0.0" } }, "node_modules/engine.io/node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -5797,18 +5806,19 @@ } }, "node_modules/eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -6785,18 +6795,18 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.4.tgz", - "integrity": "sha512-fbfMDvgBNIdDJLdLOwacjFAPYt67tr31H9ZhWSm45CDAxvd0I6WTlSOUo7K2P/K5sA5JgMKG64PI3DMcaFdWpQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz", + "integrity": "sha512-rmrXUXwbJedoXkStenj1kkljNF7ugn5ZjR9FJcwmCfcCbtOMDghPajbc+Tck6vE6F5XsDmx+Pr2le9fw8+pXBg==", "dev": true, "funding": [ - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - }, { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" } ], "optional": true, @@ -7355,9 +7365,9 @@ } }, "node_modules/gifsicle": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-5.2.1.tgz", - "integrity": "sha512-9ewIQQCAnSmkU2DhuWafd1DdsgzAkKqIWnY+023xBLSiK9Az2TDUozWQW+SyRQgFMclbe6RQldUk/49TRO3Aqw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-5.3.0.tgz", + "integrity": "sha512-FJTpgdj1Ow/FITB7SVza5HlzXa+/lqEY0tHQazAJbuAdvyJtkH4wIdsR2K414oaTwRXHFLLF+tYbipj+OpYg+Q==", "dev": true, "hasInstallScript": true, "optional": true, @@ -7526,7 +7536,7 @@ "node_modules/glob-base": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", "dev": true, "dependencies": { "glob-parent": "^2.0.0", @@ -7539,7 +7549,7 @@ "node_modules/glob-base/node_modules/glob-parent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", "dev": true, "dependencies": { "is-glob": "^2.0.0" @@ -7569,7 +7579,7 @@ "node_modules/glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "dev": true, "dependencies": { "is-glob": "^3.1.0", @@ -7591,7 +7601,7 @@ "node_modules/glob-stream": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "integrity": "sha512-uMbLGAP3S2aDOHUDfdoYcdIePUCfysbAd0IAoWVZbeGU/oNQ8asHVSshLDJUPWxfzj8zsCG7/XeHPHTtow0nsw==", "dev": true, "dependencies": { "extend": "^3.0.0", @@ -7789,7 +7799,7 @@ "node_modules/gulp-angular-embed-templates": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/gulp-angular-embed-templates/-/gulp-angular-embed-templates-2.3.0.tgz", - "integrity": "sha1-wBDv3VlN7pRRMoNFN9eSOt6EDXk=", + "integrity": "sha512-D4lOP2G9JYbRpuZo6rsiF5f/PpzU1BgaaAxbgxNQtyNp4zME/E3c/0F73F5J/nK+ZRMwdYblgqa4vCgRS9iVwg==", "dev": true, "dependencies": { "gulp-util": "^3.0.6", @@ -8516,7 +8526,7 @@ "node_modules/gulp-util": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "integrity": "sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw==", "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5", "dev": true, "dependencies": { @@ -8586,7 +8596,7 @@ "node_modules/gulp-util/node_modules/lodash.template": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==", "dev": true, "dependencies": { "lodash._basecopy": "^3.0.0", @@ -8717,7 +8727,7 @@ "node_modules/gulp-watch/node_modules/braces": { "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "integrity": "sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw==", "dev": true, "dependencies": { "expand-range": "^1.8.1", @@ -8802,7 +8812,7 @@ "node_modules/gulp-watch/node_modules/micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "integrity": "sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==", "dev": true, "dependencies": { "arr-diff": "^2.0.0", @@ -8860,7 +8870,7 @@ "node_modules/gulp-wrap-js": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/gulp-wrap-js/-/gulp-wrap-js-0.4.1.tgz", - "integrity": "sha1-3uYqpISqupVHqT0f9c0MPQvtwDE=", + "integrity": "sha512-5bWQ6ZQrUDVN0w3ufWP1ZtY8qcGQABKCSb84++qGzyqw6F8kFVeTxIQtEqF4Qzi1YOpLo0NvPlNATqBqKpA6eg==", "dev": true, "dependencies": { "escodegen": "^1.6.1", @@ -11231,9 +11241,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -11902,9 +11912,9 @@ } }, "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -12590,7 +12600,7 @@ "node_modules/parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "integrity": "sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==", "dev": true, "dependencies": { "glob-base": "^0.3.0", @@ -14455,9 +14465,9 @@ "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -14776,27 +14786,52 @@ "dev": true }, "node_modules/socket.io": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", - "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", "dev": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", + "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.2.0", - "socket.io-adapter": "~2.4.0", - "socket.io-parser": "~4.2.0" + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" }, "engines": { - "node": ">=10.0.0" + "node": ">=10.2.0" } }, "node_modules/socket.io-adapter": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", - "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", - "dev": true + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dev": true, + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } }, "node_modules/socket.io-parser": { "version": "4.2.4", @@ -15874,7 +15909,7 @@ "node_modules/trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "integrity": "sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==", "dev": true, "optional": true, "engines": { diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 82c0d66b70..5d12153e62 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@microsoft/signalr": "7.0.12", - "ace-builds": "1.30.0", + "ace-builds": "1.31.0", "angular": "1.8.3", "angular-animate": "1.8.3", "angular-aria": "1.8.3", @@ -59,7 +59,7 @@ "@babel/preset-env": "7.21.5", "autoprefixer": "10.4.16", "cssnano": "6.0.1", - "eslint": "8.51.0", + "eslint": "8.52.0", "gulp": "4.0.2", "gulp-angular-embed-templates": "2.3.0", "gulp-babel": "8.0.0", diff --git a/src/Umbraco.Web.UI.Login/package-lock.json b/src/Umbraco.Web.UI.Login/package-lock.json index ad36561339..d7c296dd28 100644 --- a/src/Umbraco.Web.UI.Login/package-lock.json +++ b/src/Umbraco.Web.UI.Login/package-lock.json @@ -14,7 +14,7 @@ }, "devDependencies": { "typescript": "^5.2.2", - "vite": "^4.4.11" + "vite": "^4.5.0" }, "engines": { "node": ">=20.8", @@ -2555,9 +2555,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { - "version": "4.4.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", - "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", "dev": true, "dependencies": { "esbuild": "^0.18.10", diff --git a/src/Umbraco.Web.UI.Login/package.json b/src/Umbraco.Web.UI.Login/package.json index 4e0d0d9c6b..57c7793b75 100644 --- a/src/Umbraco.Web.UI.Login/package.json +++ b/src/Umbraco.Web.UI.Login/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "typescript": "^5.2.2", - "vite": "^4.4.11" + "vite": "^4.5.0" }, "msw": { "workerDirectory": "public"