fix udi leaking in the management api (#15684)
* [WIP] Stop Udi leaking on ConterPicker * Refined Udi conversion for contentPicker Cleaned up base construcor usage to move away from the obsoleted one. * Fixed Udi lieaking in MNTP * Stopped Udi bleeding for MultiUrlPicker * Remove unused assignment * Resolved namespace issue * Use correct configuration value for MNTP udi parsing * Turn helper auto props into local helper function to avoid unnecesary serialization * Remove Newtonsoft.Json from Multi URL picker * Fixed MNTP configuration serialization * Changed MNTP editor data from csv guid to EditorEntityReference[] * Added remarks for the MNTP editor conversion logic * Reworked MNTPPropertyEditor Unittests changed intent of one fixed bug because of 1 rework * Update OpenApi.json --------- Co-authored-by: Sven Geusens <sge@umbraco.dk> Co-authored-by: Elitsa <elm@umbraco.dk> Co-authored-by: kjac <kja@umbraco.dk>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Text.Json.Nodes;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Editors;
|
||||
@@ -31,8 +32,16 @@ public class MultiNodeTreePickerPropertyEditor : DataEditor
|
||||
protected override IDataValueEditor CreateValueEditor() =>
|
||||
DataValueEditorFactory.Create<MultiNodeTreePickerPropertyValueEditor>(Attribute!);
|
||||
|
||||
/// <remarks>
|
||||
/// At first glance, the fromEditor and toEditor methods might seem strange.
|
||||
/// This is because we wanted to stop the leaking of UDI's to the frontend while not having to do database migrations
|
||||
/// so we opted to, for now, translate the udi string in the database into a structured format unique to the client
|
||||
/// This way, for now, no migration is needed and no changes outside of the editor logic needs to be touched to stop the leaking.
|
||||
/// </remarks>
|
||||
public class MultiNodeTreePickerPropertyValueEditor : DataValueEditor, IDataValueReference
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
public MultiNodeTreePickerPropertyValueEditor(
|
||||
IShortStringHelper shortStringHelper,
|
||||
IJsonSerializer jsonSerializer,
|
||||
@@ -40,6 +49,7 @@ public class MultiNodeTreePickerPropertyEditor : DataEditor
|
||||
DataEditorAttribute attribute)
|
||||
: base(shortStringHelper, jsonSerializer, ioHelper, attribute)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
public IEnumerable<UmbracoEntityReference> GetReferences(object? value)
|
||||
@@ -56,23 +66,41 @@ public class MultiNodeTreePickerPropertyEditor : DataEditor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override object? FromEditor(ContentPropertyData editorValue, object? currentValue)
|
||||
=> editorValue.Value is JsonArray jsonArray
|
||||
? EntityReferencesToUdis(_jsonSerializer.Deserialize<IEnumerable<EditorEntityReference>>(jsonArray.ToJsonString()) ?? Enumerable.Empty<EditorEntityReference>())
|
||||
: null;
|
||||
|
||||
public override object? ToEditor(IProperty property, string? culture = null, string? segment = null)
|
||||
{
|
||||
var value = property.GetValue(culture, segment);
|
||||
return value is string stringValue
|
||||
? ParseValidUdis(stringValue.Split(Constants.CharArrays.Comma))
|
||||
: null;
|
||||
? UdisToEntityReferences(stringValue.Split(Constants.CharArrays.Comma)).ToArray()
|
||||
: null;
|
||||
}
|
||||
|
||||
public override object? FromEditor(ContentPropertyData editorValue, object? currentValue)
|
||||
=> editorValue.Value is IEnumerable<string> stringValues
|
||||
? string.Join(",", ParseValidUdis(stringValues))
|
||||
: null;
|
||||
private IEnumerable<EditorEntityReference> UdisToEntityReferences(IEnumerable<string> stringUdis)
|
||||
{
|
||||
foreach (var stringUdi in stringUdis)
|
||||
{
|
||||
if (UdiParser.TryParse(stringUdi, out GuidUdi? guidUdi) is false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
private string[] ParseValidUdis(IEnumerable<string> stringValues)
|
||||
=> stringValues
|
||||
.Select(s => UdiParser.TryParse(s, out Udi? udi) && udi is GuidUdi guidUdi ? guidUdi.ToString() : null)
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
yield return new EditorEntityReference() { Type = guidUdi.EntityType, Unique = guidUdi.Guid };
|
||||
}
|
||||
}
|
||||
|
||||
private string EntityReferencesToUdis(IEnumerable<EditorEntityReference> nodeReferences)
|
||||
=> string.Join(",", nodeReferences.Select(entityReference => Udi.Create(entityReference.Type, entityReference.Unique).ToString()));
|
||||
|
||||
public class EditorEntityReference
|
||||
{
|
||||
public required string Type { get; set; }
|
||||
|
||||
public required Guid Unique { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,9 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference
|
||||
Trashed = trashed,
|
||||
Published = published,
|
||||
QueryString = dto.QueryString,
|
||||
Udi = udi,
|
||||
Type = dto.Udi is null ? LinkDisplay.Types.External
|
||||
: dto.Udi.EntityType,
|
||||
Unique = dto.Udi?.Guid,
|
||||
Url = url ?? string.Empty,
|
||||
});
|
||||
}
|
||||
@@ -169,8 +171,8 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference
|
||||
Name = link.Name,
|
||||
QueryString = link.QueryString,
|
||||
Target = link.Target,
|
||||
Udi = link.Udi,
|
||||
Url = link.Udi == null ? link.Url : null, // only save the URL for external links
|
||||
Udi = TypeIsUdiBased(link) ? new GuidUdi(link.Type!, link.Unique!.Value) : null,
|
||||
Url = TypeIsExternal(link) ? link.Url : null, // only save the URL for external links
|
||||
}));
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -181,6 +183,14 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference
|
||||
return base.FromEditor(editorValue, currentValue);
|
||||
}
|
||||
|
||||
private static bool TypeIsExternal(LinkDisplay link) =>
|
||||
link.Type is not null && link.Type.Equals(LinkDisplay.Types.External, StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
private static bool TypeIsUdiBased(LinkDisplay link) =>
|
||||
link.Type is not null && link.Unique is not null &&
|
||||
(link.Type.Equals(LinkDisplay.Types.Document, StringComparison.InvariantCultureIgnoreCase)
|
||||
|| link.Type.Equals(LinkDisplay.Types.Media, StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
[DataContract]
|
||||
public class LinkDto
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user