From dd5f400cf3d31204d46463b6062b8a06b4e19634 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Date: Tue, 17 Nov 2020 20:27:10 +0100 Subject: [PATCH] Netcore: Migration of Model classes from Umbraco.Infrastructure to Core (#9404) * Migrating more model, mapping and tree classes * Migrating files from Mapping dir without Newtonsoft dependency * Migrating files from PublishedContent and Editors dirs without Newtonsoft dependency + some more of the same kind * Migrating DataType class without the usage of Newtonsoft.Json and making the corresponding changes to all classes affected * Combining 3 ContentExtensions files into 1 * Refactoring from migrating ContentExtensions * Migrating more classes * Migrating ContentRepositoryExtensions - combining it with existing file in Umbraco.Core * removing Newtonsoft json dependency & migrating file. Adding partial migration of ConfigurationEditor, so PropertyTagsExtensions can be migrated * Migrating ContentTagsExtensions, and refactoring from changes in PropertyTagsExtensions * Changes that should be reverted once ConfigurationEditor class is fully migrated * VS couldn't find Composing, so build was failing. Removing the using solves the problem * Handling a single case for deserializing a subset of an input * Small changes and added tests to JsonNetSerializer Signed-off-by: Bjarke Berg * Migrated ConfigurationEditor Signed-off-by: Bjarke Berg Co-authored-by: Bjarke Berg --- .../ConfigurationEditor.cs | 59 ++-- src/Umbraco.Core/ContentExtensions.cs | 225 ++++++++++++++- .../ConventionsHelper.cs | 0 .../Models/BackOfficeTour.cs | 2 +- .../Models/BackOfficeTourFile.cs | 0 .../Models/BackOfficeTourStep.cs | 3 +- .../Models/Blocks/BlockListModel.cs | 2 +- .../Blocks/ContentAndSettingsReference.cs | 0 .../Models/ContentBaseExtensions.cs | 5 +- src/Umbraco.Core/Models/ContentExtensions.cs | 19 -- .../Models/ContentRepositoryExtensions.cs | 243 ++++++++++++++++- .../Models/ContentTagsExtensions.cs | 13 +- .../Models/ContentTypeImportModel.cs | 0 .../Models/DataType.cs | 19 +- .../Models/Editors/UmbracoEntityReference.cs | 0 .../Models/LocalPackageInstallModel.cs | 3 +- .../Models/Mapping/AuditMapDefinition.cs | 0 .../Models/Mapping/CodeFileMapDefinition.cs | 1 - .../Models/Mapping/CommonMapper.cs | 5 +- .../Models/Mapping/ContentSavedStateMapper.cs | 0 .../Mapping/ContentTypeMapDefinition.cs | 11 +- .../Models/Mapping/ContentVariantMapper.cs | 1 - .../Models/Mapping/DataTypeMapDefinition.cs | 11 +- .../Models/Mapping/DictionaryMapDefinition.cs | 0 .../Models/Mapping/LanguageMapDefinition.cs | 0 .../Models/Mapping/MacroMapDefinition.cs | 4 +- .../Mapping/MemberTabsAndPropertiesMapper.cs | 10 +- .../Models/Mapping/PropertyTypeGroupMapper.cs | 16 +- .../Mapping/RedirectUrlMapDefinition.cs | 0 .../Models/Mapping/RelationMapDefinition.cs | 3 +- .../Models/Mapping/SectionMapDefinition.cs | 0 .../Models/Mapping/TabsAndPropertiesMapper.cs | 4 +- .../Models/Mapping/TagMapDefinition.cs | 0 .../Models/Mapping/TemplateMapDefinition.cs | 0 .../Models/Mapping/UserMapDefinition.cs | 18 +- .../Models/PropertyTagsExtensions.cs | 57 ++-- .../PublishedContentExtensionsForModels.cs | 1 - .../PublishedContent/PublishedContentModel.cs | 0 .../PublishedContentTypeFactory.cs | 3 +- .../PublishedContent/PublishedModelFactory.cs | 4 +- .../PropertyEditors/IConfigurationEditor.cs | 3 +- .../IConfigurationEditorJsonSerializer.cs | 7 + .../Serialization/IJsonSerializer.cs | 2 + .../Services/Implement/DashboardService.cs | 4 +- .../Trees/ISearchableTree.cs | 0 .../Trees/TreeNode.cs | 2 - .../Trees/TreeNodeCollection.cs | 0 .../Trees/TreeNodeExtensions.cs | 1 - .../ContentExtensions.cs | 255 ----------------- .../Upgrade/V_8_0_0/DataTypeMigration.cs | 18 +- .../DropDownPropertyEditorsMigration.cs | 9 +- .../MergeDateAndDateTimePropertyEditor.cs | 9 +- ...adioAndCheckboxPropertyEditorsMigration.cs | 10 +- .../Models/ContentRepositoryExtensions.cs | 256 ------------------ .../Packaging/PackageDataInstallation.cs | 9 +- .../Persistence/Factories/DataTypeFactory.cs | 9 +- .../Implement/ContentRepositoryBase.cs | 7 +- .../Implement/DataTypeRepository.cs | 19 +- .../Implement/DocumentBlueprintRepository.cs | 8 +- .../Implement/DocumentRepository.cs | 12 +- .../Repositories/Implement/MediaRepository.cs | 10 +- .../Implement/MemberRepository.cs | 10 +- .../ConfigurationEditorOfTConfiguration.cs | 5 +- .../DecimalConfigurationEditor.cs | 3 +- .../IntegerConfigurationEditor.cs | 5 +- .../MemberPickerConfiguration.cs | 4 +- .../RichTextEditorPastedImages.cs | 8 +- .../UserPickerConfiguration.cs | 1 + .../MediaPickerValueConverter.cs | 1 - .../Runtime/CoreInitialComposer.cs | 1 + .../ConfigurationEditorJsonSerializer.cs | 37 +++ .../Serialization/JsonNetSerializer.cs | 32 ++- .../Services/Implement/EntityXmlSerializer.cs | 8 +- .../UmbracoTestDataController.cs | 5 +- .../Builders/ConfigurationEditorBuilder.cs | 2 + .../Builders/DataTypeBuilder.cs | 4 +- .../TestHelpers/SolidPublishedSnapshot.cs | 5 +- .../Mapping/ContentTypeModelMappingTests.cs | 21 +- .../DataTypeDefinitionRepositoryTest.cs | 22 +- .../Repositories/DocumentRepositoryTest.cs | 6 +- .../Repositories/MediaRepositoryTest.cs | 4 +- .../Repositories/MemberRepositoryTest.cs | 4 +- .../Repositories/TemplateRepositoryTest.cs | 4 +- .../Services/CachedDataTypeServiceTests.cs | 4 +- .../Services/ContentServiceTagsTests.cs | 124 ++++----- .../Services/ContentServiceTests.cs | 4 +- .../Services/DataTypeServiceTests.cs | 6 +- .../Services/TagServiceTests.cs | 18 +- .../Filters/ContentModelValidatorTests.cs | 6 +- .../Models/ContentExtensionsTests.cs | 1 + .../Umbraco.Core/Models/VariationTests.cs | 5 +- ...ataValueReferenceFactoryCollectionTests.cs | 10 +- .../MultiValuePropertyEditorTests.cs | 7 +- .../Umbraco.Core/Published/ConvertersTests.cs | 7 +- .../Published/NestedContentTests.cs | 9 +- .../Published/PropertyCacheLevelTests.cs | 10 +- .../Persistence/Querying/ExpressionTests.cs | 4 +- .../Serialization/JsonNetSerializerTests.cs | 82 ++++++ .../Packaging/PackageInstallationTest.cs | 4 +- .../NPocoTests/PetaPocoCachesTest.cs | 6 +- .../Published/ConvertersTests.cs | 8 +- .../PublishedContent/NuCacheChildrenTests.cs | 5 +- .../PublishedContent/NuCacheTests.cs | 5 +- .../PublishedContentDataTableTests.cs | 4 +- .../PublishedContentSnapshotTestBase.cs | 4 +- .../PublishedContentTestBase.cs | 7 +- .../PublishedContent/PublishedContentTests.cs | 17 +- .../SolidPublishedSnapshot.cs | 4 +- src/Umbraco.Tests/TestHelpers/BaseWebTest.cs | 4 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 1 + .../Controllers/ContentController.cs | 6 +- .../Controllers/ContentControllerBase.cs | 8 +- .../Controllers/ContentTypeController.cs | 8 +- .../Controllers/DataTypeController.cs | 10 +- .../Controllers/MediaController.cs | 11 +- .../Controllers/MemberController.cs | 2 +- 116 files changed, 1098 insertions(+), 897 deletions(-) rename src/{Umbraco.Infrastructure/PropertyEditors => Umbraco.Core}/ConfigurationEditor.cs (65%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/ConventionsHelper.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/BackOfficeTour.cs (95%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/BackOfficeTourFile.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/BackOfficeTourStep.cs (93%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Blocks/BlockListModel.cs (95%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Blocks/ContentAndSettingsReference.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/ContentBaseExtensions.cs (78%) delete mode 100644 src/Umbraco.Core/Models/ContentExtensions.cs rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/ContentTagsExtensions.cs (76%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/ContentTypeImportModel.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/DataType.cs (93%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Editors/UmbracoEntityReference.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/LocalPackageInstallModel.cs (98%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/AuditMapDefinition.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/CodeFileMapDefinition.cs (98%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/CommonMapper.cs (91%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/ContentSavedStateMapper.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/ContentTypeMapDefinition.cs (99%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/ContentVariantMapper.cs (99%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/DataTypeMapDefinition.cs (96%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/DictionaryMapDefinition.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/LanguageMapDefinition.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/MacroMapDefinition.cs (98%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/MemberTabsAndPropertiesMapper.cs (97%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/PropertyTypeGroupMapper.cs (95%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/RedirectUrlMapDefinition.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/RelationMapDefinition.cs (98%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/SectionMapDefinition.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/TabsAndPropertiesMapper.cs (99%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/TagMapDefinition.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/TemplateMapDefinition.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/Mapping/UserMapDefinition.cs (99%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/PropertyTagsExtensions.cs (78%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/PublishedContent/PublishedContentExtensionsForModels.cs (97%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/PublishedContent/PublishedContentModel.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/PublishedContent/PublishedContentTypeFactory.cs (98%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Models/PublishedContent/PublishedModelFactory.cs (97%) create mode 100644 src/Umbraco.Core/Serialization/IConfigurationEditorJsonSerializer.cs rename src/{Umbraco.Infrastructure => Umbraco.Core}/Services/Implement/DashboardService.cs (98%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Trees/ISearchableTree.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Trees/TreeNode.cs (98%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Trees/TreeNodeCollection.cs (100%) rename src/{Umbraco.Infrastructure => Umbraco.Core}/Trees/TreeNodeExtensions.cs (99%) delete mode 100644 src/Umbraco.Infrastructure/ContentExtensions.cs delete mode 100644 src/Umbraco.Infrastructure/Models/ContentRepositoryExtensions.cs create mode 100644 src/Umbraco.Infrastructure/Serialization/ConfigurationEditorJsonSerializer.cs create mode 100644 src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/JsonNetSerializerTests.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ConfigurationEditor.cs b/src/Umbraco.Core/ConfigurationEditor.cs similarity index 65% rename from src/Umbraco.Infrastructure/PropertyEditors/ConfigurationEditor.cs rename to src/Umbraco.Core/ConfigurationEditor.cs index 07c9c0a080..43de192914 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ConfigurationEditor.cs +++ b/src/Umbraco.Core/ConfigurationEditor.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; +using System.Runtime.Serialization; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; -namespace Umbraco.Core.PropertyEditors +namespace Umbraco.Core { /// /// Represents a data type configuration editor. @@ -35,7 +34,7 @@ namespace Umbraco.Core.PropertyEditors /// /// Gets the fields. /// - [JsonProperty("fields")] + [DataMember(Name = "fields")] public List Fields { get; } /// @@ -53,18 +52,20 @@ namespace Umbraco.Core.PropertyEditors { if (obj == null) return default; if (obj is TConfiguration configuration) return configuration; - throw new InvalidCastException($"Cannot cast configuration of type {obj.GetType().Name} to {typeof(TConfiguration).Name}."); + throw new InvalidCastException( + $"Cannot cast configuration of type {obj.GetType().Name} to {typeof(TConfiguration).Name}."); } /// /// Converts a configuration object into a serialized database value. /// - public static string ToDatabase(object configuration) - => configuration == null ? null : JsonConvert.SerializeObject(configuration, ConfigurationJsonSettings); + public static string ToDatabase(object configuration, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) + => configuration == null ? null : configurationEditorJsonSerializer.Serialize(configuration); /// - [JsonProperty("defaultConfig")] - public virtual IDictionary DefaultConfiguration { + [DataMember(Name = "defaultConfig")] + public virtual IDictionary DefaultConfiguration + { get => _defaultConfiguration; set => _defaultConfiguration = value; } @@ -75,11 +76,12 @@ namespace Umbraco.Core.PropertyEditors /// public virtual bool IsConfiguration(object obj) => obj is IDictionary; + /// - public virtual object FromDatabase(string configurationJson) + public virtual object FromDatabase(string configurationJson, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) => string.IsNullOrWhiteSpace(configurationJson) ? new Dictionary() - : JsonConvert.DeserializeObject>(configurationJson); + : configurationEditorJsonSerializer.Deserialize>(configurationJson); /// public virtual object FromConfigurationEditor(IDictionary editorValues, object configuration) @@ -108,7 +110,9 @@ namespace Umbraco.Core.PropertyEditors configuration = new Dictionary(); if (!(configuration is IDictionary c)) - throw new ArgumentException($"Expecting a {typeof(Dictionary).Name} instance but got {configuration.GetType().Name}.", nameof(configuration)); + throw new ArgumentException( + $"Expecting a {typeof(Dictionary).Name} instance but got {configuration.GetType().Name}.", + nameof(configuration)); // clone the default configuration, and apply the current configuration values var d = new Dictionary(DefaultConfiguration); @@ -121,34 +125,5 @@ namespace Umbraco.Core.PropertyEditors public virtual IDictionary 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; - } - } } } diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 51221086ec..42f47ff604 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -1,13 +1,31 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Xml.Linq; +using Umbraco.Core.IO; using Umbraco.Core.Models; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; +using Umbraco.Core.Strings; namespace Umbraco.Core { public static class ContentExtensions { + public static bool IsAnyUserPropertyDirty(this IContentBase entity) + { + return entity.Properties.Any(x => x.IsDirty()); + } - internal static bool IsMoving(this IContentBase entity) + public static bool WasAnyUserPropertyDirty(this IContentBase entity) + { + return entity.Properties.Any(x => x.WasDirty()); + } + + + public static bool IsMoving(this IContentBase entity) { // Check if this entity is being moved as a descendant as part of a bulk moving operations. // When this occurs, only Path + Level + UpdateDate are being changed. In this case we can bypass a lot of the below @@ -67,6 +85,211 @@ namespace Umbraco.Core return false; } + + /// + /// Returns all properties based on the editorAlias + /// + /// + /// + /// + public static IEnumerable GetPropertiesByEditor(this IContentBase content, string editorAlias) + => content.Properties.Where(x => x.PropertyType.PropertyEditorAlias == editorAlias); + + + #region IContent + + /// + /// Gets the current status of the Content + /// + public static ContentStatus GetStatus(this IContent content, string culture = null) + { + if (content.Trashed) + return ContentStatus.Trashed; + + if (!content.ContentType.VariesByCulture()) + culture = string.Empty; + else if (culture.IsNullOrWhiteSpace()) + throw new ArgumentNullException($"{nameof(culture)} cannot be null or empty"); + + var expires = content.ContentSchedule.GetSchedule(culture, ContentScheduleAction.Expire); + if (expires != null && expires.Any(x => x.Date > DateTime.MinValue && DateTime.Now > x.Date)) + return ContentStatus.Expired; + + var release = content.ContentSchedule.GetSchedule(culture, ContentScheduleAction.Release); + if (release != null && release.Any(x => x.Date > DateTime.MinValue && x.Date > DateTime.Now)) + return ContentStatus.AwaitingRelease; + + if (content.Published) + return ContentStatus.Published; + + return ContentStatus.Unpublished; + } + + + + #endregion + + + /// + /// Gets the for the Creator of this content item. + /// + public static IProfile GetCreatorProfile(this IContentBase content, IUserService userService) + { + return userService.GetProfileById(content.CreatorId); + } + /// + /// Gets the for the Writer of this content. + /// + public static IProfile GetWriterProfile(this IContent content, IUserService userService) + { + return userService.GetProfileById(content.WriterId); + } + + /// + /// Gets the for the Writer of this content. + /// + public static IProfile GetWriterProfile(this IMedia content, IUserService userService) + { + return userService.GetProfileById(content.WriterId); + } + + + #region User/Profile methods + + /// + /// Gets the for the Creator of this media item. + /// + public static IProfile GetCreatorProfile(this IMedia media, IUserService userService) + { + return userService.GetProfileById(media.CreatorId); + } + + + #endregion + + + /// + /// Returns properties that do not belong to a group + /// + /// + /// + public static IEnumerable GetNonGroupedProperties(this IContentBase content) + { + return content.Properties + .Where(x => x.PropertyType.PropertyGroupId == null) + .OrderBy(x => x.PropertyType.SortOrder); + } + + /// + /// Returns the Property object for the given property group + /// + /// + /// + /// + public static IEnumerable GetPropertiesForGroup(this IContentBase content, PropertyGroup propertyGroup) + { + //get the properties for the current tab + return content.Properties + .Where(property => propertyGroup.PropertyTypes + .Select(propertyType => propertyType.Id) + .Contains(property.PropertyTypeId)); + } + + + #region SetValue for setting file contents + + /// + /// Sets the posted file value of a property. + /// + public static void SetValue(this IContentBase content, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IJsonSerializer serializer, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) + { + if (filename == null || filestream == null) return; + + filename = shortStringHelper.CleanStringForSafeFileName(filename); + if (string.IsNullOrWhiteSpace(filename)) return; + filename = filename.ToLower(); + + SetUploadFile(content, mediaFileSystem, contentTypeBaseServiceProvider, serializer, propertyTypeAlias, filename, filestream, culture, segment); + } + + private static void SetUploadFile(this IContentBase content, IMediaFileSystem mediaFileSystem, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IJsonSerializer serializer, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) + { + var property = GetProperty(content, contentTypeBaseServiceProvider, propertyTypeAlias); + + // Fixes https://github.com/umbraco/Umbraco-CMS/issues/3937 - Assigning a new file to an + // existing IMedia with extension SetValue causes exception 'Illegal characters in path' + string oldpath = null; + if (property.GetValue(culture, segment) is string svalue) + { + if (svalue.DetectIsJson()) + { + // the property value is a JSON serialized image crop data set - grab the "src" property as the file source + svalue = serializer.DeserializeSubset(svalue, "src"); + } + oldpath = mediaFileSystem.GetRelativePath(svalue); + } + + var filepath = mediaFileSystem.StoreFile(content, property.PropertyType, filename, filestream, oldpath); + property.SetValue(mediaFileSystem.GetUrl(filepath), culture, segment); + } + + // gets or creates a property for a content item. + private static IProperty GetProperty(IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias) + { + var property = content.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); + if (property != null) return property; + + var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(content); + var propertyType = contentType.CompositionPropertyTypes + .FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); + if (propertyType == null) + throw new Exception("No property type exists with alias " + propertyTypeAlias + "."); + + property = new Property(propertyType); + content.Properties.Add(property); + return property; + } + + /// + /// Stores a file. + /// + /// A content item. + /// The property alias. + /// The name of the file. + /// A stream containing the file data. + /// The original file path, if any. + /// The path to the file, relative to the media filesystem. + /// + /// Does NOT set the property value, so one should probably store the file and then do + /// something alike: property.Value = MediaHelper.FileSystem.GetUrl(filepath). + /// The original file path is used, in the old media file path scheme, to try and reuse + /// the "folder number" that was assigned to the previous file referenced by the property, + /// if any. + /// + public static string StoreFile(this IContentBase content, IMediaFileSystem mediaFileSystem, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string filepath) + { + var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(content); + var propertyType = contentType + .CompositionPropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); + if (propertyType == null) throw new ArgumentException("Invalid property type alias " + propertyTypeAlias + "."); + return mediaFileSystem.StoreFile(content, propertyType, filename, filestream, filepath); + } + + #endregion + + + #region Dirty + + public static IEnumerable GetDirtyUserProperties(this IContentBase entity) + { + return entity.Properties.Where(x => x.IsDirty()).Select(x => x.Alias); + } + + + + #endregion + + /// /// Creates the full xml representation for the object and all of it's descendants /// diff --git a/src/Umbraco.Infrastructure/ConventionsHelper.cs b/src/Umbraco.Core/ConventionsHelper.cs similarity index 100% rename from src/Umbraco.Infrastructure/ConventionsHelper.cs rename to src/Umbraco.Core/ConventionsHelper.cs diff --git a/src/Umbraco.Infrastructure/Models/BackOfficeTour.cs b/src/Umbraco.Core/Models/BackOfficeTour.cs similarity index 95% rename from src/Umbraco.Infrastructure/Models/BackOfficeTour.cs rename to src/Umbraco.Core/Models/BackOfficeTour.cs index 7396d3d00d..7ebc2392f6 100644 --- a/src/Umbraco.Infrastructure/Models/BackOfficeTour.cs +++ b/src/Umbraco.Core/Models/BackOfficeTour.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.Models { public BackOfficeTour() { - RequiredSections = new List(); + RequiredSections = new List(); } [DataMember(Name = "name")] diff --git a/src/Umbraco.Infrastructure/Models/BackOfficeTourFile.cs b/src/Umbraco.Core/Models/BackOfficeTourFile.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/BackOfficeTourFile.cs rename to src/Umbraco.Core/Models/BackOfficeTourFile.cs diff --git a/src/Umbraco.Infrastructure/Models/BackOfficeTourStep.cs b/src/Umbraco.Core/Models/BackOfficeTourStep.cs similarity index 93% rename from src/Umbraco.Infrastructure/Models/BackOfficeTourStep.cs rename to src/Umbraco.Core/Models/BackOfficeTourStep.cs index c21b09523d..9c216b95fe 100644 --- a/src/Umbraco.Infrastructure/Models/BackOfficeTourStep.cs +++ b/src/Umbraco.Core/Models/BackOfficeTourStep.cs @@ -1,5 +1,4 @@ using System.Runtime.Serialization; -using Newtonsoft.Json.Linq; namespace Umbraco.Web.Models { @@ -28,7 +27,7 @@ namespace Umbraco.Web.Models [DataMember(Name = "eventElement")] public string EventElement { get; set; } [DataMember(Name = "customProperties")] - public JObject CustomProperties { get; set; } + public object CustomProperties { get; set; } [DataMember(Name = "skipStepIfVisible")] public string SkipStepIfVisible { get; set; } } diff --git a/src/Umbraco.Infrastructure/Models/Blocks/BlockListModel.cs b/src/Umbraco.Core/Models/Blocks/BlockListModel.cs similarity index 95% rename from src/Umbraco.Infrastructure/Models/Blocks/BlockListModel.cs rename to src/Umbraco.Core/Models/Blocks/BlockListModel.cs index 9a3a26ab30..92a426c3d4 100644 --- a/src/Umbraco.Infrastructure/Models/Blocks/BlockListModel.cs +++ b/src/Umbraco.Core/Models/Blocks/BlockListModel.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.Blocks /// /// The strongly typed model for the Block List editor. /// - /// + /// [DataContract(Name = "blockList", Namespace = "")] public class BlockListModel : ReadOnlyCollection { diff --git a/src/Umbraco.Infrastructure/Models/Blocks/ContentAndSettingsReference.cs b/src/Umbraco.Core/Models/Blocks/ContentAndSettingsReference.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Blocks/ContentAndSettingsReference.cs rename to src/Umbraco.Core/Models/Blocks/ContentAndSettingsReference.cs diff --git a/src/Umbraco.Infrastructure/Models/ContentBaseExtensions.cs b/src/Umbraco.Core/Models/ContentBaseExtensions.cs similarity index 78% rename from src/Umbraco.Infrastructure/Models/ContentBaseExtensions.cs rename to src/Umbraco.Core/Models/ContentBaseExtensions.cs index 15003cd981..75f6772ec5 100644 --- a/src/Umbraco.Infrastructure/Models/ContentBaseExtensions.cs +++ b/src/Umbraco.Core/Models/ContentBaseExtensions.cs @@ -15,15 +15,16 @@ namespace Umbraco.Core.Strings /// /// The content. /// The culture. + /// /// /// The url segment. - public static string GetUrlSegment(this IContentBase content, IShortStringHelper shortStringHelper, IEnumerable urlSegmentProviders, string culture = null) + public static string GetUrlSegment(this IContentBase content, IShortStringHelper shortStringHelper, IEnumerable urlSegmentProviders, string culture = null) { if (content == null) throw new ArgumentNullException(nameof(content)); if (urlSegmentProviders == null) throw new ArgumentNullException(nameof(urlSegmentProviders)); var url = urlSegmentProviders.Select(p => p.GetUrlSegment(content, culture)).FirstOrDefault(u => u != null); - url = url ?? new DefaultUrlSegmentProvider(shortStringHelper).GetUrlSegment(content, culture); // be safe + url ??= new DefaultUrlSegmentProvider(shortStringHelper).GetUrlSegment(content, culture); // be safe return url; } } diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs deleted file mode 100644 index 5fd5e576b8..0000000000 --- a/src/Umbraco.Core/Models/ContentExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Linq; - -namespace Umbraco.Core.Models -{ - public static class ContentExtensions - { - public static bool IsAnyUserPropertyDirty(this IContentBase entity) - { - return entity.Properties.Any(x => x.IsDirty()); - } - - public static bool WasAnyUserPropertyDirty(this IContentBase entity) - { - return entity.Properties.Any(x => x.WasDirty()); - } - - - } -} diff --git a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs index 1a1914496d..b94a3e9610 100644 --- a/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs +++ b/src/Umbraco.Core/Models/ContentRepositoryExtensions.cs @@ -1,8 +1,12 @@ using System; +using System.Collections.Generic; using System.Linq; namespace Umbraco.Core.Models { + /// + /// Extension methods used to manipulate content variations by the document repository + /// public static class ContentRepositoryExtensions { public static void SetCultureInfo(this IContentBase content, string culture, string name, DateTime date) @@ -52,6 +56,243 @@ namespace Umbraco.Core.Models SetCultureInfo(content, culture, infos.Name, date); } } - } + /// + /// Gets the cultures that have been flagged for unpublishing. + /// + /// Gets cultures for which content.UnpublishCulture() has been invoked. + public static IReadOnlyList GetCulturesUnpublishing(this IContent content) + { + if (!content.Published || !content.ContentType.VariesByCulture() || !content.IsPropertyDirty("PublishCultureInfos")) + return Array.Empty(); + + var culturesUnpublishing = content.CultureInfos.Values + .Where(x => content.IsPropertyDirty(ContentBase.ChangeTrackingPrefix.UnpublishedCulture + x.Culture)) + .Select(x => x.Culture); + + return culturesUnpublishing.ToList(); + } + + /// + /// Copies values from another document. + /// + public static void CopyFrom(this IContent content, IContent other, string culture = "*") + { + if (other.ContentTypeId != content.ContentTypeId) + throw new InvalidOperationException("Cannot copy values from a different content type."); + + culture = culture?.ToLowerInvariant().NullOrWhiteSpaceAsNull(); + + // the variation should be supported by the content type properties + // if the content type is invariant, only '*' and 'null' is ok + // if the content type varies, everything is ok because some properties may be invariant + if (!content.ContentType.SupportsPropertyVariation(culture, "*", true)) + throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\"."); + + // copying from the same Id and VersionPk + var copyingFromSelf = content.Id == other.Id && content.VersionId == other.VersionId; + var published = copyingFromSelf; + + // note: use property.SetValue(), don't assign pvalue.EditValue, else change tracking fails + + // clear all existing properties for the specified culture + foreach (var property in content.Properties) + { + // each property type may or may not support the variation + if (!property.PropertyType.SupportsVariation(culture, "*", wildcards: true)) + continue; + + foreach (var pvalue in property.Values) + if (property.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment, wildcards: true) && + (culture == "*" || pvalue.Culture.InvariantEquals(culture))) + { + property.SetValue(null, pvalue.Culture, pvalue.Segment); + } + } + + // copy properties from 'other' + var otherProperties = other.Properties; + foreach (var otherProperty in otherProperties) + { + if (!otherProperty.PropertyType.SupportsVariation(culture, "*", wildcards: true)) + continue; + + var alias = otherProperty.PropertyType.Alias; + foreach (var pvalue in otherProperty.Values) + { + if (otherProperty.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment, wildcards: true) && + (culture == "*" || pvalue.Culture.InvariantEquals(culture))) + { + var value = published ? pvalue.PublishedValue : pvalue.EditedValue; + content.SetValue(alias, value, pvalue.Culture, pvalue.Segment); + } + } + } + + // copy names, too + + if (culture == "*") + { + content.CultureInfos.Clear(); + content.CultureInfos = null; + } + + if (culture == null || culture == "*") + content.Name = other.Name; + + // ReSharper disable once UseDeconstruction + foreach (var cultureInfo in other.CultureInfos) + { + if (culture == "*" || culture == cultureInfo.Culture) + content.SetCultureName(cultureInfo.Name, cultureInfo.Culture); + } + } + + public static void SetPublishInfo(this IContent content, string culture, string name, DateTime date) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name)); + + if (culture == null) throw new ArgumentNullException(nameof(culture)); + if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture)); + + content.PublishCultureInfos.AddOrUpdate(culture, name, date); + } + + // sets the edited cultures on the content + public static void SetCultureEdited(this IContent content, IEnumerable cultures) + { + if (cultures == null) + content.EditedCultures = null; + else + { + var editedCultures = new HashSet(cultures.Where(x => !x.IsNullOrWhiteSpace()), StringComparer.OrdinalIgnoreCase); + content.EditedCultures = editedCultures.Count > 0 ? editedCultures : null; + } + } + + /// + /// Sets the publishing values for names and properties. + /// + /// + /// + /// A value indicating whether it was possible to publish the names and values for the specified + /// culture(s). The method may fail if required names are not set, but it does NOT validate property data + public static bool PublishCulture(this IContent content, CultureImpact impact) + { + if (impact == null) throw new ArgumentNullException(nameof(impact)); + + // the variation should be supported by the content type properties + // if the content type is invariant, only '*' and 'null' is ok + // if the content type varies, everything is ok because some properties may be invariant + if (!content.ContentType.SupportsPropertyVariation(impact.Culture, "*", true)) + throw new NotSupportedException($"Culture \"{impact.Culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\"."); + + // set names + if (impact.ImpactsAllCultures) + { + foreach (var c in content.AvailableCultures) // does NOT contain the invariant culture + { + var name = content.GetCultureName(c); + if (string.IsNullOrWhiteSpace(name)) + return false; + content.SetPublishInfo(c, name, DateTime.Now); + } + } + else if (impact.ImpactsOnlyInvariantCulture) + { + if (string.IsNullOrWhiteSpace(content.Name)) + return false; + // PublishName set by repository - nothing to do here + } + else if (impact.ImpactsExplicitCulture) + { + var name = content.GetCultureName(impact.Culture); + if (string.IsNullOrWhiteSpace(name)) + return false; + content.SetPublishInfo(impact.Culture, name, DateTime.Now); + } + + // set values + // property.PublishValues only publishes what is valid, variation-wise, + // but accepts any culture arg: null, all, specific + foreach (var property in content.Properties) + { + // for the specified culture (null or all or specific) + property.PublishValues(impact.Culture); + + // maybe the specified culture did not impact the invariant culture, so PublishValues + // above would skip it, yet it *also* impacts invariant properties + if (impact.ImpactsAlsoInvariantProperties) + property.PublishValues(null); + } + + content.PublishedState = PublishedState.Publishing; + return true; + } + + /// + /// Returns false if the culture is already unpublished + /// + /// + /// + /// + public static bool UnpublishCulture(this IContent content, string culture = "*") + { + culture = culture.NullOrWhiteSpaceAsNull(); + + // the variation should be supported by the content type properties + if (!content.ContentType.SupportsPropertyVariation(culture, "*", true)) + throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\"."); + + var keepProcessing = true; + + if (culture == "*") + { + // all cultures + content.ClearPublishInfos(); + } + else + { + // one single culture + keepProcessing = content.ClearPublishInfo(culture); + } + + if (keepProcessing) + { + // property.PublishValues only publishes what is valid, variation-wise + foreach (var property in content.Properties) + property.UnpublishValues(culture); + + content.PublishedState = PublishedState.Publishing; + } + + return keepProcessing; + } + + public static void ClearPublishInfos(this IContent content) + { + content.PublishCultureInfos = null; + } + + /// + /// Returns false if the culture is already unpublished + /// + /// + /// + /// + public static bool ClearPublishInfo(this IContent content, string culture) + { + if (culture == null) throw new ArgumentNullException(nameof(culture)); + if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture)); + + var removed = content.PublishCultureInfos.Remove(culture); + if (removed) + { + // set the culture to be dirty - it's been modified + content.TouchCulture(culture); + } + return removed; + } + } } diff --git a/src/Umbraco.Infrastructure/Models/ContentTagsExtensions.cs b/src/Umbraco.Core/Models/ContentTagsExtensions.cs similarity index 76% rename from src/Umbraco.Infrastructure/Models/ContentTagsExtensions.cs rename to src/Umbraco.Core/Models/ContentTagsExtensions.cs index 337ca3107d..60f0cc69fb 100644 --- a/src/Umbraco.Infrastructure/Models/ContentTagsExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTagsExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; namespace Umbraco.Core.Models @@ -14,25 +15,29 @@ namespace Umbraco.Core.Models /// Assign tags. /// /// The content item. + /// /// The property alias. /// The tags. /// A value indicating whether to merge the tags with existing tags instead of replacing them. /// A culture, for multi-lingual properties. - public static void AssignTags(this IContentBase content, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, string propertyTypeAlias, IEnumerable tags, bool merge = false, string culture = null) + /// + public static void AssignTags(this IContentBase content, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IJsonSerializer serializer, string propertyTypeAlias, IEnumerable tags, bool merge = false, string culture = null) { - content.GetTagProperty(propertyTypeAlias).AssignTags(propertyEditors, dataTypeService, tags, merge, culture); + content.GetTagProperty(propertyTypeAlias).AssignTags(propertyEditors, dataTypeService, serializer, tags, merge, culture); } /// /// Remove tags. /// /// The content item. + /// /// The property alias. /// The tags. /// A culture, for multi-lingual properties. - public static void RemoveTags(this IContentBase content, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, string propertyTypeAlias, IEnumerable tags, string culture = null) + /// + public static void RemoveTags(this IContentBase content, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IJsonSerializer serializer, string propertyTypeAlias, IEnumerable tags, string culture = null) { - content.GetTagProperty(propertyTypeAlias).RemoveTags(propertyEditors, dataTypeService, tags, culture); + content.GetTagProperty(propertyTypeAlias).RemoveTags(propertyEditors, dataTypeService, serializer, tags, culture); } // gets and validates the property diff --git a/src/Umbraco.Infrastructure/Models/ContentTypeImportModel.cs b/src/Umbraco.Core/Models/ContentTypeImportModel.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/ContentTypeImportModel.cs rename to src/Umbraco.Core/Models/ContentTypeImportModel.cs diff --git a/src/Umbraco.Infrastructure/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs similarity index 93% rename from src/Umbraco.Infrastructure/Models/DataType.cs rename to src/Umbraco.Core/Models/DataType.cs index fdff6f5e6d..b9fe055d4d 100644 --- a/src/Umbraco.Infrastructure/Models/DataType.cs +++ b/src/Umbraco.Core/Models/DataType.cs @@ -1,15 +1,12 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Runtime.Serialization; -using Newtonsoft.Json; using Umbraco.Core.Models.Entities; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; namespace Umbraco.Core.Models { - // TODO: This should exist within Umbraco.Core not infrastructure however there's a dependency on Newtonsoft here, how can we refactor that requirement? - /// /// Implements . /// @@ -19,6 +16,7 @@ namespace Umbraco.Core.Models { private IDataEditor _editor; private ValueStorageType _databaseType; + private readonly IConfigurationEditorJsonSerializer _serializer; private object _configuration; private bool _hasConfiguration; private string _configurationJson; @@ -26,9 +24,10 @@ namespace Umbraco.Core.Models /// /// Initializes a new instance of the class. /// - public DataType(IDataEditor editor, int parentId = -1) + public DataType(IDataEditor editor, IConfigurationEditorJsonSerializer serializer, int parentId = -1) { _editor = editor ?? throw new ArgumentNullException(nameof(editor)); + _serializer = serializer ?? throw new ArgumentNullException(nameof(editor)); ParentId = parentId; // set a default configuration @@ -49,12 +48,12 @@ namespace Umbraco.Core.Models // try to map the existing configuration to the new configuration // simulate saving to db and reloading (ie go via json) var configuration = Configuration; - var json = JsonConvert.SerializeObject(configuration); + var json = _serializer.Serialize(configuration); _editor = value; try { - Configuration = _editor.GetConfigurationEditor().FromDatabase(json); + Configuration = _editor.GetConfigurationEditor().FromDatabase(json, _serializer); } catch (Exception e) { @@ -90,7 +89,7 @@ namespace Umbraco.Core.Models try { - _configuration = _editor.GetConfigurationEditor().FromDatabase(_configurationJson); + _configuration = _editor.GetConfigurationEditor().FromDatabase(_configurationJson, _serializer); } catch (Exception e) { @@ -148,7 +147,7 @@ namespace Umbraco.Core.Models /// type, and they should be the same. /// Think before using! /// - internal void SetLazyConfiguration(string configurationJson) + public void SetLazyConfiguration(string configurationJson) { _hasConfiguration = false; _configuration = null; @@ -183,7 +182,7 @@ namespace Umbraco.Core.Models { try { - return capturedEditor.GetConfigurationEditor().FromDatabase(capturedConfiguration); + return capturedEditor.GetConfigurationEditor().FromDatabase(capturedConfiguration, _serializer); } catch (Exception e) { diff --git a/src/Umbraco.Infrastructure/Models/Editors/UmbracoEntityReference.cs b/src/Umbraco.Core/Models/Editors/UmbracoEntityReference.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Editors/UmbracoEntityReference.cs rename to src/Umbraco.Core/Models/Editors/UmbracoEntityReference.cs diff --git a/src/Umbraco.Infrastructure/Models/LocalPackageInstallModel.cs b/src/Umbraco.Core/Models/LocalPackageInstallModel.cs similarity index 98% rename from src/Umbraco.Infrastructure/Models/LocalPackageInstallModel.cs rename to src/Umbraco.Core/Models/LocalPackageInstallModel.cs index 97d27ffdcb..bd32b176a5 100644 --- a/src/Umbraco.Infrastructure/Models/LocalPackageInstallModel.cs +++ b/src/Umbraco.Core/Models/LocalPackageInstallModel.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Runtime.Serialization; -using Umbraco.Core.Models.Editors; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models @@ -9,7 +8,7 @@ namespace Umbraco.Web.Models /// A model that represents uploading a local package /// [DataContract(Name = "localPackageInstallModel")] - public class LocalPackageInstallModel : PackageInstallModel, INotificationModel + public class LocalPackageInstallModel : PackageInstallModel, INotificationModel { [DataMember(Name = "notifications")] public List Notifications { get; } = new List(); diff --git a/src/Umbraco.Infrastructure/Models/Mapping/AuditMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/AuditMapDefinition.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Mapping/AuditMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/AuditMapDefinition.cs diff --git a/src/Umbraco.Infrastructure/Models/Mapping/CodeFileMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/CodeFileMapDefinition.cs similarity index 98% rename from src/Umbraco.Infrastructure/Models/Mapping/CodeFileMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/CodeFileMapDefinition.cs index 571a994539..425f057dc5 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/CodeFileMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/CodeFileMapDefinition.cs @@ -1,7 +1,6 @@ using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Web.Models.ContentEditing; -using Stylesheet = Umbraco.Core.Models.Stylesheet; namespace Umbraco.Web.Models.Mapping { diff --git a/src/Umbraco.Infrastructure/Models/Mapping/CommonMapper.cs b/src/Umbraco.Core/Models/Mapping/CommonMapper.cs similarity index 91% rename from src/Umbraco.Infrastructure/Models/Mapping/CommonMapper.cs rename to src/Umbraco.Core/Models/Mapping/CommonMapper.cs index 6df8408edb..5ee33c72fa 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/CommonMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/CommonMapper.cs @@ -10,7 +10,6 @@ using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Web.ContentApps; using Umbraco.Web.Models.ContentEditing; - using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile; namespace Umbraco.Web.Models.Mapping @@ -21,16 +20,14 @@ namespace Umbraco.Web.Models.Mapping private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; private readonly ContentAppFactoryCollection _contentAppDefinitions; private readonly ILocalizedTextService _localizedTextService; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor, + public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService) { _userService = userService; _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider; _contentAppDefinitions = contentAppDefinitions; _localizedTextService = localizedTextService; - _umbracoContextAccessor = umbracoContextAccessor; } public UserProfile GetOwner(IContentBase source, MapperContext context) diff --git a/src/Umbraco.Infrastructure/Models/Mapping/ContentSavedStateMapper.cs b/src/Umbraco.Core/Models/Mapping/ContentSavedStateMapper.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Mapping/ContentSavedStateMapper.cs rename to src/Umbraco.Core/Models/Mapping/ContentSavedStateMapper.cs diff --git a/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs similarity index 99% rename from src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs index efe24a6efd..34408469d4 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentTypeMapDefinition.cs @@ -2,19 +2,18 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; +using Umbraco.Core.Exceptions; +using Umbraco.Core.Hosting; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; -using Umbraco.Web.Models.ContentEditing; using Umbraco.Core.Services; -using Umbraco.Core.Exceptions; -using Umbraco.Core.Hosting; -using Umbraco.Core.IO; using Umbraco.Core.Strings; -using Umbraco.Core.Configuration.Models; -using Microsoft.Extensions.Options; +using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Mapping { diff --git a/src/Umbraco.Infrastructure/Models/Mapping/ContentVariantMapper.cs b/src/Umbraco.Core/Models/Mapping/ContentVariantMapper.cs similarity index 99% rename from src/Umbraco.Infrastructure/Models/Mapping/ContentVariantMapper.cs rename to src/Umbraco.Core/Models/Mapping/ContentVariantMapper.cs index 1a852f7c72..6cefd152e9 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/ContentVariantMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/ContentVariantMapper.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using Umbraco.Core; using Umbraco.Core.Mapping; diff --git a/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/DataTypeMapDefinition.cs similarity index 96% rename from src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/DataTypeMapDefinition.cs index 0e403cd88b..1d96d92ee4 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/DataTypeMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/DataTypeMapDefinition.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Mapping @@ -17,12 +18,14 @@ namespace Umbraco.Web.Models.Mapping private readonly PropertyEditorCollection _propertyEditors; private readonly ILogger _logger; private readonly ContentSettings _contentSettings; + private readonly IConfigurationEditorJsonSerializer _serializer; - public DataTypeMapDefinition(PropertyEditorCollection propertyEditors, ILogger logger, IOptions contentSettings) + public DataTypeMapDefinition(PropertyEditorCollection propertyEditors, ILogger logger, IOptions contentSettings, IConfigurationEditorJsonSerializer serializer) { _propertyEditors = propertyEditors; _logger = logger; _contentSettings = contentSettings.Value ?? throw new ArgumentNullException(nameof(contentSettings)); + _serializer = serializer; } private static readonly int[] SystemIds = @@ -40,7 +43,7 @@ namespace Umbraco.Web.Models.Mapping mapper.Define((source, context) => new DataTypeBasic(), Map); mapper.Define((source, context) => new DataTypeDisplay(), Map); mapper.Define>(MapPreValues); - mapper.Define((source, context) => new DataType(_propertyEditors[source.EditorAlias]) { CreateDate = DateTime.Now },Map); + mapper.Define((source, context) => new DataType(_propertyEditors[source.EditorAlias], _serializer) { CreateDate = DateTime.Now }, Map); mapper.Define>(MapPreValues); } @@ -145,7 +148,7 @@ namespace Umbraco.Web.Models.Mapping throw new InvalidOperationException($"Could not find a property editor with alias \"{dataType.EditorAlias}\"."); var configurationEditor = editor.GetConfigurationEditor(); - var fields = context.MapEnumerable(configurationEditor.Fields); + var fields = context.MapEnumerable(configurationEditor.Fields); var configurationDictionary = configurationEditor.ToConfigurationEditor(dataType.Configuration); MapConfigurationFields(dataType, fields, configurationDictionary); diff --git a/src/Umbraco.Infrastructure/Models/Mapping/DictionaryMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Mapping/DictionaryMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/DictionaryMapDefinition.cs diff --git a/src/Umbraco.Infrastructure/Models/Mapping/LanguageMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/LanguageMapDefinition.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Mapping/LanguageMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/LanguageMapDefinition.cs diff --git a/src/Umbraco.Infrastructure/Models/Mapping/MacroMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/MacroMapDefinition.cs similarity index 98% rename from src/Umbraco.Infrastructure/Models/Mapping/MacroMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/MacroMapDefinition.cs index 9aef0e598c..0e003c83a2 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/MacroMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/MacroMapDefinition.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using Microsoft.Extensions.Logging; using Umbraco.Core; using Umbraco.Core.Mapping; diff --git a/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs b/src/Umbraco.Core/Models/Mapping/MemberTabsAndPropertiesMapper.cs similarity index 97% rename from src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs rename to src/Umbraco.Core/Models/Mapping/MemberTabsAndPropertiesMapper.cs index abc32fc008..0c0f415e7c 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/MemberTabsAndPropertiesMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/MemberTabsAndPropertiesMapper.cs @@ -8,13 +8,9 @@ using Umbraco.Core.Dictionary; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Core.Dictionary; -using Umbraco.Core.Configuration; -using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Security; -using Umbraco.Web.Security; namespace Umbraco.Web.Models.Mapping { @@ -83,11 +79,11 @@ namespace Umbraco.Web.Models.Mapping if (_backofficeSecurityAccessor.BackofficeSecurity.CurrentUser != null && _backofficeSecurityAccessor.BackofficeSecurity.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) { - var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", source.ContentTypeId); + var memberTypeLink = $"#/member/memberTypes/edit/{source.ContentTypeId}"; // Replace the doctype property var docTypeProperty = resolved.SelectMany(x => x.Properties) - .First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix)); + .First(x => x.Alias == $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}doctype"); docTypeProperty.Value = new List { new diff --git a/src/Umbraco.Infrastructure/Models/Mapping/PropertyTypeGroupMapper.cs b/src/Umbraco.Core/Models/Mapping/PropertyTypeGroupMapper.cs similarity index 95% rename from src/Umbraco.Infrastructure/Models/Mapping/PropertyTypeGroupMapper.cs rename to src/Umbraco.Core/Models/Mapping/PropertyTypeGroupMapper.cs index 1bdac7618c..e2d4784aae 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/PropertyTypeGroupMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/PropertyTypeGroupMapper.cs @@ -11,7 +11,7 @@ using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Mapping { - internal class PropertyTypeGroupMapper + public class PropertyTypeGroupMapper where TPropertyType : PropertyTypeDisplay, new() { private readonly PropertyEditorCollection _propertyEditors; @@ -132,7 +132,7 @@ namespace Umbraco.Web.Models.Mapping var definingContentType = GetContentTypeForPropertyType(source, compositionGenericProperty.Id); if (definingContentType == null) throw new Exception("PropertyType with id=" + compositionGenericProperty.Id + " was not found on any of the content type's compositions."); - genericProperties.AddRange(MapProperties(new [] { compositionGenericProperty }, definingContentType, PropertyGroupBasic.GenericPropertiesGroupId, true)); + genericProperties.AddRange(MapProperties(new[] { compositionGenericProperty }, definingContentType, PropertyGroupBasic.GenericPropertiesGroupId, true)); } // if there are any generic properties, add the corresponding tab @@ -226,12 +226,12 @@ namespace Umbraco.Web.Models.Mapping Description = p.Description, Editor = p.PropertyEditorAlias, Validation = new PropertyTypeValidation - { - Mandatory = p.Mandatory, - MandatoryMessage = p.MandatoryMessage, - Pattern = p.ValidationRegExp, - PatternMessage = p.ValidationRegExpMessage, - }, + { + Mandatory = p.Mandatory, + MandatoryMessage = p.MandatoryMessage, + Pattern = p.ValidationRegExp, + PatternMessage = p.ValidationRegExpMessage, + }, Label = p.Name, View = propertyEditor.GetValueEditor().View, Config = config, diff --git a/src/Umbraco.Infrastructure/Models/Mapping/RedirectUrlMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/RedirectUrlMapDefinition.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Mapping/RedirectUrlMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/RedirectUrlMapDefinition.cs diff --git a/src/Umbraco.Infrastructure/Models/Mapping/RelationMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/RelationMapDefinition.cs similarity index 98% rename from src/Umbraco.Infrastructure/Models/Mapping/RelationMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/RelationMapDefinition.cs index 836b04ca69..9de506b5eb 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/RelationMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/RelationMapDefinition.cs @@ -1,5 +1,4 @@ -using System.Linq; -using Umbraco.Core; +using Umbraco.Core; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Services; diff --git a/src/Umbraco.Infrastructure/Models/Mapping/SectionMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/SectionMapDefinition.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Mapping/SectionMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/SectionMapDefinition.cs diff --git a/src/Umbraco.Infrastructure/Models/Mapping/TabsAndPropertiesMapper.cs b/src/Umbraco.Core/Models/Mapping/TabsAndPropertiesMapper.cs similarity index 99% rename from src/Umbraco.Infrastructure/Models/Mapping/TabsAndPropertiesMapper.cs rename to src/Umbraco.Core/Models/Mapping/TabsAndPropertiesMapper.cs index 932b12cff1..d2c8fc1303 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/TabsAndPropertiesMapper.cs +++ b/src/Umbraco.Core/Models/Mapping/TabsAndPropertiesMapper.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core; +using Umbraco.Core.Dictionary; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Core.Dictionary; namespace Umbraco.Web.Models.Mapping { @@ -143,7 +143,7 @@ namespace Umbraco.Web.Models.Mapping // merge properties for groups with the same name foreach (var group in groupsByName) { - var groupProperties = source.GetPropertiesForGroup(group) + var groupProperties = source.GetPropertiesForGroup(group) .Where(x => IgnoreProperties.Contains(x.Alias) == false); // skip ignored properties.AddRange(groupProperties); diff --git a/src/Umbraco.Infrastructure/Models/Mapping/TagMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/TagMapDefinition.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Mapping/TagMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/TagMapDefinition.cs diff --git a/src/Umbraco.Infrastructure/Models/Mapping/TemplateMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/TemplateMapDefinition.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/Mapping/TemplateMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/TemplateMapDefinition.cs diff --git a/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs b/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs similarity index 99% rename from src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs rename to src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs index 58a0d98be1..d206aac998 100644 --- a/src/Umbraco.Infrastructure/Models/Mapping/UserMapDefinition.cs +++ b/src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs @@ -2,24 +2,22 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.Models; using Umbraco.Core.IO; using Umbraco.Core.Mapping; -using Umbraco.Core.Models.Membership; -using Umbraco.Web.Models.ContentEditing; +using Umbraco.Core.Media; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Sections; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Actions; +using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Services; -using Umbraco.Core.Media; -using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Configuration.Models; -using Microsoft.Extensions.Options; namespace Umbraco.Web.Models.Mapping { @@ -296,7 +294,7 @@ namespace Umbraco.Web.Models.Mapping target.Id = source.Id; target.Key = source.Key; target.LastLockoutDate = source.LastLockoutDate; - target.LastLoginDate = source.LastLoginDate == default ? null : (DateTime?) source.LastLoginDate; + target.LastLoginDate = source.LastLoginDate == default ? null : (DateTime?)source.LastLoginDate; target.LastPasswordChangeDate = source.LastPasswordChangeDate; target.Name = source.Name; target.Navigation = CreateUserEditorNavigation(); @@ -322,7 +320,7 @@ namespace Umbraco.Web.Models.Mapping target.EmailHash = source.Email.ToLowerInvariant().Trim().GenerateHash(); target.Id = source.Id; target.Key = source.Key; - target.LastLoginDate = source.LastLoginDate == default ? null : (DateTime?) source.LastLoginDate; + target.LastLoginDate = source.LastLoginDate == default ? null : (DateTime?)source.LastLoginDate; target.Name = source.Name; target.ParentId = -1; target.Path = "-1," + source.Id; @@ -447,6 +445,6 @@ namespace Umbraco.Web.Models.Mapping Trashed = false, ParentId = -1 }; - } + } } } diff --git a/src/Umbraco.Infrastructure/Models/PropertyTagsExtensions.cs b/src/Umbraco.Core/Models/PropertyTagsExtensions.cs similarity index 78% rename from src/Umbraco.Infrastructure/Models/PropertyTagsExtensions.cs rename to src/Umbraco.Core/Models/PropertyTagsExtensions.cs index f92dfe751b..ba33547dd6 100644 --- a/src/Umbraco.Infrastructure/Models/PropertyTagsExtensions.cs +++ b/src/Umbraco.Core/Models/PropertyTagsExtensions.cs @@ -2,9 +2,8 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; namespace Umbraco.Core.Models @@ -16,7 +15,7 @@ namespace Umbraco.Core.Models { // gets the tag configuration for a property // from the datatype configuration, and the editor tag configuration attribute - internal static TagConfiguration GetTagConfiguration(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService) + public static TagConfiguration GetTagConfiguration(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService) { if (property == null) throw new ArgumentNullException(nameof(property)); @@ -37,10 +36,13 @@ namespace Umbraco.Core.Models /// Assign tags. /// /// The property. + /// /// The tags. /// A value indicating whether to merge the tags with existing tags instead of replacing them. /// A culture, for multi-lingual properties. - public static void AssignTags(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IEnumerable tags, bool merge = false, string culture = null) + /// + /// + public static void AssignTags(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IJsonSerializer serializer, IEnumerable tags, bool merge = false, string culture = null) { if (property == null) throw new ArgumentNullException(nameof(property)); @@ -48,18 +50,18 @@ namespace Umbraco.Core.Models if (configuration == null) throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags."); - property.AssignTags(tags, merge, configuration.StorageType, configuration.Delimiter, culture); + property.AssignTags(tags, merge, configuration.StorageType, serializer, configuration.Delimiter, culture); } // assumes that parameters are consistent with the datatype configuration - private static void AssignTags(this IProperty property, IEnumerable tags, bool merge, TagsStorageType storageType, char delimiter, string culture) + private static void AssignTags(this IProperty property, IEnumerable tags, bool merge, TagsStorageType storageType, IJsonSerializer serializer, char delimiter, string culture) { // set the property value var trimmedTags = tags.Select(x => x.Trim()).ToArray(); if (merge) { - var currentTags = property.GetTagsValue(storageType, delimiter); + var currentTags = property.GetTagsValue(storageType, serializer, delimiter); switch (storageType) { @@ -68,7 +70,7 @@ namespace Umbraco.Core.Models break; case TagsStorageType.Json: - property.SetValue(JsonConvert.SerializeObject(currentTags.Union(trimmedTags).ToArray()), culture); // json array + property.SetValue(serializer.Serialize(currentTags.Union(trimmedTags).ToArray()), culture); // json array break; } } @@ -81,7 +83,7 @@ namespace Umbraco.Core.Models break; case TagsStorageType.Json: - property.SetValue(JsonConvert.SerializeObject(trimmedTags), culture); // json array + property.SetValue(serializer.Serialize(trimmedTags), culture); // json array break; } } @@ -91,9 +93,12 @@ namespace Umbraco.Core.Models /// Removes tags. /// /// The property. + /// /// The tags. /// A culture, for multi-lingual properties. - public static void RemoveTags(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IEnumerable tags, string culture = null) + /// + /// + public static void RemoveTags(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IJsonSerializer serializer, IEnumerable tags, string culture = null) { if (property == null) throw new ArgumentNullException(nameof(property)); @@ -101,11 +106,11 @@ namespace Umbraco.Core.Models if (configuration == null) throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags."); - property.RemoveTags(tags, configuration.StorageType, configuration.Delimiter, culture); + property.RemoveTags(tags, configuration.StorageType, serializer, configuration.Delimiter, culture); } // assumes that parameters are consistent with the datatype configuration - private static void RemoveTags(this IProperty property, IEnumerable tags, TagsStorageType storageType, char delimiter, string culture) + private static void RemoveTags(this IProperty property, IEnumerable tags, TagsStorageType storageType, IJsonSerializer serializer, char delimiter, string culture) { // already empty = nothing to do var value = property.GetValue(culture)?.ToString(); @@ -113,7 +118,7 @@ namespace Umbraco.Core.Models // set the property value var trimmedTags = tags.Select(x => x.Trim()).ToArray(); - var currentTags = property.GetTagsValue(storageType, delimiter, culture); + var currentTags = property.GetTagsValue(storageType, serializer, delimiter, culture); switch (storageType) { case TagsStorageType.Csv: @@ -121,13 +126,13 @@ namespace Umbraco.Core.Models break; case TagsStorageType.Json: - property.SetValue(JsonConvert.SerializeObject(currentTags.Except(trimmedTags).ToArray()), culture); // json array + property.SetValue(serializer.Serialize(currentTags.Except(trimmedTags).ToArray()), culture); // json array break; } } // used by ContentRepositoryBase - internal static IEnumerable GetTagsValue(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, string culture = null) + public static IEnumerable GetTagsValue(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IJsonSerializer serializer, string culture = null) { if (property == null) throw new ArgumentNullException(nameof(property)); @@ -135,10 +140,10 @@ namespace Umbraco.Core.Models if (configuration == null) throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags."); - return property.GetTagsValue(configuration.StorageType, configuration.Delimiter, culture); + return property.GetTagsValue(configuration.StorageType, serializer, configuration.Delimiter, culture); } - private static IEnumerable GetTagsValue(this IProperty property, TagsStorageType storageType, char delimiter, string culture = null) + private static IEnumerable GetTagsValue(this IProperty property, TagsStorageType storageType, IJsonSerializer serializer, char delimiter, string culture = null) { if (property == null) throw new ArgumentNullException(nameof(property)); @@ -153,9 +158,9 @@ namespace Umbraco.Core.Models case TagsStorageType.Json: try { - return JsonConvert.DeserializeObject(value).Select(x => x.ToString().Trim()); + return serializer.Deserialize(value).Select(x => x.ToString().Trim()); } - catch (JsonException) + catch (Exception) { //cannot parse, malformed return Enumerable.Empty(); @@ -178,7 +183,7 @@ namespace Umbraco.Core.Models /// This is used both by the content repositories to initialize a property with some tag values, and by the /// content controllers to update a property with values received from the property editor. /// - public static void SetTagsValue(this IProperty property, object value, TagConfiguration tagConfiguration, string culture) + public static void SetTagsValue(this IProperty property, IJsonSerializer serializer, object value, TagConfiguration tagConfiguration, string culture) { if (property == null) throw new ArgumentNullException(nameof(property)); if (tagConfiguration == null) throw new ArgumentNullException(nameof(tagConfiguration)); @@ -186,19 +191,19 @@ namespace Umbraco.Core.Models var storageType = tagConfiguration.StorageType; var delimiter = tagConfiguration.Delimiter; - SetTagsValue(property, value, storageType, delimiter, culture); + SetTagsValue(property, value, storageType, serializer, delimiter, culture); } // assumes that parameters are consistent with the datatype configuration // value can be an enumeration of string, or a serialized value using storageType format - private static void SetTagsValue(IProperty property, object value, TagsStorageType storageType, char delimiter, string culture) + private static void SetTagsValue(IProperty property, object value, TagsStorageType storageType, IJsonSerializer serializer, char delimiter, string culture) { if (value == null) value = Enumerable.Empty(); // if value is already an enumeration of strings, just use it if (value is IEnumerable tags1) { - property.AssignTags(tags1, false, storageType, delimiter, culture); + property.AssignTags(tags1, false, storageType, serializer, delimiter, culture); return; } @@ -207,14 +212,14 @@ namespace Umbraco.Core.Models { case TagsStorageType.Csv: var tags2 = value.ToString().Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries); - property.AssignTags(tags2, false, storageType, delimiter, culture); + property.AssignTags(tags2, false, storageType, serializer, delimiter, culture); break; case TagsStorageType.Json: try { - var tags3 = JsonConvert.DeserializeObject>(value.ToString()); - property.AssignTags(tags3 ?? Enumerable.Empty(), false, storageType, delimiter, culture); + var tags3 = serializer.Deserialize>(value.ToString()); + property.AssignTags(tags3 ?? Enumerable.Empty(), false, storageType, serializer, delimiter, culture); } catch (Exception ex) { diff --git a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedContentExtensionsForModels.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtensionsForModels.cs similarity index 97% rename from src/Umbraco.Infrastructure/Models/PublishedContent/PublishedContentExtensionsForModels.cs rename to src/Umbraco.Core/Models/PublishedContent/PublishedContentExtensionsForModels.cs index 8f0db2a7fd..5739f559a6 100644 --- a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedContentExtensionsForModels.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtensionsForModels.cs @@ -1,5 +1,4 @@ using System; -using Umbraco.Core.Composing; namespace Umbraco.Core.Models.PublishedContent { diff --git a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedContentModel.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentModel.cs similarity index 100% rename from src/Umbraco.Infrastructure/Models/PublishedContent/PublishedContentModel.cs rename to src/Umbraco.Core/Models/PublishedContent/PublishedContentModel.cs diff --git a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedContentTypeFactory.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs similarity index 98% rename from src/Umbraco.Infrastructure/Models/PublishedContent/PublishedContentTypeFactory.cs rename to src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs index cd7da378d5..1d32feba16 100644 --- a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedContentTypeFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Composing; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -10,7 +9,7 @@ namespace Umbraco.Core.Models.PublishedContent /// /// Provides a default implementation for . /// - internal class PublishedContentTypeFactory : IPublishedContentTypeFactory + public class PublishedContentTypeFactory : IPublishedContentTypeFactory { private readonly IPublishedModelFactory _publishedModelFactory; private readonly PropertyValueConverterCollection _propertyValueConverters; diff --git a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedModelFactory.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedModelFactory.cs similarity index 97% rename from src/Umbraco.Infrastructure/Models/PublishedContent/PublishedModelFactory.cs rename to src/Umbraco.Core/Models/PublishedContent/PublishedModelFactory.cs index e065ac17b7..3ea7653a7f 100644 --- a/src/Umbraco.Infrastructure/Models/PublishedContent/PublishedModelFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedModelFactory.cs @@ -73,7 +73,7 @@ namespace Umbraco.Core.Models.PublishedContent throw new InvalidOperationException($"Both types '{type.AssemblyQualifiedName}' and '{modelInfo.ModelType.AssemblyQualifiedName}' want to be a model type for content type with alias \"{typeName}\"."); // have to use an unsafe ctor because we don't know the types, really - var modelCtor = ReflectionUtilities.EmitConstructorUnsafe>(constructor); + var modelCtor = ReflectionUtilities.EmitConstructorUnsafe>(constructor); modelInfos[typeName] = new ModelInfo { ParameterType = parameterType, ModelType = type, Ctor = modelCtor }; modelTypeMap[typeName] = type; } @@ -98,7 +98,7 @@ namespace Umbraco.Core.Models.PublishedContent throw new InvalidOperationException($"Model {modelInfo.ModelType} expects argument of type {modelInfo.ParameterType.FullName}, but got {element.GetType().FullName}."); // can cast, because we checked when creating the ctor - return (IPublishedElement) modelInfo.Ctor(element, _publishedValueFallback); + return (IPublishedElement)modelInfo.Ctor(element, _publishedValueFallback); } /// diff --git a/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs index 875e2c0e8f..d38c594def 100644 --- a/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IConfigurationEditor.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Core.PropertyEditors { @@ -48,7 +49,7 @@ namespace Umbraco.Core.PropertyEditors /// /// Converting the configuration object to the serialized database value is /// achieved by simply serializing the configuration. See . - object FromDatabase(string configurationJson); + object FromDatabase(string configurationJson, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer); /// /// Converts the values posted by the configuration editor into the actual configuration object. diff --git a/src/Umbraco.Core/Serialization/IConfigurationEditorJsonSerializer.cs b/src/Umbraco.Core/Serialization/IConfigurationEditorJsonSerializer.cs new file mode 100644 index 0000000000..7370225bce --- /dev/null +++ b/src/Umbraco.Core/Serialization/IConfigurationEditorJsonSerializer.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Serialization +{ + public interface IConfigurationEditorJsonSerializer : IJsonSerializer + { + + } +} diff --git a/src/Umbraco.Core/Serialization/IJsonSerializer.cs b/src/Umbraco.Core/Serialization/IJsonSerializer.cs index c619f173fe..c952394dcb 100644 --- a/src/Umbraco.Core/Serialization/IJsonSerializer.cs +++ b/src/Umbraco.Core/Serialization/IJsonSerializer.cs @@ -5,5 +5,7 @@ string Serialize(object input); T Deserialize(string input); + + T DeserializeSubset(string input, string key); } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/DashboardService.cs b/src/Umbraco.Core/Services/Implement/DashboardService.cs similarity index 98% rename from src/Umbraco.Infrastructure/Services/Implement/DashboardService.cs rename to src/Umbraco.Core/Services/Implement/DashboardService.cs index 918ab57485..a89cd244dc 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/DashboardService.cs +++ b/src/Umbraco.Core/Services/Implement/DashboardService.cs @@ -10,7 +10,7 @@ using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Services { - /// + /// /// A utility class for determine dashboard security /// public class DashboardService : IDashboardService @@ -44,7 +44,7 @@ namespace Umbraco.Web.Services if (dashboard.View.InvariantEndsWith(".ascx")) throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported."); - var dashboards = new List {dashboard}; + var dashboards = new List { dashboard }; tabs.Add(new Tab { Id = tabId++, diff --git a/src/Umbraco.Infrastructure/Trees/ISearchableTree.cs b/src/Umbraco.Core/Trees/ISearchableTree.cs similarity index 100% rename from src/Umbraco.Infrastructure/Trees/ISearchableTree.cs rename to src/Umbraco.Core/Trees/ISearchableTree.cs diff --git a/src/Umbraco.Infrastructure/Trees/TreeNode.cs b/src/Umbraco.Core/Trees/TreeNode.cs similarity index 98% rename from src/Umbraco.Infrastructure/Trees/TreeNode.cs rename to src/Umbraco.Core/Trees/TreeNode.cs index ad64f3dc5e..95c8a20b76 100644 --- a/src/Umbraco.Infrastructure/Trees/TreeNode.cs +++ b/src/Umbraco.Core/Trees/TreeNode.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Models; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Trees @@ -116,5 +115,4 @@ namespace Umbraco.Web.Models.Trees [DataMember(Name = "cssClasses")] public IList CssClasses { get; private set; } } - } diff --git a/src/Umbraco.Infrastructure/Trees/TreeNodeCollection.cs b/src/Umbraco.Core/Trees/TreeNodeCollection.cs similarity index 100% rename from src/Umbraco.Infrastructure/Trees/TreeNodeCollection.cs rename to src/Umbraco.Core/Trees/TreeNodeCollection.cs diff --git a/src/Umbraco.Infrastructure/Trees/TreeNodeExtensions.cs b/src/Umbraco.Core/Trees/TreeNodeExtensions.cs similarity index 99% rename from src/Umbraco.Infrastructure/Trees/TreeNodeExtensions.cs rename to src/Umbraco.Core/Trees/TreeNodeExtensions.cs index e25c317716..10aaf342f0 100644 --- a/src/Umbraco.Infrastructure/Trees/TreeNodeExtensions.cs +++ b/src/Umbraco.Core/Trees/TreeNodeExtensions.cs @@ -73,6 +73,5 @@ treeNode.CssClasses.Add("not-published"); } } - } } diff --git a/src/Umbraco.Infrastructure/ContentExtensions.cs b/src/Umbraco.Infrastructure/ContentExtensions.cs deleted file mode 100644 index e71815f911..0000000000 --- a/src/Umbraco.Infrastructure/ContentExtensions.cs +++ /dev/null @@ -1,255 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Umbraco.Core.IO; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Services; -using Umbraco.Core.Strings; - -namespace Umbraco.Core -{ - public static class ContentExtensions - { - /// - /// Returns all properties based on the editorAlias - /// - /// - /// - /// - public static IEnumerable GetPropertiesByEditor(this IContentBase content, string editorAlias) - => content.Properties.Where(x => x.PropertyType.PropertyEditorAlias == editorAlias); - - internal static bool IsMoving(this IContentBase entity) - { - // Check if this entity is being moved as a descendant as part of a bulk moving operations. - // When this occurs, only Path + Level + UpdateDate are being changed. In this case we can bypass a lot of the below - // operations which will make this whole operation go much faster. When moving we don't need to create - // new versions, etc... because we cannot roll this operation back anyways. - var isMoving = entity.IsPropertyDirty(nameof(entity.Path)) - && entity.IsPropertyDirty(nameof(entity.Level)) - && entity.IsPropertyDirty(nameof(entity.UpdateDate)); - - return isMoving; - } - - - - #region IContent - - /// - /// Gets the current status of the Content - /// - public static ContentStatus GetStatus(this IContent content, string culture = null) - { - if (content.Trashed) - return ContentStatus.Trashed; - - if (!content.ContentType.VariesByCulture()) - culture = string.Empty; - else if (culture.IsNullOrWhiteSpace()) - throw new ArgumentNullException($"{nameof(culture)} cannot be null or empty"); - - var expires = content.ContentSchedule.GetSchedule(culture, ContentScheduleAction.Expire); - if (expires != null && expires.Any(x => x.Date > DateTime.MinValue && DateTime.Now > x.Date)) - return ContentStatus.Expired; - - var release = content.ContentSchedule.GetSchedule(culture, ContentScheduleAction.Release); - if (release != null && release.Any(x => x.Date > DateTime.MinValue && x.Date > DateTime.Now)) - return ContentStatus.AwaitingRelease; - - if (content.Published) - return ContentStatus.Published; - - return ContentStatus.Unpublished; - } - - - - #endregion - - /// - /// Gets the for the Creator of this content item. - /// - public static IProfile GetCreatorProfile(this IContentBase content, IUserService userService) - { - return userService.GetProfileById(content.CreatorId); - } - /// - /// Gets the for the Writer of this content. - /// - public static IProfile GetWriterProfile(this IContent content, IUserService userService) - { - return userService.GetProfileById(content.WriterId); - } - - /// - /// Gets the for the Writer of this content. - /// - public static IProfile GetWriterProfile(this IMedia content, IUserService userService) - { - return userService.GetProfileById(content.WriterId); - } - - #region User/Profile methods - - /// - /// Gets the for the Creator of this media item. - /// - public static IProfile GetCreatorProfile(this IMedia media, IUserService userService) - { - return userService.GetProfileById(media.CreatorId); - } - - - #endregion - - /// - /// Checks if the IContentBase has children - /// - /// - /// - /// - /// - /// This is a bit of a hack because we need to type check! - /// - internal static bool HasChildren(IContentBase content, ServiceContext services) - { - if (content is IContent) - { - return services.ContentService.HasChildren(content.Id); - } - if (content is IMedia) - { - return services.MediaService.HasChildren(content.Id); - } - return false; - } - - - /// - /// Returns properties that do not belong to a group - /// - /// - /// - public static IEnumerable GetNonGroupedProperties(this IContentBase content) - { - return content.Properties - .Where(x => x.PropertyType.PropertyGroupId == null) - .OrderBy(x => x.PropertyType.SortOrder); - } - - /// - /// Returns the Property object for the given property group - /// - /// - /// - /// - public static IEnumerable GetPropertiesForGroup(this IContentBase content, PropertyGroup propertyGroup) - { - //get the properties for the current tab - return content.Properties - .Where(property => propertyGroup.PropertyTypes - .Select(propertyType => propertyType.Id) - .Contains(property.PropertyTypeId)); - } - - - #region SetValue for setting file contents - - /// - /// Sets the posted file value of a property. - /// - public static void SetValue(this IContentBase content, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) - { - if (filename == null || filestream == null) return; - - filename = shortStringHelper.CleanStringForSafeFileName(filename); - if (string.IsNullOrWhiteSpace(filename)) return; - filename = filename.ToLower(); - - SetUploadFile(content, mediaFileSystem, contentTypeBaseServiceProvider, propertyTypeAlias, filename, filestream, culture, segment); - } - - private static void SetUploadFile(this IContentBase content, IMediaFileSystem mediaFileSystem, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null) - { - var property = GetProperty(content, contentTypeBaseServiceProvider, propertyTypeAlias); - - // Fixes https://github.com/umbraco/Umbraco-CMS/issues/3937 - Assigning a new file to an - // existing IMedia with extension SetValue causes exception 'Illegal characters in path' - string oldpath = null; - if (property.GetValue(culture, segment) is string svalue) - { - if (svalue.DetectIsJson()) - { - // the property value is a JSON serialized image crop data set - grab the "src" property as the file source - var jObject = JsonConvert.DeserializeObject(svalue); - svalue = jObject != null ? jObject.GetValueAsString("src") : svalue; - } - oldpath = mediaFileSystem.GetRelativePath(svalue); - } - - var filepath = mediaFileSystem.StoreFile(content, property.PropertyType, filename, filestream, oldpath); - property.SetValue(mediaFileSystem.GetUrl(filepath), culture, segment); - } - - // gets or creates a property for a content item. - private static IProperty GetProperty(IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias) - { - var property = content.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); - if (property != null) return property; - - var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(content); - var propertyType = contentType.CompositionPropertyTypes - .FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); - if (propertyType == null) - throw new Exception("No property type exists with alias " + propertyTypeAlias + "."); - - property = new Property(propertyType); - content.Properties.Add(property); - return property; - } - - /// - /// Stores a file. - /// - /// A content item. - /// The property alias. - /// The name of the file. - /// A stream containing the file data. - /// The original file path, if any. - /// The path to the file, relative to the media filesystem. - /// - /// Does NOT set the property value, so one should probably store the file and then do - /// something alike: property.Value = MediaHelper.FileSystem.GetUrl(filepath). - /// The original file path is used, in the old media file path scheme, to try and reuse - /// the "folder number" that was assigned to the previous file referenced by the property, - /// if any. - /// - public static string StoreFile(this IContentBase content, IMediaFileSystem mediaFileSystem, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string filepath) - { - var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(content); - var propertyType = contentType - .CompositionPropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyTypeAlias)); - if (propertyType == null) throw new ArgumentException("Invalid property type alias " + propertyTypeAlias + "."); - return mediaFileSystem.StoreFile(content, propertyType, filename, filestream, filepath); - } - - #endregion - - - #region Dirty - - public static IEnumerable GetDirtyUserProperties(this IContentBase entity) - { - return entity.Properties.Where(x => x.IsDirty()).Select(x => x.Alias); - } - - - - #endregion - } -} diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs index fcd3a98218..d813550750 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs @@ -1,14 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json; using Microsoft.Extensions.Logging; -using Umbraco.Core.Composing; using Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; -using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { @@ -18,6 +16,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 private readonly PreValueMigratorCollection _preValueMigrators; private readonly PropertyEditorCollection _propertyEditors; private readonly ILogger _logger; + private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer; private static readonly ISet LegacyAliases = new HashSet() { @@ -31,12 +30,17 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 Constants.PropertyEditors.Legacy.Aliases.MultiNodeTreePicker2, }; - public DataTypeMigration(IMigrationContext context, PreValueMigratorCollection preValueMigrators, PropertyEditorCollection propertyEditors, ILogger logger) + public DataTypeMigration(IMigrationContext context, + PreValueMigratorCollection preValueMigrators, + PropertyEditorCollection propertyEditors, + ILogger logger, + IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) : base(context) { _preValueMigrators = preValueMigrators; _propertyEditors = propertyEditors; _logger = logger; + _configurationEditorJsonSerializer = configurationEditorJsonSerializer; } public override void Migrate() @@ -86,7 +90,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 // migrate the preValues to configuration var migrator = _preValueMigrators.GetMigrator(dataType.EditorAlias) ?? new DefaultPreValueMigrator(); var config = migrator.GetConfiguration(dataType.NodeId, dataType.EditorAlias, dictionary); - var json = JsonConvert.SerializeObject(config); + var json = _configurationEditorJsonSerializer.Serialize(config); // validate - and kill the migration if it fails var newAlias = migrator.GetNewAlias(dataType.EditorAlias); @@ -115,7 +119,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 var configEditor = propertyEditor.GetConfigurationEditor(); try { - var _ = configEditor.FromDatabase(json); + var _ = configEditor.FromDatabase(json, _configurationEditorJsonSerializer); } catch (Exception e) { @@ -126,7 +130,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 } // update - dataType.Configuration = JsonConvert.SerializeObject(config); + dataType.Configuration = _configurationEditorJsonSerializer.Serialize(config); Database.Update(dataType); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs index 6b1d734bc8..031abc17f9 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs @@ -8,17 +8,20 @@ using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models; +using Umbraco.Core.Serialization; namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { public class DropDownPropertyEditorsMigration : PropertyEditorsMigrationBase { private readonly IIOHelper _ioHelper; + private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer; - public DropDownPropertyEditorsMigration(IMigrationContext context, IIOHelper ioHelper) + public DropDownPropertyEditorsMigration(IMigrationContext context, IIOHelper ioHelper, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) : base(context) { _ioHelper = ioHelper; + _configurationEditorJsonSerializer = configurationEditorJsonSerializer; } public override void Migrate() @@ -47,7 +50,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 configurationEditor = new ValueListConfigurationEditor(_ioHelper); try { - config = (ValueListConfiguration) configurationEditor.FromDatabase(dataType.Configuration); + config = (ValueListConfiguration) configurationEditor.FromDatabase(dataType.Configuration, _configurationEditorJsonSerializer); } catch (Exception ex) { @@ -112,7 +115,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 Items = config.Items, Multiple = isMultiple }; - dataType.Configuration = ConfigurationEditor.ToDatabase(flexConfig); + dataType.Configuration = ConfigurationEditor.ToDatabase(flexConfig, _configurationEditorJsonSerializer); Database.Update(dataType); } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs index 00092f3feb..8e71c8ff4f 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs @@ -5,17 +5,20 @@ using Umbraco.Core.IO; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { public class MergeDateAndDateTimePropertyEditor : MigrationBase { private readonly IIOHelper _ioHelper; + private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer; - public MergeDateAndDateTimePropertyEditor(IMigrationContext context, IIOHelper ioHelper) + public MergeDateAndDateTimePropertyEditor(IMigrationContext context, IIOHelper ioHelper, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) : base(context) { _ioHelper = ioHelper; + _configurationEditorJsonSerializer = configurationEditorJsonSerializer; } public override void Migrate() @@ -28,7 +31,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 try { config = (DateTimeConfiguration) new CustomDateTimeConfigurationEditor(_ioHelper).FromDatabase( - dataType.Configuration); + dataType.Configuration, _configurationEditorJsonSerializer); // If the Umbraco.Date type is the default from V7 and it has never been updated, then the // configuration is empty, and the format stuff is handled by in JS by moment.js. - We can't do that @@ -51,7 +54,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 config.OffsetTime = false; dataType.EditorAlias = Constants.PropertyEditors.Aliases.DateTime; - dataType.Configuration = ConfigurationEditor.ToDatabase(config); + dataType.Configuration = ConfigurationEditor.ToDatabase(config, _configurationEditorJsonSerializer); Database.Update(dataType); } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs index 20218dc2c6..e1173ed3a4 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs @@ -8,17 +8,23 @@ using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 { public class RadioAndCheckboxPropertyEditorsMigration : PropertyEditorsMigrationBase { private readonly IIOHelper _ioHelper; + private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer; - public RadioAndCheckboxPropertyEditorsMigration(IMigrationContext context, IIOHelper ioHelper) + public RadioAndCheckboxPropertyEditorsMigration( + IMigrationContext context, + IIOHelper ioHelper, + IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) : base(context) { _ioHelper = ioHelper; + _configurationEditorJsonSerializer = configurationEditorJsonSerializer; } public override void Migrate() @@ -51,7 +57,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 configurationEditor = new ValueListConfigurationEditor(_ioHelper); try { - config = (ValueListConfiguration) configurationEditor.FromDatabase(dataType.Configuration); + config = (ValueListConfiguration) configurationEditor.FromDatabase(dataType.Configuration, _configurationEditorJsonSerializer); } catch (Exception ex) { diff --git a/src/Umbraco.Infrastructure/Models/ContentRepositoryExtensions.cs b/src/Umbraco.Infrastructure/Models/ContentRepositoryExtensions.cs deleted file mode 100644 index 6d1f565944..0000000000 --- a/src/Umbraco.Infrastructure/Models/ContentRepositoryExtensions.cs +++ /dev/null @@ -1,256 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Umbraco.Core.Models -{ - /// - /// Extension methods used to manipulate content variations by the document repository - /// - public static class ContentRepositoryExtensions - { - /// - /// Gets the cultures that have been flagged for unpublishing. - /// - /// Gets cultures for which content.UnpublishCulture() has been invoked. - public static IReadOnlyList GetCulturesUnpublishing(this IContent content) - { - if (!content.Published || !content.ContentType.VariesByCulture() || !content.IsPropertyDirty("PublishCultureInfos")) - return Array.Empty(); - - var culturesUnpublishing = content.CultureInfos.Values - .Where(x => content.IsPropertyDirty(ContentBase.ChangeTrackingPrefix.UnpublishedCulture + x.Culture)) - .Select(x => x.Culture); - - return culturesUnpublishing.ToList(); - } - - /// - /// Copies values from another document. - /// - public static void CopyFrom(this IContent content, IContent other, string culture = "*") - { - if (other.ContentTypeId != content.ContentTypeId) - throw new InvalidOperationException("Cannot copy values from a different content type."); - - culture = culture?.ToLowerInvariant().NullOrWhiteSpaceAsNull(); - - // the variation should be supported by the content type properties - // if the content type is invariant, only '*' and 'null' is ok - // if the content type varies, everything is ok because some properties may be invariant - if (!content.ContentType.SupportsPropertyVariation(culture, "*", true)) - throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\"."); - - // copying from the same Id and VersionPk - var copyingFromSelf = content.Id == other.Id && content.VersionId == other.VersionId; - var published = copyingFromSelf; - - // note: use property.SetValue(), don't assign pvalue.EditValue, else change tracking fails - - // clear all existing properties for the specified culture - foreach (var property in content.Properties) - { - // each property type may or may not support the variation - if (!property.PropertyType.SupportsVariation(culture, "*", wildcards: true)) - continue; - - foreach (var pvalue in property.Values) - if (property.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment, wildcards: true) && - (culture == "*" || pvalue.Culture.InvariantEquals(culture))) - { - property.SetValue(null, pvalue.Culture, pvalue.Segment); - } - } - - // copy properties from 'other' - var otherProperties = other.Properties; - foreach (var otherProperty in otherProperties) - { - if (!otherProperty.PropertyType.SupportsVariation(culture, "*", wildcards: true)) - continue; - - var alias = otherProperty.PropertyType.Alias; - foreach (var pvalue in otherProperty.Values) - { - if (otherProperty.PropertyType.SupportsVariation(pvalue.Culture, pvalue.Segment, wildcards: true) && - (culture == "*" || pvalue.Culture.InvariantEquals(culture))) - { - var value = published ? pvalue.PublishedValue : pvalue.EditedValue; - content.SetValue(alias, value, pvalue.Culture, pvalue.Segment); - } - } - } - - // copy names, too - - if (culture == "*") - { - content.CultureInfos.Clear(); - content.CultureInfos = null; - } - - if (culture == null || culture == "*") - content.Name = other.Name; - - // ReSharper disable once UseDeconstruction - foreach (var cultureInfo in other.CultureInfos) - { - if (culture == "*" || culture == cultureInfo.Culture) - content.SetCultureName(cultureInfo.Name, cultureInfo.Culture); - } - } - - public static void SetPublishInfo(this IContent content, string culture, string name, DateTime date) - { - if (name == null) throw new ArgumentNullException(nameof(name)); - if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(name)); - - if (culture == null) throw new ArgumentNullException(nameof(culture)); - if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture)); - - content.PublishCultureInfos.AddOrUpdate(culture, name, date); - } - - - - // sets the edited cultures on the content - public static void SetCultureEdited(this IContent content, IEnumerable cultures) - { - if (cultures == null) - content.EditedCultures = null; - else - { - var editedCultures = new HashSet(cultures.Where(x => !x.IsNullOrWhiteSpace()), StringComparer.OrdinalIgnoreCase); - content.EditedCultures = editedCultures.Count > 0 ? editedCultures : null; - } - } - - /// - /// Sets the publishing values for names and properties. - /// - /// - /// - /// A value indicating whether it was possible to publish the names and values for the specified - /// culture(s). The method may fail if required names are not set, but it does NOT validate property data - public static bool PublishCulture(this IContent content, CultureImpact impact) - { - if (impact == null) throw new ArgumentNullException(nameof(impact)); - - // the variation should be supported by the content type properties - // if the content type is invariant, only '*' and 'null' is ok - // if the content type varies, everything is ok because some properties may be invariant - if (!content.ContentType.SupportsPropertyVariation(impact.Culture, "*", true)) - throw new NotSupportedException($"Culture \"{impact.Culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\"."); - - // set names - if (impact.ImpactsAllCultures) - { - foreach (var c in content.AvailableCultures) // does NOT contain the invariant culture - { - var name = content.GetCultureName(c); - if (string.IsNullOrWhiteSpace(name)) - return false; - content.SetPublishInfo(c, name, DateTime.Now); - } - } - else if (impact.ImpactsOnlyInvariantCulture) - { - if (string.IsNullOrWhiteSpace(content.Name)) - return false; - // PublishName set by repository - nothing to do here - } - else if (impact.ImpactsExplicitCulture) - { - var name = content.GetCultureName(impact.Culture); - if (string.IsNullOrWhiteSpace(name)) - return false; - content.SetPublishInfo(impact.Culture, name, DateTime.Now); - } - - // set values - // property.PublishValues only publishes what is valid, variation-wise, - // but accepts any culture arg: null, all, specific - foreach (var property in content.Properties) - { - // for the specified culture (null or all or specific) - property.PublishValues(impact.Culture); - - // maybe the specified culture did not impact the invariant culture, so PublishValues - // above would skip it, yet it *also* impacts invariant properties - if (impact.ImpactsAlsoInvariantProperties) - property.PublishValues(null); - } - - content.PublishedState = PublishedState.Publishing; - return true; - } - - /// - /// Returns false if the culture is already unpublished - /// - /// - /// - /// - public static bool UnpublishCulture(this IContent content, string culture = "*") - { - culture = culture.NullOrWhiteSpaceAsNull(); - - // the variation should be supported by the content type properties - if (!content.ContentType.SupportsPropertyVariation(culture, "*", true)) - throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\"."); - - - var keepProcessing = true; - - if (culture == "*") - { - // all cultures - content.ClearPublishInfos(); - } - else - { - // one single culture - keepProcessing = content.ClearPublishInfo(culture); - } - - - if (keepProcessing) - { - // property.PublishValues only publishes what is valid, variation-wise - foreach (var property in content.Properties) - property.UnpublishValues(culture); - - content.PublishedState = PublishedState.Publishing; - } - - return keepProcessing; - } - - public static void ClearPublishInfos(this IContent content) - { - content.PublishCultureInfos = null; - } - - /// - /// Returns false if the culture is already unpublished - /// - /// - /// - /// - public static bool ClearPublishInfo(this IContent content, string culture) - { - if (culture == null) throw new ArgumentNullException(nameof(culture)); - if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(culture)); - - var removed = content.PublishCultureInfos.Remove(culture); - if (removed) - { - // set the culture to be dirty - it's been modified - content.TouchCulture(culture); - } - return removed; - } - - - } -} diff --git a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs index 16f4a8bc25..1dedd016ac 100644 --- a/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs @@ -15,6 +15,7 @@ using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Packaging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; @@ -34,6 +35,7 @@ namespace Umbraco.Core.Packaging private readonly IShortStringHelper _shortStringHelper; private readonly GlobalSettings _globalSettings; private readonly ILocalizedTextService _localizedTextService; + private readonly IConfigurationEditorJsonSerializer _serializer; private readonly IEntityService _entityService; private readonly IContentTypeService _contentTypeService; private readonly IContentService _contentService; @@ -41,7 +43,7 @@ namespace Umbraco.Core.Packaging public PackageDataInstallation(ILogger logger, ILoggerFactory loggerFactory, IFileService fileService, IMacroService macroService, ILocalizationService localizationService, IDataTypeService dataTypeService, IEntityService entityService, IContentTypeService contentTypeService, IContentService contentService, PropertyEditorCollection propertyEditors, IScopeProvider scopeProvider, IShortStringHelper shortStringHelper, IOptions globalSettings, - ILocalizedTextService localizedTextService) + ILocalizedTextService localizedTextService, IConfigurationEditorJsonSerializer serializer) { _logger = logger; _loggerFactory = loggerFactory; @@ -54,6 +56,7 @@ namespace Umbraco.Core.Packaging _shortStringHelper = shortStringHelper; _globalSettings = globalSettings.Value; _localizedTextService = localizedTextService; + _serializer = serializer; _entityService = entityService; _contentTypeService = contentTypeService; _contentService = contentService; @@ -908,7 +911,7 @@ namespace Umbraco.Core.Packaging if (!_propertyEditors.TryGet(editorAlias, out var editor)) editor = new VoidEditor(_loggerFactory, _dataTypeService, _localizationService, _localizedTextService, _shortStringHelper) { Alias = editorAlias }; - var dataType = new DataType(editor) + var dataType = new DataType(editor, _serializer) { Key = dataTypeDefinitionId, Name = dataTypeDefinitionName, @@ -918,7 +921,7 @@ namespace Umbraco.Core.Packaging var configurationAttributeValue = dataTypeElement.Attribute("Configuration")?.Value; if (!string.IsNullOrWhiteSpace(configurationAttributeValue)) - dataType.Configuration = editor.GetConfigurationEditor().FromDatabase(configurationAttributeValue); + dataType.Configuration = editor.GetConfigurationEditor().FromDatabase(configurationAttributeValue, _serializer); dataTypes.Add(dataType); } diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs index 77d8199775..5f915c18aa 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs @@ -3,12 +3,13 @@ using Microsoft.Extensions.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; namespace Umbraco.Core.Persistence.Factories { internal static class DataTypeFactory { - public static IDataType BuildEntity(DataTypeDto dto, PropertyEditorCollection editors, ILogger logger) + public static IDataType BuildEntity(DataTypeDto dto, PropertyEditorCollection editors, ILogger logger, IConfigurationEditorJsonSerializer serializer) { // Check we have an editor for the data type. if (!editors.TryGet(dto.EditorAlias, out var editor)) @@ -21,7 +22,7 @@ namespace Umbraco.Core.Persistence.Factories editor = new MissingPropertyEditor(); } - var dataType = new DataType(editor); + var dataType = new DataType(editor, serializer); try { @@ -52,14 +53,14 @@ namespace Umbraco.Core.Persistence.Factories } } - public static DataTypeDto BuildDto(IDataType entity) + public static DataTypeDto BuildDto(IDataType entity, IConfigurationEditorJsonSerializer serializer) { var dataTypeDto = new DataTypeDto { EditorAlias = entity.EditorAlias, NodeId = entity.Id, DbType = entity.DatabaseType.ToString(), - Configuration = ConfigurationEditor.ToDatabase(entity.Configuration), + Configuration = ConfigurationEditor.ToDatabase(entity.Configuration, serializer), NodeDto = BuildNodeDto(entity) }; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs index a0a26ea428..d48508ba8d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using static Umbraco.Core.Persistence.SqlExtensionsStatics; @@ -243,7 +244,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// /// Updates tags for an item. /// - protected void SetEntityTags(IContentBase entity, ITagRepository tagRepo) + protected void SetEntityTags(IContentBase entity, ITagRepository tagRepo, IJsonSerializer serializer) { foreach (var property in entity.Properties) { @@ -255,7 +256,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var tags = new List(); foreach (var pvalue in property.Values) { - var tagsValue = property.GetTagsValue(PropertyEditors, DataTypeService, pvalue.Culture); + var tagsValue = property.GetTagsValue(PropertyEditors, DataTypeService, serializer, pvalue.Culture); var languageId = LanguageRepository.GetIdByIsoCode(pvalue.Culture); var cultureTags = tagsValue.Select(x => new Tag { Group = tagConfiguration.Group, Text = x, LanguageId = languageId }); tags.AddRange(cultureTags); @@ -264,7 +265,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } else { - var tagsValue = property.GetTagsValue(PropertyEditors, DataTypeService); // strings + var tagsValue = property.GetTagsValue(PropertyEditors, DataTypeService, serializer); // strings var tags = tagsValue.Select(x => new Tag { Group = tagConfiguration.Group, Text = x }); tagRepo.Assign(entity.Id, property.PropertyTypeId, tags); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs index 853e0da181..482a333631 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -15,6 +15,7 @@ using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using static Umbraco.Core.Persistence.SqlExtensionsStatics; @@ -26,12 +27,20 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class DataTypeRepository : NPocoRepositoryBase, IDataTypeRepository { private readonly Lazy _editors; + private readonly IConfigurationEditorJsonSerializer _serializer; private readonly ILogger _dataTypeLogger; - public DataTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, Lazy editors, ILogger logger, ILoggerFactory loggerFactory) + public DataTypeRepository( + IScopeAccessor scopeAccessor, + AppCaches cache, + Lazy editors, + ILogger logger, + ILoggerFactory loggerFactory, + IConfigurationEditorJsonSerializer serializer) : base(scopeAccessor, cache, logger) { _editors = editors; + _serializer = serializer; _dataTypeLogger = loggerFactory.CreateLogger(); } @@ -56,7 +65,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } var dtos = Database.Fetch(dataTypeSql); - return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, _dataTypeLogger)).ToArray(); + return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, _dataTypeLogger, _serializer)).ToArray(); } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -67,7 +76,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var dtos = Database.Fetch(sql); - return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, _dataTypeLogger)).ToArray(); + return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, _dataTypeLogger, _serializer)).ToArray(); } #endregion @@ -126,7 +135,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement throw new DuplicateNameException("A data type with the name " + entity.Name + " already exists"); } - var dto = DataTypeFactory.BuildDto(entity); + var dto = DataTypeFactory.BuildDto(entity, _serializer); //Logic for setting Path, Level and SortOrder var parent = Database.First("WHERE id = @ParentId", new { ParentId = entity.ParentId }); @@ -191,7 +200,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.SortOrder = maxSortOrder + 1; } - var dto = DataTypeFactory.BuildDto(entity); + var dto = DataTypeFactory.BuildDto(entity, _serializer); //Updates the (base) node data - umbracoNode var nodeDto = dto.NodeDto; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs index 32553a8fd4..a647ba49d3 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs @@ -4,6 +4,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; namespace Umbraco.Core.Persistence.Repositories.Implement @@ -32,8 +33,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement IRelationTypeRepository relationTypeRepository, Lazy propertyEditorCollection, IDataTypeService dataTypeService, - DataValueReferenceFactoryCollection dataValueReferenceFactories) - : base(scopeAccessor, appCaches, logger, loggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, dataValueReferenceFactories, dataTypeService) + DataValueReferenceFactoryCollection dataValueReferenceFactories, + IJsonSerializer serializer) + : base(scopeAccessor, appCaches, logger, loggerFactory, contentTypeRepository, templateRepository, + tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, + dataValueReferenceFactories, dataTypeService, serializer) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs index 7e19c1aef4..0dc0e79504 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; namespace Umbraco.Core.Persistence.Repositories.Implement @@ -25,6 +26,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly IContentTypeRepository _contentTypeRepository; private readonly ITemplateRepository _templateRepository; private readonly ITagRepository _tagRepository; + private readonly IJsonSerializer _serializer; private readonly AppCaches _appCaches; private readonly ILoggerFactory _loggerFactory; private PermissionRepository _permissionRepository; @@ -58,12 +60,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement IRelationTypeRepository relationTypeRepository, Lazy propertyEditors, DataValueReferenceFactoryCollection dataValueReferenceFactories, - IDataTypeService dataTypeService) + IDataTypeService dataTypeService, + IJsonSerializer serializer) : base(scopeAccessor, appCaches, logger, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferenceFactories, dataTypeService) { _contentTypeRepository = contentTypeRepository ?? throw new ArgumentNullException(nameof(contentTypeRepository)); _templateRepository = templateRepository ?? throw new ArgumentNullException(nameof(templateRepository)); _tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository)); + _serializer = serializer; _appCaches = appCaches; _loggerFactory = loggerFactory; _scopeAccessor = scopeAccessor; @@ -502,7 +506,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.PublishName = entity.Name; entity.PublishDate = entity.UpdateDate; - SetEntityTags(entity, _tagRepository); + SetEntityTags(entity, _tagRepository, _serializer); } else if (entity.PublishedState == PublishedState.Unpublishing) { @@ -705,7 +709,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // if entity is publishing, update tags, else leave tags there // means that implicitly unpublished, or trashed, entities *still* have tags in db if (entity.PublishedState == PublishedState.Publishing) - SetEntityTags(entity, _tagRepository); + SetEntityTags(entity, _tagRepository, _serializer); } // trigger here, before we reset Published etc @@ -723,7 +727,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.PublishName = entity.Name; entity.PublishDate = entity.UpdateDate; - SetEntityTags(entity, _tagRepository); + SetEntityTags(entity, _tagRepository, _serializer); } else if (entity.PublishedState == PublishedState.Unpublishing) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs index 9f47fd2f6b..3b2b0bd308 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using static Umbraco.Core.Persistence.SqlExtensionsStatics; @@ -26,6 +27,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly IMediaTypeRepository _mediaTypeRepository; private readonly ITagRepository _tagRepository; private readonly MediaUrlGeneratorCollection _mediaUrlGenerators; + private readonly IJsonSerializer _serializer; private readonly MediaByGuidReadRepository _mediaByGuidReadRepository; public MediaRepository( @@ -41,12 +43,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Lazy propertyEditorCollection, MediaUrlGeneratorCollection mediaUrlGenerators, DataValueReferenceFactoryCollection dataValueReferenceFactories, - IDataTypeService dataTypeService) + IDataTypeService dataTypeService, + IJsonSerializer serializer) : base(scopeAccessor, cache, logger, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, dataValueReferenceFactories, dataTypeService) { _mediaTypeRepository = mediaTypeRepository ?? throw new ArgumentNullException(nameof(mediaTypeRepository)); _tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository)); _mediaUrlGenerators = mediaUrlGenerators; + _serializer = serializer; _mediaByGuidReadRepository = new MediaByGuidReadRepository(this, scopeAccessor, cache, loggerFactory.CreateLogger()); } @@ -299,7 +303,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Database.Insert(propertyDataDto); // set tags - SetEntityTags(entity, _tagRepository); + SetEntityTags(entity, _tagRepository, _serializer); PersistRelations(entity); @@ -365,7 +369,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement foreach (var propertyDataDto in propertyDataDtos) Database.Insert(propertyDataDto); - SetEntityTags(entity, _tagRepository); + SetEntityTags(entity, _tagRepository, _serializer); PersistRelations(entity); } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs index 5b1aba12ca..1f319f483e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberRepository.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using static Umbraco.Core.Persistence.SqlExtensionsStatics; @@ -25,6 +26,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement private readonly IMemberTypeRepository _memberTypeRepository; private readonly ITagRepository _tagRepository; private readonly IPasswordHasher _passwordHasher; + private readonly IJsonSerializer _serializer; private readonly IMemberGroupRepository _memberGroupRepository; private readonly IRepositoryCachePolicy _memberByUsernameCachePolicy; @@ -33,12 +35,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement IPasswordHasher passwordHasher, Lazy propertyEditors, DataValueReferenceFactoryCollection dataValueReferenceFactories, - IDataTypeService dataTypeService) + IDataTypeService dataTypeService, + IJsonSerializer serializer) : base(scopeAccessor, cache, logger, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferenceFactories, dataTypeService) { _memberTypeRepository = memberTypeRepository ?? throw new ArgumentNullException(nameof(memberTypeRepository)); _tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository)); _passwordHasher = passwordHasher; + _serializer = serializer; _memberGroupRepository = memberGroupRepository; _memberByUsernameCachePolicy = new DefaultRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, DefaultOptions); @@ -326,7 +330,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement foreach (var propertyDataDto in propertyDataDtos) Database.Insert(propertyDataDto); - SetEntityTags(entity, _tagRepository); + SetEntityTags(entity, _tagRepository, _serializer); PersistRelations(entity); @@ -408,7 +412,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } } - SetEntityTags(entity, _tagRepository); + SetEntityTags(entity, _tagRepository, _serializer); PersistRelations(entity); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ConfigurationEditorOfTConfiguration.cs b/src/Umbraco.Infrastructure/PropertyEditors/ConfigurationEditorOfTConfiguration.cs index 0efa42929a..7ccf39abcf 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ConfigurationEditorOfTConfiguration.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ConfigurationEditorOfTConfiguration.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core.Composing; using Umbraco.Core.IO; +using Umbraco.Core.Serialization; namespace Umbraco.Core.PropertyEditors { @@ -106,12 +107,12 @@ namespace Umbraco.Core.PropertyEditors => obj is TConfiguration; /// - public override object FromDatabase(string configuration) + public override object FromDatabase(string configuration, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) { try { if (string.IsNullOrWhiteSpace(configuration)) return new TConfiguration(); - return JsonConvert.DeserializeObject(configuration, ConfigurationJsonSettings); + return configurationEditorJsonSerializer.Deserialize(configuration); } catch (Exception e) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs index 952e3557dd..207a82844d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.PropertyEditors; +using Umbraco.Core; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; namespace Umbraco.Web.PropertyEditors diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs index 7c5b8e5133..e80c0fcb0e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.PropertyEditors; +using Umbraco.Core; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; namespace Umbraco.Web.PropertyEditors @@ -35,4 +36,4 @@ namespace Umbraco.Web.PropertyEditors }); } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs b/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs index d8a6a97d04..255be498bc 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Umbraco.Core.PropertyEditors; +using Umbraco.Core; namespace Umbraco.Web.PropertyEditors { @@ -10,4 +10,4 @@ namespace Umbraco.Web.PropertyEditors { "idType", "udi" } }; } -} \ No newline at end of file +} diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs index cd8b228a6f..b5a0972c3e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs @@ -8,11 +8,11 @@ using Umbraco.Core.Exceptions; using Umbraco.Core.IO; using Umbraco.Core.Media; using Umbraco.Core.Models; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Models; using Umbraco.Web.Routing; -using Umbraco.Web.Templates; namespace Umbraco.Web.PropertyEditors { @@ -26,10 +26,11 @@ namespace Umbraco.Web.PropertyEditors private readonly IMediaFileSystem _mediaFileSystem; private readonly IShortStringHelper _shortStringHelper; private readonly IPublishedUrlProvider _publishedUrlProvider; + private readonly IJsonSerializer _serializer; const string TemporaryImageDataAttribute = "data-tmpimg"; - public RichTextEditorPastedImages(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IIOHelper ioHelper, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IPublishedUrlProvider publishedUrlProvider) + public RichTextEditorPastedImages(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IIOHelper ioHelper, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IPublishedUrlProvider publishedUrlProvider, IJsonSerializer serializer) { _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); @@ -39,6 +40,7 @@ namespace Umbraco.Web.PropertyEditors _mediaFileSystem = mediaFileSystem; _shortStringHelper = shortStringHelper; _publishedUrlProvider = publishedUrlProvider; + _serializer = serializer; } /// @@ -92,7 +94,7 @@ namespace Umbraco.Web.PropertyEditors if (fileStream == null) throw new InvalidOperationException("Could not acquire file stream"); using (fileStream) { - mediaFile.SetValue(_mediaFileSystem, _shortStringHelper, _contentTypeBaseServiceProvider, Constants.Conventions.Media.File, safeFileName, fileStream); + mediaFile.SetValue(_mediaFileSystem, _shortStringHelper, _contentTypeBaseServiceProvider, _serializer, Constants.Conventions.Media.File, safeFileName, fileStream); } _mediaService.Save(mediaFile, userId); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs b/src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs index bf3cd197a3..88eb1d224e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs index cf0e872c1a..5405727791 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs @@ -6,7 +6,6 @@ using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Web.PublishedCache; - namespace Umbraco.Web.PropertyEditors.ValueConverters { /// diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs index 2ae6f74465..8bbc75fbac 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs @@ -91,6 +91,7 @@ namespace Umbraco.Core.Runtime composition.Services.AddUnique(f => f.GetRequiredService()); composition.Services.AddUnique(); + composition.Services.AddUnique(); composition.Services.AddUnique(); composition.Services.AddUnique(); diff --git a/src/Umbraco.Infrastructure/Serialization/ConfigurationEditorJsonSerializer.cs b/src/Umbraco.Infrastructure/Serialization/ConfigurationEditorJsonSerializer.cs new file mode 100644 index 0000000000..ec40848fb5 --- /dev/null +++ b/src/Umbraco.Infrastructure/Serialization/ConfigurationEditorJsonSerializer.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Core.Serialization +{ + public class ConfigurationEditorJsonSerializer : JsonNetSerializer, IConfigurationEditorJsonSerializer + { + public ConfigurationEditorJsonSerializer() + { + JsonSerializerSettings.Converters.Add(new FuzzyBooleanConverter()); + JsonSerializerSettings.ContractResolver = new ConfigurationCustomContractResolver(); + } + + 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; + } + } + } +} diff --git a/src/Umbraco.Infrastructure/Serialization/JsonNetSerializer.cs b/src/Umbraco.Infrastructure/Serialization/JsonNetSerializer.cs index 16d8668394..1974619a70 100644 --- a/src/Umbraco.Infrastructure/Serialization/JsonNetSerializer.cs +++ b/src/Umbraco.Infrastructure/Serialization/JsonNetSerializer.cs @@ -1,28 +1,44 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; namespace Umbraco.Core.Serialization { public class JsonNetSerializer : IJsonSerializer { - private static readonly JsonConverter[] _defaultConverters = new JsonConverter[] + protected static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings() { - new StringEnumConverter() + Converters = new List() + { + new StringEnumConverter() + } }; - public string Serialize(object input) { - return JsonConvert.SerializeObject(input, _defaultConverters); + return JsonConvert.SerializeObject(input, JsonSerializerSettings); } public T Deserialize(string input) { - return JsonConvert.DeserializeObject(input, _defaultConverters); + return JsonConvert.DeserializeObject(input, JsonSerializerSettings); + } + + public T DeserializeSubset(string input, string key) + { + if (key == null) throw new ArgumentNullException(nameof(key)); + + var root = JsonConvert.DeserializeObject(input); + + var jToken = root.SelectToken(key); + + return jToken switch + { + JArray jArray => jArray.ToObject(), + JObject jObject => jObject.ToObject(), + _ => jToken is null ? default : jToken.Value() + }; } } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs index 2d0a44986c..8d27d56c7c 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/EntityXmlSerializer.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json; using Umbraco.Core.Composing; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Strings; namespace Umbraco.Core.Services.Implement @@ -26,6 +27,7 @@ namespace Umbraco.Core.Services.Implement private readonly UrlSegmentProviderCollection _urlSegmentProviders; private readonly IShortStringHelper _shortStringHelper; private readonly PropertyEditorCollection _propertyEditors; + private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer; public EntityXmlSerializer( IContentService contentService, @@ -36,7 +38,8 @@ namespace Umbraco.Core.Services.Implement IContentTypeService contentTypeService, UrlSegmentProviderCollection urlSegmentProviders, IShortStringHelper shortStringHelper, - PropertyEditorCollection propertyEditors) + PropertyEditorCollection propertyEditors, + IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) { _contentTypeService = contentTypeService; _mediaService = mediaService; @@ -47,6 +50,7 @@ namespace Umbraco.Core.Services.Implement _urlSegmentProviders = urlSegmentProviders; _shortStringHelper = shortStringHelper; _propertyEditors = propertyEditors; + _configurationEditorJsonSerializer = configurationEditorJsonSerializer; } /// @@ -179,7 +183,7 @@ namespace Umbraco.Core.Services.Implement xml.Add(new XAttribute("Id", dataType.EditorAlias)); xml.Add(new XAttribute("Definition", dataType.Key)); xml.Add(new XAttribute("DatabaseType", dataType.DatabaseType.ToString())); - xml.Add(new XAttribute("Configuration", JsonConvert.SerializeObject(dataType.Configuration, PropertyEditors.ConfigurationEditor.ConfigurationJsonSettings))); + xml.Add(new XAttribute("Configuration", _configurationEditorJsonSerializer.Serialize(dataType.Configuration))); var folderNames = string.Empty; if (dataType.Level != 1) diff --git a/src/Umbraco.TestData/UmbracoTestDataController.cs b/src/Umbraco.TestData/UmbracoTestDataController.cs index 33c361df2d..f6b5e625a2 100644 --- a/src/Umbraco.TestData/UmbracoTestDataController.cs +++ b/src/Umbraco.TestData/UmbracoTestDataController.cs @@ -16,6 +16,7 @@ using Umbraco.Web.Mvc; using System.Configuration; using Bogus; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Strings; namespace Umbraco.TestData @@ -278,7 +279,9 @@ namespace Umbraco.TestData if (editor == null) throw new InvalidOperationException($"No {editorAlias} editor found"); - dt = new DataType(editor) + var serializer = new ConfigurationEditorJsonSerializer(); + + dt = new DataType(editor, serializer) { Name = name, Configuration = editor.GetConfigurationEditor().DefaultConfigurationObject, diff --git a/src/Umbraco.Tests.Common/Builders/ConfigurationEditorBuilder.cs b/src/Umbraco.Tests.Common/Builders/ConfigurationEditorBuilder.cs index f0761a983e..f80529ccab 100644 --- a/src/Umbraco.Tests.Common/Builders/ConfigurationEditorBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/ConfigurationEditorBuilder.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; +using Umbraco.Core; using Umbraco.Core.PropertyEditors; + namespace Umbraco.Tests.Common.Builders { public class ConfigurationEditorBuilder : ChildBuilderBase diff --git a/src/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs b/src/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs index 291981cb84..3ed7334367 100644 --- a/src/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs +++ b/src/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs @@ -1,5 +1,6 @@ using System; using Umbraco.Core.Models; +using Umbraco.Core.Serialization; using Umbraco.Tests.Common.Builders.Interfaces; namespace Umbraco.Tests.Common.Builders @@ -65,8 +66,9 @@ namespace Umbraco.Tests.Common.Builders var creatorId = _creatorId ?? 1; var databaseType = _databaseType ?? ValueStorageType.Ntext; var sortOrder = _sortOrder ?? 0; + var serializer = new ConfigurationEditorJsonSerializer(); - return new DataType(editor, parentId) + return new DataType(editor, serializer, parentId) { Id = id, Key = key, diff --git a/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs index 975f656b82..958b7e558b 100644 --- a/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests.Common/TestHelpers/SolidPublishedSnapshot.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.PublishedCache; @@ -411,9 +412,11 @@ namespace Umbraco.Tests.Common.PublishedContent static AutoPublishedContentType() { + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); + var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 666 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/ContentTypeModelMappingTests.cs index 03e8f04cfc..7aa9c76791 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Core/Mapping/ContentTypeModelMappingTests.cs @@ -6,6 +6,7 @@ using Umbraco.Core; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common.Builders; @@ -22,6 +23,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping private IDataTypeService _dataTypeService; private UmbracoMapper _sut; private IFileService _fileService; + private IConfigurationEditorJsonSerializer _serializer; [SetUp] public void SetupTest() @@ -29,6 +31,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping _sut = Services.GetRequiredService(); _dataTypeService = Services.GetRequiredService(); _fileService = Services.GetRequiredService(); + _serializer = Services.GetRequiredService(); } [Test] @@ -36,7 +39,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping { //Arrange //TODO use builder - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; @@ -94,7 +97,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping { //Arrange //TODO use builder - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; @@ -148,7 +151,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping { //Arrange //TODO use builder - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; @@ -225,7 +228,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping { //Arrange //TODO use builder - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; @@ -250,7 +253,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping //Arrange //TODO use builder - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; @@ -443,7 +446,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping public void MemberPropertyGroupBasic_To_MemberPropertyGroup() { //TODO use builder - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; @@ -517,7 +520,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping [Test] public void PropertyGroupBasic_To_PropertyGroup() { - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; @@ -622,7 +625,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping public void PropertyTypeBasic_To_PropertyType() { //TODO use builder - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; @@ -867,7 +870,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Core.Mapping public void PropertyTypeBasic_To_PropertyTypeDisplay() { //TODO use builder - var dataType = new DataType(Services.GetRequiredService()) + var dataType = new DataType(Services.GetRequiredService(), _serializer) { Name = "TODO" }; diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index 195ecc5aa2..ebfcd3e7de 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories; using Umbraco.Tests.Testing; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Web.PropertyEditors; @@ -21,15 +22,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor private IContentTypeRepository ContentTypeRepository => GetRequiredService(); private IDataTypeContainerRepository DataTypeContainerRepository => GetRequiredService(); private IDataTypeRepository DataTypeRepository => GetRequiredService(); + private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService(); [Test] public void Can_Find_Usages() { using (ScopeProvider.CreateScope()) { - IDataType dataType1 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) { Name = "dt1" }; + IDataType dataType1 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = "dt1" }; DataTypeRepository.Save(dataType1); - IDataType dataType2 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) { Name = "dt2" }; + IDataType dataType2 = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = "dt2" }; DataTypeRepository.Save(dataType2); IContentType ct = new ContentType(ShortStringHelper, -1) @@ -92,14 +94,14 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var container2 = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah2", ParentId = container1.Id }; DataTypeContainerRepository.Save(container2); - var dataType = (IDataType) new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container2.Id) + var dataType = (IDataType) new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer, container2.Id) { Name = "dt1" }; DataTypeRepository.Save(dataType); //create a - var dataType2 = (IDataType)new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), dataType.Id) + var dataType2 = (IDataType)new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer, dataType.Id) { Name = "dt2" }; @@ -158,7 +160,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" }; DataTypeContainerRepository.Save(container); - var dataTypeDefinition = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container.Id) { Name = "test" }; + var dataTypeDefinition = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer, container.Id) { Name = "test" }; DataTypeRepository.Save(dataTypeDefinition); Assert.AreEqual(container.Id, dataTypeDefinition.ParentId); @@ -173,7 +175,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" }; DataTypeContainerRepository.Save(container); - IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), container.Id) { Name = "test" }; + IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer, container.Id) { Name = "test" }; DataTypeRepository.Save(dataType); // Act @@ -193,7 +195,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { using (ScopeProvider.CreateScope()) { - IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper)) {Name = "test"}; + IDataType dataType = new DataType(new RadioButtonsPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper), ConfigurationEditorJsonSerializer) {Name = "test"}; DataTypeRepository.Save(dataType); @@ -293,7 +295,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { using (ScopeProvider.CreateScope()) { - var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper)) + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", @@ -328,7 +330,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { using (ScopeProvider.CreateScope()) { - var dataTypeDefinition = new DataType(new IntegerPropertyEditor(LoggerFactory, DataTypeService, LocalizationService, ShortStringHelper, LocalizedTextService)) + var dataTypeDefinition = new DataType(new IntegerPropertyEditor(LoggerFactory, DataTypeService, LocalizationService, ShortStringHelper, LocalizedTextService), ConfigurationEditorJsonSerializer) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", @@ -356,7 +358,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { using (ScopeProvider.CreateScope()) { - var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService,LocalizedTextService, LocalizationService, ShortStringHelper)) + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService,LocalizedTextService, LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) { DatabaseType = ValueStorageType.Integer, Name = "AgeDataType", diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs index 6d4303f7a1..b0ba97eedf 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; @@ -35,6 +36,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor private IFileService FileService => GetRequiredService(); private IDataTypeService DataTypeService => GetRequiredService(); private IFileSystems FileSystems => GetRequiredService(); + private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService(); [SetUp] public void SetUpData() @@ -90,7 +92,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor TemplateRepository tr; var ctRepository = CreateRepository(scopeAccessor, out contentTypeRepository, out tr); var editors = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, new Lazy(() => editors), LoggerFactory.CreateLogger(), LoggerFactory); + dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, new Lazy(() => editors), LoggerFactory.CreateLogger(), LoggerFactory, ConfigurationEditorJsonSerializer); return ctRepository; } @@ -117,7 +119,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); var repository = new DocumentRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, - relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService); + relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService, ConfigurationEditorJsonSerializer); return repository; } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs index dfc25c7e50..7d3dcc7202 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; @@ -29,6 +30,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor private IMediaTypeService MediaTypeService => GetRequiredService(); private ITemplateRepository TemplateRepository => GetRequiredService(); private IDataTypeService DataTypeService => GetRequiredService(); + private IJsonSerializer JsonSerializer => GetRequiredService(); // Makes handing IDs easier, these are set by CreateTestData private Media _testFolder; @@ -56,7 +58,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var mediaUrlGenerators = new MediaUrlGeneratorCollection(Enumerable.Empty()); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new MediaRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), LoggerFactory, mediaTypeRepository, tagRepository, Mock.Of(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService); + var repository = new MediaRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), LoggerFactory, mediaTypeRepository, tagRepository, Mock.Of(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService, JsonSerializer); return repository; } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberRepositoryTest.cs index fa7ae66047..7b26ccd500 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberRepositoryTest.cs @@ -16,6 +16,7 @@ using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; @@ -31,6 +32,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor private IDataTypeService DataTypeService => GetRequiredService(); private IMemberTypeRepository MemberTypeRepository => GetRequiredService(); private IMemberGroupRepository MemberGroupRepository => GetRequiredService(); + private IJsonSerializer JsonSerializer => GetRequiredService(); private MemberRepository CreateRepository(IScopeProvider provider) { @@ -40,7 +42,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var relationRepository = GetRequiredService(); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var repository = new MemberRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), MemberTypeRepository, MemberGroupRepository, tagRepo, Mock.Of(), relationRepository, relationTypeRepository, PasswordHasher, propertyEditors, dataValueReferences, DataTypeService); + var repository = new MemberRepository(accessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), MemberTypeRepository, MemberGroupRepository, tagRepo, Mock.Of(), relationRepository, relationTypeRepository, PasswordHasher, propertyEditors, dataValueReferences, DataTypeService, JsonSerializer); return repository; } diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs index 3452ab22ae..c41b7eaf6b 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs @@ -15,6 +15,7 @@ using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Implementations; @@ -253,6 +254,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor { var templateRepository = CreateRepository(provider); var globalSettings = new GlobalSettings(); + var serializer = new JsonNetSerializer(); var tagRepository = new TagRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches, ShortStringHelper); var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), Microsoft.Extensions.Options.Options.Create(globalSettings)); @@ -262,7 +264,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositor var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); var propertyEditors = new Lazy(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty()))); var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty()); - var contentRepo = new DocumentRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, dataTypeService); + var contentRepo = new DocumentRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), LoggerFactory, contentTypeRepository, templateRepository, tagRepository, languageRepository, relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, dataTypeService, serializer); var template = TemplateBuilder.CreateTextPageTemplate(); fileService.SaveTemplate(template); // else, FK violation on contentType! diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs index 89a3cdafb1..4dbc7b3efc 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/CachedDataTypeServiceTests.cs @@ -2,6 +2,7 @@ using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Integration.Testing; using Umbraco.Tests.Testing; @@ -19,6 +20,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services private IDataTypeService DataTypeService => GetRequiredService(); private ILocalizedTextService LocalizedTextService => GetRequiredService(); private ILocalizationService LocalizationService => GetRequiredService(); + private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService(); /// /// This tests validates that with the new scope changes that the underlying cache policies work - in this case it tests that the cache policy @@ -27,7 +29,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services [Test] public void DataTypeService_Can_Get_All() { - IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper)) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; + IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; DataTypeService.Save(dataType); //Get all the first time (no cache) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs index 829fcfa65f..193f343305 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTagsTests.cs @@ -5,6 +5,7 @@ using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Common.Builders.Extensions; @@ -26,6 +27,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services private IDataTypeService DataTypeService => GetRequiredService(); private ILocalizationService LocalizationService => GetRequiredService(); private IFileService FileService => GetRequiredService(); + private IJsonSerializer Serializer => GetRequiredService(); public PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); [SetUp] @@ -51,12 +53,12 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services ContentTypeService.Save(contentType); IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "another", "one" }); ContentService.SaveAndPublish(content1); content1 = ContentService.GetById(content1.Id); - var enTags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService).ToArray(); + var enTags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer).ToArray(); Assert.AreEqual(4, enTags.Length); Assert.Contains("one", enTags); Assert.AreEqual(-1, enTags.IndexOf("plus")); @@ -84,30 +86,30 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); ContentTypeService.Save(contentType); IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); ContentService.SaveAndPublish(content1); content1 = ContentService.GetById(content1.Id); - var frTags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "fr-FR").ToArray(); + var frTags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer, "fr-FR").ToArray(); Assert.AreEqual(5, frTags.Length); Assert.Contains("plus", frTags); Assert.AreEqual(-1, frTags.IndexOf("one")); - var enTags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "en-US").ToArray(); + var enTags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer, "en-US").ToArray(); Assert.AreEqual(4, enTags.Length); Assert.Contains("one", enTags); Assert.AreEqual(-1, enTags.IndexOf("plus")); - var tagGroups = TagService.GetAllTags(culture:"*").GroupBy(x => x.LanguageId); + var tagGroups = TagService.GetAllTags(culture: "*").GroupBy(x => x.LanguageId); foreach (var tag in TagService.GetAllTags()) Console.WriteLine($"{tag.Group}:{tag.Text} {tag.LanguageId}"); Assert.AreEqual(2, tagGroups.Count()); @@ -136,7 +138,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services ContentTypeService.Save(contentType); IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "another", "one" }); ContentService.SaveAndPublish(content1); contentType.Variations = ContentVariation.Culture; @@ -145,7 +147,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services // no changes content1 = ContentService.GetById(content1.Id); - var tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService).ToArray(); + var tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer).ToArray(); Assert.AreEqual(4, tags.Length); Assert.Contains("one", tags); Assert.AreEqual(-1, tags.IndexOf("plus")); @@ -167,10 +169,10 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services content1 = ContentService.GetById(content1.Id); // property value has been moved from invariant to en-US - tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService).ToArray(); + tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer).ToArray(); Assert.IsEmpty(tags); - tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "en-US").ToArray(); + tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer, "en-US").ToArray(); Assert.AreEqual(4, tags.Length); Assert.Contains("one", tags); Assert.AreEqual(-1, tags.IndexOf("plus")); @@ -208,8 +210,8 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); ContentService.SaveAndPublish(content1); contentType.Variations = ContentVariation.Nothing; @@ -219,10 +221,10 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services content1 = ContentService.GetById(content1.Id); // property value has been moved from en-US to invariant, fr-FR tags are gone - Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "fr-FR")); - Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "en-US")); + Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer, "fr-FR")); + Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer, "en-US")); - var tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService).ToArray(); + var tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer).ToArray(); Assert.AreEqual(4, tags.Length); Assert.Contains("one", tags); Assert.AreEqual(-1, tags.IndexOf("plus")); @@ -253,22 +255,22 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); var propertyType = CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); ContentTypeService.Save(contentType); IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); ContentService.SaveAndPublish(content1); IContent content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", -1); content2.SetCultureName("name-fr", "fr-FR"); content2.SetCultureName("name-en", "en-US"); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + content2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); ContentService.SaveAndPublish(content2); //// pretend we already have invariant values @@ -295,15 +297,15 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); var propertyType = CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); ContentTypeService.Save(contentType); IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); ContentService.SaveAndPublish(content1); propertyType.Variations = ContentVariation.Nothing; @@ -313,10 +315,10 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services content1 = ContentService.GetById(content1.Id); // property value has been moved from en-US to invariant, fr-FR tags are gone - Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "fr-FR")); - Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, "en-US")); + Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer, "fr-FR")); + Assert.IsEmpty(content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer, "en-US")); - var tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService).ToArray(); + var tags = content1.Properties["tags"].GetTagsValue(PropertyEditorCollection, DataTypeService, Serializer).ToArray(); Assert.AreEqual(4, tags.Length); Assert.Contains("one", tags); Assert.AreEqual(-1, tags.IndexOf("plus")); @@ -345,15 +347,15 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); var propertyType = CreateAndAddTagsPropertyType(contentType, ContentVariation.Culture); ContentTypeService.Save(contentType); IContent content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); content1.SetCultureName("name-fr", "fr-FR"); content1.SetCultureName("name-en", "en-US"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "plus" }, culture: "fr-FR"); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "another", "one" }, culture: "en-US"); ContentService.SaveAndPublish(content1); propertyType.Variations = ContentVariation.Nothing; @@ -372,16 +374,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "plus" }); ContentService.SaveAndPublish(content1); var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content2); // verify @@ -399,16 +401,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "bam" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "bam" }); ContentService.SaveAndPublish(content1); var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content2); // verify @@ -428,16 +430,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "plus" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "plus" }); ContentService.SaveAndPublish(content1); var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", content1.Id); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content2); // verify @@ -500,16 +502,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "bam" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "bam" }); ContentService.SaveAndPublish(content1); var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content2); ContentService.Unpublish(content1); @@ -523,16 +525,16 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); var content1 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags", "bam" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags", "bam" }); ContentService.SaveAndPublish(content1); var content2 = ContentBuilder.CreateSimpleContent(contentType, "Tagged content 2", content1); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content2); ContentService.Unpublish(content1); @@ -572,21 +574,21 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services var template = TemplateBuilder.CreateTextPageTemplate(); FileService.SaveTemplate(template); - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy(() => contentType.Id), 0, contentType.Alias) }; var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); - content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.Save(content); var child1 = ContentBuilder.CreateSimpleContent(contentType, "child 1 content", content.Id); - child1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello1", "world1", "some1" }); + child1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello1", "world1", "some1" }); ContentService.Save(child1); var child2 = ContentBuilder.CreateSimpleContent(contentType, "child 2 content", content.Id); - child2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello2", "world2" }); + child2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello2", "world2" }); ContentService.Save(child2); // Act @@ -620,17 +622,17 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services FileService.SaveTemplate(template); // create content type with a tag property - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); // create a content with tags and publish var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); - content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content); // edit tags and save - content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "another", "world" }, merge: true); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "another", "world" }, merge: true); ContentService.Save(content); // the (edit) property does contain all tags @@ -654,7 +656,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services FileService.SaveTemplate(template); //Arrange - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); @@ -662,7 +664,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services // Act - content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content); // Assert @@ -685,15 +687,15 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services FileService.SaveTemplate(template); //Arrange - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); - content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content); // Act - content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "another", "world" }, merge: true); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "another", "world" }, merge: true); ContentService.SaveAndPublish(content); // Assert @@ -716,15 +718,15 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services FileService.SaveTemplate(template); //Arrange - var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); + var contentType = ContentTypeBuilder.CreateSimpleContentType("umbMandatory", "Mandatory Doc Type", mandatoryProperties: true, defaultTemplateId: template.Id); CreateAndAddTagsPropertyType(contentType); ContentTypeService.Save(contentType); var content = ContentBuilder.CreateSimpleContent(contentType, "Tagged content", -1); - content.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "hello", "world", "some", "tags" }); ContentService.SaveAndPublish(content); // Act - content.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "some", "world" }); + content.RemoveTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "some", "world" }); ContentService.SaveAndPublish(content); // Assert diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs index 5fab0e0d06..66aec0d177 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceTests.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Tests.Common.Builders; @@ -47,6 +48,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services private INotificationService NotificationService => GetRequiredService(); private PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); private IDocumentRepository DocumentRepository => GetRequiredService(); + private IJsonSerializer Serializer => GetRequiredService(); [SetUp] public void Setup() @@ -1954,7 +1956,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services ContentTypeService.Save(contentType); var content = ContentBuilder.CreateSimpleContent(contentType, "Simple Tags Page", Constants.System.Root); - content.AssignTags(PropertyEditorCollection, DataTypeService, propAlias, new[] {"hello", "world"}); + content.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, propAlias, new[] {"hello", "world"}); ContentService.Save(content); // value has been set but no tags have been created (not published) diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs index 33762f9b3c..0af3ae6fb5 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/DataTypeServiceTests.cs @@ -4,6 +4,7 @@ using System.Threading; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; @@ -24,12 +25,13 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services private IFileService FileService => GetRequiredService(); private ILocalizedTextService LocalizedTextService => GetRequiredService(); private ILocalizationService LocalizationService => GetRequiredService(); + private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService(); [Test] public void DataTypeService_Can_Persist_New_DataTypeDefinition() { // Act - IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper)) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; + IDataType dataType = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService, LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext }; DataTypeService.Save(dataType); // Assert @@ -72,7 +74,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public void Cannot_Save_DataType_With_Empty_Name() { // Act - var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService,LocalizationService, ShortStringHelper)) { Name = string.Empty, DatabaseType = ValueStorageType.Ntext }; + var dataTypeDefinition = new DataType(new LabelPropertyEditor(LoggerFactory, IOHelper, DataTypeService, LocalizedTextService,LocalizationService, ShortStringHelper), ConfigurationEditorJsonSerializer) { Name = string.Empty, DatabaseType = ValueStorageType.Ntext }; // Act & Assert Assert.Throws(() => DataTypeService.Save(dataTypeDefinition)); diff --git a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TagServiceTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TagServiceTests.cs index a0632668aa..c48f56e9a7 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TagServiceTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/TagServiceTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; using Umbraco.Tests.Integration.Testing; @@ -27,6 +28,7 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services private IFileService FileService => GetRequiredService(); private ITagService TagService => GetRequiredService(); private IDataTypeService DataTypeService => GetRequiredService(); + private IJsonSerializer Serializer => GetRequiredService(); private PropertyEditorCollection PropertyEditorCollection => GetRequiredService(); private IContentType _contentType; @@ -49,18 +51,18 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public void TagApiConsistencyTest() { IContent content1 = ContentBuilder.CreateSimpleContent(_contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig", "goat" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "cow", "pig", "goat" }); ContentService.SaveAndPublish(content1); // change - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "elephant" }, true); - content1.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "elephant" }, true); + content1.RemoveTags(PropertyEditorCollection, DataTypeService, Serializer,"tags", new[] { "cow" }); ContentService.SaveAndPublish(content1); // more changes - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "mouse" }, true); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "mouse" }, true); ContentService.SaveAndPublish(content1); - content1.RemoveTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "mouse" }); + content1.RemoveTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "mouse" }); ContentService.SaveAndPublish(content1); // get it back @@ -86,15 +88,15 @@ namespace Umbraco.Tests.Integration.Umbraco.Infrastructure.Services public void TagList_Contains_NodeCount() { var content1 = ContentBuilder.CreateSimpleContent(_contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig", "goat" }); + content1.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "cow", "pig", "goat" }); ContentService.SaveAndPublish(content1); var content2 = ContentBuilder.CreateSimpleContent(_contentType, "Tagged content 2", -1); - content2.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow", "pig" }); + content2.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "cow", "pig" }); ContentService.SaveAndPublish(content2); var content3 = ContentBuilder.CreateSimpleContent(_contentType, "Tagged content 3", -1); - content3.AssignTags(PropertyEditorCollection, DataTypeService, "tags", new[] { "cow" }); + content3.AssignTags(PropertyEditorCollection, DataTypeService, Serializer, "tags", new[] { "cow" }); ContentService.SaveAndPublish(content3); // Act diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs index 629f9470ac..a6da06436c 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.BackOffice/Filters/ContentModelValidatorTests.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common.Builders; @@ -50,14 +51,15 @@ namespace Umbraco.Tests.Integration.Umbraco.Web.Backoffice.Filters var complexTestEditor = Services.GetRequiredService(); var testEditor = Services.GetRequiredService(); var dataTypeService = Services.GetRequiredService(); + var serializer = Services.GetRequiredService(); - var complexDataType = new DataType(complexTestEditor) + var complexDataType = new DataType(complexTestEditor, serializer) { Name = "ComplexTest", Configuration = complexEditorConfig }; - var testDataType = new DataType(testEditor) + var testDataType = new DataType(testEditor, serializer) { Name = "Test", }; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentExtensionsTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentExtensionsTests.cs index 333ec11720..eb46a2b919 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentExtensionsTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/ContentExtensionsTests.cs @@ -2,6 +2,7 @@ using System.Linq; using Moq; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Tests.Common.Builders; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs index ec1d60ba1b..81c868656e 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/VariationTests.cs @@ -6,6 +6,7 @@ using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common.Builders; @@ -594,9 +595,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Models localizedTextService ); + var serializer = new ConfigurationEditorJsonSerializer(); + var mockDataTypeService = new Mock(); Mock.Get(dataTypeService).Setup(x => x.GetDataType(It.Is(y => y == Constants.DataTypes.Textbox))) - .Returns(new DataType(textBoxEditor)); + .Returns(new DataType(textBoxEditor, serializer)); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(new[] { textBoxEditor })); return new PropertyValidationService( diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs index 85c7af9313..0fa864ae06 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs @@ -15,6 +15,7 @@ using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using Umbraco.Web.PropertyEditors; using static Umbraco.Core.Models.Property; +using Umbraco.Core.Serialization; namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors { @@ -47,7 +48,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var trackedUdi2 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi3 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi4 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); - var property = new Property(new PropertyType(ShortStringHelper, new DataType(labelEditor)) + var serializer = new ConfigurationEditorJsonSerializer(); + var property = new Property(new PropertyType(ShortStringHelper, new DataType(labelEditor, serializer)) { Variations = ContentVariation.CultureAndSegment }) @@ -115,7 +117,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var trackedUdi2 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi3 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi4 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); - var property = new Property(new PropertyType(ShortStringHelper, new DataType(mediaPicker)) + var serializer = new ConfigurationEditorJsonSerializer(); + var property = new Property(new PropertyType(ShortStringHelper, new DataType(mediaPicker, serializer)) { Variations = ContentVariation.CultureAndSegment }) @@ -183,7 +186,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors var trackedUdi2 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi3 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); var trackedUdi4 = Udi.Create(Constants.UdiEntityType.Media, Guid.NewGuid()).ToString(); - var property = new Property(new PropertyType(ShortStringHelper, new DataType(mediaPicker)) + var serializer = new ConfigurationEditorJsonSerializer(); + var property = new Property(new PropertyType(ShortStringHelper, new DataType(mediaPicker, serializer)) { Variations = ContentVariation.Nothing | ContentVariation.Segment }) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs index 675951cad1..5b3e3f1ff6 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/MultiValuePropertyEditorTests.cs @@ -8,6 +8,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.PropertyEditors; @@ -28,7 +29,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void DropDownMultipleValueEditor_Format_Data_For_Cache() { - var dataType = new DataType(new CheckBoxListPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) + var serializer = new ConfigurationEditorJsonSerializer(); + var dataType = new DataType(new CheckBoxListPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Configuration = new ValueListConfiguration { @@ -60,7 +62,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.PropertyEditors [Test] public void DropDownValueEditor_Format_Data_For_Cache() { - var dataType = new DataType(new CheckBoxListPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) + var serializer = new ConfigurationEditorJsonSerializer(); + var dataType = new DataType(new CheckBoxListPropertyEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Configuration = new ValueListConfiguration { diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs index 2c444ee67d..a46662c3a1 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/ConvertersTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common.PublishedContent; @@ -29,9 +30,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published new SimpleConverter1(), }); + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); @@ -112,9 +114,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published new SimpleConverter2(publishedSnapshotAccessor), }); + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); var dataType = new DataType(new VoidEditor(Mock.Of(), dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs index 1b7ebec5ec..613b251249 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common.PublishedContent; @@ -36,7 +37,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published var editor = new NestedContentPropertyEditor(loggerFactory, new Lazy(() => editors), Mock.Of(),localizationService, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); editors = new PropertyEditorCollection(new DataEditorCollection(new DataEditor[] { editor })); - var dataType1 = new DataType(editor) + var serializer = new ConfigurationEditorJsonSerializer(); + + var dataType1 = new DataType(editor, serializer) { Id = 1, Configuration = new NestedContentConfiguration @@ -50,7 +53,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published } }; - var dataType2 = new DataType(editor) + var dataType2 = new DataType(editor, serializer) { Id = 2, Configuration = new NestedContentConfiguration @@ -64,7 +67,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published } }; - var dataType3 = new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, Mock.Of(), Mock.Of(), Mock.Of())) + var dataType3 = new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 3 }; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs index f30029c94c..b412ab1153 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PropertyCacheLevelTests.cs @@ -9,6 +9,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.PublishedCache; @@ -31,9 +32,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published converter, }); + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); @@ -116,9 +118,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published converter, }); + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); @@ -196,9 +199,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Published converter, }); + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ExpressionTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ExpressionTests.cs index 38a2addad6..436c202398 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ExpressionTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Persistence/Querying/ExpressionTests.cs @@ -13,6 +13,7 @@ using System.Linq; using Microsoft.Extensions.Logging.Abstractions; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; @@ -24,7 +25,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Persistence.Querying [Test] public void Equals_Claus_With_Two_Entity_Values() { - var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) + var serializer = new ConfigurationEditorJsonSerializer(); + var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of()), serializer) { Id = 12345 }; diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/JsonNetSerializerTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/JsonNetSerializerTests.cs new file mode 100644 index 0000000000..40a932181c --- /dev/null +++ b/src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Serialization/JsonNetSerializerTests.cs @@ -0,0 +1,82 @@ +using Newtonsoft.Json; +using NUnit.Framework; +using Umbraco.Core.Serialization; + +namespace Umbraco.Tests.UnitTests.Umbraco.Infrastructure.Serialization +{ + [TestFixture] + public class JsonNetSerializerTests + { + private IJsonSerializer Sut => new JsonNetSerializer(); + + [Test] + public void DeserializeSubset__Subset_as_integer() + { + var expected = 3; + var key = "int"; + var full = $"{{\"{key}\": {expected}}}"; + + var actual = Sut.DeserializeSubset(full, key); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void DeserializeSubset__Subset_as_string() + { + var expected = "test"; + var key = "text"; + var full = $"{{\"{key}\": \"{expected}\"}}"; + + var actual = Sut.DeserializeSubset(full, key); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void DeserializeSubset__Subset_nested_value_as_string() + { + var expected = "test"; + var key = "text"; + var key2 = "text2"; + var full = $"{{\"{key}\": {{\"{key2}\": \"{expected}\"}}}}"; + + var actual = Sut.DeserializeSubset(full, key + "." + key2); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void DeserializeSubset__Subset_value_as_object() + { + + var expected = new MyStruct() + { + Key = "Test" + }; + var key = nameof(MyStruct.Key); + var full = $"{{\"{key}\": {JsonConvert.SerializeObject(expected)}"; + + var actual = Sut.DeserializeSubset(full, key); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void DeserializeSubset__Subset_value_as_array() + { + var expected = new []{"test"}; + var key = "text"; + var full = $"{{\"{key}\": {JsonConvert.SerializeObject(expected)}"; + + var actual = Sut.DeserializeSubset(full, key); + + Assert.AreEqual(expected, actual); + } + + private struct MyStruct + { + public string Key { get; set; } + } + } +} diff --git a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs index e6816ba779..d09faf6757 100644 --- a/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs +++ b/src/Umbraco.Tests/Packaging/PackageInstallationTest.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Models.Packaging; using Umbraco.Core.Packaging; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; @@ -60,7 +61,8 @@ namespace Umbraco.Tests.Packaging Factory.GetRequiredService(), Factory.GetRequiredService(), Microsoft.Extensions.Options.Options.Create(new GlobalSettings()), - Factory.GetRequiredService()); + Factory.GetRequiredService(), + Factory.GetRequiredService()); private IPackageInstallation PackageInstallation => new PackageInstallation( PackageDataInstallation, diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs b/src/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs index 1e2f7231c2..a30a703ee1 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/PetaPocoCachesTest.cs @@ -6,6 +6,7 @@ using System.Threading; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Persistence; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; using Umbraco.Tests.Services; @@ -145,6 +146,7 @@ namespace Umbraco.Tests.Persistence.NPocoTests private void CreateStuff(out int id1, out int id2, out int id3, out string alias) { var contentService = ServiceContext.ContentService; + var serializer = new JsonNetSerializer(); var ctAlias = "umbTextpage" + Guid.NewGuid().ToString("N"); alias = ctAlias; @@ -180,13 +182,13 @@ namespace Umbraco.Tests.Persistence.NPocoTests }); contentTypeService.Save(contentType); var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1); - content1.AssignTags(PropertyEditorCollection.Value, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content1.AssignTags(PropertyEditorCollection.Value, DataTypeService, serializer, "tags", new[] { "hello", "world", "some", "tags" }); content1.PublishCulture(CultureImpact.Invariant); contentService.SaveAndPublish(content1); id2 = content1.Id; var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1); - content2.AssignTags(PropertyEditorCollection.Value, DataTypeService, "tags", new[] { "hello", "world", "some", "tags" }); + content2.AssignTags(PropertyEditorCollection.Value, DataTypeService, serializer, "tags", new[] { "hello", "world", "some", "tags" }); content2.PublishCulture(CultureImpact.Invariant); contentService.SaveAndPublish(content2); id3 = content2.Id; diff --git a/src/Umbraco.Tests/Published/ConvertersTests.cs b/src/Umbraco.Tests/Published/ConvertersTests.cs index 428011f243..76e2c52978 100644 --- a/src/Umbraco.Tests/Published/ConvertersTests.cs +++ b/src/Umbraco.Tests/Published/ConvertersTests.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.PublishedContent; @@ -54,7 +55,7 @@ namespace Umbraco.Tests.Published }, Mock.Of()); register.AddTransient(f => factory); - + var cacheMock = new Mock(); var cacheContent = new Dictionary(); @@ -68,12 +69,13 @@ namespace Umbraco.Tests.Published var registerFactory = composition.CreateServiceProvider(); var converters = registerFactory.GetRequiredService(); + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); var dataType1 = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }; var dataType2 = new DataType(new VoidEditor("2", NullLoggerFactory.Instance, Mock.Of(), - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 2 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new []{dataType1, dataType2 }); diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs index 55c56348a4..78cae13b13 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheChildrenTests.cs @@ -31,6 +31,7 @@ using Umbraco.Web.PublishedCache; using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.PublishedCache.NuCache.DataSource; using Current = Umbraco.Web.Composing.Current; +using Umbraco.Core.Serialization; namespace Umbraco.Tests.PublishedContent { @@ -65,8 +66,10 @@ namespace Umbraco.Tests.PublishedContent var runtime = Mock.Of(); Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); + var serializer = new ConfigurationEditorJsonSerializer(); + // create data types, property types and content types - var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 3 }; + var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 3 }; var dataTypes = new[] { diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index 56f5804f12..af2f738cf7 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Services.Changes; using Umbraco.Core.Strings; @@ -115,8 +116,10 @@ namespace Umbraco.Tests.PublishedContent var runtime = Mock.Of(); Mock.Get(runtime).Setup(x => x.Level).Returns(RuntimeLevel.Run); + var serializer = new ConfigurationEditorJsonSerializer(); + // create data types, property types and content types - var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 3 }; + var dataType = new DataType(new VoidEditor("Editor", NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 3 }; var dataTypes = new[] { diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index 9010ed1a6a..37cc8911b1 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; @@ -127,8 +128,9 @@ namespace Umbraco.Tests.PublishedContent private IPublishedContent GetContent(bool createChildren, int indexVals) { + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 1 }); + new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var contentTypeAlias = createChildren ? "Parent" : "Child"; diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs index 62fabf4a71..a402a705b1 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentSnapshotTestBase.cs @@ -19,6 +19,7 @@ using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; @@ -89,8 +90,9 @@ namespace Umbraco.Tests.PublishedContent private SolidPublishedSnapshot CreatePublishedSnapshot() { + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of())) { Id = 1 }); + new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var caches = new SolidPublishedSnapshot(); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index c4bcd86e36..0e7bdbc068 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -18,6 +18,7 @@ using Umbraco.Web.Routing; using Umbraco.Core.Media; using System; using Microsoft.Extensions.DependencyInjection; +using Umbraco.Core.Serialization; namespace Umbraco.Tests.PublishedContent { @@ -48,9 +49,10 @@ namespace Umbraco.Tests.PublishedContent var umbracoContextAccessor = Mock.Of(); var publishedUrlProvider = Mock.Of(); var loggerFactory = NullLoggerFactory.Instance; + var serializer = new ConfigurationEditorJsonSerializer(); var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); - var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), IOHelper, Mock.Of(), Mock.Of(), Mock.Of(), ShortStringHelper, publishedUrlProvider); + var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), IOHelper, Mock.Of(), Mock.Of(), Mock.Of(), ShortStringHelper, publishedUrlProvider, serializer); var localLinkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); var dataTypeService = new TestObjects.TestDataTypeService( new DataType(new RichTextPropertyEditor( @@ -64,7 +66,8 @@ namespace Umbraco.Tests.PublishedContent ShortStringHelper, IOHelper, LocalizedTextService, - Mock.Of())) { Id = 1 }); + Mock.Of()), + serializer) { Id = 1 }); var publishedContentTypeFactory = new PublishedContentTypeFactory(Mock.Of(), converters, dataTypeService); diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 50889bacd9..e75abf500d 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -25,10 +25,10 @@ using Umbraco.Tests.Testing; using Umbraco.Web.Models.PublishedContent; using Umbraco.Web.PropertyEditors; using Umbraco.Web.Templates; -using Umbraco.Web.Models; using Umbraco.Web.Routing; using Current = Umbraco.Web.Composing.Current; using Umbraco.Core.Media; +using Umbraco.Core.Serialization; namespace Umbraco.Tests.PublishedContent { @@ -56,17 +56,18 @@ namespace Umbraco.Tests.PublishedContent var umbracoContextAccessor = Mock.Of(); var publishedUrlProvider = Mock.Of(); var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider); - var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), IOHelper, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper, publishedUrlProvider); + var serializer = new ConfigurationEditorJsonSerializer(); + var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, loggerFactory.CreateLogger(), IOHelper, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper, publishedUrlProvider, serializer); var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider); var localizationService = Mock.Of(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(loggerFactory, Mock.Of(), localizationService, LocalizedTextService, ShortStringHelper)) { Id = 1 }, - new DataType(new TrueFalsePropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1001 }, - new DataType(new RichTextPropertyEditor(loggerFactory,umbracoContextAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of())) { Id = 1002 }, - new DataType(new IntegerPropertyEditor(loggerFactory, Mock.Of(), localizationService, ShortStringHelper, LocalizedTextService)) { Id = 1003 }, - new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1004 }, - new DataType(new MediaPickerPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService)) { Id = 1005 }); + new DataType(new VoidEditor(loggerFactory, Mock.Of(), localizationService, LocalizedTextService, ShortStringHelper), serializer) { Id = 1 }, + new DataType(new TrueFalsePropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1001 }, + new DataType(new RichTextPropertyEditor(loggerFactory,umbracoContextAccessor, Mock.Of(), localizationService, imageSourceParser, linkParser, pastedImages, ShortStringHelper, IOHelper, LocalizedTextService, Mock.Of()), serializer) { Id = 1002 }, + new DataType(new IntegerPropertyEditor(loggerFactory, Mock.Of(), localizationService, ShortStringHelper, LocalizedTextService), serializer) { Id = 1003 }, + new DataType(new TextboxPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1004 }, + new DataType(new MediaPickerPropertyEditor(loggerFactory, Mock.Of(), localizationService, IOHelper, ShortStringHelper, LocalizedTextService), serializer) { Id = 1005 }); Composition.Services.AddUnique(f => dataTypeService); } diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index 8a47d9b25a..6bdca6f0f6 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -9,6 +9,7 @@ using Umbraco.Web.Composing; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.PublishedCache; @@ -411,9 +412,10 @@ namespace Umbraco.Tests.PublishedContent static AutoPublishedContentType() { + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeServiceMock = new Mock(); var dataType = new DataType(new VoidEditor(NullLoggerFactory.Instance, dataTypeServiceMock.Object, - Mock.Of(), Mock.Of(), Mock.Of())) + Mock.Of(), Mock.Of(), Mock.Of()), serializer) { Id = 666 }; dataTypeServiceMock.Setup(x => x.GetAll()).Returns(dataType.Yield); diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index e9455a22d5..eaa186bef6 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -14,6 +14,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Tests.Common; @@ -47,8 +48,9 @@ namespace Umbraco.Tests.TestHelpers // need to specify a custom callback for unit tests // AutoPublishedContentTypes generates properties automatically + var serializer = new ConfigurationEditorJsonSerializer(); var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of())) { Id = 1 }); + new DataType(new VoidEditor(NullLoggerFactory.Instance, Mock.Of(), Mock.Of(),Mock.Of(), Mock.Of()), serializer) { Id = 1 }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); var type = new AutoPublishedContentType(Guid.NewGuid(), 0, "anything", new PublishedPropertyType[] { }); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index e009afacac..6fa4f921ab 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -463,6 +463,7 @@ namespace Umbraco.Tests.Testing Composition.Services.AddUnique(); Composition.Services.AddUnique(); + Composition.Services.AddUnique(); Composition.Services.AddUnique(); Composition.Services.AddUnique(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs index 709be76acc..19314d768b 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -21,6 +21,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Actions; @@ -98,8 +99,9 @@ namespace Umbraco.Web.BackOffice.Controllers INotificationService notificationService, ActionCollection actionCollection, IMemberGroupService memberGroupService, - ISqlContext sqlContext) - : base(cultureDictionary, loggerFactory, shortStringHelper, eventMessages, localizedTextService) + ISqlContext sqlContext, + IJsonSerializer serializer) + : base(cultureDictionary, loggerFactory, shortStringHelper, eventMessages, localizedTextService, serializer) { _propertyEditors = propertyEditors; _contentService = contentService; diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs index a3c1cfb89a..aef6abdd5e 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Extensions; @@ -34,13 +35,15 @@ namespace Umbraco.Web.BackOffice.Controllers protected IEventMessagesFactory EventMessages { get; } protected ILocalizedTextService LocalizedTextService { get; } private readonly ILogger _logger; + private readonly IJsonSerializer _serializer; protected ContentControllerBase( ICultureDictionary cultureDictionary, ILoggerFactory loggerFactory, IShortStringHelper shortStringHelper, IEventMessagesFactory eventMessages, - ILocalizedTextService localizedTextService) + ILocalizedTextService localizedTextService, + IJsonSerializer serializer) { CultureDictionary = cultureDictionary; LoggerFactory = loggerFactory; @@ -48,6 +51,7 @@ namespace Umbraco.Web.BackOffice.Controllers ShortStringHelper = shortStringHelper; EventMessages = eventMessages; LocalizedTextService = localizedTextService; + _serializer = serializer; } protected NotFoundObjectResult HandleContentNotFound(object id, bool throwException = true) @@ -117,7 +121,7 @@ namespace Umbraco.Web.BackOffice.Controllers var tagConfiguration = ConfigurationEditor.ConfigurationAs(propertyDto.DataType.Configuration); if (tagConfiguration.Delimiter == default) tagConfiguration.Delimiter = tagAttribute.Delimiter; var tagCulture = property.PropertyType.VariesByCulture() ? culture : null; - property.SetTagsValue(value, tagConfiguration, tagCulture); + property.SetTagsValue(_serializer, value, tagConfiguration, tagCulture); } else savePropertyValue(contentItem, property, value); diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs index 6d15333abd..e674810943 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentTypeController.cs @@ -35,6 +35,7 @@ using Umbraco.Web.Security; using ContentType = Umbraco.Core.Models.ContentType; using Umbraco.Core.Configuration.Models; using Microsoft.Extensions.Options; +using Umbraco.Core.Serialization; namespace Umbraco.Web.BackOffice.Controllers { @@ -70,6 +71,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMacroService _macroService; private readonly IEntityService _entityService; private readonly IHostingEnvironment _hostingEnvironment; + private readonly IConfigurationEditorJsonSerializer _jsonSerializer; public ContentTypeController( ICultureDictionary cultureDictionary, @@ -95,7 +97,8 @@ namespace Umbraco.Web.BackOffice.Controllers IMacroService macroService, IEntityService entityService, IHostingEnvironment hostingEnvironment, - EditorValidatorCollection editorValidatorCollection) + EditorValidatorCollection editorValidatorCollection, + IConfigurationEditorJsonSerializer jsonSerializer) : base(cultureDictionary, editorValidatorCollection, contentTypeService, @@ -124,6 +127,7 @@ namespace Umbraco.Web.BackOffice.Controllers _macroService = macroService; _entityService = entityService; _hostingEnvironment = hostingEnvironment; + _jsonSerializer = jsonSerializer; } public int GetCount() @@ -621,7 +625,7 @@ namespace Umbraco.Web.BackOffice.Controllers } var dataInstaller = new PackageDataInstallation(_loggerFactory.CreateLogger(), _loggerFactory, _fileService, _macroService, _LocalizationService, - _dataTypeService, _entityService, _contentTypeService, _contentService, _propertyEditors, _scopeProvider, _shortStringHelper, Options.Create(_globalSettings), _localizedTextService); + _dataTypeService, _entityService, _contentTypeService, _contentService, _propertyEditors, _scopeProvider, _shortStringHelper, Options.Create(_globalSettings), _localizedTextService, _jsonSerializer); var xd = new XmlDocument {XmlResolver = null}; xd.Load(filePath); diff --git a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs index 3ffcd5cec3..c88d0d16c9 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Web.BackOffice.Filters; using Umbraco.Web.Common.Attributes; @@ -43,6 +44,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IMemberTypeService _memberTypeService; private readonly ILocalizedTextService _localizedTextService; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IConfigurationEditorJsonSerializer _serializer; public DataTypeController( PropertyEditorCollection propertyEditors, @@ -54,7 +56,8 @@ namespace Umbraco.Web.BackOffice.Controllers IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, ILocalizedTextService localizedTextService, - IUmbracoContextAccessor umbracoContextAccessor) + IUmbracoContextAccessor umbracoContextAccessor, + IConfigurationEditorJsonSerializer serializer) { _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors)); _dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService)); @@ -66,6 +69,7 @@ namespace Umbraco.Web.BackOffice.Controllers _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); _localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService)); _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _serializer = serializer ?? throw new ArgumentNullException(nameof(serializer)); } /// @@ -155,7 +159,7 @@ namespace Umbraco.Web.BackOffice.Controllers { // cannot create an "empty" data type, so use something by default. var editor = _propertyEditors[Constants.PropertyEditors.Aliases.Label]; - var dt = new DataType(editor, parentId); + var dt = new DataType(editor, _serializer, parentId); return _umbracoMapper.Map(dt); } @@ -188,7 +192,7 @@ namespace Umbraco.Web.BackOffice.Controllers if (dt == null) { var editor = _propertyEditors[Constants.PropertyEditors.Aliases.ListView]; - dt = new DataType(editor) { Name = Constants.Conventions.DataTypes.ListViewPrefix + contentTypeAlias }; + dt = new DataType(editor, _serializer) { Name = Constants.Conventions.DataTypes.ListViewPrefix + contentTypeAlias }; _dataTypeService.Save(dt); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs index 19b58942fd..70e5bac29e 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MediaController.cs @@ -28,6 +28,7 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; +using Umbraco.Core.Serialization; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Extensions; @@ -63,6 +64,7 @@ namespace Umbraco.Web.BackOffice.Controllers private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; private readonly IRelationService _relationService; private readonly IImageUrlGenerator _imageUrlGenerator; + private readonly IJsonSerializer _serializer; private readonly ILogger _logger; public MediaController( @@ -84,8 +86,9 @@ namespace Umbraco.Web.BackOffice.Controllers PropertyEditorCollection propertyEditors, IMediaFileSystem mediaFileSystem, IHostingEnvironment hostingEnvironment, - IImageUrlGenerator imageUrlGenerator) - : base(cultureDictionary, loggerFactory, shortStringHelper, eventMessages, localizedTextService) + IImageUrlGenerator imageUrlGenerator, + IJsonSerializer serializer) + : base(cultureDictionary, loggerFactory, shortStringHelper, eventMessages, localizedTextService, serializer) { _shortStringHelper = shortStringHelper; _contentSettings = contentSettings.Value; @@ -104,6 +107,7 @@ namespace Umbraco.Web.BackOffice.Controllers _hostingEnvironment = hostingEnvironment; _logger = loggerFactory.CreateLogger(); _imageUrlGenerator = imageUrlGenerator; + _serializer = serializer; } /// @@ -764,7 +768,7 @@ namespace Umbraco.Web.BackOffice.Controllers await using (var stream = formFile.OpenReadStream()) { - f.SetValue(_mediaFileSystem,_shortStringHelper, _contentTypeBaseServiceProvider, Constants.Conventions.Media.File,fileName, stream); + f.SetValue(_mediaFileSystem,_shortStringHelper, _contentTypeBaseServiceProvider, _serializer, Constants.Conventions.Media.File,fileName, stream); } @@ -774,7 +778,6 @@ namespace Umbraco.Web.BackOffice.Controllers AddCancelMessage(tempFiles, message: _localizedTextService.Localize("speechBubbles/operationCancelledText") + " -- " + mediaItemName); } - } else { diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs index 82321e7e12..d9d98cc6f8 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MemberController.cs @@ -71,7 +71,7 @@ namespace Umbraco.Web.BackOffice.Controllers IDataTypeService dataTypeService, IBackofficeSecurityAccessor backofficeSecurityAccessor, IJsonSerializer jsonSerializer) - : base(cultureDictionary, loggerFactory, shortStringHelper, eventMessages, localizedTextService) + : base(cultureDictionary, loggerFactory, shortStringHelper, eventMessages, localizedTextService, jsonSerializer) { _passwordConfig = passwordConfig.Value; _propertyEditors = propertyEditors;