From 632e401d33bc60d03394ee21a5a88f11b9efb93b Mon Sep 17 00:00:00 2001 From: Stephan Date: Sun, 3 Jun 2018 13:30:50 +0200 Subject: [PATCH] Implement typed labels --- src/Umbraco.Core/Constants-DataTypes.cs | 7 ++ .../Migrations/Install/DatabaseDataCreator.cs | 75 ++++++++--- .../Migrations/Upgrade/UmbracoPlan.cs | 13 +- .../Upgrade/V_8_0_0/AddTypedLabels.cs | 116 ++++++++++++++++++ .../PropertyEditors/LabelConfiguration.cs | 7 +- .../LabelConfigurationEditor.cs | 4 +- .../PropertyEditors/LabelPropertyEditor.cs | 72 ++++++----- .../ValueConverters/LabelValueConverter.cs | 55 ++++++++- .../PropertyEditors/ValueTypes.cs | 6 + src/Umbraco.Core/Umbraco.Core.csproj | 4 + .../Services/CachedDataTypeServiceTests.cs | 1 + .../Services/DataTypeServiceTests.cs | 1 + src/Umbraco.Web/Umbraco.Web.csproj | 3 - 13 files changed, 291 insertions(+), 73 deletions(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddTypedLabels.cs rename src/{Umbraco.Web => Umbraco.Core}/PropertyEditors/LabelConfiguration.cs (78%) rename src/{Umbraco.Web => Umbraco.Core}/PropertyEditors/LabelConfigurationEditor.cs (91%) rename src/{Umbraco.Web => Umbraco.Core}/PropertyEditors/LabelPropertyEditor.cs (87%) diff --git a/src/Umbraco.Core/Constants-DataTypes.cs b/src/Umbraco.Core/Constants-DataTypes.cs index 510bbbb82b..c9a33ba04d 100644 --- a/src/Umbraco.Core/Constants-DataTypes.cs +++ b/src/Umbraco.Core/Constants-DataTypes.cs @@ -4,6 +4,13 @@ { public static class DataTypes { + public const int LabelString = -92; + public const int LabelInt = -91; + public const int LabelBigint = -93; + public const int LabelDateTime = -94; + public const int LabelTime = -98; + public const int LabelDecimal = -99; + public const int Textbox = -88; public const int Boolean = -49; public const int Datetime = -36; diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index dda1207f92..f5732c6597 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -81,10 +81,35 @@ namespace Umbraco.Core.Migrations.Install private void CreateNodeData() { + void InsertDataTypeNodeDto(int id, int sortOrder, string uniqueId, string text) + { + var nodeDto = new NodeDto + { + NodeId = id, + Trashed = false, + ParentId = -1, + UserId = -1, + Level = 1, + Path = "-1,-" + id, + SortOrder = sortOrder, + UniqueId = new Guid(uniqueId), + Text = text, + NodeObjectType = Constants.ObjectTypes.DataType, + CreateDate = DateTime.Now + }; + + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, nodeDto); + } + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -1, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1", SortOrder = 0, UniqueId = new Guid("916724a5-173d-4619-b97e-b9de133dd6f5"), Text = "SYSTEM DATA: umbraco master root", NodeObjectType = Constants.ObjectTypes.SystemRoot, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -20, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,-20", SortOrder = 0, UniqueId = new Guid("0F582A79-1E41-4CF0-BFA0-76340651891A"), Text = "Recycle Bin", NodeObjectType = Constants.ObjectTypes.ContentRecycleBin, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -21, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,-21", SortOrder = 0, UniqueId = new Guid("BF7C7CBC-952F-4518-97A2-69E9C7B33842"), Text = "Recycle Bin", NodeObjectType = Constants.ObjectTypes.MediaRecycleBin, CreateDate = DateTime.Now }); - _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -92, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-92", SortOrder = 35, UniqueId = new Guid("f0bc4bfb-b499-40d6-ba86-058885a5178c"), Text = "Label", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); + InsertDataTypeNodeDto(Constants.DataTypes.LabelString, 35, "f0bc4bfb-b499-40d6-ba86-058885a5178c", "Label"); + InsertDataTypeNodeDto(Constants.DataTypes.LabelInt, 36, "8e7f995c-bd81-4627-9932-c40e568ec788", "Label (integer)"); + InsertDataTypeNodeDto(Constants.DataTypes.LabelBigint, 36, "930861bf-e262-4ead-a704-f99453565708", "Label (bigint)"); + InsertDataTypeNodeDto(Constants.DataTypes.LabelDateTime, 37, "0e9794eb-f9b5-4f20-a788-93acd233a7e4", "Label (datetime)"); + InsertDataTypeNodeDto(Constants.DataTypes.LabelTime, 38, "a97cec69-9b71-4c30-8b12-ec398860d7e8", "Label (time)"); + InsertDataTypeNodeDto(Constants.DataTypes.LabelDecimal, 39, "8f1ef1e1-9de4-40d3-a072-6673f631ca64", "Label (decimal)"); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -90, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-90", SortOrder = 34, UniqueId = new Guid("84c6b441-31df-4ffe-b67e-67d5bc3ae65a"), Text = "Upload", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -89, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-89", SortOrder = 33, UniqueId = new Guid("c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3"), Text = "Textarea", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -88, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-88", SortOrder = 32, UniqueId = new Guid("0cc0eba1-9960-42c9-bf9b-60e150b429ae"), Text = "Textstring", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); @@ -114,11 +139,6 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Related Links", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - - //TODO: We're not creating these for 7.0 - //_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1039, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1039", SortOrder = 2, UniqueId = new Guid("06f349a9-c949-4b6a-8660-59c10451af42"), Text = "Ultimate Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - //_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1038, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1038", SortOrder = 2, UniqueId = new Guid("1251c96c-185c-4e9b-93f4-b48205573cbd"), Text = "Simple Editor", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - //_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1042, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1042", SortOrder = 2, UniqueId = new Guid("0a452bd5-83f9-4bc3-8403-1286e13fb77e"), Text = "Macro Container", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); } private void CreateLockData() @@ -193,22 +213,22 @@ namespace Umbraco.Core.Migrations.Install private void CreatePropertyTypeData() { _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 6, UniqueId = 6.ToGuid(), DataTypeId = 1043, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.File, Name = "Upload image", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 7, UniqueId = 7.ToGuid(), DataTypeId = -92, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Width, Name = "Width", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 8, UniqueId = 8.ToGuid(), DataTypeId = -92, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Height, Name = "Height", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 9, UniqueId = 9.ToGuid(), DataTypeId = -92, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 7, UniqueId = 7.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Width, Name = "Width", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 8, UniqueId = 8.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Height, Name = "Height", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 9, UniqueId = 9.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 10, UniqueId = 10.ToGuid(), DataTypeId = -92, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = -90, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "Upload file", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 25, UniqueId = 25.ToGuid(), DataTypeId = -92, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 26, UniqueId = 26.ToGuid(), DataTypeId = -92, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 26, UniqueId = 26.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 27, UniqueId = 27.ToGuid(), DataTypeId = Constants.DataTypes.DefaultMediaListView, ContentTypeId = 1031, PropertyTypeGroupId = 5, Alias = "contents", Name = "Contents:", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); //membership property types _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 28, UniqueId = 28.ToGuid(), DataTypeId = -89, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.Comments, Name = Constants.Conventions.Member.CommentsLabel, SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 29, UniqueId = 29.ToGuid(), DataTypeId = -92, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.FailedPasswordAttempts, Name = Constants.Conventions.Member.FailedPasswordAttemptsLabel, SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 29, UniqueId = 29.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.FailedPasswordAttempts, Name = Constants.Conventions.Member.FailedPasswordAttemptsLabel, SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 30, UniqueId = 30.ToGuid(), DataTypeId = -49, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsApproved, Name = Constants.Conventions.Member.IsApprovedLabel, SortOrder = 2, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 31, UniqueId = 31.ToGuid(), DataTypeId = -49, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsLockedOut, Name = Constants.Conventions.Member.IsLockedOutLabel, SortOrder = 3, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = -92, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = -92, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); - _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = -92, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); + _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.InvariantNeutral }); } @@ -226,6 +246,21 @@ namespace Umbraco.Core.Migrations.Install private void CreateDataTypeData() { + void InsertDataTypeDto(int id, string dbType, string configuration = null) + { + var dataTypeDto = new DataTypeDto + { + NodeId = id, + EditorAlias = Constants.PropertyEditors.Aliases.NoEdit, + DbType = dbType + }; + + if (configuration != null) + dataTypeDto.Configuration = configuration; + + _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, dataTypeDto); + } + //layouts for the list view const string cardLayout = "{\"name\": \"Grid\",\"path\": \"views/propertyeditors/listview/layouts/grid/grid.html\", \"icon\": \"icon-thumbnails-small\", \"isSystem\": 1, \"selected\": true}"; const string listLayout = "{\"name\": \"List\",\"path\": \"views/propertyeditors/listview/layouts/list/list.html\",\"icon\": \"icon-list\", \"isSystem\": 1,\"selected\": true}"; @@ -239,7 +274,12 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -88, EditorAlias = Constants.PropertyEditors.Aliases.TextBox, DbType = "Nvarchar" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -89, EditorAlias = Constants.PropertyEditors.Aliases.TextArea, DbType = "Ntext" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -90, EditorAlias = Constants.PropertyEditors.Aliases.UploadField, DbType = "Nvarchar" }); - _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -92, EditorAlias = Constants.PropertyEditors.Aliases.NoEdit, DbType = "Nvarchar" }); + InsertDataTypeDto(Constants.DataTypes.LabelString, "Nvarchar", "{\"umbracoDataValueType\":\"STRING\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelInt,"Integer", "{\"umbracoDataValueType\":\"INT\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelBigint, "Nvarchar", "{\"umbracoDataValueType\":\"BIGINT\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelDateTime, "Date", "{\"umbracoDataValueType\":\"DATETIME\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelDecimal, "Decimal", "{\"umbracoDataValueType\":\"DECIMAL\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelTime, "Date", "{\"umbracoDataValueType\":\"TIME\"}"); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -36, EditorAlias = Constants.PropertyEditors.Aliases.DateTime, DbType = "Date" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -37, EditorAlias = Constants.PropertyEditors.Aliases.ColorPicker, DbType = "Nvarchar" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -39, EditorAlias = Constants.PropertyEditors.Aliases.DropDownListMultiple, DbType = "Nvarchar" }); @@ -264,11 +304,6 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1049, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext", Configuration = "{\"multiPicker\":1}" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1050, EditorAlias = Constants.PropertyEditors.Aliases.RelatedLinks, DbType = "Ntext" }); - - //TODO: We're not creating these for 7.0 - //_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { DataTypeId = 1038, PropertyEditorAlias = Constants.PropertyEditors.MarkdownEditorAlias, DbType = "Ntext" }); - //_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { DataTypeId = 1039, PropertyEditorAlias = Constants.PropertyEditors.UltimatePickerAlias, DbType = "Ntext" }); - //_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { DataTypeId = 1042, PropertyEditorAlias = Constants.PropertyEditors.MacroContainerAlias, DbType = "Ntext" }); } private void CreateRelationTypeData() diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index cf531a0610..b7a77b10ce 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -120,9 +120,10 @@ namespace Umbraco.Core.Migrations.Upgrade Chain("{49506BAE-CEBB-4431-A1A6-24AD6EBBBC57}"); Chain("{083A9894-903D-41B7-B6B3-9EAF2D4CCED0}"); Chain("{42097524-0F8C-482C-BD79-AC7407D8A028}"); + Chain("{3608CD41-792A-4E9A-A97D-42A5E797EE31}"); // must chain to v8 final state (see at end of file) - Chain("{A7540C58-171D-462A-91C5-7A9AA5CB8BFD}"); + Chain("{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}"); // UPGRADE FROM 7, MORE RECENT @@ -211,13 +212,19 @@ namespace Umbraco.Core.Migrations.Upgrade // however, need to take care of ppl in post-AddVariationTables1 state Add("{941B2ABA-2D06-4E04-81F5-74224F1DB037}", "{76DF5CD7-A884-41A5-8DC6-7860D95B1DF5}"); + // 8.0.0 Chain("{A7540C58-171D-462A-91C5-7A9AA5CB8BFD}"); - Chain("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}"); + + // merge + Chain("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}"); // shannon added that one - let's keep it as the default path + Chain("{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}"); // then add stephan's - to new final state + //Chain("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}"); // stephan added that one - need a path to final state + Add("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}", "{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}"); // FINAL STATE - MUST MATCH LAST ONE ABOVE ! // whenever this changes, update all references in this file! - Add(string.Empty, "{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}"); + Add(string.Empty, "{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}"); } } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddTypedLabels.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddTypedLabels.cs new file mode 100644 index 0000000000..cb8a58f3e3 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddTypedLabels.cs @@ -0,0 +1,116 @@ +using System; +using System.Globalization; +using NPoco; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class AddTypedLabels : MigrationBase + { + public AddTypedLabels(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + // insert other label datatypes + + void InsertNodeDto(int id, int sortOrder, string uniqueId, string text) + { + var nodeDto = new NodeDto + { + NodeId = id, + Trashed = false, + ParentId = -1, + UserId = -1, + Level = 1, + Path = "-1,-" + id, + SortOrder = sortOrder, + UniqueId = new Guid(uniqueId), + Text = text, + NodeObjectType = Constants.ObjectTypes.DataType, + CreateDate = DateTime.Now + }; + + Database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, nodeDto); + } + + if (SqlSyntax.SupportsIdentityInsert()) + Database.Execute(new Sql($"SET IDENTITY_INSERT {SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.Node)} ON ")); + + InsertNodeDto(Constants.DataTypes.LabelInt, 36, "8e7f995c-bd81-4627-9932-c40e568ec788", "Label (integer)"); + InsertNodeDto(Constants.DataTypes.LabelBigint, 36, "930861bf-e262-4ead-a704-f99453565708", "Label (bigint)"); + InsertNodeDto(Constants.DataTypes.LabelDateTime, 37, "0e9794eb-f9b5-4f20-a788-93acd233a7e4", "Label (datetime)"); + InsertNodeDto(Constants.DataTypes.LabelTime, 38, "a97cec69-9b71-4c30-8b12-ec398860d7e8", "Label (time)"); + InsertNodeDto(Constants.DataTypes.LabelDecimal, 39, "8f1ef1e1-9de4-40d3-a072-6673f631ca64", "Label (decimal)"); + + if (SqlSyntax.SupportsIdentityInsert()) + Database.Execute(new Sql($"SET IDENTITY_INSERT {SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.Node)} OFF ")); + + void InsertDataTypeDto(int id, string dbType, string configuration = null) + { + var dataTypeDto = new DataTypeDto + { + NodeId = id, + EditorAlias = Constants.PropertyEditors.Aliases.NoEdit, + DbType = dbType + }; + + if (configuration != null) + dataTypeDto.Configuration = configuration; + + Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, dataTypeDto); + } + + InsertDataTypeDto(Constants.DataTypes.LabelInt, "Integer", "{\"umbracoDataValueType\":\"INT\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelBigint, "Nvarchar", "{\"umbracoDataValueType\":\"BIGINT\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelDateTime, "Date", "{\"umbracoDataValueType\":\"DATETIME\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelDecimal, "Decimal", "{\"umbracoDataValueType\":\"DECIMAL\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelTime, "Date", "{\"umbracoDataValueType\":\"TIME\"}"); + + // flip known property types + + var intPropertyTypes = new[] { 7, 8, 29 }; + var bigintPropertyTypes = new[] { 9, 26 }; + var dtPropertyTypes = new[] { 32, 33, 34 }; + + Database.Execute(Sql().Update(u => u.Set(x => x.DataTypeId, Constants.DataTypes.LabelInt)).WhereIn(x => x.Id, intPropertyTypes)); + Database.Execute(Sql().Update(u => u.Set(x => x.DataTypeId, Constants.DataTypes.LabelBigint)).WhereIn(x => x.Id, bigintPropertyTypes)); + Database.Execute(Sql().Update(u => u.Set(x => x.DataTypeId, Constants.DataTypes.LabelDateTime)).WhereIn(x => x.Id, dtPropertyTypes)); + + // update values for known property types + // depending on the size of the site, that *may* take time + // but we want to parse in C# not in the database + var values = Database.Fetch(Sql() + .Select(x => x.Id, x => x.VarcharValue) + .From() + .WhereIn(x => x.PropertyTypeId, intPropertyTypes)); + foreach (var value in values) + Database.Execute(Sql() + .Update(u => u + .Set(x => x.IntegerValue, string.IsNullOrWhiteSpace(value.VarcharValue) ? (int?) null : int.Parse(value.VarcharValue, NumberStyles.Any, CultureInfo.InvariantCulture)) + .Set(x => x.TextValue, null)) + .Where(x => x.Id == value.Id)); + + values = Database.Fetch(Sql().Select(x => x.Id, x => x.VarcharValue).From().WhereIn(x => x.PropertyTypeId, dtPropertyTypes)); + foreach (var value in values) + Database.Execute(Sql() + .Update(u => u + .Set(x => x.DateValue, string.IsNullOrWhiteSpace(value.VarcharValue) ? (DateTime?) null : DateTime.Parse(value.VarcharValue, CultureInfo.InvariantCulture, DateTimeStyles.None)) + .Set(x => x.TextValue, null)) + .Where(x => x.Id == value.Id)); + + // anything that's custom... ppl will have to figure it out manually, there isn't much we can do about it + } + + // ReSharper disable once ClassNeverInstantiated.Local + // ReSharper disable UnusedAutoPropertyAccessor.Local + private class PropertyDataValue + { + public int Id { get; set; } + public string VarcharValue { get;set; } + } + // ReSharper restore UnusedAutoPropertyAccessor.Local + } +} diff --git a/src/Umbraco.Web/PropertyEditors/LabelConfiguration.cs b/src/Umbraco.Core/PropertyEditors/LabelConfiguration.cs similarity index 78% rename from src/Umbraco.Web/PropertyEditors/LabelConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/LabelConfiguration.cs index 47e4e8ef9b..bbdd437e54 100644 --- a/src/Umbraco.Web/PropertyEditors/LabelConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/LabelConfiguration.cs @@ -1,7 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.PropertyEditors; - -namespace Umbraco.Web.PropertyEditors +namespace Umbraco.Core.PropertyEditors { /// /// Represents the configuration for the label value editor. @@ -11,4 +8,4 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField(Constants.PropertyEditors.ConfigurationKeys.DataValueType, "Value type", "valuetype")] public string ValueType { get; set; } = ValueTypes.String; } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/PropertyEditors/LabelConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/LabelConfigurationEditor.cs similarity index 91% rename from src/Umbraco.Web/PropertyEditors/LabelConfigurationEditor.cs rename to src/Umbraco.Core/PropertyEditors/LabelConfigurationEditor.cs index c248eb1f71..e323cbbb6f 100644 --- a/src/Umbraco.Web/PropertyEditors/LabelConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/LabelConfigurationEditor.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; -using Umbraco.Core; -using Umbraco.Core.PropertyEditors; -namespace Umbraco.Web.PropertyEditors +namespace Umbraco.Core.PropertyEditors { /// /// Represents the configuration for the label value editor. diff --git a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs similarity index 87% rename from src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs rename to src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs index 0e1a031284..2b8a207491 100644 --- a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs @@ -1,37 +1,35 @@ -using Umbraco.Core; -using Umbraco.Core.Logging; -using Umbraco.Core.PropertyEditors; - -namespace Umbraco.Web.PropertyEditors -{ - /// - /// Represents a property editor for label properties. - /// - [DataEditor(Constants.PropertyEditors.Aliases.NoEdit, "Label", "readonlyvalue", Icon = "icon-readonly")] - public class LabelPropertyEditor : DataEditor - { - /// - /// Initializes a new instance of the class. - /// - public LabelPropertyEditor(ILogger logger) - : base(logger) - { } - - /// - protected override IDataValueEditor CreateValueEditor() => new LabelPropertyValueEditor(Attribute); - - /// - protected override IConfigurationEditor CreateConfigurationEditor() => new LabelConfigurationEditor(); - - // provides the property value editor - internal class LabelPropertyValueEditor : DataValueEditor - { - public LabelPropertyValueEditor(DataEditorAttribute attribute) - : base(attribute) - { } - - /// - public override bool IsReadOnly => true; - } - } -} +using Umbraco.Core.Logging; + +namespace Umbraco.Core.PropertyEditors +{ + /// + /// Represents a property editor for label properties. + /// + [DataEditor(Constants.PropertyEditors.Aliases.NoEdit, "Label", "readonlyvalue", Icon = "icon-readonly")] + public class LabelPropertyEditor : DataEditor + { + /// + /// Initializes a new instance of the class. + /// + public LabelPropertyEditor(ILogger logger) + : base(logger) + { } + + /// + protected override IDataValueEditor CreateValueEditor() => new LabelPropertyValueEditor(Attribute); + + /// + protected override IConfigurationEditor CreateConfigurationEditor() => new LabelConfigurationEditor(); + + // provides the property value editor + internal class LabelPropertyValueEditor : DataValueEditor + { + public LabelPropertyValueEditor(DataEditorAttribute attribute) + : base(attribute) + { } + + /// + public override bool IsReadOnly => true; + } + } +} diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs index 039c1e34b2..1be37e9c94 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core.PropertyEditors.ValueConverters @@ -19,14 +20,64 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters => Constants.PropertyEditors.Aliases.NoEdit.Equals(propertyType.EditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - => typeof (string); + { + var valueType = ConfigurationEditor.ConfigurationAs(propertyType.DataType.Configuration); + switch (valueType.ValueType) + { + case ValueTypes.DateTime: + case ValueTypes.Date: + return typeof(DateTime); + case ValueTypes.Time: + return typeof(TimeSpan); + case ValueTypes.Decimal: + return typeof(decimal); + case ValueTypes.Integer: + return typeof(int); + case ValueTypes.Bigint: + return typeof(long); + default: // everything else is a string + return typeof(string); + } + } public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) => PropertyCacheLevel.Element; public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview) { - return source?.ToString() ?? string.Empty; + var valueType = ConfigurationEditor.ConfigurationAs(propertyType.DataType.Configuration); + switch (valueType.ValueType) + { + case ValueTypes.DateTime: + case ValueTypes.Date: + if (source is DateTime sourceDateTime) + return sourceDateTime; + if (source is string sourceDateTimeString) + return DateTime.TryParse(sourceDateTimeString, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : DateTime.MinValue; + return DateTime.MinValue; + case ValueTypes.Time: + if (source is DateTime sourceTime) + return sourceTime.TimeOfDay; + if (source is string sourceTimeString) + return TimeSpan.TryParse(sourceTimeString, CultureInfo.InvariantCulture, out var ts) ? ts : TimeSpan.Zero; + return TimeSpan.Zero; + case ValueTypes.Decimal: + if (source is decimal sourceDecimal) return sourceDecimal; + if (source is string sourceDecimalString) + return decimal.TryParse(sourceDecimalString, NumberStyles.Any, CultureInfo.InvariantCulture, out var d) ? d : 0; + return (decimal) 0; + case ValueTypes.Integer: + if (source is int sourceInt) return sourceInt; + if (source is string sourceIntString) + return int.TryParse(sourceIntString, out var i) ? i : 0; + return 0; + case ValueTypes.Bigint: + if (source is string sourceLongString) + return long.TryParse(sourceLongString, out var i) ? i : 0; + return (long) 0; + default: // everything else is a string + return source?.ToString() ?? string.Empty; + } } } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueTypes.cs b/src/Umbraco.Core/PropertyEditors/ValueTypes.cs index 88b1fb35f7..a8ecea5cf3 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueTypes.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueTypes.cs @@ -42,6 +42,11 @@ namespace Umbraco.Core.PropertyEditors /// public const string Integer = "INT"; // Integer + /// + /// Integer value. + /// + public const string Bigint = "BIGINT"; // String + /// /// Json value. /// @@ -87,6 +92,7 @@ namespace Umbraco.Core.PropertyEditors return ValueStorageType.Decimal; case String: + case Bigint: return ValueStorageType.Nvarchar; case Text: diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index c4d7fab76c..2050419f69 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -321,6 +321,7 @@ + @@ -389,6 +390,9 @@ + + + diff --git a/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs b/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs index 27db2475ca..8ef7e24cae 100644 --- a/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs @@ -2,6 +2,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; +using Umbraco.Core.PropertyEditors; using Umbraco.Tests.Testing; using Umbraco.Web.PropertyEditors; diff --git a/src/Umbraco.Tests/Services/DataTypeServiceTests.cs b/src/Umbraco.Tests/Services/DataTypeServiceTests.cs index ceafa411d3..a623cc15e4 100644 --- a/src/Umbraco.Tests/Services/DataTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/DataTypeServiceTests.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; +using Umbraco.Core.PropertyEditors; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; using Umbraco.Web.PropertyEditors; diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 537be3fbfa..b0dc6b7a8b 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -280,8 +280,6 @@ - - @@ -750,7 +748,6 @@ -