diff --git a/Directory.Build.props b/Directory.Build.props index 1bd4721a..0c5bee3b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -46,6 +46,7 @@ + \ No newline at end of file diff --git a/uSync.Core/DataTypes/ConfigurationSerializerBase.cs b/uSync.Core/DataTypes/ConfigurationSerializerBase.cs index 167ee6e1..60791beb 100644 --- a/uSync.Core/DataTypes/ConfigurationSerializerBase.cs +++ b/uSync.Core/DataTypes/ConfigurationSerializerBase.cs @@ -1,4 +1,8 @@ -namespace uSync.Core.DataTypes; +using System.Collections.Immutable; + +using uSync.Core.Extensions; + +namespace uSync.Core.DataTypes; public abstract class ConfigurationSerializerBase { @@ -7,4 +11,23 @@ public virtual IDictionary GetConfigurationExport(IDictionary GetConfigurationImport(IDictionary configuration) => configuration; + + /// + /// renames properties that might exist in a json string (if it is one). + /// + /// + /// will check if the string is JSON if its not, we return the source + /// + protected static IDictionary MigratePropertyNames(IDictionary source, Dictionary names, bool sort = true) + { + foreach (var keyValue in names) + { + if (source.TryGetValue(keyValue.Key, out var propertyValue) == false) continue; + source[keyValue.Value] = propertyValue; + source.Remove(keyValue.Key); + } + + return sort ? source.ToImmutableSortedDictionary() : source; + } + } diff --git a/uSync.Core/DataTypes/ConfigurationSerializerCollectionBuilder.cs b/uSync.Core/DataTypes/ConfigurationSerializerCollectionBuilder.cs index 9bdd2ffe..60772d24 100644 --- a/uSync.Core/DataTypes/ConfigurationSerializerCollectionBuilder.cs +++ b/uSync.Core/DataTypes/ConfigurationSerializerCollectionBuilder.cs @@ -20,4 +20,7 @@ public ConfigurationSerializerCollection(Func this.FirstOrDefault(x => x.Editors.InvariantContains(editorAlias)); + + public IEnumerable GetSerializers(string editorAlias) + => this.Where(x => x.Editors.InvariantContains(editorAlias)); } diff --git a/uSync.Core/DataTypes/DataTypeSerializers/ColourPickerMigratingConfigSerializer.cs b/uSync.Core/DataTypes/DataTypeSerializers/ColourPickerMigratingConfigSerializer.cs new file mode 100644 index 00000000..73f864ef --- /dev/null +++ b/uSync.Core/DataTypes/DataTypeSerializers/ColourPickerMigratingConfigSerializer.cs @@ -0,0 +1,53 @@ +using System.Text.Json; +using System.Text.Json.Nodes; + +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Strings; + +using uSync.Core.Extensions; + +using static Umbraco.Cms.Core.PropertyEditors.ColorPickerConfiguration; + +namespace uSync.Core.DataTypes.DataTypeSerializers; + +internal class ColourPickerMigratingConfigSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(ColourPickerMigratingConfigSerializer); + public string[] Editors => [Constants.PropertyEditors.Aliases.ColorPicker]; + public override IDictionary GetConfigurationImport(IDictionary configuration) + { + if (configuration.TryGetValue("items", out var items) is false || items is null) + return configuration; + + if (items is JsonElement element == false) return configuration; + if (element.ValueKind != JsonValueKind.Array) return configuration; + + var convertedItems = new List(); + + var array = element.EnumerateArray().Select(x => x); + + foreach(var item in element.EnumerateArray()) + { + if (item.ValueKind != JsonValueKind.Object) continue; + var obj = JsonSerializer.Deserialize(item.ToString()); + if (obj == null) continue; + + var valueJson = obj.GetPropertyAsString("value"); + if (string.IsNullOrEmpty(valueJson)) continue; + + if (valueJson.TryDeserialize(out var itemValues) is false || itemValues is null) + return configuration; + + convertedItems.Add(new ColorPickerItem + { + Label = itemValues.GetPropertyAsString("label"), + Value = itemValues.GetPropertyAsString("value") + }); + } + + configuration.Remove("items"); + configuration.Add("items", convertedItems); + + return configuration; + } +} \ No newline at end of file diff --git a/uSync.Core/DataTypes/DataTypeSerializers/DataListMigratingConfigSerializer.cs b/uSync.Core/DataTypes/DataTypeSerializers/DataListMigratingConfigSerializer.cs new file mode 100644 index 00000000..e1a50e82 --- /dev/null +++ b/uSync.Core/DataTypes/DataTypeSerializers/DataListMigratingConfigSerializer.cs @@ -0,0 +1,47 @@ +using System.Text.Json; + +using Umbraco.Cms.Core; + +using uSync.Core.Extensions; + +namespace uSync.Core.DataTypes.DataTypeSerializers; + +internal class DataListMigratingConfigSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(DataListMigratingConfigSerializer); + public string[] Editors => [ + Constants.PropertyEditors.Aliases.CheckBoxList, + Constants.PropertyEditors.Aliases.DropDownListFlexible, + Constants.PropertyEditors.Aliases.RadioButtonList + ]; + + public override IDictionary GetConfigurationImport(IDictionary configuration) + { + if (configuration.TryGetValue("items", out var items) is false || items is null) + return configuration; + + if (items is JsonElement element == false) return configuration; + if (element.ValueKind != JsonValueKind.Array) return configuration; + + if (element.ToString().TryDeserialize>(out var values) is false || values is null) + return configuration; + + var convertedItems = new List(); + + foreach(var item in values.OrderBy(x => x.Id)) + { + if (item?.Value is null) continue; + convertedItems.Add(item.Value); + } + + configuration["items"] = convertedItems; + + return configuration; + } + private class IdValuePair + { + public int? Id { get; set; } + public string? Value { get; set; } + } + +} diff --git a/uSync.Core/DataTypes/DataTypeSerializers/FileUploadMigratingConfigSerializer.cs b/uSync.Core/DataTypes/DataTypeSerializers/FileUploadMigratingConfigSerializer.cs new file mode 100644 index 00000000..b116c15e --- /dev/null +++ b/uSync.Core/DataTypes/DataTypeSerializers/FileUploadMigratingConfigSerializer.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +using Umbraco.Cms.Core; + +using uSync.Core.Extensions; + +namespace uSync.Core.DataTypes.DataTypeSerializers; +internal class FileUploadMigratingConfigSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(FileUploadMigratingConfigSerializer); + + public string[] Editors => [Constants.PropertyEditors.Aliases.UploadField]; + + public override IDictionary GetConfigurationImport(IDictionary configuration) + { + if (configuration.TryGetValue("fileExtensions", out var items) is false || items is null) + return configuration; + + if (items is JsonElement element == false) return configuration; + if (element.ValueKind != JsonValueKind.Array) return configuration; + + if (element.ToString().TryDeserialize>(out var values) is false || values is null) + return configuration; + + var convertedItems = new List(); + + foreach(var item in values.OrderBy(x => x.Id)) + { + if (item.Value is null) continue; + convertedItems.Add(item.Value); + } + + configuration["fileExtensions"] = convertedItems; + return configuration; + } + + private class IdValuePair + { + public int? Id { get; set; } + public string? Value { get; set; } + } + +} diff --git a/uSync.Core/DataTypes/DataTypeSerializers/LabelMigratingConfigSerializer.cs b/uSync.Core/DataTypes/DataTypeSerializers/LabelMigratingConfigSerializer.cs new file mode 100644 index 00000000..fe2a3681 --- /dev/null +++ b/uSync.Core/DataTypes/DataTypeSerializers/LabelMigratingConfigSerializer.cs @@ -0,0 +1,15 @@ +using Umbraco.Cms.Core; + +namespace uSync.Core.DataTypes.DataTypeSerializers; + +internal class LabelMigratingConfigSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(LabelMigratingConfigSerializer); + public string[] Editors => [Constants.PropertyEditors.Aliases.Label]; + + public override IDictionary GetConfigurationImport(IDictionary configuration) + => MigratePropertyNames(configuration, new() + { + { "ValueType", "umbracoDataValueType" } + }); +} \ No newline at end of file diff --git a/uSync.Core/DataTypes/DataTypeSerializers/MarkdownMigratingConfigSerializer.cs b/uSync.Core/DataTypes/DataTypeSerializers/MarkdownMigratingConfigSerializer.cs new file mode 100644 index 00000000..a87e34bf --- /dev/null +++ b/uSync.Core/DataTypes/DataTypeSerializers/MarkdownMigratingConfigSerializer.cs @@ -0,0 +1,15 @@ +using Umbraco.Cms.Core; + +namespace uSync.Core.DataTypes.DataTypeSerializers; +internal class MarkdownMigratingConfigSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(MarkdownMigratingConfigSerializer); + + public string[] Editors => [ Constants.PropertyEditors.Aliases.MarkdownEditor ]; + + public override IDictionary GetConfigurationImport(IDictionary configuration) + => MigratePropertyNames(configuration, new() + { + { "displayLivePreview", "preview" } + }); +} diff --git a/uSync.Core/DataTypes/DataTypeSerializers/MultipleTextMigratingConfigSerializer.cs b/uSync.Core/DataTypes/DataTypeSerializers/MultipleTextMigratingConfigSerializer.cs new file mode 100644 index 00000000..6203ba95 --- /dev/null +++ b/uSync.Core/DataTypes/DataTypeSerializers/MultipleTextMigratingConfigSerializer.cs @@ -0,0 +1,17 @@ +using Umbraco.Cms.Core; + +namespace uSync.Core.DataTypes.DataTypeSerializers; + +internal class MultipleTextMigratingConfigSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(MultipleTextMigratingConfigSerializer); + + public string[] Editors => [Constants.PropertyEditors.Aliases.MultipleTextstring]; + + public override IDictionary GetConfigurationImport(IDictionary configuration) + => MigratePropertyNames(configuration, new() + { + { "maximum", "max" }, + { "minimum", "min" } + }); +} diff --git a/uSync.Core/DataTypes/DataTypeSerializers/SliderMigratingConfigSerializer.cs b/uSync.Core/DataTypes/DataTypeSerializers/SliderMigratingConfigSerializer.cs new file mode 100644 index 00000000..7b6a3626 --- /dev/null +++ b/uSync.Core/DataTypes/DataTypeSerializers/SliderMigratingConfigSerializer.cs @@ -0,0 +1,21 @@ +using NPoco.Linq; + +using Umbraco.Cms.Core; + +namespace uSync.Core.DataTypes.DataTypeSerializers; + +internal class SliderMigratingConfigSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(SliderMigratingConfigSerializer); + public string[] Editors => [Constants.PropertyEditors.Aliases.Slider]; + + public override IDictionary GetConfigurationImport(IDictionary configuration) + => MigratePropertyNames(configuration, new() + { + { "initialValue", "initVal1" }, + { "initialValue2", "initVal2" }, + { "maximumValue", "maxVal" }, + { "minimumValue", "minVal" }, + { "stepIncrements", "step" } + }); +} diff --git a/uSync.Core/DataTypes/DataTypeSerializers/TagMigratingConfigSerializer.cs b/uSync.Core/DataTypes/DataTypeSerializers/TagMigratingConfigSerializer.cs new file mode 100644 index 00000000..233444dc --- /dev/null +++ b/uSync.Core/DataTypes/DataTypeSerializers/TagMigratingConfigSerializer.cs @@ -0,0 +1,41 @@ +using System.Text.Json; + +using Umbraco.Cms.Core; + +using uSync.Core.Extensions; + +namespace uSync.Core.DataTypes.DataTypeSerializers; + +internal class TagMigratingConfigSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(TagMigratingConfigSerializer); + + public string[] Editors => [Constants.PropertyEditors.Aliases.Tags]; + + public override IDictionary GetConfigurationImport(IDictionary configuration) + { + if (configuration.TryGetValue("StorageType", out var storageType) is false + || storageType == null) + { + return configuration; + } + + if (configuration.ContainsKey("delimiter")) + configuration.Remove("delimiter"); + + if (storageType is JsonElement element == false) return configuration; + if (element.ValueKind != JsonValueKind.Number) return configuration; + var storageNumber = element.GetValueAs(); + + var typeString = storageNumber == 0 ? "csv" : "Json"; + // if storage type is a number. + configuration.Remove("StorageType"); + + configuration.Add("storageType", new string[] { typeString }); + + return configuration; + + + } + +} diff --git a/uSync.Core/Extensions/DictionaryExtensions.cs b/uSync.Core/Extensions/DictionaryExtensions.cs index 161ef326..e5d02efc 100644 --- a/uSync.Core/Extensions/DictionaryExtensions.cs +++ b/uSync.Core/Extensions/DictionaryExtensions.cs @@ -97,7 +97,7 @@ public static IDictionary MergeIgnoreDuplicates(this public static IDictionary ConvertToCamelCase(this IDictionary originalDictionary) => originalDictionary - .ToDictionary(kvp => kvp.Key.ToCamelCase(), kvp => kvp.Value); + .ToDictionary(kvp => kvp.Key.ToCamelCase(), kvp => kvp.Value, StringComparer.OrdinalIgnoreCase); public static string ToCamelCase(this string s) { diff --git a/uSync.Core/Extensions/JsonTextExtensions.cs b/uSync.Core/Extensions/JsonTextExtensions.cs index e00f734d..737805b8 100644 --- a/uSync.Core/Extensions/JsonTextExtensions.cs +++ b/uSync.Core/Extensions/JsonTextExtensions.cs @@ -2,6 +2,11 @@ using System.Text.Json; using System.Text.Json.Nodes; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +using Org.BouncyCastle.Bcpg.Sig; + +using Umbraco.Cms.Core.Security; using Umbraco.Extensions; using uSync.Core.Json; @@ -13,7 +18,7 @@ namespace uSync.Core.Extensions; /// public static class JsonTextExtensions { - private static readonly JsonSerializerOptions _defaultOptions = new() + internal static readonly JsonSerializerOptions _defaultOptions = new() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, @@ -21,7 +26,7 @@ public static class JsonTextExtensions TypeInfoResolver = new OrderedPropertiesJsonResolver(), }; - private static readonly JsonSerializerOptions _flatOptions = new() + internal static readonly JsonSerializerOptions _flatOptions = new() { WriteIndented = false, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, @@ -392,6 +397,9 @@ public static bool TryGetPropertyAsObject(this JsonObject jsonObject, string pro return result != default; } + /// + /// Gets the json property as a string, or returns string.empty + /// public static string GetPropertyAsString(this JsonObject obj, string propertyName) { if (obj.TryGetPropertyValue(propertyName, out var value)) @@ -400,6 +408,28 @@ public static string GetPropertyAsString(this JsonObject obj, string propertyNam return string.Empty; } + public static bool GetPropertyAsBool(this JsonObject obj, string propertyName, bool defaultValue) + { + if (obj.TryGetPropertyValue(propertyName, out var value)) + { + if (bool.TryParse(value?.ToString() ?? string.Empty, out var result) is false) + return defaultValue; + + return result; + } + + return defaultValue; + } + + public static TResult GetPropertyValueOrDefault(this JsonObject obj, string propertyName, TResult defaultValue) + { + if (obj.TryGetPropertyValue(propertyName, out var value) is false || value is null) + return defaultValue; + + var attempt = value.TryConvertTo(); + return attempt.ResultOr(defaultValue); + } + public static bool TryGetPropertyAsArray(this JsonObject jsonObject, string propertyName, [MaybeNullWhen(false)] out JsonArray result) { result = default; diff --git a/uSync.Core/Json/OrderedPropertiesJsonResolver.cs b/uSync.Core/Json/OrderedPropertiesJsonResolver.cs index 397dc5c1..b28b9f33 100644 --- a/uSync.Core/Json/OrderedPropertiesJsonResolver.cs +++ b/uSync.Core/Json/OrderedPropertiesJsonResolver.cs @@ -18,17 +18,25 @@ internal class OrderedPropertiesJsonResolver : DefaultJsonTypeInfoResolver { public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { - var order = 0; - JsonTypeInfo typeInfo = base.GetTypeInfo(type, options); - if (typeInfo.Kind != JsonTypeInfoKind.Object) return typeInfo; - foreach(var property in typeInfo.Properties.OrderBy(x => x.Name)) + switch(typeInfo.Kind) { - property.Order = order++; + case JsonTypeInfoKind.Object: + return SortObject(typeInfo); + default: + return typeInfo; } - - return typeInfo; } + private JsonTypeInfo SortObject(JsonTypeInfo typeInfo) + { + var order = 0; + foreach (var property in typeInfo.Properties.OrderBy(x => x.Name)) + { + property.Order = order++; + } + + return typeInfo; + } } diff --git a/uSync.Core/Serialization/Serializers/DataTypeSerializer.cs b/uSync.Core/Serialization/Serializers/DataTypeSerializer.cs index 060fb46c..d0fef12c 100644 --- a/uSync.Core/Serialization/Serializers/DataTypeSerializer.cs +++ b/uSync.Core/Serialization/Serializers/DataTypeSerializer.cs @@ -164,23 +164,28 @@ protected override SyncAttempt DeserializeCore(XElement node, SyncSer private List DeserializeConfiguration(IDataType item, XElement node) { - var serializer = _configurationSerializers.GetSerializer(item.EditorAlias); + // var serializer = _configurationSerializers.GetSerializer(item.EditorAlias); var config = node.Element("Config").ValueOrDefault(string.Empty); if (string.IsNullOrEmpty(config)) return []; var changes = new List(); - if (config.TryDeserialize(out IDictionary? dictionaryData) is false || dictionaryData is null) + if (config.TryDeserialize(out IDictionary? importData) is false || importData is null) { changes.AddWarning("Data", item.Name ?? item.Id.ToString(), "Failed to deserialize config for item"); return changes; } // v8,9,etc configs the properties - dictionaryData = dictionaryData.ConvertToCamelCase(); + importData = importData.ConvertToCamelCase(); - var importData = serializer == null ? dictionaryData : serializer.GetConfigurationImport(dictionaryData); + // multiple serializers can run per property. + var serializers = _configurationSerializers.GetSerializers(item.EditorAlias); + foreach(var serializer in serializers) { + logger.LogDebug("Running Configuration Serializer : {name} for {type}", serializer.Name, item.EditorAlias); + importData = serializer.GetConfigurationImport(importData); + } if (IsJsonEqual(importData, item.ConfigurationData) is false) { @@ -239,7 +244,7 @@ protected override IEnumerable GetContainers(IDataType item) private XElement SerializeConfiguration(IDataType item) { var serializer = _configurationSerializers.GetSerializer(item.EditorAlias); - + var configurationObject = TryGetConfigurationObject(item); // merge the configurationData and configurationObject into one dictionary diff --git a/uSync.Core/Serialization/Serializers/RichTextEditorMigratingSerializer.cs b/uSync.Core/Serialization/Serializers/RichTextEditorMigratingSerializer.cs new file mode 100644 index 00000000..e38c55ce --- /dev/null +++ b/uSync.Core/Serialization/Serializers/RichTextEditorMigratingSerializer.cs @@ -0,0 +1,82 @@ +using System.Collections.Immutable; +using System.Text.Json; + +using Umbraco.Cms.Core; +using Umbraco.Extensions; + +using uSync.Core.DataTypes; +using uSync.Core.Extensions; + +namespace uSync.Core.Serialization.Serializers; +internal class RichTextEditorMigratingSerializer : ConfigurationSerializerBase, IConfigurationSerializer +{ + public string Name => nameof(RichTextEditorMigratingSerializer); + + public string[] Editors => [Constants.PropertyEditors.Aliases.RichText]; + + public override IDictionary GetConfigurationImport(IDictionary configuration) + { + configuration = TopLevelEditor(configuration); + configuration = FixMediaParent(configuration); + + return configuration.ToImmutableSortedDictionary(); + } + + private IDictionary FixMediaParent(IDictionary configuration) + { + if (configuration.TryGetValue("mediaParentId", out var mediaParent) is false || mediaParent is null) + return configuration; + + if (mediaParent is JsonElement element is false || element.ValueKind != JsonValueKind.String) + return configuration; + + var mediaParentKey = element.ToString(); + if (string.IsNullOrWhiteSpace(mediaParentKey)) return configuration; + + + if (UdiParser.TryParse(mediaParentKey, out var mediaUdi) is false) + return configuration; + + if (mediaUdi is GuidUdi guidUdi is false) + return configuration; + + var mediaItem = new MediaParentItem() + { + Key = $"_media_parent_{mediaParentKey}".EncodeAsGuid().ToString(), + MediaKey = guidUdi.Guid.ToString() + }; + + configuration["mediaParentId"] = mediaItem.AsEnumerableOfOne(); + return configuration; + } + + private class MediaParentItem + { + public required string Key { get; set; } + public required string MediaKey { get; set; } + public string MediaTypeAlias { get; set; } = ""; + public string? FocalPoint { get; set; } = null; + public string[] Crops { get; set; } = []; + } + + private IDictionary TopLevelEditor(IDictionary configuration) + { + if (configuration.TryGetValue("editor", out var editorObject) is false || editorObject is null) + return configuration; + + if (editorObject is JsonElement element == false) return configuration; + if (element.ValueKind != JsonValueKind.Object) return configuration; + + if (element.ToString().TryDeserialize>(out var obj) is false || obj is null) + return configuration; + + configuration.Remove("editor"); + + foreach (var value in obj) + { + configuration[value.Key] = value.Value; + } + + return configuration; + } +} diff --git a/uSync.Core/uSync.Core.csproj b/uSync.Core/uSync.Core.csproj index 95d1760c..c5d04327 100644 --- a/uSync.Core/uSync.Core.csproj +++ b/uSync.Core/uSync.Core.csproj @@ -15,13 +15,9 @@ readme.md enable - - - - - + diff --git a/uSync.Core/uSyncCoreBuilderExtensions.cs b/uSync.Core/uSyncCoreBuilderExtensions.cs index ad4a6327..4da510c1 100644 --- a/uSync.Core/uSyncCoreBuilderExtensions.cs +++ b/uSync.Core/uSyncCoreBuilderExtensions.cs @@ -35,7 +35,7 @@ public static IUmbracoBuilder AdduSyncCore(this IUmbracoBuilder builder) // cache for entity items, we use it to speed up lookups. builder.Services.AddSingleton(); - + // register *all* ConfigurationSerializers except those marked [HideFromTypeFinder] // has to happen before the DataTypeSerializer is loaded, because that is where // they are used diff --git a/uSync.Tests/Migrations/ColourPickerTests.cs b/uSync.Tests/Migrations/ColourPickerTests.cs new file mode 100644 index 00000000..0801a83f --- /dev/null +++ b/uSync.Tests/Migrations/ColourPickerTests.cs @@ -0,0 +1,39 @@ +using NUnit.Framework; + +using uSync.Core.DataTypes.DataTypeSerializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class ColourPickerTests : MigrationTestBase +{ + private ColourPickerMigratingConfigSerializer _serializer = new ColourPickerMigratingConfigSerializer(); + + private static string Source = "{\r\n \"Items\": [\r\n {\r\n \"id\": 1,\r\n \"value\": \"{\\\"value\\\":\\\"ff0000\\\",\\\"label\\\":\\\"Red\\\"}\"\r\n },\r\n {\r\n \"id\": 2,\r\n \"value\": \"{\\\"value\\\":\\\"00ff00\\\",\\\"label\\\":\\\"Green\\\"}\"\r\n },\r\n {\r\n \"id\": 3,\r\n \"value\": \"{\\\"value\\\":\\\"0000ff\\\",\\\"label\\\":\\\"Blue\\\"}\"\r\n }\r\n ],\r\n \"UseLabel\": true\r\n}"; + private static string Target = @"{ + ""items"": [ + { + ""label"": ""Red"", + ""value"": ""ff0000"" + }, + { + ""label"": ""Green"", + ""value"": ""00ff00"" + }, + { + ""label"": ""Blue"", + ""value"": ""0000ff"" + } + ], + ""useLabel"": true +}"; + + [Test] + public void ColourPickerValuesTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + + [Test] + public void ColourPickerMigratedValueTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); + +} diff --git a/uSync.Tests/Migrations/FileUploadMigrationTests.cs b/uSync.Tests/Migrations/FileUploadMigrationTests.cs new file mode 100644 index 00000000..cde6341e --- /dev/null +++ b/uSync.Tests/Migrations/FileUploadMigrationTests.cs @@ -0,0 +1,40 @@ +using NUnit.Framework; + +using uSync.Core.DataTypes.DataTypeSerializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class FileUploadMigrationTests : MigrationTestBase +{ + private FileUploadMigratingConfigSerializer _serializer = new(); + + private static string Source = @"{ + ""FileExtensions"": [ + { + ""id"": 0, + ""value"": ""pdf"" + }, + { + ""id"": 1, + ""value"": ""png"" + } + ] +}"; + + private static string Target = @"{ + ""fileExtensions"": [ + ""pdf"", + ""png"" + ] +}"; + + + [Test] + public void FileMigrationValueTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + + [Test] + public void FileUploadMigratedValueTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); +} diff --git a/uSync.Tests/Migrations/LabelMigrationTests.cs b/uSync.Tests/Migrations/LabelMigrationTests.cs new file mode 100644 index 00000000..d0fd6d22 --- /dev/null +++ b/uSync.Tests/Migrations/LabelMigrationTests.cs @@ -0,0 +1,23 @@ +using NUnit.Framework; + +using uSync.Core.DataTypes.DataTypeSerializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class LabelMigrationTests : MigrationTestBase +{ + private LabelMigratingConfigSerializer _serializer= new LabelMigratingConfigSerializer(); + + private static string Source = "{ \"ValueType\": \"DECIMAL\" }"; + private static string Target = "{\r\n \"umbracoDataValueType\": \"DECIMAL\"\r\n}"; + + [Test] + public void LabelMigrationValueTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + + [Test] + public void LabelMigrationMigratedValueTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); + +} diff --git a/uSync.Tests/Migrations/ListMigrationTests.cs b/uSync.Tests/Migrations/ListMigrationTests.cs new file mode 100644 index 00000000..316ceefd --- /dev/null +++ b/uSync.Tests/Migrations/ListMigrationTests.cs @@ -0,0 +1,22 @@ +using NUnit.Framework; + +using uSync.Core.DataTypes.DataTypeSerializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class ListMigrationTests : MigrationTestBase +{ + private DataListMigratingConfigSerializer _serializer = new DataListMigratingConfigSerializer(); + + private static string Source = "{\r\n\t\"Items\": [\r\n\t\t{\r\n\t\t\t\"id\": 1,\r\n\t\t\t\"value\": \"One\"\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": 2,\r\n\t\t\t\"value\": \"Two\"\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": 3,\r\n\t\t\t\"value\": \"Three\"\r\n\t\t}\r\n\t]\r\n}\r\n"; + private static string Target = "{\r\n \"items\": [\r\n \"One\",\r\n \"Two\",\r\n \"Three\"\r\n ]\r\n}"; + + [Test] + public void DropdownListMigrationTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + + [Test] + public void DropdownListMigratedValueTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); +} diff --git a/uSync.Tests/Migrations/MarkdownEditorMigrationTest.cs b/uSync.Tests/Migrations/MarkdownEditorMigrationTest.cs new file mode 100644 index 00000000..2d66c35c --- /dev/null +++ b/uSync.Tests/Migrations/MarkdownEditorMigrationTest.cs @@ -0,0 +1,21 @@ +using NUnit.Framework; + +using uSync.Core.DataTypes.DataTypeSerializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class MarkdownEditorMigrationTest : MigrationTestBase +{ + private MarkdownMigratingConfigSerializer _serializer = new MarkdownMigratingConfigSerializer(); + + private static string Source = "{\r\n \"DefaultValue\": \"#Hello\",\r\n \"DisplayLivePreview\": false,\r\n \"OverlaySize\": \"medium\"\r\n}"; + private static string Target = "{\r\n \"defaultValue\": \"#Hello\",\r\n \"overlaySize\": \"medium\",\r\n \"preview\": false\r\n}"; + + [Test] + public void MarkdownSerializeTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + [Test] + public void MarkdownMigratedValueTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); +} diff --git a/uSync.Tests/Migrations/MigrationTestBase.cs b/uSync.Tests/Migrations/MigrationTestBase.cs new file mode 100644 index 00000000..6dc898bb --- /dev/null +++ b/uSync.Tests/Migrations/MigrationTestBase.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; + +using NUnit.Framework; + +using Umbraco.Extensions; + +using uSync.Core.DataTypes; +using uSync.Core.Extensions; + +namespace uSync.Tests.Migrations; +internal class MigrationTestBase +{ + + protected void TestSerializerPropertyMigration(IConfigurationSerializer serializer, string source, string target) + { + if (source.TryDeserialize(out IDictionary dictionaryData) is false || dictionaryData is null) + return; + + dictionaryData = dictionaryData.ConvertToCamelCase(); + + var result = serializer.GetConfigurationImport(dictionaryData); + + var targetDictionary = + JsonSerializer.Serialize( + JsonSerializer.Deserialize(target).ToDictionary(), + JsonTextExtensions._defaultOptions + ); + var resultJson = JsonSerializer.Serialize(result, JsonTextExtensions._defaultOptions); + + Assert.AreEqual(targetDictionary, resultJson); + } +} diff --git a/uSync.Tests/Migrations/MultipleTextMigratorTests.cs b/uSync.Tests/Migrations/MultipleTextMigratorTests.cs new file mode 100644 index 00000000..3add1373 --- /dev/null +++ b/uSync.Tests/Migrations/MultipleTextMigratorTests.cs @@ -0,0 +1,22 @@ +using NUnit.Framework; + +using uSync.Core.DataTypes.DataTypeSerializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class MultipleTextMigratorTests : MigrationTestBase +{ + private MultipleTextMigratingConfigSerializer _serializer = new MultipleTextMigratingConfigSerializer(); + + private static string Source = "{\r\n \"Maximum\": 4,\r\n \"Minimum\": 1\r\n }"; + private static string Target = "{\r\n \"max\": 4,\r\n \"min\": 1\r\n}"; + + [Test] + public void MultipleTextMigratorValuesTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + + [Test] + public void MultipleTextMigratedValuesTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); +} diff --git a/uSync.Tests/Migrations/RichTextMigrationTests.cs b/uSync.Tests/Migrations/RichTextMigrationTests.cs new file mode 100644 index 00000000..5b0640cf --- /dev/null +++ b/uSync.Tests/Migrations/RichTextMigrationTests.cs @@ -0,0 +1,128 @@ +using NUnit.Framework; + +using uSync.Core.Serialization.Serializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class RichTextMigrationTests: MigrationTestBase +{ + private RichTextEditorMigratingSerializer _serializer = new(); + + private static string Source = @"{ + ""Blocks"": [ + { + ""backgroundColor"": null, + ""contentElementTypeKey"": ""a0eec50c-54ce-47d3-97f1-c01843887567"", + ""displayInline"": false, + ""editorSize"": ""medium"", + ""forceHideContentEditorInOverlay"": false, + ""iconColor"": null, + ""label"": null, + ""settingsElementTypeKey"": null, + ""stylesheet"": null, + ""thumbnail"": null, + ""view"": null + } + ], + ""Editor"": { + ""toolbar"": [ + ""ace"", + ""styles"", + ""bold"", + ""italic"", + ""alignleft"", + ""aligncenter"", + ""alignright"", + ""bullist"", + ""numlist"", + ""outdent"", + ""indent"", + ""link"", + ""umbmediapicker"", + ""umbmacro"", + ""umbembeddialog"" + ], + ""stylesheets"": [ + ""/Editor Styles.css"" + ], + ""maxImageSize"": 500, + ""mode"": ""classic"", + ""dimensions"": { + ""width"": 500, + ""height"": 500 + } + }, + ""HideLabel"": false, + ""IgnoreUserStartNodes"": false, + ""MediaParentId"": ""umb://media/71332aa78bea44f19aa600de961b66e8"", + ""OverlaySize"": ""medium"", + ""UseLiveEditing"": false +}"; + + private static string Target = @"{ + ""blocks"": [ + { + ""backgroundColor"": null, + ""contentElementTypeKey"": ""a0eec50c-54ce-47d3-97f1-c01843887567"", + ""displayInline"": false, + ""editorSize"": ""medium"", + ""forceHideContentEditorInOverlay"": false, + ""iconColor"": null, + ""label"": null, + ""settingsElementTypeKey"": null, + ""stylesheet"": null, + ""thumbnail"": null, + ""view"": null + } + ], + ""dimensions"": { + ""width"": 500, + ""height"": 500 + }, + ""hideLabel"": false, + ""ignoreUserStartNodes"": false, + ""maxImageSize"": 500, + ""mediaParentId"": [ + { + ""crops"": [], + ""focalPoint"": null, + ""key"": ""5f6d6564-6961-5f70-6172-656e745f756d"", + ""mediaKey"": ""71332aa7-8bea-44f1-9aa6-00de961b66e8"", + ""mediaTypeAlias"": """" + } + ], + ""mode"": ""classic"", + ""overlaySize"": ""medium"", + ""stylesheets"": [ + ""/Editor Styles.css"" + ], + ""toolbar"": [ + ""ace"", + ""styles"", + ""bold"", + ""italic"", + ""alignleft"", + ""aligncenter"", + ""alignright"", + ""bullist"", + ""numlist"", + ""outdent"", + ""indent"", + ""link"", + ""umbmediapicker"", + ""umbmacro"", + ""umbembeddialog"" + ], + ""useLiveEditing"": false +}"; + + [Test] + public void RichTextMigrationValueTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + + [Test] + public void RichTextMigratedValueTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); + +} \ No newline at end of file diff --git a/uSync.Tests/Migrations/SliderMigrationTests.cs b/uSync.Tests/Migrations/SliderMigrationTests.cs new file mode 100644 index 00000000..4394257a --- /dev/null +++ b/uSync.Tests/Migrations/SliderMigrationTests.cs @@ -0,0 +1,22 @@ +using NUnit.Framework; + +using uSync.Core.DataTypes.DataTypeSerializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class SliderMigrationTests : MigrationTestBase +{ + private SliderMigratingConfigSerializer _serializer = new SliderMigratingConfigSerializer(); + + private static string Source = "{\r\n \"EnableRange\": false,\r\n \"InitialValue\": 1,\r\n \"InitialValue2\": 2,\r\n \"MaximumValue\": 5,\r\n \"MinimumValue\": 1,\r\n \"StepIncrements\": 1\r\n}"; + private static string Target = "{\r\n \"enableRange\": false,\r\n \"initVal1\": 1,\r\n \"initVal2\": 2,\r\n \"maxVal\": 5,\r\n \"minVal\": 1,\r\n \"step\": 1\r\n}"; + + [Test] + public void SliderMigrationValueTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + + [Test] + public void SliderMigratedValueTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); +} diff --git a/uSync.Tests/Migrations/TagMigrationTest.cs b/uSync.Tests/Migrations/TagMigrationTest.cs new file mode 100644 index 00000000..3658770a --- /dev/null +++ b/uSync.Tests/Migrations/TagMigrationTest.cs @@ -0,0 +1,32 @@ +using NUnit.Framework; + +using uSync.Core.DataTypes.DataTypeSerializers; + +namespace uSync.Tests.Migrations; + +[TestFixture] +internal class TagMigrationTest : MigrationTestBase +{ + private TagMigratingConfigSerializer _serializer = new TagMigratingConfigSerializer(); + + private static string Source = @"{ + ""Delimiter"": ""\u0000"", + ""Group"": ""taggroup"", + ""StorageType"": 0 +}"; + private static string Target = @"{ + ""group"": ""taggroup"", + ""storageType"": [ + ""csv"" + ] +}"; + + [Test] + public void TagValueMigrationTest() + => TestSerializerPropertyMigration(_serializer, Source, Target); + + [Test] + + public void TagValueMigratedValuesTest() + => TestSerializerPropertyMigration(_serializer, Target, Target); +} \ No newline at end of file