2018-09-11 12:33:32 +01:00
|
|
|
|
using System;
|
2019-01-03 09:27:52 +01:00
|
|
|
|
using System.Collections.Generic;
|
2018-09-11 12:33:32 +01:00
|
|
|
|
using System.Linq;
|
2017-07-19 13:42:47 +02:00
|
|
|
|
using AutoMapper;
|
|
|
|
|
|
using Umbraco.Core;
|
|
|
|
|
|
using Umbraco.Core.Models;
|
|
|
|
|
|
using Umbraco.Core.Services;
|
|
|
|
|
|
using Umbraco.Web.Models.ContentEditing;
|
2017-09-19 15:51:47 +02:00
|
|
|
|
using Umbraco.Web.Trees;
|
2017-07-19 13:42:47 +02:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Web.Models.Mapping
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Declares how model mappings for content
|
|
|
|
|
|
/// </summary>
|
2017-09-20 20:06:46 +02:00
|
|
|
|
internal class ContentMapperProfile : Profile
|
2017-07-19 13:42:47 +02:00
|
|
|
|
{
|
2018-07-16 22:32:46 +10:00
|
|
|
|
public ContentMapperProfile(
|
2018-07-18 14:34:32 +10:00
|
|
|
|
ContentUrlResolver contentUrlResolver,
|
|
|
|
|
|
ContentTreeNodeUrlResolver<IContent, ContentTreeController> contentTreeNodeUrlResolver,
|
2018-07-19 19:30:38 +10:00
|
|
|
|
TabsAndPropertiesResolver<IContent, ContentVariantDisplay> tabsAndPropertiesResolver,
|
2018-07-19 19:32:07 +10:00
|
|
|
|
ContentAppResolver contentAppResolver,
|
2018-07-16 22:32:46 +10:00
|
|
|
|
IUserService userService,
|
|
|
|
|
|
IContentService contentService,
|
|
|
|
|
|
IContentTypeService contentTypeService,
|
2019-02-01 17:16:50 +01:00
|
|
|
|
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
|
2019-02-12 08:14:21 +01:00
|
|
|
|
ILocalizationService localizationService,
|
|
|
|
|
|
ILocalizedTextService localizedTextService)
|
2017-07-19 13:42:47 +02:00
|
|
|
|
{
|
|
|
|
|
|
// create, capture, cache
|
|
|
|
|
|
var contentOwnerResolver = new OwnerResolver<IContent>(userService);
|
|
|
|
|
|
var creatorResolver = new CreatorResolver(userService);
|
2018-03-27 10:04:07 +02:00
|
|
|
|
var actionButtonsResolver = new ActionButtonsResolver(userService, contentService);
|
|
|
|
|
|
var childOfListViewResolver = new ContentChildOfListViewResolver(contentService, contentTypeService);
|
2019-02-01 17:16:50 +01:00
|
|
|
|
var contentTypeBasicResolver = new ContentTypeBasicResolver<IContent, ContentItemDisplay>(contentTypeBaseServiceProvider);
|
2019-02-12 08:14:21 +01:00
|
|
|
|
var allowedTemplatesResolver = new AllowedTemplatesResolver(contentTypeService, localizedTextService);
|
2018-03-27 10:04:07 +02:00
|
|
|
|
var defaultTemplateResolver = new DefaultTemplateResolver();
|
2018-08-16 23:30:33 +10:00
|
|
|
|
var variantResolver = new ContentVariantResolver(localizationService);
|
2018-11-14 22:31:51 +11:00
|
|
|
|
var schedPublishReleaseDateResolver = new ScheduledPublishDateResolver(ContentScheduleAction.Release);
|
|
|
|
|
|
var schedPublishExpireDateResolver = new ScheduledPublishDateResolver(ContentScheduleAction.Expire);
|
2018-11-09 16:12:08 +11:00
|
|
|
|
|
2017-07-19 13:42:47 +02:00
|
|
|
|
//FROM IContent TO ContentItemDisplay
|
|
|
|
|
|
CreateMap<IContent, ContentItemDisplay>()
|
2018-03-27 10:04:07 +02:00
|
|
|
|
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, src.Key)))
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.Owner, opt => opt.MapFrom(src => contentOwnerResolver.Resolve(src)))
|
|
|
|
|
|
.ForMember(dest => dest.Updater, opt => opt.MapFrom(src => creatorResolver.Resolve(src)))
|
|
|
|
|
|
.ForMember(dest => dest.Variants, opt => opt.MapFrom(variantResolver))
|
|
|
|
|
|
.ForMember(dest => dest.ContentApps, opt => opt.MapFrom(contentAppResolver))
|
2017-07-19 13:42:47 +02:00
|
|
|
|
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon))
|
|
|
|
|
|
.ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias))
|
2019-02-12 08:14:21 +01:00
|
|
|
|
.ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(src => localizedTextService.UmbracoDictionaryTranslate(src.ContentType.Name)))
|
2017-07-19 13:42:47 +02:00
|
|
|
|
.ForMember(dest => dest.IsContainer, opt => opt.MapFrom(src => src.ContentType.IsContainer))
|
2019-01-15 15:12:59 +01:00
|
|
|
|
.ForMember(dest => dest.IsElement, opt => opt.MapFrom(src => src.ContentType.IsElement))
|
2017-11-15 08:53:20 +01:00
|
|
|
|
.ForMember(dest => dest.IsBlueprint, opt => opt.MapFrom(src => src.Blueprint))
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.IsChildOfListView, opt => opt.MapFrom(childOfListViewResolver))
|
2017-07-19 13:42:47 +02:00
|
|
|
|
.ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed))
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.TemplateAlias, opt => opt.MapFrom(defaultTemplateResolver))
|
|
|
|
|
|
.ForMember(dest => dest.Urls, opt => opt.MapFrom(contentUrlResolver))
|
2017-07-19 13:42:47 +02:00
|
|
|
|
.ForMember(dest => dest.AllowPreview, opt => opt.Ignore())
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.TreeNodeUrl, opt => opt.MapFrom(contentTreeNodeUrlResolver))
|
2017-07-19 13:42:47 +02:00
|
|
|
|
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
|
|
|
|
|
|
.ForMember(dest => dest.Errors, opt => opt.Ignore())
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.DocumentType, opt => opt.MapFrom(contentTypeBasicResolver))
|
|
|
|
|
|
.ForMember(dest => dest.AllowedTemplates, opt => opt.MapFrom(allowedTemplatesResolver))
|
|
|
|
|
|
.ForMember(dest => dest.AllowedActions, opt => opt.MapFrom(src => actionButtonsResolver.Resolve(src)))
|
2018-07-13 12:45:04 +10:00
|
|
|
|
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore());
|
|
|
|
|
|
|
|
|
|
|
|
CreateMap<IContent, ContentVariantDisplay>()
|
|
|
|
|
|
.ForMember(dest => dest.PublishDate, opt => opt.MapFrom(src => src.PublishDate))
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.ReleaseDate, opt => opt.MapFrom(schedPublishReleaseDateResolver))
|
|
|
|
|
|
.ForMember(dest => dest.ExpireDate, opt => opt.MapFrom(schedPublishExpireDateResolver))
|
2018-07-16 20:24:49 +10:00
|
|
|
|
.ForMember(dest => dest.Segment, opt => opt.Ignore())
|
|
|
|
|
|
.ForMember(dest => dest.Language, opt => opt.Ignore())
|
2018-09-07 11:34:55 +02:00
|
|
|
|
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.State, opt => opt.MapFrom<ContentSavedStateResolver<ContentPropertyDisplay>>())
|
|
|
|
|
|
.ForMember(dest => dest.Tabs, opt => opt.MapFrom(tabsAndPropertiesResolver));
|
2017-07-19 13:42:47 +02:00
|
|
|
|
|
|
|
|
|
|
//FROM IContent TO ContentItemBasic<ContentPropertyBasic, IContent>
|
2018-08-01 15:40:54 +10:00
|
|
|
|
CreateMap<IContent, ContentItemBasic<ContentPropertyBasic>>()
|
2017-09-19 15:51:47 +02:00
|
|
|
|
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src =>
|
2018-03-27 10:04:07 +02:00
|
|
|
|
Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, src.Key)))
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.Owner, opt => opt.MapFrom(src => contentOwnerResolver.Resolve(src)))
|
|
|
|
|
|
.ForMember(dest => dest.Updater, opt => opt.MapFrom(src => creatorResolver.Resolve(src)))
|
2017-07-19 13:42:47 +02:00
|
|
|
|
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon))
|
|
|
|
|
|
.ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed))
|
|
|
|
|
|
.ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias))
|
2018-01-29 19:23:25 +01:00
|
|
|
|
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
2018-09-10 09:09:24 +01:00
|
|
|
|
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
|
2019-02-06 21:14:50 +11:00
|
|
|
|
.ForMember(dest => dest.UpdateDate, opt => opt.MapFrom<UpdateDateResolver>())
|
|
|
|
|
|
.ForMember(dest => dest.Name, opt => opt.MapFrom<NameResolver>())
|
|
|
|
|
|
.ForMember(dest => dest.State, opt => opt.MapFrom<ContentBasicSavedStateResolver<ContentPropertyBasic>>())
|
2018-11-01 11:29:16 +00:00
|
|
|
|
.ForMember(dest => dest.VariesByCulture, opt => opt.MapFrom(src => src.ContentType.VariesByCulture()));
|
2017-07-19 13:42:47 +02:00
|
|
|
|
|
2018-08-01 16:46:13 +10:00
|
|
|
|
//FROM IContent TO ContentPropertyCollectionDto
|
|
|
|
|
|
//NOTE: the property mapping for cultures relies on a culture being set in the mapping context
|
|
|
|
|
|
CreateMap<IContent, ContentPropertyCollectionDto>();
|
2017-07-19 13:42:47 +02:00
|
|
|
|
}
|
2018-09-10 09:09:24 +01:00
|
|
|
|
|
2018-09-14 10:08:09 +10:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Resolves the update date for a content item/content variant
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private class UpdateDateResolver : IValueResolver<IContent, ContentItemBasic<ContentPropertyBasic>, DateTime>
|
2018-09-12 12:08:51 +01:00
|
|
|
|
{
|
2018-09-14 10:08:09 +10:00
|
|
|
|
public DateTime Resolve(IContent source, ContentItemBasic<ContentPropertyBasic> destination, DateTime destMember, ResolutionContext context)
|
2018-09-12 12:08:51 +01:00
|
|
|
|
{
|
2018-09-17 13:19:24 +02:00
|
|
|
|
// invariant = global date
|
|
|
|
|
|
if (!source.ContentType.VariesByCulture()) return source.UpdateDate;
|
2018-09-12 12:08:51 +01:00
|
|
|
|
|
2018-09-17 13:19:24 +02:00
|
|
|
|
// variant = depends on culture
|
|
|
|
|
|
var culture = context.Options.GetCulture();
|
2018-09-12 12:08:51 +01:00
|
|
|
|
|
2018-09-17 13:19:24 +02:00
|
|
|
|
// 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.");
|
2018-09-13 12:07:33 +01:00
|
|
|
|
|
2018-09-17 13:19:24 +02:00
|
|
|
|
// if we don't have a date 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 date
|
2018-09-25 18:05:14 +02:00
|
|
|
|
var date = source.GetUpdateDate(culture);
|
2018-09-17 13:19:24 +02:00
|
|
|
|
return date ?? source.UpdateDate;
|
2018-09-14 10:08:09 +10:00
|
|
|
|
}
|
2018-09-11 12:33:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-09-14 10:08:09 +10:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Resolves the name for a content item/content variant
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private class NameResolver : IValueResolver<IContent, ContentItemBasic<ContentPropertyBasic>, string>
|
2018-09-11 12:33:32 +01:00
|
|
|
|
{
|
2018-09-14 10:08:09 +10:00
|
|
|
|
public string Resolve(IContent source, ContentItemBasic<ContentPropertyBasic> destination, string destMember, ResolutionContext context)
|
|
|
|
|
|
{
|
2018-09-17 13:19:24 +02:00
|
|
|
|
// invariant = only 1 name
|
|
|
|
|
|
if (!source.ContentType.VariesByCulture()) return source.Name;
|
|
|
|
|
|
|
|
|
|
|
|
// variant = depends on culture
|
|
|
|
|
|
var culture = context.Options.GetCulture();
|
2018-09-13 12:07:33 +01:00
|
|
|
|
|
2018-09-17 13:19:24 +02:00
|
|
|
|
// 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.");
|
2018-09-14 10:08:09 +10:00
|
|
|
|
|
2018-09-17 13:19:24 +02:00
|
|
|
|
// 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
|
2019-02-09 18:42:55 +01:00
|
|
|
|
return source.CultureInfos.TryGetValue(culture, out var name) && !name.Name.IsNullOrWhiteSpace() ? name.Name : $"({source.Name})";
|
2018-09-14 10:08:09 +10:00
|
|
|
|
}
|
2018-09-11 12:33:32 +01:00
|
|
|
|
}
|
2019-01-03 09:27:52 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private class AllowedTemplatesResolver : IValueResolver<IContent, ContentItemDisplay, IDictionary<string, string>>
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly IContentTypeService _contentTypeService;
|
2019-02-12 08:14:21 +01:00
|
|
|
|
private readonly ILocalizedTextService _localizedTextService;
|
2019-01-03 09:27:52 +01:00
|
|
|
|
|
2019-02-12 08:14:21 +01:00
|
|
|
|
public AllowedTemplatesResolver(IContentTypeService contentTypeService, ILocalizedTextService localizedTextService)
|
2019-01-03 09:27:52 +01:00
|
|
|
|
{
|
|
|
|
|
|
_contentTypeService = contentTypeService;
|
2019-02-12 08:14:21 +01:00
|
|
|
|
_localizedTextService = localizedTextService;
|
2019-01-03 09:27:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public IDictionary<string, string> Resolve(IContent source, ContentItemDisplay destination, IDictionary<string, string> destMember, ResolutionContext context)
|
|
|
|
|
|
{
|
|
|
|
|
|
var contentType = _contentTypeService.Get(source.ContentTypeId);
|
|
|
|
|
|
|
|
|
|
|
|
return contentType.AllowedTemplates
|
|
|
|
|
|
.Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false)
|
2019-02-12 08:14:21 +01:00
|
|
|
|
.ToDictionary(t => t.Alias, t => _localizedTextService.UmbracoDictionaryTranslate(t.Name));
|
2019-01-03 09:27:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-07-20 11:21:28 +02:00
|
|
|
|
}
|