Merge remote-tracking branch 'upstream' into v8/bugfix/enum-extensions
This commit is contained in:
@@ -16,20 +16,32 @@ namespace Umbraco.Web.Models
|
||||
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[DataMember(Name = "group")]
|
||||
public string Group { get; set; }
|
||||
|
||||
[DataMember(Name = "groupOrder")]
|
||||
public int GroupOrder { get; set; }
|
||||
|
||||
[DataMember(Name = "hidden")]
|
||||
public bool Hidden { get; set; }
|
||||
|
||||
[DataMember(Name = "allowDisable")]
|
||||
public bool AllowDisable { get; set; }
|
||||
|
||||
[DataMember(Name = "requiredSections")]
|
||||
public List<string> RequiredSections { get; set; }
|
||||
|
||||
[DataMember(Name = "steps")]
|
||||
public BackOfficeTourStep[] Steps { get; set; }
|
||||
|
||||
[DataMember(Name = "culture")]
|
||||
public string Culture { get; set; }
|
||||
|
||||
[DataMember(Name = "contentType")]
|
||||
public string ContentType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,11 +53,21 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[ReadOnly(true)]
|
||||
public string Culture { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The segment of the property
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The segment value of a property can always be null but can only have a non-null value
|
||||
/// when the property can be varied by segment.
|
||||
/// </remarks>
|
||||
[DataMember(Name = "segment")]
|
||||
[ReadOnly(true)]
|
||||
public string Segment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used internally during model mapping
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
internal IDataEditor PropertyEditor { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,12 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "culture")]
|
||||
public string Culture { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The segment of this variant, if this is invariant than this is null or empty
|
||||
/// </summary>
|
||||
[DataMember(Name = "segment")]
|
||||
public string Segment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the variant should be updated
|
||||
/// </summary>
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataContract(Name = "contentType", Namespace = "")]
|
||||
public class MediaTypeDisplay : ContentTypeCompositionDisplay<PropertyTypeDisplay>
|
||||
{
|
||||
|
||||
[DataMember(Name = "isSystemMediaType")]
|
||||
public bool IsSystemMediaType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember(Name = "parentObjectType", IsRequired = true)]
|
||||
public Guid ParentObjectType { get; set; }
|
||||
public Guid? ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Parent's object type name.
|
||||
@@ -38,7 +38,7 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// </summary>
|
||||
/// <remarks>Corresponds to the NodeObjectType in the umbracoNode table</remarks>
|
||||
[DataMember(Name = "childObjectType", IsRequired = true)]
|
||||
public Guid ChildObjectType { get; set; }
|
||||
public Guid? ChildObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Child's object type name.
|
||||
@@ -47,13 +47,6 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[ReadOnly(true)]
|
||||
public string ChildObjectTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the relations associated with this relation type.
|
||||
/// </summary>
|
||||
[DataMember(Name = "relations")]
|
||||
[ReadOnly(true)]
|
||||
public IEnumerable<RelationDisplay> Relations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.
|
||||
/// </summary>
|
||||
|
||||
@@ -16,12 +16,12 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// Gets or sets the parent object type ID.
|
||||
/// </summary>
|
||||
[DataMember(Name = "parentObjectType", IsRequired = false)]
|
||||
public Guid ParentObjectType { get; set; }
|
||||
public Guid? ParentObjectType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the child object type ID.
|
||||
/// </summary>
|
||||
[DataMember(Name = "childObjectType", IsRequired = false)]
|
||||
public Guid ChildObjectType { get; set; }
|
||||
public Guid? ChildObjectType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,13 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
dest.Culture = culture;
|
||||
|
||||
// Get the segment, which is always allowed to be null even if the propertyType *can* be varied by segment.
|
||||
// There is therefore no need to perform the null check like with culture above.
|
||||
var segment = !property.PropertyType.VariesBySegment() ? null : context.GetSegment();
|
||||
dest.Segment = segment;
|
||||
|
||||
// if no 'IncludeProperties' were specified or this property is set to be included - we will map the value and return.
|
||||
dest.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, culture);
|
||||
dest.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, culture, segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +145,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
//default listview
|
||||
target.ListViewEditorName = Constants.Conventions.DataTypes.ListViewPrefix + "Media";
|
||||
target.IsSystemMediaType = source.IsSystemMediaType();
|
||||
|
||||
if (string.IsNullOrEmpty(source.Name)) return;
|
||||
|
||||
@@ -488,7 +489,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Udi = MapContentTypeUdi(source);
|
||||
target.UpdateDate = source.UpdateDate;
|
||||
|
||||
target.AllowedContentTypes = source.AllowedContentTypes.Select(x => x.Id.Value);
|
||||
target.AllowedContentTypes = source.AllowedContentTypes.OrderBy(c => c.SortOrder).Select(x => x.Id.Value);
|
||||
target.CompositeContentTypes = source.ContentTypeComposition.Select(x => x.Alias);
|
||||
target.LockedCompositeContentTypes = MapLockedCompositions(source);
|
||||
}
|
||||
|
||||
@@ -21,52 +21,117 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
public IEnumerable<ContentVariantDisplay> Map(IContent source, MapperContext context)
|
||||
{
|
||||
var result = new List<ContentVariantDisplay>();
|
||||
if (!source.ContentType.VariesByCulture())
|
||||
var variesByCulture = source.ContentType.VariesByCulture();
|
||||
var variesBySegment = source.ContentType.VariesBySegment();
|
||||
|
||||
IList<ContentVariantDisplay> variants = new List<ContentVariantDisplay>();
|
||||
|
||||
if (!variesByCulture && !variesBySegment)
|
||||
{
|
||||
//this is invariant so just map the IContent instance to ContentVariationDisplay
|
||||
result.Add(context.Map<ContentVariantDisplay>(source));
|
||||
// this is invariant so just map the IContent instance to ContentVariationDisplay
|
||||
var variantDisplay = context.Map<ContentVariantDisplay>(source);
|
||||
variants.Add(variantDisplay);
|
||||
}
|
||||
else if (variesByCulture && !variesBySegment)
|
||||
{
|
||||
var languages = GetLanguages(context);
|
||||
variants = languages
|
||||
.Select(language => CreateVariantDisplay(context, source, language, null))
|
||||
.ToList();
|
||||
}
|
||||
else if (variesBySegment && !variesByCulture)
|
||||
{
|
||||
// Segment only
|
||||
var segments = GetSegments(source);
|
||||
variants = segments
|
||||
.Select(segment => CreateVariantDisplay(context, source, null, segment))
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
var allLanguages = _localizationService.GetAllLanguages().OrderBy(x => x.Id).ToList();
|
||||
if (allLanguages.Count == 0) return Enumerable.Empty<ContentVariantDisplay>(); //this should never happen
|
||||
// Culture and segment
|
||||
var languages = GetLanguages(context).ToList();
|
||||
var segments = GetSegments(source).ToList();
|
||||
|
||||
var langs = context.MapEnumerable<ILanguage, Language>(allLanguages).ToList();
|
||||
|
||||
//create a variant for each language, then we'll populate the values
|
||||
var variants = langs.Select(x =>
|
||||
if (languages.Count == 0 || segments.Count == 0)
|
||||
{
|
||||
//We need to set the culture in the mapping context since this is needed to ensure that the correct property values
|
||||
//are resolved during the mapping
|
||||
context.SetCulture(x.IsoCode);
|
||||
return context.Map<ContentVariantDisplay>(source);
|
||||
}).ToList();
|
||||
|
||||
for (int i = 0; i < langs.Count; i++)
|
||||
{
|
||||
var x = langs[i];
|
||||
var variant = variants[i];
|
||||
|
||||
variant.Language = x;
|
||||
variant.Name = source.GetCultureName(x.IsoCode);
|
||||
// This should not happen
|
||||
throw new InvalidOperationException("No languages or segments available");
|
||||
}
|
||||
|
||||
//Put the default language first in the list & then sort rest by a-z
|
||||
var defaultLang = variants.SingleOrDefault(x => x.Language.IsDefault);
|
||||
variants = languages
|
||||
.SelectMany(language => segments
|
||||
.Select(segment => CreateVariantDisplay(context, source, language, segment)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
//Remove the default language from the list for now
|
||||
variants.Remove(defaultLang);
|
||||
|
||||
//Sort the remaining languages a-z
|
||||
variants = variants.OrderBy(x => x.Language.Name).ToList();
|
||||
|
||||
//Insert the default language as the first item
|
||||
variants.Insert(0, defaultLang);
|
||||
return SortVariants(variants);
|
||||
}
|
||||
|
||||
private IList<ContentVariantDisplay> SortVariants(IList<ContentVariantDisplay> variants)
|
||||
{
|
||||
if (variants == null || variants.Count <= 1)
|
||||
{
|
||||
return variants;
|
||||
}
|
||||
return result;
|
||||
|
||||
// Default variant first, then order by language, segment.
|
||||
return variants
|
||||
.OrderBy(v => IsDefaultLanguage(v) ? 0 : 1)
|
||||
.ThenBy(v => IsDefaultSegment(v) ? 0 : 1)
|
||||
.ThenBy(v => v?.Language?.Name)
|
||||
.ThenBy(v => v.Segment)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static bool IsDefaultSegment(ContentVariantDisplay variant)
|
||||
{
|
||||
return variant.Segment == null;
|
||||
}
|
||||
|
||||
private static bool IsDefaultLanguage(ContentVariantDisplay variant)
|
||||
{
|
||||
return variant.Language == null || variant.Language.IsDefault;
|
||||
}
|
||||
|
||||
private IEnumerable<Language> GetLanguages(MapperContext context)
|
||||
{
|
||||
var allLanguages = _localizationService.GetAllLanguages().OrderBy(x => x.Id).ToList();
|
||||
if (allLanguages.Count == 0)
|
||||
{
|
||||
// This should never happen
|
||||
return Enumerable.Empty<Language>();
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.MapEnumerable<ILanguage, Language>(allLanguages).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all segments assigned to the content
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns>
|
||||
/// Returns all segments assigned to the content including 'null' values
|
||||
/// </returns>
|
||||
private IEnumerable<string> GetSegments(IContent content)
|
||||
{
|
||||
return content.Properties.SelectMany(p => p.Values.Select(v => v.Segment)).Distinct();
|
||||
}
|
||||
|
||||
private ContentVariantDisplay CreateVariantDisplay(MapperContext context, IContent content, Language language, string segment)
|
||||
{
|
||||
context.SetCulture(language?.IsoCode);
|
||||
context.SetSegment(segment);
|
||||
|
||||
var variantDisplay = context.Map<ContentVariantDisplay>(content);
|
||||
|
||||
variantDisplay.Segment = segment;
|
||||
variantDisplay.Language = language;
|
||||
variantDisplay.Name = content.GetCultureName(language?.IsoCode);
|
||||
|
||||
return variantDisplay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,11 +234,11 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
switch (entity)
|
||||
{
|
||||
case ContentEntitySlim contentEntity:
|
||||
// NOTE: this case covers both content and media entities
|
||||
return contentEntity.ContentTypeIcon;
|
||||
case MemberEntitySlim memberEntity:
|
||||
case IMemberEntitySlim memberEntity:
|
||||
return memberEntity.ContentTypeIcon.IfNullOrWhiteSpace(Constants.Icons.Member);
|
||||
case IContentEntitySlim contentEntity:
|
||||
// NOTE: this case covers both content and media entities
|
||||
return contentEntity.ContentTypeIcon;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -23,6 +24,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
public void DefineMaps(UmbracoMapper mapper)
|
||||
{
|
||||
mapper.Define<IMacro, EntityBasic>((source, context) => new EntityBasic(), Map);
|
||||
mapper.Define<IMacro, MacroDisplay>((source, context) => new MacroDisplay(), Map);
|
||||
mapper.Define<IMacro, IEnumerable<MacroParameter>>((source, context) => context.MapEnumerable<IMacroProperty, MacroParameter>(source.Properties.Values));
|
||||
mapper.Define<IMacroProperty, MacroParameter>((source, context) => new MacroParameter(), Map);
|
||||
}
|
||||
@@ -40,6 +42,23 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Udi = Udi.Create(Constants.UdiEntityType.Macro, source.Key);
|
||||
}
|
||||
|
||||
private void Map(IMacro source, MacroDisplay target, MapperContext context)
|
||||
{
|
||||
target.Alias = source.Alias;
|
||||
target.Icon = Constants.Icons.Macro;
|
||||
target.Id = source.Id;
|
||||
target.Key = source.Key;
|
||||
target.Name = source.Name;
|
||||
target.ParentId = -1;
|
||||
target.Path = "-1," + source.Id;
|
||||
target.Udi = Udi.Create(Constants.UdiEntityType.Macro, source.Key);
|
||||
target.CacheByPage = source.CacheByPage;
|
||||
target.CacheByUser = source.CacheByMember;
|
||||
target.CachePeriod = source.CacheDuration;
|
||||
target.UseInEditor = source.UseInEditor;
|
||||
target.RenderInEditor = !source.DontRender;
|
||||
target.View = source.MacroSource;
|
||||
}
|
||||
// Umbraco.Code.MapAll -Value
|
||||
private void Map(IMacroProperty source, MacroParameter target, MapperContext context)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
internal static class MapperContextExtensions
|
||||
{
|
||||
private const string CultureKey = "Map.Culture";
|
||||
private const string SegmentKey = "Map.Segment";
|
||||
private const string IncludedPropertiesKey = "Map.IncludedProperties";
|
||||
|
||||
/// <summary>
|
||||
@@ -18,6 +19,14 @@ namespace Umbraco.Web.Models.Mapping
|
||||
return context.HasItems && context.Items.TryGetValue(CultureKey, out var obj) && obj is string s ? s : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the context segment.
|
||||
/// </summary>
|
||||
public static string GetSegment(this MapperContext context)
|
||||
{
|
||||
return context.HasItems && context.Items.TryGetValue(SegmentKey, out var obj) && obj is string s ? s : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a context culture.
|
||||
/// </summary>
|
||||
@@ -26,6 +35,14 @@ namespace Umbraco.Web.Models.Mapping
|
||||
context.Items[CultureKey] = culture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a context segment.
|
||||
/// </summary>
|
||||
public static void SetSegment(this MapperContext context, string segment)
|
||||
{
|
||||
context.Items[SegmentKey] = segment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get included properties.
|
||||
/// </summary>
|
||||
@@ -42,4 +59,4 @@ namespace Umbraco.Web.Models.Mapping
|
||||
context.Items[IncludedPropertiesKey] = properties;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
using Umbraco.Core;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class RelationMapDefinition : IMapDefinition
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IRelationService _relationService;
|
||||
|
||||
public RelationMapDefinition(IEntityService entityService, IRelationService relationService)
|
||||
{
|
||||
_entityService = entityService;
|
||||
_relationService = relationService;
|
||||
}
|
||||
|
||||
public void DefineMaps(UmbracoMapper mapper)
|
||||
{
|
||||
mapper.Define<IRelationType, RelationTypeDisplay>((source, context) => new RelationTypeDisplay(), Map);
|
||||
@@ -15,8 +26,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -Icon -Trashed -AdditionalData
|
||||
// Umbraco.Code.MapAll -Relations -ParentId -Notifications
|
||||
private static void Map(IRelationType source, RelationTypeDisplay target, MapperContext context)
|
||||
// Umbraco.Code.MapAll -ParentId -Notifications
|
||||
private void Map(IRelationType source, RelationTypeDisplay target, MapperContext context)
|
||||
{
|
||||
target.ChildObjectType = source.ChildObjectType;
|
||||
target.Id = source.Id;
|
||||
@@ -28,18 +39,32 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Udi = Udi.Create(Constants.UdiEntityType.RelationType, source.Key);
|
||||
target.Path = "-1," + source.Id;
|
||||
|
||||
// Set the "friendly" names for the parent and child object types
|
||||
target.ParentObjectTypeName = ObjectTypes.GetUmbracoObjectType(source.ParentObjectType).GetFriendlyName();
|
||||
target.ChildObjectTypeName = ObjectTypes.GetUmbracoObjectType(source.ChildObjectType).GetFriendlyName();
|
||||
// Set the "friendly" and entity names for the parent and child object types
|
||||
if (source.ParentObjectType.HasValue)
|
||||
{
|
||||
var objType = ObjectTypes.GetUmbracoObjectType(source.ParentObjectType.Value);
|
||||
target.ParentObjectTypeName = objType.GetFriendlyName();
|
||||
}
|
||||
|
||||
if (source.ChildObjectType.HasValue)
|
||||
{
|
||||
var objType = ObjectTypes.GetUmbracoObjectType(source.ChildObjectType.Value);
|
||||
target.ChildObjectTypeName = objType.GetFriendlyName();
|
||||
}
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -ParentName -ChildName
|
||||
private static void Map(IRelation source, RelationDisplay target, MapperContext context)
|
||||
private void Map(IRelation source, RelationDisplay target, MapperContext context)
|
||||
{
|
||||
target.ChildId = source.ChildId;
|
||||
target.Comment = source.Comment;
|
||||
target.CreateDate = source.CreateDate;
|
||||
target.ParentId = source.ParentId;
|
||||
|
||||
var entities = _relationService.GetEntitiesFromRelation(source);
|
||||
|
||||
target.ParentName = entities.Item1.Name;
|
||||
target.ChildName = entities.Item2.Name;
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -CreateDate -UpdateDate -DeleteDate
|
||||
|
||||
@@ -380,8 +380,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ToDictionary(x => x.Key, x => (IEnumerable<Permission>)x.ToArray());
|
||||
}
|
||||
|
||||
private static string MapContentTypeIcon(EntitySlim entity)
|
||||
=> entity is ContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null;
|
||||
private static string MapContentTypeIcon(IEntitySlim entity)
|
||||
=> entity is IContentEntitySlim contentEntity ? contentEntity.ContentTypeIcon : null;
|
||||
|
||||
private IEnumerable<EntityBasic> GetStartNodes(int[] startNodeIds, UmbracoObjectTypes objectType, string localizedKey, MapperContext context)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user