Added composite types to the ct mapper

This commit is contained in:
Per Ploug
2015-05-20 20:56:39 +02:00
parent 58c93c899a
commit 1bfe7840a9
8 changed files with 132 additions and 23 deletions

View File

@@ -30,6 +30,8 @@ namespace Umbraco.Tests.Models.Mapping
private Mock<IDataTypeService> _dataTypeService = new Mock<IDataTypeService>();
private Mock<PropertyEditorResolver> _propertyEditorResolver;
private Mock<IEntityService> _entityService = new Mock<IEntityService>();
[SetUp]
public void Setup()
{
@@ -77,6 +79,7 @@ namespace Umbraco.Tests.Models.Mapping
&& definition.PropertyEditorAlias == "myPropertyType"
&& definition.DatabaseType == DataTypeDatabaseType.Nvarchar));
var display = CreateSimpleContentTypeDisplay();
//Act
@@ -152,10 +155,8 @@ namespace Umbraco.Tests.Models.Mapping
return new ContentTypeDisplay
{
Alias = "test",
AllowedParentNodeTypes = new List<EntityBasic>(),
AllowedTemplates = new List<EntityBasic>(),
AvailableContentTypes = new List<EntityBasic>(),
AvailableTemplates = new List<EntityBasic>(),
AvailableCompositeContentTypes = new List<EntityBasic>(),
DefaultTemplate = new EntityBasic(){ Alias = "test" },
Description = "hello world",
Icon = "tree-icon",

View File

@@ -54,6 +54,8 @@ namespace Umbraco.Tests.TestHelpers.Entities
//ensure that nothing is marked as dirty
contentType.ResetDirtyProperties(false);
contentType.SetDefaultTemplate(new Template("Textpage", "textpage"));
return contentType;
}

View File

@@ -14,9 +14,8 @@ namespace Umbraco.Web.Models.ContentEditing
{
//initialize collections so at least their never null
AllowedTemplates = new List<EntityBasic>();
AvailableTemplates = new List<EntityBasic>();
AvailableContentTypes = new List<EntityBasic>();
AllowedParentNodeTypes = new List<EntityBasic>();
AvailableCompositeContentTypes = new List<EntityBasic>();
AllowedContentTypes = new List<EntityBasic>();
CompositeContentTypes = new List<EntityBasic>();
Groups = new List<PropertyTypeGroupDisplay>();
}
@@ -28,22 +27,19 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "allowedTemplates")]
public IEnumerable<EntityBasic> AllowedTemplates { get; set; }
[DataMember(Name = "availableTemplates")]
public IEnumerable<EntityBasic> AvailableTemplates { get; set; }
[DataMember(Name = "defaultTemplate")]
public EntityBasic DefaultTemplate { get; set; }
// Allowed parent node types (can include root)
[DataMember(Name = "allowedParentNodeTypes")]
public IEnumerable<EntityBasic> AllowedParentNodeTypes { get; set; }
// Allowed parent node types (could include root?)
[DataMember(Name = "allowedContentTypes")]
public IEnumerable<EntityBasic> AllowedContentTypes { get; set; }
//List view
[DataMember(Name = "enableListView")]
public bool EnableListView { get; set; }
//we might not need this...
[DataMember(Name = "allowedAtRoot")]
public bool AllowedAsRoot { get; set; }
@@ -51,8 +47,8 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "compositeContentTypes")]
public IEnumerable<EntityBasic> CompositeContentTypes { get; set; }
[DataMember(Name = "availableContentTypes")]
public IEnumerable<EntityBasic> AvailableContentTypes { get; set; }
[DataMember(Name = "availableCompositeContentTypes")]
public IEnumerable<EntityBasic> AvailableCompositeContentTypes { get; set; }
//Tabs

View File

