From 087c07bcbd8c3f024ce7c41a280ea0346e8912ea Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 4 Jun 2015 16:52:22 +0200 Subject: [PATCH] started updating the content type mapping. --- .../Mapping/ContentTypeModelMappingTests.cs | 92 ++++++++++++++++++- .../Editors/ContentTypeController.cs | 26 +++--- .../ContentEditing/ContentTypeDisplay.cs | 4 +- ...roupDisplay.cs => PropertyGroupDisplay.cs} | 6 +- .../Models/Mapping/ContentTypeModelMapper.cs | 59 ++++++++---- .../Models/Mapping/EntityModelMapper.cs | 42 ++++++--- .../Mapping/PropertyTypeGroupResolver.cs | 19 ++-- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- 8 files changed, 184 insertions(+), 66 deletions(-) rename src/Umbraco.Web/Models/ContentEditing/{PropertyTypeGroupDisplay.cs => PropertyGroupDisplay.cs} (89%) diff --git a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs index ba104df97d..31c9bf436b 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs @@ -61,10 +61,89 @@ namespace Umbraco.Tests.Models.Mapping { //initialize our content type mapper var mapper = new ContentTypeModelMapper(new Lazy(() => _propertyEditorResolver.Object)); - mapper.ConfigureMappings(configuration, appContext); + mapper.ConfigureMappings(configuration, appContext); + var entityMapper = new EntityModelMapper(); + entityMapper.ConfigureMappings(configuration, appContext); }); } + [Test] + public void ContentTypeDisplay_To_PropertyType() + { + // setup the mocks to return the data we want to test against... + + _dataTypeService.Setup(x => x.GetDataTypeDefinitionById(It.IsAny())) + .Returns(Mock.Of( + definition => + definition.Id == 555 + && definition.PropertyEditorAlias == "myPropertyType" + && definition.DatabaseType == DataTypeDatabaseType.Nvarchar)); + + var display = new PropertyTypeDisplay() + { + Id = 1, + Alias = "test", + ContentTypeId = 4, + Description = "testing", + DataTypeId = 555, + + Value = "testsdfasdf", + Inherited = false, + Editor = "blah", + SortOrder = 6, + ContentTypeName = "Hello", + Label = "asdfasdf", + GroupId = 8, + Validation = new PropertyTypeValidation() + { + Mandatory = true, + Pattern = "asdfasdfa" + } + }; + + var result = Mapper.Map(display); + + Assert.AreEqual(1, result.Id); + Assert.AreEqual("test", result.Alias); + Assert.AreEqual("testing", result.Description); + Assert.AreEqual("blah", result.PropertyEditorAlias); + Assert.AreEqual(6, result.SortOrder); + Assert.AreEqual("asdfasdf", result.Name); + Assert.AreEqual(8, result.PropertyGroupId.Value); + + } + + [Test] + public void ContentGroupDisplay_To_PropertyGroup() + { + var display = new PropertyGroupDisplay() + { + ContentTypeId = 2, + Id = 1, + Inherited = false, + Name = "test", + ParentGroupId = 4, + ParentTabContentTypeNames = new[] + { + "hello", "world" + }, + SortOrder = 5, + ParentTabContentTypes = new[] + { + 10, 11 + } + }; + + + var result = Mapper.Map(display); + + Assert.AreEqual(1, result.Id); + Assert.AreEqual("test", result.Name); + Assert.AreEqual(4, result.ParentId); + Assert.AreEqual(5, result.SortOrder); + + } + [Test] public void ContentTypeDisplay_To_IContentType() { @@ -97,10 +176,12 @@ namespace Umbraco.Tests.Models.Mapping Assert.AreEqual(display.Path, result.Path); Assert.AreEqual(display.Thumbnail, result.Thumbnail); Assert.AreEqual(display.IsContainer, result.IsContainer); + Assert.AreEqual(display.AllowAsRoot, result.AllowedAsRoot); //TODO: Now we need to assert all of the more complicated parts Assert.AreEqual(1, result.PropertyGroups.Count); Assert.AreEqual(1, result.PropertyGroups[0].PropertyTypes.Count); + Assert.AreEqual(display.AllowedTemplates.Count(), result.AllowedTemplates.Count()); } [Test] @@ -152,7 +233,8 @@ namespace Umbraco.Tests.Models.Mapping { return new ContentTypeDisplay { - Alias = "test", + Alias = "test", + AllowAsRoot = true, AllowedTemplates = new List(), AvailableCompositeContentTypes = new List(), DefaultTemplate = new EntityBasic(){ Alias = "test" }, @@ -165,15 +247,15 @@ namespace Umbraco.Tests.Models.Mapping ParentId = -1, Thumbnail = "tree-thumb", IsContainer = true, - Groups = new List() + Groups = new List() { - new PropertyTypeGroupDisplay + new PropertyGroupDisplay { Id = 987, Name = "Tab 1", ParentGroupId = -1, SortOrder = 0, - Inherited = false, + Inherited = false, Properties = new List { new PropertyTypeDisplay diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 7cc4d37725..3bf104de8f 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -59,7 +59,7 @@ namespace Umbraco.Web.Editors } - public Umbraco.Web.Models.ContentEditing.ContentTypeDisplay GetById(int id) + public ContentTypeDisplay GetById(int id) { var ct = Services.ContentTypeService.GetContentType(id); if (ct == null) @@ -67,14 +67,14 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - var dto = Mapper.Map(ct); + var dto = Mapper.Map(ct); return dto; } - public Umbraco.Web.Models.ContentEditing.ContentTypeDisplay GetScaffold() + public ContentTypeDisplay GetScaffold() { var ct = new ContentType(-1); - var dto = Mapper.Map(ct); + var dto = Mapper.Map(ct); return dto; } @@ -102,18 +102,17 @@ namespace Umbraco.Web.Editors /// /// Returns all content type objects /// - /// public IEnumerable GetAll() { var types = Services.ContentTypeService.GetAllContentTypes(); var basics = types.Select(Mapper.Map); - foreach (var basic in basics) + + return basics.Select(basic => { basic.Name = TranslateItem(basic.Name); basic.Description = TranslateItem(basic.Description); - } - - return basics; + return basic; + }); } /// @@ -166,10 +165,10 @@ namespace Umbraco.Web.Editors var ctService = ApplicationContext.Services.ContentTypeService; - ///TODO: warn on content type alias conflicts - ///TODO: warn on property alias conflicts + //TODO: warn on content type alias conflicts + //TODO: warn on property alias conflicts - ///TODO: Validate the submitted model + //TODO: Validate the submitted model var ctId = Convert.ToInt32(contentType.Id); @@ -196,8 +195,7 @@ namespace Umbraco.Web.Editors contentType.Id = null; //save as new - IContentType newCt = new ContentType(-1); - Mapper.Map(contentType, newCt); + var newCt = Mapper.Map(contentType); ctService.Save(newCt); diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentTypeDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentTypeDisplay.cs index 853e10d94f..3662516bcc 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentTypeDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentTypeDisplay.cs @@ -17,7 +17,7 @@ namespace Umbraco.Web.Models.ContentEditing AvailableCompositeContentTypes = new List(); AllowedContentTypes = new List(); CompositeContentTypes = new List(); - Groups = new List(); + Groups = new List(); } //name, alias, icon, thumb, desc, inherited from basic @@ -54,6 +54,6 @@ namespace Umbraco.Web.Models.ContentEditing //Tabs [DataMember(Name = "groups")] - public IEnumerable Groups { get; set; } + public IEnumerable Groups { get; set; } } } diff --git a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeGroupDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/PropertyGroupDisplay.cs similarity index 89% rename from src/Umbraco.Web/Models/ContentEditing/PropertyTypeGroupDisplay.cs rename to src/Umbraco.Web/Models/ContentEditing/PropertyGroupDisplay.cs index 2dfc94d10c..85ee636b9a 100644 --- a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeGroupDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/PropertyGroupDisplay.cs @@ -7,10 +7,10 @@ using System.Threading.Tasks; namespace Umbraco.Web.Models.ContentEditing { - [DataContract(Name = "propertyTypeGroup", Namespace = "")] - public class PropertyTypeGroupDisplay + [DataContract(Name = "propertyGroup", Namespace = "")] + public class PropertyGroupDisplay { - public PropertyTypeGroupDisplay() + public PropertyGroupDisplay() { Properties = new List(); } diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs index d6d8712c05..98af6a07ce 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs @@ -1,6 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; - +using System.Threading; using AutoMapper; using Umbraco.Core; using Umbraco.Core.Models; @@ -40,53 +41,57 @@ namespace Umbraco.Web.Models.Mapping //only map id if set to something higher then zero .ForMember(dto => dto.Id, expression => expression.Condition(display => (Convert.ToInt32(display.Id) > 0))) - + .ForMember(dto => dto.AllowedAsRoot, expression => expression.MapFrom(display => display.AllowAsRoot)) .ForMember(dto => dto.CreatorId, expression => expression.Ignore()) .ForMember(dto => dto.Level, expression => expression.Ignore()) .ForMember(dto => dto.CreateDate, expression => expression.Ignore()) .ForMember(dto => dto.UpdateDate, expression => expression.Ignore()) .ForMember(dto => dto.SortOrder, expression => expression.Ignore()) - //ignore, we'll do this in after map .ForMember(dto => dto.PropertyGroups, expression => expression.Ignore()) .AfterMap((source, dest) => { - dest.PropertyGroups = new PropertyGroupCollection(); - foreach (var groupDisplay in source.Groups.Where(x => !x.Name.IsNullOrWhiteSpace() ) ) + foreach (var groupDisplay in source.Groups.Where(x => x.Name.IsNullOrWhiteSpace() == false ) ) { dest.PropertyGroups.Add(Mapper.Map(groupDisplay)); } //sync compositions - var current = dest.CompositionAliases(); + var current = dest.CompositionAliases().ToArray(); var proposed = source.CompositeContentTypes; - var remove = current.Where(x => !proposed.Contains(x)); - var add = proposed.Where(x => !current.Contains(x)); + var remove = current.Where(x => proposed.Contains(x) == false); + var add = proposed.Where(x => current.Contains(x) == false); - foreach(var rem in remove) + foreach (var rem in remove) + { dest.RemoveContentType(rem); + } - foreach(var a in add){ - var add_ct = applicationContext.Services.ContentTypeService.GetContentType(a); - if(add_ct != null) - dest.AddContentType(add_ct); + foreach(var a in add) + { + //TODO: Remove N+1 lookup + var addCt = applicationContext.Services.ContentTypeService.GetContentType(a); + if(addCt != null) + dest.AddContentType(addCt); } }); config.CreateMap().ConvertUsing(x => x.Alias); config.CreateMap() + .ForMember(display => display.AllowAsRoot, expression => expression.MapFrom(type => type.AllowedAsRoot)) //Ignore because this is not actually used for content types .ForMember(display => display.Trashed, expression => expression.Ignore()) - + //Ignore, we'll do this in after map + .ForMember(dto => dto.AllowedContentTypes, expression => expression.Ignore()) .ForMember( dto => dto.AvailableCompositeContentTypes, expression => expression.ResolveUsing(new AvailableCompositeContentTypesResolver(applicationContext))) .ForMember( dto => dto.CompositeContentTypes, - expression => expression.MapFrom(dto => dto.ContentTypeComposition) ) + expression => expression.MapFrom(dto => dto.ContentTypeComposition)) .ForMember( dto => dto.CompositeContentTypes, @@ -94,12 +99,24 @@ namespace Umbraco.Web.Models.Mapping .ForMember( dto => dto.Groups, - expression => expression.ResolveUsing(new PropertyTypeGroupResolver(applicationContext, _propertyEditorResolver))); + expression => expression.ResolveUsing(new PropertyTypeGroupResolver(applicationContext, _propertyEditorResolver))) + + .AfterMap((source, dest) => + { + //do allowed content types, we need to look them up then assign to a list of entity basic, + //we are doing this manually because ContentTypeSort doesnt have a Name and we want that + var foundCts = applicationContext.Services.ContentTypeService + .GetAllContentTypes(source.AllowedContentTypes.Select(x => Convert.ToInt32(x.Id)).ToArray()); + dest.AllowedContentTypes = foundCts.Select(Mapper.Map); + }); - config.CreateMap() + config.CreateMap() .ForMember(dest => dest.Id, expression => expression.Condition(source => source.Id > 0)) - .ForMember(g => g.CreateDate, expression => expression.Ignore()) + .ForMember(g => g.CreateDate, expression => expression.Ignore()) + .ForMember(g => g.Key, expression => expression.Ignore()) + .ForMember(g => g.CreateDate, expression => expression.Ignore()) + .ForMember(g => g.HasIdentity, expression => expression.Ignore()) .ForMember(g => g.UpdateDate, expression => expression.Ignore()) //only map if a parent is actually set @@ -110,6 +127,8 @@ namespace Umbraco.Web.Models.Mapping .ForMember(g => g.PropertyTypes, expression => expression.Ignore()) .AfterMap((source, destination) => { + + destination.PropertyTypes = new PropertyTypeCollection(); foreach (var propertyTypeDisplay in source.Properties.Where(x => x.Label.IsNullOrWhiteSpace() == false )) { @@ -125,6 +144,10 @@ namespace Umbraco.Web.Models.Mapping if (dataType == null) throw new NullReferenceException("No data type found with id " + propertyTypeDisplay.DataTypeId); return new PropertyType(dataType, propertyTypeDisplay.Alias); }) + .ForMember(type => type.PropertyGroupId, expression => expression.MapFrom(display => new Lazy(() => display.GroupId, LazyThreadSafetyMode.None))) + .ForMember(type => type.Key, expression => expression.Ignore()) + .ForMember(type => type.HelpText, expression => expression.Ignore()) + .ForMember(type => type.HasIdentity, expression => expression.Ignore()) //ignore because this is set in the ctor .ForMember(type => type.Alias, expression => expression.Ignore()) //ignore because this is obsolete and shouldn't be used diff --git a/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs b/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs index 20fc9cdd6a..d853bd5340 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs @@ -47,25 +47,39 @@ namespace Umbraco.Web.Models.Mapping config.CreateMap() .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-layout")) - .ForMember(basic => basic.Path, expression => expression.UseValue("")) + .ForMember(basic => basic.Path, expression => expression.MapFrom(template => template.Path)) .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) .ForMember(dto => dto.Trashed, expression => expression.Ignore()) .ForMember(x => x.AdditionalData, expression => expression.Ignore()); + config.CreateMap() + .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-grid")) + .ForMember(dto => dto.Trashed, expression => expression.Ignore()) + .ForMember(x => x.AdditionalData, expression => expression.Ignore()); + + config.CreateMap() + .ConstructUsing(basic => new Template(basic.Name, basic.Alias) + { + Id = Convert.ToInt32(basic.Id), + Key = basic.Key + }) + .ForMember(t => t.Path, expression => expression.MapFrom(template => template.Path)) + .ForMember(t => t.Id, expression => expression.MapFrom(template => Convert.ToInt32(template.Id))) + .ForMember(x => x.VirtualPath, expression => expression.Ignore()) + .ForMember(x => x.CreateDate, expression => expression.Ignore()) + .ForMember(x => x.UpdateDate, expression => expression.Ignore()) + .ForMember(x => x.Content, expression => expression.Ignore()); + + config.CreateMap() + .ForMember(x => x.Id, expression => expression.MapFrom(entity => new Lazy(() => Convert.ToInt32(entity.Id)))) + .ForMember(x => x.SortOrder, expression => expression.Ignore()); + config.CreateMap() - .ForMember(basic => basic.Path, expression => expression.UseValue("")) - .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) - .ForMember(dto => dto.Trashed, expression => expression.Ignore()) - .ForMember(x => x.AdditionalData, expression => expression.Ignore()); - - config.CreateMap() - .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-grid")) - .ForMember(basic => basic.Path, expression => expression.UseValue("")) - .ForMember(basic => basic.ParentId, expression => expression.UseValue(-1)) - .ForMember(dto => dto.Trashed, expression => expression.Ignore()) - .ForMember(x => x.AdditionalData, expression => expression.Ignore()); - - + .ForMember(basic => basic.Icon, expression => expression.UseValue("icon-grid")) + .ForMember(basic => basic.Path, expression => expression.MapFrom(x => x.Path)) + .ForMember(basic => basic.ParentId, expression => expression.MapFrom(x => x.ParentId)) + .ForMember(dto => dto.Trashed, expression => expression.Ignore()) + .ForMember(x => x.AdditionalData, expression => expression.Ignore()); config.CreateMap() //default to document icon diff --git a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs index 21aca8d540..a30bab1e3d 100644 --- a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs @@ -11,8 +11,9 @@ using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Models.Mapping { - - internal class PropertyTypeGroupResolver : ValueResolver> + + + internal class PropertyTypeGroupResolver : ValueResolver> { private readonly ApplicationContext _applicationContext; private readonly Lazy _propertyEditorResolver; @@ -24,9 +25,9 @@ namespace Umbraco.Web.Models.Mapping } - protected override IEnumerable ResolveCore(IContentType source) + protected override IEnumerable ResolveCore(IContentType source) { - var groups = new Dictionary(); + var groups = new Dictionary(); //for storing generic properties var genericProperties = new List(); @@ -37,7 +38,7 @@ namespace Umbraco.Web.Models.Mapping { //process each tab foreach(var tab in ct.CompositionPropertyGroups){ - var group = new PropertyTypeGroupDisplay() { Id = tab.Id, Inherited = true, Name = tab.Name, SortOrder = tab.SortOrder }; + var group = new PropertyGroupDisplay() { Id = tab.Id, Inherited = true, Name = tab.Name, SortOrder = tab.SortOrder }; group.ContentTypeId = ct.Id; group.ParentTabContentTypes = new[] { ct.Id }; group.ParentTabContentTypeNames = new[] { ct.Name }; @@ -60,7 +61,7 @@ namespace Umbraco.Web.Models.Mapping //pull from own groups foreach (var ownTab in source.CompositionPropertyGroups) { - PropertyTypeGroupDisplay group; + PropertyGroupDisplay group; //if already added if (groups.ContainsKey(ownTab.Id)) @@ -73,7 +74,7 @@ namespace Umbraco.Web.Models.Mapping else { //if own - group = new PropertyTypeGroupDisplay() { Id = ownTab.Id, Inherited = false, Name = ownTab.Name, SortOrder = ownTab.SortOrder, ContentTypeId = source.Id }; + group = new PropertyGroupDisplay() { Id = ownTab.Id, Inherited = false, Name = ownTab.Name, SortOrder = ownTab.SortOrder, ContentTypeId = source.Id }; groups.Add(ownTab.Id, group); } @@ -94,7 +95,7 @@ namespace Umbraco.Web.Models.Mapping if (genericProperties.Any()) { - var genericTab = new PropertyTypeGroupDisplay() { Id = 0, Name = "Generic properties", ParentGroupId = 0, ContentTypeId = source.Id, SortOrder = 999, Inherited = false }; + var genericTab = new PropertyGroupDisplay() { Id = 0, Name = "Generic properties", ParentGroupId = 0, ContentTypeId = source.Id, SortOrder = 999, Inherited = false }; groups.Add(0, genericTab); } @@ -103,7 +104,7 @@ namespace Umbraco.Web.Models.Mapping var nameGroupedGroups = groups.Values.GroupBy(x => x.Name); if (nameGroupedGroups.Any(x => x.Count() > 1)) { - var sortedGroups = new List(); + var sortedGroups = new List(); foreach (var groupOfGroups in nameGroupedGroups) { diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 75039e9c4f..63de138ad5 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -306,7 +306,7 @@ - +