diff --git a/src/Umbraco.Core/Constants-DataTypes.cs b/src/Umbraco.Core/Constants-DataTypes.cs index 5db4d71efc..e22ca00ae2 100644 --- a/src/Umbraco.Core/Constants-DataTypes.cs +++ b/src/Umbraco.Core/Constants-DataTypes.cs @@ -13,6 +13,8 @@ public static partial class Constants public const int LabelDateTime = -94; public const int LabelTime = -98; public const int LabelDecimal = -99; + public const int LabelBytes = -104; + public const int LabelPixels = -105; public const int Textarea = -89; public const int Textbox = -88; @@ -225,6 +227,16 @@ public static partial class Constants /// public const string LabelDecimal = "8f1ef1e1-9de4-40d3-a072-6673f631ca64"; + /// + /// Guid for Label as bytes + /// + public const string LabelBytes = "ba5bdbe6-ab3e-46a8-82b3-2c45f10bc47f"; + + /// + /// Guid for Label as pixels + /// + public const string LabelPixels = "5eb57825-e15e-4fc7-8e37-fca65cdafbde"; + /// /// Guid for Content Picker /// diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index 5d56d29b7e..1b707d45db 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -320,6 +320,10 @@ internal sealed class DatabaseDataCreator InsertDataTypeNodeDto(Constants.DataTypes.LabelTime, 38, Constants.DataTypes.Guids.LabelTime, "Label (time)"); InsertDataTypeNodeDto(Constants.DataTypes.LabelDecimal, 39, Constants.DataTypes.Guids.LabelDecimal, "Label (decimal)"); + InsertDataTypeNodeDto(Constants.DataTypes.LabelBytes, 40, Constants.DataTypes.Guids.LabelBytes, + "Label (bytes)"); + InsertDataTypeNodeDto(Constants.DataTypes.LabelPixels, 41, Constants.DataTypes.Guids.LabelPixels, + "Label (pixels)"); ConditionalInsert( Constants.Configuration.NamedOptions.InstallDefaultData.DataTypes, @@ -1454,7 +1458,7 @@ internal sealed class DatabaseDataCreator { Id = 7, UniqueId = new Guid("A68D453B-1F62-44F4-9F71-0B6BBD43C355"), - DataTypeId = Constants.DataTypes.LabelInt, + DataTypeId = Constants.DataTypes.LabelPixels, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Width, @@ -1462,7 +1466,7 @@ internal sealed class DatabaseDataCreator SortOrder = 0, Mandatory = false, ValidationRegExp = null, - Description = "in pixels", + Description = null, Variations = (byte)ContentVariation.Nothing, }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, @@ -1470,7 +1474,7 @@ internal sealed class DatabaseDataCreator { Id = 8, UniqueId = new Guid("854087F6-648B-40ED-BC98-B8A9789E80B9"), - DataTypeId = Constants.DataTypes.LabelInt, + DataTypeId = Constants.DataTypes.LabelPixels, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Height, @@ -1478,7 +1482,7 @@ internal sealed class DatabaseDataCreator SortOrder = 0, Mandatory = false, ValidationRegExp = null, - Description = "in pixels", + Description = null, Variations = (byte)ContentVariation.Nothing, }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, @@ -1486,15 +1490,15 @@ internal sealed class DatabaseDataCreator { Id = 9, UniqueId = new Guid("BD4C5ACE-26E3-4A8B-AF1A-E8206A35FA07"), - DataTypeId = Constants.DataTypes.LabelBigint, + DataTypeId = Constants.DataTypes.LabelBytes, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Bytes, - Name = "Size", + Name = "File size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, - Description = "in bytes", + Description = null, Variations = (byte)ContentVariation.Nothing, }); _database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, @@ -1502,11 +1506,11 @@ internal sealed class DatabaseDataCreator { Id = 10, UniqueId = new Guid("F7786FE8-724A-4ED0-B244-72546DB32A92"), - DataTypeId = -92, + DataTypeId = Constants.DataTypes.LabelString, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Extension, - Name = "Type", + Name = "File extension", SortOrder = 0, Mandatory = false, ValidationRegExp = null, @@ -1538,11 +1542,11 @@ internal sealed class DatabaseDataCreator { Id = 25, UniqueId = new Guid("3531C0A3-4E0A-4324-A621-B9D3822B071F"), - DataTypeId = -92, + DataTypeId = Constants.DataTypes.LabelString, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Extension, - Name = "Type", + Name = "File extension", SortOrder = 0, Mandatory = false, ValidationRegExp = null, @@ -1554,15 +1558,15 @@ internal sealed class DatabaseDataCreator { Id = 26, UniqueId = new Guid("F9527050-59BC-43E4-8FA8-1658D1319FF5"), - DataTypeId = Constants.DataTypes.LabelBigint, + DataTypeId = Constants.DataTypes.LabelBytes, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, - Name = "Size", + Name = "File size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, - Description = "in bytes", + Description = null, Variations = (byte)ContentVariation.Nothing, }); } @@ -1590,11 +1594,11 @@ internal sealed class DatabaseDataCreator { Id = 41, UniqueId = new Guid("EDD2B3FD-1E57-4E57-935E-096DEFCCDC9B"), - DataTypeId = -92, + DataTypeId = Constants.DataTypes.LabelString, ContentTypeId = 1034, PropertyTypeGroupId = 52, Alias = Constants.Conventions.Media.Extension, - Name = "Type", + Name = "File extension", SortOrder = 0, Mandatory = false, ValidationRegExp = null, @@ -1606,15 +1610,15 @@ internal sealed class DatabaseDataCreator { Id = 42, UniqueId = new Guid("180EEECF-1F00-409E-8234-BBA967E08B0A"), - DataTypeId = Constants.DataTypes.LabelBigint, + DataTypeId = Constants.DataTypes.LabelBytes, ContentTypeId = 1034, PropertyTypeGroupId = 52, Alias = Constants.Conventions.Media.Bytes, - Name = "Size", + Name = "File size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, - Description = "in bytes", + Description = null, Variations = (byte)ContentVariation.Nothing, }); } @@ -1642,11 +1646,11 @@ internal sealed class DatabaseDataCreator { Id = 44, UniqueId = new Guid("1BEE433F-A21A-4031-8E03-AF01BB8D2DE9"), - DataTypeId = -92, + DataTypeId = Constants.DataTypes.LabelString, ContentTypeId = 1035, PropertyTypeGroupId = 53, Alias = Constants.Conventions.Media.Extension, - Name = "Type", + Name = "File extension", SortOrder = 0, Mandatory = false, ValidationRegExp = null, @@ -1658,15 +1662,15 @@ internal sealed class DatabaseDataCreator { Id = 45, UniqueId = new Guid("3CBF538A-29AB-4317-A9EB-BBCDF1A54260"), - DataTypeId = Constants.DataTypes.LabelBigint, + DataTypeId = Constants.DataTypes.LabelBytes, ContentTypeId = 1035, PropertyTypeGroupId = 53, Alias = Constants.Conventions.Media.Bytes, - Name = "Size", + Name = "File size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, - Description = "in bytes", + Description = null, Variations = (byte)ContentVariation.Nothing, }); } @@ -1694,11 +1698,11 @@ internal sealed class DatabaseDataCreator { Id = 47, UniqueId = new Guid("EF1B4AF7-36DE-45EB-8C18-A2DE07319227"), - DataTypeId = -92, + DataTypeId = Constants.DataTypes.LabelString, ContentTypeId = 1036, PropertyTypeGroupId = 54, Alias = Constants.Conventions.Media.Extension, - Name = "Type", + Name = "File extension", SortOrder = 0, Mandatory = false, ValidationRegExp = null, @@ -1710,15 +1714,15 @@ internal sealed class DatabaseDataCreator { Id = 48, UniqueId = new Guid("AAB7D00C-7209-4337-BE3F-A4421C8D79A0"), - DataTypeId = Constants.DataTypes.LabelBigint, + DataTypeId = Constants.DataTypes.LabelBytes, ContentTypeId = 1036, PropertyTypeGroupId = 54, Alias = Constants.Conventions.Media.Bytes, - Name = "Size", + Name = "File size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, - Description = "in bytes", + Description = null, Variations = (byte)ContentVariation.Nothing, }); } @@ -1746,11 +1750,11 @@ internal sealed class DatabaseDataCreator { Id = 50, UniqueId = new Guid("0F25A89E-2EB7-49BC-A7B4-759A7E4C69F2"), - DataTypeId = -92, + DataTypeId = Constants.DataTypes.LabelString, ContentTypeId = 1037, PropertyTypeGroupId = 55, Alias = Constants.Conventions.Media.Extension, - Name = "Type", + Name = "File extension", SortOrder = 0, Mandatory = false, ValidationRegExp = null, @@ -1762,15 +1766,15 @@ internal sealed class DatabaseDataCreator { Id = 51, UniqueId = new Guid("09A07AFF-861D-4769-A2B0-C165EBD43D39"), - DataTypeId = Constants.DataTypes.LabelBigint, + DataTypeId = Constants.DataTypes.LabelBytes, ContentTypeId = 1037, PropertyTypeGroupId = 55, Alias = Constants.Conventions.Media.Bytes, - Name = "Size", + Name = "File size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, - Description = "in bytes", + Description = null, Variations = (byte)ContentVariation.Nothing, }); } @@ -1995,6 +1999,10 @@ internal sealed class DatabaseDataCreator "Umb.PropertyEditorUi.Label", "Decimal", "{\"umbracoDataValueType\":\"DECIMAL\"}"); InsertDataTypeDto(Constants.DataTypes.LabelTime, Constants.PropertyEditors.Aliases.Label, "Umb.PropertyEditorUi.Label", "Date", "{\"umbracoDataValueType\":\"TIME\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelBytes, Constants.PropertyEditors.Aliases.Label, + "Umb.PropertyEditorUi.Label", "Nvarchar", "{\"umbracoDataValueType\":\"BIGINT\", \"labelTemplate\":\"{=value | bytes}\"}"); + InsertDataTypeDto(Constants.DataTypes.LabelPixels, Constants.PropertyEditors.Aliases.Label, + "Umb.PropertyEditorUi.Label", "Integer", "{\"umbracoDataValueType\":\"INT\", \"labelTemplate\":\"{=value}px\"}"); if (_database.Exists(Constants.DataTypes.DateTime)) { diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index 0d7babbacf..21294c9e76 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -126,5 +126,6 @@ public class UmbracoPlan : MigrationPlan // To 16.3.0 To("{A917FCBC-C378-4A08-A36C-220C581A6581}"); + To("{FB7073AF-DFAF-4AC1-800D-91F9BD5B5238}"); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_16_3_0/MigrateMediaTypeLabelProperties.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_16_3_0/MigrateMediaTypeLabelProperties.cs new file mode 100644 index 0000000000..3ced4a2a6a --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_16_3_0/MigrateMediaTypeLabelProperties.cs @@ -0,0 +1,193 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; +using Umbraco.Cms.Infrastructure.Persistence.Dtos; + +namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_16_3_0; + +[Obsolete("Remove in Umbraco 18.")] +public class MigrateMediaTypeLabelProperties : AsyncMigrationBase +{ + private readonly IMediaTypeService _mediaTypeService; + + private readonly InstallDefaultDataSettings? _dataTypeSettings; + private readonly InstallDefaultDataSettings? _mediaTypeSettings; + + private readonly Guid _labelBytesDataTypeKey = new(Constants.DataTypes.Guids.LabelBytes); + private readonly Guid _labelPixelsDataTypeKey = new(Constants.DataTypes.Guids.LabelPixels); + + public MigrateMediaTypeLabelProperties( + IMigrationContext context, + IMediaTypeService mediaTypeService, + IOptionsMonitor installDefaultDataSettings) + : base(context) + { + _mediaTypeService = mediaTypeService; + + _dataTypeSettings = installDefaultDataSettings.Get(Constants.Configuration.NamedOptions.InstallDefaultData.DataTypes); + _mediaTypeSettings = installDefaultDataSettings.Get(Constants.Configuration.NamedOptions.InstallDefaultData.MediaTypes); + } + + protected override async Task MigrateAsync() + { + if (_dataTypeSettings?.InstallData == InstallDefaultDataOption.None) + { + return; + } + + if (_mediaTypeSettings?.InstallData == InstallDefaultDataOption.None) + { + return; + } + + IfNotExistsCreateBytesLabel(); + IfNotExistsCreatePixelsLabel(); + await MigrateMediaTypeLabels(); + } + + private void IfNotExistsCreateBytesLabel() + { + if (Database.Exists(Constants.DataTypes.LabelBytes)) + { + return; + } + + var nodeDto = new NodeDto + { + NodeId = Constants.DataTypes.LabelBytes, + Trashed = false, + ParentId = -1, + UserId = -1, + Level = 1, + Path = "-1," + Constants.DataTypes.LabelBytes, + SortOrder = 40, + UniqueId = _labelBytesDataTypeKey, + Text = "Label (bytes)", + NodeObjectType = Constants.ObjectTypes.DataType, + CreateDate = DateTime.Now, + }; + + _ = Database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, nodeDto); + + var dataTypeDto = new DataTypeDto + { + NodeId = Constants.DataTypes.LabelBytes, + EditorAlias = Constants.PropertyEditors.Aliases.Label, + EditorUiAlias = "Umb.PropertyEditorUi.Label", + DbType = nameof(ValueStorageType.Nvarchar), + Configuration = "{\"umbracoDataValueType\":\"BIGINT\", \"labelTemplate\":\"{=value | bytes}\"}", + }; + + _ = Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, dataTypeDto); + } + + private void IfNotExistsCreatePixelsLabel() + { + if (Database.Exists(Constants.DataTypes.LabelPixels)) + { + return; + } + + var nodeDto = new NodeDto + { + NodeId = Constants.DataTypes.LabelPixels, + Trashed = false, + ParentId = -1, + UserId = -1, + Level = 1, + Path = "-1," + Constants.DataTypes.LabelPixels, + SortOrder = 41, + UniqueId = _labelPixelsDataTypeKey, + Text = "Label (pixels)", + NodeObjectType = Constants.ObjectTypes.DataType, + CreateDate = DateTime.Now, + }; + + _ = Database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, nodeDto); + + var dataTypeDto = new DataTypeDto + { + NodeId = Constants.DataTypes.LabelPixels, + EditorAlias = Constants.PropertyEditors.Aliases.Label, + EditorUiAlias = "Umb.PropertyEditorUi.Label", + DbType = nameof(ValueStorageType.Integer), + Configuration = "{\"umbracoDataValueType\":\"INT\", \"labelTemplate\":\"{=value}px\"}", + }; + + _ = Database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, dataTypeDto); + } + + private async Task MigrateMediaTypeLabels() + { + // update all media types with the new data-type references + IMediaType[] allMediaTypes = _mediaTypeService.GetAll().ToArray(); + foreach (IMediaType mediaType in allMediaTypes) + { + bool updated = false; + + foreach (IPropertyType propertyType in mediaType.PropertyTypes) + { + switch (propertyType.Alias) + { + case Constants.Conventions.Media.Bytes when propertyType.DataTypeId == Constants.DataTypes.LabelBigint: + propertyType.DataTypeId = Constants.DataTypes.LabelBytes; + propertyType.DataTypeKey = _labelBytesDataTypeKey; + + if (propertyType.Name == "Size") + { + propertyType.Name = "File size"; + } + + if (propertyType.Description == "in bytes") + { + propertyType.Description = null; + } + + updated = true; + + break; + + case Constants.Conventions.Media.Height when propertyType.DataTypeId == Constants.DataTypes.LabelInt: + case Constants.Conventions.Media.Width when propertyType.DataTypeId == Constants.DataTypes.LabelInt: + propertyType.DataTypeId = Constants.DataTypes.LabelPixels; + propertyType.DataTypeKey = _labelPixelsDataTypeKey; + + if (propertyType.Description == "in pixels") + { + propertyType.Description = null; + } + + updated = true; + + break; + + case Constants.Conventions.Media.Extension when propertyType.DataTypeId == Constants.DataTypes.LabelString: + if (propertyType.Name == "Type") + { + propertyType.Name = "File extension"; + } + + updated = true; + + break; + + default: + break; + } + } + + if (updated) + { + Attempt attempt = await _mediaTypeService.UpdateAsync(mediaType, Constants.Security.SuperUserKey); + if (!attempt.Success) + { + Logger.LogError(attempt.Exception, $"Failed to update media type '{mediaType.Alias}' during migration."); + } + } + } + } +} diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index 66ac4278a3..4ff77c86fa 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -250,7 +250,7 @@ internal sealed class DataTypeDefinitionRepositoryTest : UmbracoIntegrationTest Assert.That(dataTypeDefinitions, Is.Not.Null); Assert.That(dataTypeDefinitions.Any(), Is.True); Assert.That(dataTypeDefinitions.Any(x => x == null), Is.False); - Assert.That(dataTypeDefinitions.Length, Is.EqualTo(34)); + Assert.That(dataTypeDefinitions.Length, Is.EqualTo(36)); } }