@@ -0,0 +1,106 @@
using AutoMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models.Mapping
{
internal class AvailableCompositeContentTypesResolver : ValueResolver<IContentType, IEnumerable<EntityBasic>>
{
private ApplicationContext _context;
private bool _mediaType;
internal AvailableCompositeContentTypesResolver(ApplicationContext context, bool mediaType = false)
{
_context = context;
_mediaType = mediaType;
}
protected override IEnumerable<EntityBasic> ResolveCore(IContentType source)
{
//below is all ported from the old doc type editor and comes with the same weaknesses /insanity
//get all types
var allContentTypes = _mediaType
? _context.Services.ContentTypeService.GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray()
: _context.Services.ContentTypeService.GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
// note: there are many sanity checks missing here and there ;-((
// make sure once and for all
//if (allContentTypes.Any(x => x.ParentId > 0 && x.ContentTypeComposition.Any(y => y.Id == x.ParentId) == false))
// throw new Exception("A parent does not belong to a composition.");
// find out if any content type uses this content type
var isUsing = allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == source.Id)).ToArray();
if (isUsing.Length > 0)
{
//if already in use a composition, do not allow any composited types
return new List<EntityBasic>();
}
else
{
// if it is not used then composition is possible
// hashset guarantees unicity on Id
var list = new HashSet<IContentTypeComposition>(new DelegateEqualityComparer<IContentTypeComposition>(
(x, y) => x.Id == y.Id,
x => x.Id));
// usable types are those that are top-level
var usableContentTypes = allContentTypes
.Where(x => x.ContentTypeComposition.Any() == false).ToArray();
foreach (var x in usableContentTypes)
list.Add(x);
// indirect types are those that we use, directly or indirectly
var indirectContentTypes = GetIndirect(source).ToArray();
foreach (var x in indirectContentTypes)
list.Add(x);
// directContentTypes are those we use directly
// they are already in indirectContentTypes, no need to add to the list
var directContentTypes = source.ContentTypeComposition.ToArray();
var enabled = usableContentTypes.Select(x => x.Id) // those we can use
.Except(indirectContentTypes.Select(x => x.Id)) // except those that are indirectly used
.Union(directContentTypes.Select(x => x.Id)) // but those that are directly used
.Where(x => x != source.ParentId) // but not the parent
.Distinct()
.ToArray();
var wtf = new List<EntityBasic>();
foreach (var contentType in list.OrderBy(x => x.Name).Where(x => x.Id != source.Id))
wtf.Add(Mapper.Map<IContentTypeComposition, EntityBasic>(contentType));
return wtf;
}
}
private IEnumerable<IContentTypeComposition> GetIndirect(IContentTypeComposition ctype)
{
// hashset guarantees unicity on Id
var all = new HashSet<IContentTypeComposition>(new DelegateEqualityComparer<IContentTypeComposition>(
(x, y) => x.Id == y.Id,
x => x.Id));
var stack = new Stack<IContentTypeComposition>();
foreach (var x in ctype.ContentTypeComposition)
stack.Push(x);
while (stack.Count > 0)
{
var x = stack.Pop();
all.Add(x);
foreach (var y in x.ContentTypeComposition)
stack.Push(y);
}
return all;
}
}
}

View File

@@ -58,15 +58,13 @@ namespace Umbraco.Web.Models.Mapping
//Ignore because this is not actually used for content types
.ForMember(display => display.Trashed, expression => expression.Ignore())
//Ignore for now, this will need to be manually mapped or mapped with a resolver
// since there is no source property to map from
.ForMember(display => display.AvailableContentTypes, expression => expression.Ignore())
//Ignore for now, this will need to be manually mapped or mapped with a resolver
// since there is no source property to map from
.ForMember(display => display.AvailableTemplates, expression => expression.Ignore())
.ForMember(
dto => dto.AvailableCompositeContentTypes,
expression => expression.ResolveUsing(new AvailableCompositeContentTypesResolver(applicationContext)))
.ForMember(display => display.EnableListView, expression => expression.MapFrom(type => type.IsContainer))
.ForMember(
dto => dto.Groups,
expression => expression.ResolveUsing(new PropertyTypeGroupResolver(applicationContext, _propertyEditorResolver)));

View File

@@ -52,6 +52,12 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.Trashed, expression => expression.Ignore())
.ForMember(x => x.AdditionalData, expression => expression.Ignore());
config.CreateMap<IContentTypeComposition, EntityBasic>()
.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<SearchResult, EntityBasic>()
//default to document icon
.ForMember(x => x.Icon, expression => expression.Ignore())

View File

@@ -26,7 +26,6 @@ namespace Umbraco.Web.Models.Mapping
protected override IEnumerable<PropertyTypeGroupDisplay> ResolveCore(IContentType source)
{
var groups = new List<PropertyTypeGroupDisplay>();
var propGroups = source.CompositionPropertyGroups.ToArray();
var genericGroup = new PropertyTypeGroupDisplay() { Name = "properties", Id = 0, ParentGroupId = 0 };

View File

@@ -307,6 +307,7 @@
<Compile Include="Models\ContentEditing\ContentTypeDisplay.cs" />
<Compile Include="Models\ContentEditing\PropertyTypeDisplay.cs" />
<Compile Include="Models\ContentEditing\PropertyTypeGroupDisplay.cs" />
<Compile Include="Models\Mapping\AvailableCompositeContentTypesResolver.cs" />
<Compile Include="Models\Mapping\PropertyTypeGroupResolver.cs" />
<Compile Include="Trees\DocumentTypeTreeController.cs" />
<Compile Include="UmbracoDefaultOwinStartup.cs" />