From b3a93ac86c3a80557f7c167fb440000a5f0ecb54 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 24 May 2023 10:22:31 +0200 Subject: [PATCH 1/4] Ensure that blocks always open automatically when added to block list or block grid (#14294) --- .../blockgrid/umbBlockGridPropertyEditor.component.js | 2 +- .../blocklist/umbBlockListPropertyEditor.component.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbBlockGridPropertyEditor.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbBlockGridPropertyEditor.component.js index 9279788a1f..78e5f19357 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbBlockGridPropertyEditor.component.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blockgrid/umbBlockGridPropertyEditor.component.js @@ -1011,7 +1011,7 @@ blockObject = vm.layout[createIndex].$block; } // edit block if not `hideContentInOverlay` and there is content properties. - if(blockObject.hideContentInOverlay !== true && blockObject.content.variants[0].tabs[0]?.properties.length > 0) { + if(blockObject.hideContentInOverlay !== true && blockObject.content.variants[0].tabs.find(tab => tab.properties.length > 0) !== undefined) { vm.options.createFlow = true; blockObject.edit(); vm.options.createFlow = false; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js index ab027fcdd8..162b1306ee 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js @@ -621,7 +621,7 @@ var blockObject = vm.layout[createIndex].$block; if (inlineEditing === true) { blockObject.activate(); - } else if (inlineEditing === false && blockObject.hideContentInOverlay !== true && blockObject.content.variants[0].tabs[0]?.properties.length > 0) { + } else if (inlineEditing === false && blockObject.hideContentInOverlay !== true && blockObject.content.variants[0].tabs.find(tab => tab.properties.length > 0) !== undefined) { vm.options.createFlow = true; blockObject.edit(); vm.options.createFlow = false; From 999a83995e8a2b8a9d7bc32ec5c3b3980cac5f52 Mon Sep 17 00:00:00 2001 From: Mole Date: Wed, 24 May 2023 11:48:56 +0200 Subject: [PATCH 2/4] V10: Add external login provider count to detailed telemetry (#14282) * Add backoffice external login provider count to telemetry * Update translation * Fix integration test --- src/Umbraco.Core/Constants-Telemetry.cs | 1 + .../EmbeddedResources/Lang/en_us.xml | 2 +- .../Interfaces/IDetailedTelemetryProvider.cs | 2 +- .../UmbracoBuilder.BackOfficeIdentity.cs | 3 +++ .../ExternalLoginTelemetryProvider.cs | 22 +++++++++++++++++++ .../Telemetry/TelemetryServiceTests.cs | 3 ++- 6 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Web.BackOffice/Telemetry/ExternalLoginTelemetryProvider.cs diff --git a/src/Umbraco.Core/Constants-Telemetry.cs b/src/Umbraco.Core/Constants-Telemetry.cs index 0fc2cb1612..64ce58b2f5 100644 --- a/src/Umbraco.Core/Constants-Telemetry.cs +++ b/src/Umbraco.Core/Constants-Telemetry.cs @@ -28,5 +28,6 @@ public static partial class Constants public static string IsDebug = "IsDebug"; public static string DatabaseProvider = "DatabaseProvider"; public static string CurrentServerRole = "CurrentServerRole"; + public static string BackofficeExternalLoginProviderCount = "BackofficeExternalLoginProviderCount"; } } diff --git a/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml b/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml index 15382310e5..46c7dad6cd 100644 --- a/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml +++ b/src/Umbraco.Core/EmbeddedResources/Lang/en_us.xml @@ -3005,7 +3005,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont We will send: diff --git a/src/Umbraco.Infrastructure/Telemetry/Interfaces/IDetailedTelemetryProvider.cs b/src/Umbraco.Infrastructure/Telemetry/Interfaces/IDetailedTelemetryProvider.cs index b21b216e68..e6ce3b005f 100644 --- a/src/Umbraco.Infrastructure/Telemetry/Interfaces/IDetailedTelemetryProvider.cs +++ b/src/Umbraco.Infrastructure/Telemetry/Interfaces/IDetailedTelemetryProvider.cs @@ -2,7 +2,7 @@ using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Infrastructure.Telemetry.Interfaces; -internal interface IDetailedTelemetryProvider +public interface IDetailedTelemetryProvider { IEnumerable GetInformation(); } diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.BackOfficeIdentity.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.BackOfficeIdentity.cs index 6d3ff7edda..1844cf5885 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.BackOfficeIdentity.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.BackOfficeIdentity.cs @@ -11,7 +11,9 @@ using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Security; +using Umbraco.Cms.Infrastructure.Telemetry.Interfaces; using Umbraco.Cms.Web.BackOffice.Security; +using Umbraco.Cms.Web.BackOffice.Telemetry; using Umbraco.Cms.Web.Common.AspNetCore; using Umbraco.Cms.Web.Common.Security; @@ -65,6 +67,7 @@ public static partial class UmbracoBuilderExtensions services.TryAddScoped(); services.TryAddSingleton(); services.TryAddSingleton(); + services.AddTransient(); return new BackOfficeIdentityBuilder(services); } diff --git a/src/Umbraco.Web.BackOffice/Telemetry/ExternalLoginTelemetryProvider.cs b/src/Umbraco.Web.BackOffice/Telemetry/ExternalLoginTelemetryProvider.cs new file mode 100644 index 0000000000..21a59796b3 --- /dev/null +++ b/src/Umbraco.Web.BackOffice/Telemetry/ExternalLoginTelemetryProvider.cs @@ -0,0 +1,22 @@ +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Infrastructure.Telemetry.Interfaces; +using Umbraco.Cms.Web.BackOffice.Security; + +namespace Umbraco.Cms.Web.BackOffice.Telemetry; + +public class ExternalLoginTelemetryProvider : IDetailedTelemetryProvider +{ + private readonly IBackOfficeExternalLoginProviders _externalLoginProviders; + + public ExternalLoginTelemetryProvider(IBackOfficeExternalLoginProviders externalLoginProviders) + { + _externalLoginProviders = externalLoginProviders; + } + + public IEnumerable GetInformation() + { + IEnumerable providers = _externalLoginProviders.GetBackOfficeProvidersAsync().GetAwaiter().GetResult(); + yield return new UsageInformation(Constants.Telemetry.BackofficeExternalLoginProviderCount, providers.Count()); + } +} diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Core/Telemetry/TelemetryServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Core/Telemetry/TelemetryServiceTests.cs index 2acb31a5a0..4abfefc7e1 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Core/Telemetry/TelemetryServiceTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Core/Telemetry/TelemetryServiceTests.cs @@ -49,7 +49,8 @@ public class TelemetryServiceTests : UmbracoIntegrationTest Constants.Telemetry.AspEnvironment, Constants.Telemetry.IsDebug, Constants.Telemetry.DatabaseProvider, - Constants.Telemetry.CurrentServerRole + Constants.Telemetry.CurrentServerRole, + Constants.Telemetry.BackofficeExternalLoginProviderCount }; MetricsConsentService.SetConsentLevel(TelemetryLevel.Detailed); From b37bb517ab6e8861015c547e10341241838fdd18 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Thu, 25 May 2023 08:36:42 +0200 Subject: [PATCH 3/4] V10: Implement varying blocklist indexing (#14287) * Implement available culture in Interface and base classes * Add available cultures * DI localizationService and use it * Make the new method have default implementation to avoid breaking change * Create implementations for old method * Pass available cultures * Pass localization service * Create new method that takes available cultures * Add ILocalizationService to DI * implement missing method * Add database for schema test * Fixed issue with indexes not added correctly to nested types.. --------- Co-authored-by: Zeegaan Co-authored-by: Bjarke Berg --- .../DefaultPropertyIndexValueFactory.cs | 6 +- .../IPropertyIndexValueFactory.cs | 4 ++ .../JsonPropertyIndexValueFactoryBase.cs | 22 ++++++- .../NoopPropertyIndexValueFactory.cs | 6 +- .../TagPropertyIndexValueFactory.cs | 12 ++++ .../UmbracoBuilder.Examine.cs | 6 +- .../Examine/BaseValueSetBuilder.cs | 6 +- .../Examine/ContentValueSetBuilder.cs | 36 ++++++++++- .../Examine/MediaValueSetBuilder.cs | 2 +- .../Examine/MemberValueSetBuilder.cs | 2 +- .../GridPropertyIndexValueFactory.cs | 6 +- .../NestedPropertyIndexValueFactoryBase.cs | 64 +++++++++++++------ .../PropertyEditors/RichTextPropertyEditor.cs | 6 +- .../UmbracoExamine/IndexInitializer.cs | 28 +++++++- .../UmbracoExamine/IndexTest.cs | 6 +- 15 files changed, 172 insertions(+), 40 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/DefaultPropertyIndexValueFactory.cs b/src/Umbraco.Core/PropertyEditors/DefaultPropertyIndexValueFactory.cs index 705ab034fc..0193f45778 100644 --- a/src/Umbraco.Core/PropertyEditors/DefaultPropertyIndexValueFactory.cs +++ b/src/Umbraco.Core/PropertyEditors/DefaultPropertyIndexValueFactory.cs @@ -10,10 +10,14 @@ namespace Umbraco.Cms.Core.PropertyEditors; public class DefaultPropertyIndexValueFactory : IPropertyIndexValueFactory { /// - public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable availableCultures) { yield return new KeyValuePair>( property.Alias, property.GetValue(culture, segment, published).Yield()); } + + [Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")] + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) + => GetIndexValues(property, culture, segment, published, Enumerable.Empty()); } diff --git a/src/Umbraco.Core/PropertyEditors/IPropertyIndexValueFactory.cs b/src/Umbraco.Core/PropertyEditors/IPropertyIndexValueFactory.cs index fd607f4054..732644b288 100644 --- a/src/Umbraco.Core/PropertyEditors/IPropertyIndexValueFactory.cs +++ b/src/Umbraco.Core/PropertyEditors/IPropertyIndexValueFactory.cs @@ -22,5 +22,9 @@ public interface IPropertyIndexValueFactory /// more than one value for a given field. /// /// + IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable availableCultures) + => GetIndexValues(property, culture, segment, published); + + [Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")] IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published); } diff --git a/src/Umbraco.Core/PropertyEditors/JsonPropertyIndexValueFactoryBase.cs b/src/Umbraco.Core/PropertyEditors/JsonPropertyIndexValueFactoryBase.cs index e639ff7ca8..a56bf0ed88 100644 --- a/src/Umbraco.Core/PropertyEditors/JsonPropertyIndexValueFactoryBase.cs +++ b/src/Umbraco.Core/PropertyEditors/JsonPropertyIndexValueFactoryBase.cs @@ -25,7 +25,8 @@ public abstract class JsonPropertyIndexValueFactoryBase : IProperty IProperty property, string? culture, string? segment, - bool published) + bool published, + IEnumerable availableCultures) { var result = new List>>(); @@ -43,7 +44,7 @@ public abstract class JsonPropertyIndexValueFactoryBase : IProperty return result; } - result.AddRange(Handle(deserializedPropertyValue, property, culture, segment, published)); + result.AddRange(Handle(deserializedPropertyValue, property, culture, segment, published, availableCultures)); } catch (InvalidCastException) { @@ -62,6 +63,10 @@ public abstract class JsonPropertyIndexValueFactoryBase : IProperty return result; } + [Obsolete("Use method overload that has availableCultures, scheduled for removal in v14")] + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) + => GetIndexValues(property, culture, segment, published, Enumerable.Empty()); + /// /// Method to return a list of resume of the content. By default this returns an empty list /// @@ -75,10 +80,23 @@ public abstract class JsonPropertyIndexValueFactoryBase : IProperty /// /// Method that handle the deserialized object. /// + [Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")] protected abstract IEnumerable>> Handle( TSerialized deserializedPropertyValue, IProperty property, string? culture, string? segment, bool published); + + /// + /// Method that handle the deserialized object. + /// + protected virtual IEnumerable>> Handle( + TSerialized deserializedPropertyValue, + IProperty property, + string? culture, + string? segment, + bool published, + IEnumerable availableCultures) => + Handle(deserializedPropertyValue, property, culture, segment, published); } diff --git a/src/Umbraco.Core/PropertyEditors/NoopPropertyIndexValueFactory.cs b/src/Umbraco.Core/PropertyEditors/NoopPropertyIndexValueFactory.cs index 7e64b368c4..223f8632ff 100644 --- a/src/Umbraco.Core/PropertyEditors/NoopPropertyIndexValueFactory.cs +++ b/src/Umbraco.Core/PropertyEditors/NoopPropertyIndexValueFactory.cs @@ -8,5 +8,9 @@ namespace Umbraco.Cms.Core.PropertyEditors; public class NoopPropertyIndexValueFactory : IPropertyIndexValueFactory { /// - public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) => Array.Empty>>(); + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable availableCultures) => Array.Empty>>(); + + [Obsolete("Use the overload with the availableCultures parameter instead, scheduled for removal in v14")] + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) + => GetIndexValues(property, culture, segment, published); } diff --git a/src/Umbraco.Core/PropertyEditors/TagPropertyIndexValueFactory.cs b/src/Umbraco.Core/PropertyEditors/TagPropertyIndexValueFactory.cs index 83a327e0ef..b3a8e9a2b8 100644 --- a/src/Umbraco.Core/PropertyEditors/TagPropertyIndexValueFactory.cs +++ b/src/Umbraco.Core/PropertyEditors/TagPropertyIndexValueFactory.cs @@ -9,6 +9,18 @@ public class TagPropertyIndexValueFactory : JsonPropertyIndexValueFactoryBase>> Handle( + string[] deserializedPropertyValue, + IProperty property, + string? culture, + string? segment, + bool published, + IEnumerable availableCultures) + { + yield return new KeyValuePair>(property.Alias, deserializedPropertyValue); + } + + [Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")] protected override IEnumerable>> Handle( string[] deserializedPropertyValue, IProperty property, diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs index aabadc5197..ab344745ca 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs @@ -37,7 +37,8 @@ public static partial class UmbracoBuilderExtensions factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService(), - true)); + true, + factory.GetRequiredService())); builder.Services.AddUnique(factory => new ContentValueSetBuilder( factory.GetRequiredService(), @@ -45,7 +46,8 @@ public static partial class UmbracoBuilderExtensions factory.GetRequiredService(), factory.GetRequiredService(), factory.GetRequiredService(), - false)); + false, + factory.GetRequiredService())); builder.Services.AddUnique, MediaValueSetBuilder>(); builder.Services.AddUnique, MemberValueSetBuilder>(); builder.Services.AddSingleton(); diff --git a/src/Umbraco.Infrastructure/Examine/BaseValueSetBuilder.cs b/src/Umbraco.Infrastructure/Examine/BaseValueSetBuilder.cs index db6182ee3e..3574c3077f 100644 --- a/src/Umbraco.Infrastructure/Examine/BaseValueSetBuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/BaseValueSetBuilder.cs @@ -22,7 +22,11 @@ public abstract class BaseValueSetBuilder : IValueSetBuilder /// public abstract IEnumerable GetValueSets(params TContent[] content); + [Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")] protected void AddPropertyValue(IProperty property, string? culture, string? segment, IDictionary>? values) + => AddPropertyValue(property, culture, segment, values, Enumerable.Empty()); + + protected void AddPropertyValue(IProperty property, string? culture, string? segment, IDictionary>? values, IEnumerable availableCultures) { IDataEditor? editor = _propertyEditors[property.PropertyType.PropertyEditorAlias]; if (editor == null) @@ -31,7 +35,7 @@ public abstract class BaseValueSetBuilder : IValueSetBuilder } IEnumerable>> indexVals = - editor.PropertyIndexValueFactory.GetIndexValues(property, culture, segment, PublishedValuesOnly); + editor.PropertyIndexValueFactory.GetIndexValues(property, culture, segment, PublishedValuesOnly, availableCultures); foreach (KeyValuePair> keyVal in indexVals) { if (keyVal.Key.IsNullOrWhiteSpace()) diff --git a/src/Umbraco.Infrastructure/Examine/ContentValueSetBuilder.cs b/src/Umbraco.Infrastructure/Examine/ContentValueSetBuilder.cs index 05274fc28e..228610879d 100644 --- a/src/Umbraco.Infrastructure/Examine/ContentValueSetBuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/ContentValueSetBuilder.cs @@ -1,10 +1,12 @@ using Examine; +using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; using IScope = Umbraco.Cms.Infrastructure.Scoping.IScope; @@ -24,6 +26,7 @@ public class ContentValueSetBuilder : BaseValueSetBuilder, IContentVal private readonly IShortStringHelper _shortStringHelper; private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly IUserService _userService; + private readonly ILocalizationService _localizationService; public ContentValueSetBuilder( PropertyEditorCollection propertyEditors, @@ -31,13 +34,34 @@ public class ContentValueSetBuilder : BaseValueSetBuilder, IContentVal IUserService userService, IShortStringHelper shortStringHelper, IScopeProvider scopeProvider, - bool publishedValuesOnly) + bool publishedValuesOnly, + ILocalizationService localizationService) : base(propertyEditors, publishedValuesOnly) { _urlSegmentProviders = urlSegmentProviders; _userService = userService; _shortStringHelper = shortStringHelper; _scopeProvider = scopeProvider; + _localizationService = localizationService; + } + + [Obsolete("Use the constructor that takes an ILocalizationService, scheduled for removal in v14")] + public ContentValueSetBuilder( + PropertyEditorCollection propertyEditors, + UrlSegmentProviderCollection urlSegmentProviders, + IUserService userService, + IShortStringHelper shortStringHelper, + IScopeProvider scopeProvider, + bool publishedValuesOnly) + : this( + propertyEditors, + urlSegmentProviders, + userService, + shortStringHelper, + scopeProvider, + publishedValuesOnly, + StaticServiceProvider.Instance.GetRequiredService()) + { } /// @@ -128,17 +152,23 @@ public class ContentValueSetBuilder : BaseValueSetBuilder, IContentVal } } + var availableCultures = new List(c.AvailableCultures); + if (availableCultures.Any() is false) + { + availableCultures.Add(_localizationService.GetDefaultLanguageIsoCode()); + } + foreach (IProperty property in c.Properties) { if (!property.PropertyType.VariesByCulture()) { - AddPropertyValue(property, null, null, values); + AddPropertyValue(property, null, null, values, availableCultures); } else { foreach (var culture in c.AvailableCultures) { - AddPropertyValue(property, culture.ToLowerInvariant(), null, values); + AddPropertyValue(property, culture.ToLowerInvariant(), null, values, availableCultures); } } } diff --git a/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs b/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs index 344c7d08d2..fa7d6509cd 100644 --- a/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/MediaValueSetBuilder.cs @@ -65,7 +65,7 @@ public class MediaValueSetBuilder : BaseValueSetBuilder foreach (IProperty property in m.Properties) { - AddPropertyValue(property, null, null, values); + AddPropertyValue(property, null, null, values, m.AvailableCultures); } var vs = new ValueSet(m.Id.ToInvariantString(), IndexTypes.Media, m.ContentType.Alias, values); diff --git a/src/Umbraco.Infrastructure/Examine/MemberValueSetBuilder.cs b/src/Umbraco.Infrastructure/Examine/MemberValueSetBuilder.cs index 74d3829d6a..1b0bf7219f 100644 --- a/src/Umbraco.Infrastructure/Examine/MemberValueSetBuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/MemberValueSetBuilder.cs @@ -37,7 +37,7 @@ public class MemberValueSetBuilder : BaseValueSetBuilder foreach (IProperty property in m.Properties) { - AddPropertyValue(property, null, null, values); + AddPropertyValue(property, null, null, values, m.AvailableCultures); } var vs = new ValueSet(m.Id.ToInvariantString(), IndexTypes.Member, m.ContentType.Alias, values); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyIndexValueFactory.cs b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyIndexValueFactory.cs index 70eb9e3b7b..a3bb55e643 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyIndexValueFactory.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/GridPropertyIndexValueFactory.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Core.PropertyEditors /// public class GridPropertyIndexValueFactory : IPropertyIndexValueFactory { - public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable availableCultures) { var result = new List>>(); @@ -88,5 +88,9 @@ namespace Umbraco.Cms.Core.PropertyEditors return result; } + + [Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")] + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) + => GetIndexValues(property, culture, segment, published); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedPropertyIndexValueFactoryBase.cs b/src/Umbraco.Infrastructure/PropertyEditors/NestedPropertyIndexValueFactoryBase.cs index 4eb7051745..b3799aaa95 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedPropertyIndexValueFactoryBase.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/NestedPropertyIndexValueFactoryBase.cs @@ -18,15 +18,26 @@ internal abstract class NestedPropertyIndexValueFactoryBase _propertyEditorCollection = propertyEditorCollection; } + [Obsolete("Use the overload that specifies availableCultures, scheduled for removal in v14")] protected override IEnumerable>> Handle( TSerialized deserializedPropertyValue, IProperty property, string? culture, string? segment, - bool published) + bool published) => + Handle(deserializedPropertyValue, property, culture, segment, published, Enumerable.Empty()); + + protected override IEnumerable>> Handle( + TSerialized deserializedPropertyValue, + IProperty property, + string? culture, + string? segment, + bool published, + IEnumerable availableCultures) { var result = new List>>(); + var index = 0; foreach (TItem nestedContentRowValue in GetDataItems(deserializedPropertyValue)) { IContentType? contentType = GetContentTypeOfNestedItem(nestedContentRowValue); @@ -60,12 +71,15 @@ internal abstract class NestedPropertyIndexValueFactoryBase .ToDictionary(x => x.Alias); result.AddRange(GetNestedResults( - property.Alias, + $"{property.Alias}.items[{index}]", culture, segment, published, propertyTypeDictionary, - nestedContentRowValue)); + nestedContentRowValue, + availableCultures)); + + index++; } return RenameKeysToEnsureRawSegmentsIsAPrefix(result); @@ -160,39 +174,51 @@ internal abstract class NestedPropertyIndexValueFactoryBase string? segment, bool published, IDictionary propertyTypeDictionary, - TItem nestedContentRowValue) + TItem nestedContentRowValue, + IEnumerable availableCultures) { - var blockIndex = 0; - foreach ((var propertyAlias, var propertyValue) in GetRawProperty(nestedContentRowValue)) { if (propertyTypeDictionary.TryGetValue(propertyAlias, out IPropertyType? propertyType)) { - IProperty subProperty = new Property(propertyType); - subProperty.SetValue(propertyValue, culture, segment); - - if (published) - { - subProperty.PublishValues(culture, segment ?? "*"); - } - IDataEditor? editor = _propertyEditorCollection[propertyType.PropertyEditorAlias]; if (editor is null) { continue; } - IEnumerable>> indexValues = - editor.PropertyIndexValueFactory.GetIndexValues(subProperty, culture, segment, published); + IProperty subProperty = new Property(propertyType); + IEnumerable>> indexValues = null!; + + if (propertyType.VariesByCulture() && culture is null) + { + foreach (var availableCulture in availableCultures) + { + subProperty.SetValue(propertyValue, availableCulture, segment); + if (published) + { + subProperty.PublishValues(availableCulture, segment ?? "*"); + } + indexValues = + editor.PropertyIndexValueFactory.GetIndexValues(subProperty, availableCulture, segment, published, availableCultures); + } + } + else + { + subProperty.SetValue(propertyValue, culture, segment); + if (published) + { + subProperty.PublishValues(culture ?? "*", segment ?? "*"); + } + indexValues = editor.PropertyIndexValueFactory.GetIndexValues(subProperty, culture, segment, published, availableCultures); + } foreach ((var nestedAlias, IEnumerable nestedValue) in indexValues) { yield return new KeyValuePair>( - $"{keyPrefix}.items[{blockIndex}].{nestedAlias}", nestedValue!); + $"{keyPrefix}.{nestedAlias}", nestedValue!); } } - - blockIndex++; } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs index 8525de17b6..21313b3b77 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs @@ -305,7 +305,7 @@ public class RichTextPropertyEditor : DataEditor internal class RichTextPropertyIndexValueFactory : IPropertyIndexValueFactory { - public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published, IEnumerable availableCultures) { var val = property.GetValue(culture, segment, published); @@ -323,5 +323,9 @@ public class RichTextPropertyEditor : DataEditor yield return new KeyValuePair>( $"{UmbracoExamineFieldNames.RawFieldPrefix}{property.Alias}", new object[] { strVal }); } + + [Obsolete("Use the overload with the 'availableCultures' parameter instead, scheduled for removal in v14")] + public IEnumerable>> GetIndexValues(IProperty property, string? culture, string? segment, bool published) + => GetIndexValues(property, culture, segment, published); } } diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs b/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs index 6ae7f3628e..5ea360f241 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs @@ -3,6 +3,7 @@ using Examine.Lucene; using Examine.Lucene.Directories; using Lucene.Net.Analysis; using Lucene.Net.Analysis.Standard; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; @@ -18,6 +19,7 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Examine; using Umbraco.Cms.Infrastructure.Persistence; +using Umbraco.Cms.Web.Common.DependencyInjection; using Directory = Lucene.Net.Store.Directory; namespace Umbraco.Cms.Tests.Integration.Umbraco.Examine.Lucene.UmbracoExamine; @@ -28,6 +30,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Examine.Lucene.UmbracoExamine; public class IndexInitializer { private readonly IOptions _contentSettings; + private readonly ILocalizationService _localizationService; private readonly ILoggerFactory _loggerFactory; private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; private readonly PropertyEditorCollection _propertyEditors; @@ -40,7 +43,8 @@ public class IndexInitializer MediaUrlGeneratorCollection mediaUrlGenerators, IScopeProvider scopeProvider, ILoggerFactory loggerFactory, - IOptions contentSettings) + IOptions contentSettings, + ILocalizationService localizationService) { _shortStringHelper = shortStringHelper; _propertyEditors = propertyEditors; @@ -48,6 +52,25 @@ public class IndexInitializer _scopeProvider = scopeProvider; _loggerFactory = loggerFactory; _contentSettings = contentSettings; + _localizationService = localizationService; + } + + public IndexInitializer( + IShortStringHelper shortStringHelper, + PropertyEditorCollection propertyEditors, + MediaUrlGeneratorCollection mediaUrlGenerators, + IScopeProvider scopeProvider, + ILoggerFactory loggerFactory, + IOptions contentSettings) + : this( + shortStringHelper, + propertyEditors, + mediaUrlGenerators, + scopeProvider, + loggerFactory, + contentSettings, + StaticServiceProvider.Instance.GetRequiredService()) + { } public ContentValueSetBuilder GetContentValueSetBuilder(bool publishedValuesOnly) @@ -58,7 +81,8 @@ public class IndexInitializer GetMockUserService(), _shortStringHelper, _scopeProvider, - publishedValuesOnly); + publishedValuesOnly, + _localizationService); return contentValueSetBuilder; } diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexTest.cs index b271cabb08..cb2e0d7a7a 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexTest.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; using Bogus; using Examine; using Lucene.Net.Util; @@ -10,7 +7,6 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Infrastructure.Examine; using Umbraco.Cms.Tests.Common.Builders; using Umbraco.Cms.Tests.Common.Testing; -using Umbraco.Extensions; using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Cms.Tests.Integration.Umbraco.Examine.Lucene.UmbracoExamine; @@ -19,7 +15,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Examine.Lucene.UmbracoExamine; /// Tests the standard indexing capabilities /// [TestFixture] -[UmbracoTest(Database = UmbracoTestOptions.Database.None)] +[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] public class IndexTest : ExamineBaseTest { [Test] From 407263d09005bc4f8cb5060151ca1cf42707af81 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Wed, 31 May 2023 08:43:14 +0200 Subject: [PATCH 4/4] V10: Handle blob images (#14317) * Handle blob images * remove dots from mapping * Revert bad formatting --------- Co-authored-by: Zeegaan --- .../Controllers/TinyMceController.cs | 50 ++++++++++++++----- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs b/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs index 3d93f9af6c..a9f81344a0 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TinyMceController.cs @@ -26,6 +26,19 @@ public class TinyMceController : UmbracoAuthorizedApiController private readonly IIOHelper _ioHelper; private readonly IShortStringHelper _shortStringHelper; + private readonly Dictionary _fileContentTypeMappings = + new() + { + { "image/png", "png" }, + { "image/jpeg", "jpg" }, + { "image/gif", "gif" }, + { "image/bmp", "bmp" }, + { "image/x-icon", "ico" }, + { "image/svg+xml", "svg" }, + { "image/tiff", "tiff" }, + { "image/webp", "webp" }, + }; + public TinyMceController( IHostingEnvironment hostingEnvironment, IShortStringHelper shortStringHelper, @@ -43,16 +56,6 @@ public class TinyMceController : UmbracoAuthorizedApiController [HttpPost] public async Task UploadImage(List file) { - // Create an unique folder path to help with concurrent users to avoid filename clash - var imageTempPath = - _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempImageUploads + "/" + Guid.NewGuid()); - - // Ensure image temp path exists - if (Directory.Exists(imageTempPath) == false) - { - Directory.CreateDirectory(imageTempPath); - } - // Must have a file if (file.Count == 0) { @@ -65,13 +68,36 @@ public class TinyMceController : UmbracoAuthorizedApiController return new UmbracoProblemResult("Only one file can be uploaded at a time", HttpStatusCode.BadRequest); } + // Create an unique folder path to help with concurrent users to avoid filename clash + var imageTempPath = + _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempImageUploads + "/" + Guid.NewGuid()); + + // Ensure image temp path exists + if (Directory.Exists(imageTempPath) == false) + { + Directory.CreateDirectory(imageTempPath); + } + IFormFile formFile = file.First(); // Really we should only have one file per request to this endpoint // var file = result.FileData[0]; - var fileName = formFile.FileName.Trim(new[] { '\"' }).TrimEnd(); + var fileName = formFile.FileName.Trim(new[] {'\"'}).TrimEnd(); var safeFileName = fileName.ToSafeFileName(_shortStringHelper); - var ext = safeFileName.Substring(safeFileName.LastIndexOf('.') + 1).ToLowerInvariant(); + string ext; + var fileExtensionIndex = safeFileName.LastIndexOf('.'); + if (fileExtensionIndex is not -1) + { + ext = safeFileName.Substring(fileExtensionIndex + 1).ToLowerInvariant(); + } + else + { + _fileContentTypeMappings.TryGetValue(formFile.ContentType, out var fileExtension); + ext = fileExtension ?? string.Empty; + + // safeFileName will not have a file extension, so we need to add it back + safeFileName += $".{ext}"; + } if (_contentSettings.IsFileAllowedForUpload(ext) == false || _imageUrlGenerator.IsSupportedImageFormat(ext) == false)