using System; using System.Collections.Generic; using System.Globalization; using Examine; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.Entities; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Infrastructure.Examine; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Models.Mapping { public class EntityMapDefinition : IMapDefinition { public void DefineMaps(IUmbracoMapper mapper) { mapper.Define((source, context) => new EntityBasic(), Map); mapper.Define((source, context) => new EntityBasic(), Map); mapper.Define((source, context) => new EntityBasic(), Map); mapper.Define((source, context) => new EntityBasic(), Map); mapper.Define((source, context) => new EntityBasic(), Map); mapper.Define((source, context) => new ContentTypeSort(), Map); mapper.Define((source, context) => new EntityBasic(), Map); mapper.Define((source, context) => new SearchResultEntity(), Map); mapper.Define((source, context) => new SearchResultEntity(), Map); mapper.Define>((source, context) => context.MapEnumerable(source)); mapper.Define, IEnumerable>((source, context) => context.MapEnumerable(source)); } // Umbraco.Code.MapAll -Alias private static void Map(IEntitySlim source, EntityBasic target, MapperContext context) { target.Icon = MapContentTypeIcon(source); target.Id = source.Id; target.Key = source.Key; target.Name = MapName(source, context); target.ParentId = source.ParentId; target.Path = source.Path; target.Trashed = source.Trashed; target.Udi = Udi.Create(ObjectTypes.GetUdiType(source.NodeObjectType), source.Key); if (source is IContentEntitySlim contentSlim) { source.AdditionalData!["ContentTypeAlias"] = contentSlim.ContentTypeAlias; } if (source is IDocumentEntitySlim documentSlim) { source.AdditionalData!["IsPublished"] = documentSlim.Published; } if (source is IMediaEntitySlim mediaSlim) { if (source.AdditionalData is not null) { //pass UpdateDate for MediaPicker ListView ordering source.AdditionalData["UpdateDate"] = mediaSlim.UpdateDate; source.AdditionalData["MediaPath"] = mediaSlim.MediaPath; } } if (source.AdditionalData is not null) { // NOTE: we're mapping the objects in AdditionalData by object reference here. // it works fine for now, but it's something to keep in mind in the future foreach(var kvp in source.AdditionalData) { if (kvp.Value is not null) { target.AdditionalData[kvp.Key] = kvp.Value; } } } target.AdditionalData.Add("IsContainer", source.IsContainer); } // Umbraco.Code.MapAll -Udi -Trashed private static void Map(PropertyType source, EntityBasic target, MapperContext context) { target.Alias = source.Alias; target.Icon = "icon-box"; target.Id = source.Id; target.Key = source.Key; target.Name = source.Name; target.ParentId = -1; target.Path = ""; } // Umbraco.Code.MapAll -Udi -Trashed private static void Map(PropertyGroup source, EntityBasic target, MapperContext context) { target.Alias = source.Alias; target.Icon = "icon-tab"; target.Id = source.Id; target.Key = source.Key; target.Name = source.Name; target.ParentId = -1; target.Path = ""; } // Umbraco.Code.MapAll -Udi -Trashed private static void Map(IUser source, EntityBasic target, MapperContext context) { target.Alias = source.Username; target.Icon = Constants.Icons.User; target.Id = source.Id; target.Key = source.Key; target.Name = source.Name; target.ParentId = -1; target.Path = ""; } // Umbraco.Code.MapAll -Trashed private static void Map(ITemplate source, EntityBasic target, MapperContext context) { target.Alias = source.Alias; target.Icon = Constants.Icons.Template; target.Id = source.Id; target.Key = source.Key; target.Name = source.Name; target.ParentId = -1; target.Path = source.Path; target.Udi = Udi.Create(Constants.UdiEntityType.Template, source.Key); } // Umbraco.Code.MapAll -SortOrder private static void Map(EntityBasic source, ContentTypeSort target, MapperContext context) { target.Alias = source.Alias; target.Id = new Lazy(() => Convert.ToInt32(source.Id)); } // Umbraco.Code.MapAll -Trashed private static void Map(IContentTypeComposition source, EntityBasic target, MapperContext context) { target.Alias = source.Alias; target.Icon = source.Icon; target.Id = source.Id; target.Key = source.Key; target.Name = source.Name; target.ParentId = source.ParentId; target.Path = source.Path; target.Udi = ContentTypeMapDefinition.MapContentTypeUdi(source); } // Umbraco.Code.MapAll -Trashed -Alias -Score private static void Map(EntitySlim source, SearchResultEntity target, MapperContext context) { target.Icon = MapContentTypeIcon(source); target.Id = source.Id; target.Key = source.Key; target.Name = source.Name; target.ParentId = source.ParentId; target.Path = source.Path; target.Udi = Udi.Create(ObjectTypes.GetUdiType(source.NodeObjectType), source.Key); if (target.Icon.IsNullOrWhiteSpace()) { if (source.NodeObjectType == Constants.ObjectTypes.Document) target.Icon = Constants.Icons.Content; if (source.NodeObjectType == Constants.ObjectTypes.Media) target.Icon = Constants.Icons.Content; if (source.NodeObjectType == Constants.ObjectTypes.Member) target.Icon = Constants.Icons.Member; else if (source.NodeObjectType == Constants.ObjectTypes.DataType) target.Icon = Constants.Icons.DataType; else if (source.NodeObjectType == Constants.ObjectTypes.DocumentType) target.Icon = Constants.Icons.ContentType; else if (source.NodeObjectType == Constants.ObjectTypes.MediaType) target.Icon = Constants.Icons.MediaType; else if (source.NodeObjectType == Constants.ObjectTypes.MemberType) target.Icon = Constants.Icons.MemberType; else if (source.NodeObjectType == Constants.ObjectTypes.TemplateType) target.Icon = Constants.Icons.Template; } } // Umbraco.Code.MapAll -Alias -Trashed private static void Map(ISearchResult source, SearchResultEntity target, MapperContext context) { target.Id = source.Id; target.Score = source.Score; // TODO: Properly map this (not aftermap) //get the icon if there is one target.Icon = source.Values.ContainsKey(UmbracoExamineFieldNames.IconFieldName) ? source.Values[UmbracoExamineFieldNames.IconFieldName] : Constants.Icons.DefaultIcon; target.Name = source.Values.ContainsKey(UmbracoExamineFieldNames.NodeNameFieldName) ? source.Values[UmbracoExamineFieldNames.NodeNameFieldName] : "[no name]"; var culture = context.GetCulture()?.ToLowerInvariant(); if(culture.IsNullOrWhiteSpace() == false) { target.Name = source.Values.ContainsKey($"nodeName_{culture}") ? source.Values[$"nodeName_{culture}"] : target.Name; } if (source.Values.TryGetValue(UmbracoExamineFieldNames.UmbracoFileFieldName, out var umbracoFile) && umbracoFile.IsNullOrWhiteSpace() == false) { if (umbracoFile != null) { target.Name = $"{target.Name} ({umbracoFile})"; } } if (source.Values.ContainsKey(UmbracoExamineFieldNames.NodeKeyFieldName)) { if (Guid.TryParse(source.Values[UmbracoExamineFieldNames.NodeKeyFieldName], out var key)) { target.Key = key; //need to set the UDI if (source.Values.ContainsKey(ExamineFieldNames.CategoryFieldName)) { switch (source.Values[ExamineFieldNames.CategoryFieldName]) { case IndexTypes.Member: target.Udi = new GuidUdi(Constants.UdiEntityType.Member, target.Key); break; case IndexTypes.Content: target.Udi = new GuidUdi(Constants.UdiEntityType.Document, target.Key); break; case IndexTypes.Media: target.Udi = new GuidUdi(Constants.UdiEntityType.Media, target.Key); break; } } } } if (source.Values.ContainsKey("parentID")) { if (int.TryParse(source.Values["parentID"], NumberStyles.Integer, CultureInfo.InvariantCulture,out var parentId)) { target.ParentId = parentId; } else { target.ParentId = -1; } } target.Path = source.Values.ContainsKey(UmbracoExamineFieldNames.IndexPathFieldName) ? source.Values[UmbracoExamineFieldNames.IndexPathFieldName] : ""; if (source.Values.ContainsKey(ExamineFieldNames.ItemTypeFieldName)) { target.AdditionalData.Add("contentType", source.Values[ExamineFieldNames.ItemTypeFieldName]); } } private static string? MapContentTypeIcon(IEntitySlim entity) { switch (entity) { case IMemberEntitySlim memberEntity: return memberEntity.ContentTypeIcon; case IContentEntitySlim contentEntity: // NOTE: this case covers both content and media entities return contentEntity.ContentTypeIcon; } return null; } private static string MapName(IEntitySlim source, MapperContext context) { if (!(source is DocumentEntitySlim doc)) return source.Name; // invariant = only 1 name if (!doc.Variations.VariesByCulture()) return source.Name; // variant = depends on culture var culture = context.GetCulture(); // if there's no culture here, the issue is somewhere else (UI, whatever) - throw! if (culture == null) //throw new InvalidOperationException("Missing culture in mapping options."); // TODO: we should throw, but this is used in various places that won't set a culture yet return source.Name; // if we don't have a name for a culture, it means the culture is not available, and // hey we should probably not be mapping it, but it's too late, return a fallback name return doc.CultureNames.TryGetValue(culture, out var name) && !name.IsNullOrWhiteSpace() ? name : $"({source.Name})"; } } }