diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs
index b2912eea16..56c174b68c 100644
--- a/src/Umbraco.Core/Constants-PropertyEditors.cs
+++ b/src/Umbraco.Core/Constants-PropertyEditors.cs
@@ -27,7 +27,7 @@ namespace Umbraco.Core
///
/// Color Picker.
///
- public const string ColorPicker = "Umbraco.ColorPickerAlias";
+ public const string ColorPicker = "Umbraco.ColorPicker";
///
/// Content Picker.
diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
index 21ce08de20..5e9e09e63b 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
@@ -84,7 +84,7 @@ namespace Umbraco.Core.Migrations.Upgrade
.Chain("{3D18920C-E84D-405C-A06A-B7CEE52FE5DD}")
.Chain("{FB0A5429-587E-4BD0-8A67-20F0E7E62FF7}")
.Chain("{F0C42457-6A3B-4912-A7EA-F27ED85A2092}")
- .Chain("{8640C9E4-A1C0-4C59-99BB-609B4E604981}")
+ .Chain("{8640C9E4-A1C0-4C59-99BB-609B4E604981}")
.Chain("{DD1B99AF-8106-4E00-BAC7-A43003EA07F8}")
.Chain("{CC1B1201-1328-443C-954A-E0BBB8CCC1B5}");
@@ -154,7 +154,7 @@ namespace Umbraco.Core.Migrations.Upgrade
// 8.0.0
Chain("{6550C7E8-77B7-4DE3-9B58-E31C81CB9504}");
Chain("{E3388F73-89FA-45FE-A539-C7FACC8D63DD}");
- Chain("{82C4BA1D-7720-46B1-BBD7-07F3F73800E6}");
+ Chain("{82C4BA1D-7720-46B1-BBD7-07F3F73800E6}");
Chain("{139F26D7-7E08-48E3-81D9-E50A21A72F67}");
Chain("{CC1B1201-1328-443C-954A-E0BBB8CCC1B5}");
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorDataType.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs
similarity index 80%
rename from src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorDataType.cs
rename to src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs
index b93b68b27d..202a4f0c0a 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorDataType.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs
@@ -1,20 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Reflection;
using Newtonsoft.Json;
using NPoco;
using Umbraco.Core.Migrations.Install;
using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Dtos;
+using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
- public class RefactorDataType : MigrationBase
+ public class DataTypeMigration : MigrationBase
{
- public RefactorDataType(IMigrationContext context)
+ public DataTypeMigration(IMigrationContext context)
: base(context)
{ }
@@ -38,6 +37,12 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
foreach (var x in DatabaseSchemaCreator.OrderedTables)
Create.KeysAndIndexes(x.Value).Do();
+ // renames
+ Database.Execute(Sql()
+ .Update(u => u.Set(x => x.EditorAlias, "Umbraco.ColorPicker"))
+ .Where(x => x.EditorAlias == "Umbraco.ColorPickerAlias"));
+
+ // from preValues to configuration...
var sql = Sql()
.Select()
.AndSelect(x => x.Alias, x => x.SortOrder, x => x.Value)
@@ -64,9 +69,9 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
}
else
{
- // fixme deal with null or empty aliases
- // fixme deal with duplicate aliases
- // in these cases, fallback to array?
+ // assuming we don't want to fall back to array
+ if (aliases.Length != group.Count() || aliases.Any(string.IsNullOrWhiteSpace))
+ throw new InvalidOperationException($"Cannot migrate datatype w/ id={dataType.NodeId} preValues: duplicate or null/empty alias.");
// dictionary-base prevalues
var values = group.ToDictionary(x => x.Alias, x => x.Value);
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
index fc85a70c6a..f9b1a959f8 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
@@ -11,8 +11,9 @@
var exists = Database.Fetch("select id from umbracoUser where id=-1;").Count > 0;
if (exists) return;
- Database.Execute("set identity_insert umbracoUser on;");
Database.Execute("update umbracoUser set userLogin = userLogin + '__' where userId=0");
+
+ Database.Execute("set identity_insert umbracoUser on;");
Database.Execute(@"
insert into umbracoUser select -1,
userDisabled, userNoConsole, userName, substring(userLogin, 1, len(userLogin) - 2), userPassword, passwordConfig,
@@ -20,9 +21,12 @@
lastPasswordChangeDate, lastLoginDate, emailConfirmedDate, invitedDate,
createDate, updateDate, avatar
from umbracoUser where id=0;");
- Database.Execute("update umbracoUser2UserGroup set userId=-1 where userId=0;");
- Database.Execute("delete from umbracoUser where id=0;");
Database.Execute("set identity_insert umbracoUser off;");
+
+ Database.Execute("update umbracoUser2UserGroup set userId=-1 where userId=0;");
+ Database.Execute("update umbracoNode set nodeUser=-1 where nodeUser=0;");
+ Database.Execute("update uContentVersion set userId=-1 where userId=0;");
+ Database.Execute("delete from umbracoUser where id=0;");
}
}
}
diff --git a/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
index 66cbcb354f..226aa07483 100644
--- a/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
@@ -1,5 +1,7 @@
using System;
+using System.Reflection;
using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
@@ -51,7 +53,7 @@ namespace Umbraco.Core.Persistence.Factories
EditorAlias = entity.EditorAlias,
NodeId = entity.Id,
DbType = entity.DatabaseType.ToString(),
- Configuration = entity.Configuration == null ? null : JsonConvert.SerializeObject(entity.Configuration),
+ Configuration = entity.Configuration == null ? null : JsonConvert.SerializeObject(entity.Configuration, ConfigurationEditor.ConfigurationJsonSettings),
NodeDto = BuildNodeDto(entity)
};
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
index 159dc5ec7d..a4b6e52b3d 100644
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+using Umbraco.Core.Serialization;
namespace Umbraco.Core.PropertyEditors
{
@@ -99,5 +102,35 @@ namespace Umbraco.Core.PropertyEditors
///
public virtual Dictionary ToValueEditor(object configuration)
=> ToConfigurationEditor(configuration);
+
+ ///
+ /// Gets the custom json serializer settings for configurations.
+ ///
+ public static JsonSerializerSettings ConfigurationJsonSettings { get; } = new JsonSerializerSettings
+ {
+ ContractResolver = new ConfigurationCustomContractResolver(),
+ Converters = new List(new[]{new FuzzyBooleanConverter()})
+ };
+
+ private class ConfigurationCustomContractResolver : DefaultContractResolver
+ {
+ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ {
+ // base.CreateProperty deals with [JsonProperty("name")]
+ var property = base.CreateProperty(member, memberSerialization);
+
+ // override with our custom attribute, if any
+ var attribute = member.GetCustomAttribute();
+ if (attribute != null) property.PropertyName = attribute.Key;
+
+ // for value types,
+ // don't try to deserialize nulls (in legacy json)
+ // no impact on serialization (value cannot be null)
+ if (member is PropertyInfo propertyInfo && propertyInfo.PropertyType.IsValueType)
+ property.NullValueHandling = NullValueHandling.Ignore;
+
+ return property;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
index 96965f731a..bfa32bd06e 100644
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
+++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
@@ -104,7 +104,7 @@ namespace Umbraco.Core.PropertyEditors
try
{
if (string.IsNullOrWhiteSpace(configuration)) return new TConfiguration();
- return JsonConvert.DeserializeObject(configuration);
+ return JsonConvert.DeserializeObject(configuration, ConfigurationJsonSettings);
}
catch (Exception e)
{
diff --git a/src/Umbraco.Core/Serialization/FuzzyBooleanConverter.cs b/src/Umbraco.Core/Serialization/FuzzyBooleanConverter.cs
new file mode 100644
index 0000000000..db94f41845
--- /dev/null
+++ b/src/Umbraco.Core/Serialization/FuzzyBooleanConverter.cs
@@ -0,0 +1,42 @@
+using System;
+using Newtonsoft.Json;
+
+namespace Umbraco.Core.Serialization
+{
+ public class FuzzyBooleanConverter : JsonConverter
+ {
+ public override bool CanWrite => false;
+
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override bool CanRead => true;
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ var value = reader.Value;
+ if (value is bool) return value;
+
+ switch (value.ToString().ToLower().Trim())
+ {
+ case "true":
+ case "yes":
+ case "y":
+ case "1":
+ return true;
+
+ case "false":
+ case "no":
+ case "n":
+ case "0":
+ return false;
+ }
+
+ return new JsonSerializer().Deserialize(reader, objectType);
+ }
+
+ public override bool CanConvert(Type objectType) => objectType == typeof(bool);
+ }
+}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index e1f4a31be3..154c0a273a 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -314,7 +314,7 @@
-
+
@@ -1294,6 +1294,7 @@
+
diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeConfigurationFieldDisplayResolver.cs b/src/Umbraco.Web/Models/Mapping/DataTypeConfigurationFieldDisplayResolver.cs
index ba76b96778..3e70f36839 100644
--- a/src/Umbraco.Web/Models/Mapping/DataTypeConfigurationFieldDisplayResolver.cs
+++ b/src/Umbraco.Web/Models/Mapping/DataTypeConfigurationFieldDisplayResolver.cs
@@ -36,7 +36,7 @@ namespace Umbraco.Web.Models.Mapping
///
public IEnumerable Resolve(IDataType dataType)
{
- if (!string.IsNullOrWhiteSpace(dataType.EditorAlias) || !Current.PropertyEditors.TryGet(dataType.EditorAlias, out var e) || !(e is DataEditor editor))
+ if (string.IsNullOrWhiteSpace(dataType.EditorAlias) || !Current.PropertyEditors.TryGet(dataType.EditorAlias, out var e) || !(e is DataEditor editor))
throw new InvalidOperationException($"Could not find a property editor with alias \"{dataType.EditorAlias}\".");
var configuration = dataType.Configuration;
diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentConfiguration.cs b/src/Umbraco.Web/PropertyEditors/NestedContentConfiguration.cs
index b1ea7c633a..44648ee859 100644
--- a/src/Umbraco.Web/PropertyEditors/NestedContentConfiguration.cs
+++ b/src/Umbraco.Web/PropertyEditors/NestedContentConfiguration.cs
@@ -18,15 +18,12 @@ namespace Umbraco.Web.PropertyEditors
public int? MaxItems { get; set; }
[ConfigurationField("confirmDeletes", "Confirm Deletes", "boolean", Description = "Set whether item deletions should require confirming.")]
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // do not try to map a null value to a boolean
public bool ConfirmDeletes { get; set; } = true;
[ConfigurationField("showIcons", "Show Icons", "boolean", Description = "Set whether to show the items doc type icon in the list.")]
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // do not try to map a null value to a boolean
public bool ShowIcons { get; set; } = true;
[ConfigurationField("hideLabel", "Hide Label", "boolean", Description = "Set whether to hide the editor label and have the list take up the full width of the editor window.")]
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // do not try to map a null value to a boolean
public bool HideLabel { get; set; }
public class ContentType