Cleanup and fix mappers
This commit is contained in:
101
src/Umbraco.Web/Models/Mapping/CommonMapper.cs
Normal file
101
src/Umbraco.Web/Models/Mapping/CommonMapper.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.ContentEditing;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class CommonMapper
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
private readonly ContentAppFactoryCollection _contentAppDefinitions;
|
||||
private readonly ILocalizedTextService _localizedTextService;
|
||||
|
||||
public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService)
|
||||
{
|
||||
_userService = userService;
|
||||
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_contentAppDefinitions = contentAppDefinitions;
|
||||
_localizedTextService = localizedTextService;
|
||||
}
|
||||
|
||||
public UserProfile GetOwner(IContentBase source, Mapper mapper)
|
||||
{
|
||||
var profile = source.GetCreatorProfile(_userService);
|
||||
return profile == null ? null : mapper.Map<IProfile, UserProfile>(profile);
|
||||
}
|
||||
|
||||
public UserProfile GetCreator(IContent source, Mapper mapper)
|
||||
{
|
||||
var profile = source.GetWriterProfile(_userService);
|
||||
return profile == null ? null : mapper.Map<IProfile, UserProfile>(profile);
|
||||
}
|
||||
|
||||
public ContentTypeBasic GetContentType(IContentBase source, Mapper mapper)
|
||||
{
|
||||
// TODO: We can resolve the UmbracoContext from the IValueResolver options!
|
||||
// OMG
|
||||
if (HttpContext.Current != null && Composing.Current.UmbracoContext != null && Composing.Current.UmbracoContext.Security.CurrentUser != null
|
||||
&& Composing.Current.UmbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
|
||||
{
|
||||
var contentType = _contentTypeBaseServiceProvider.GetContentTypeOf(source);
|
||||
var contentTypeBasic = mapper.Map<IContentTypeComposition, ContentTypeBasic>(contentType);
|
||||
|
||||
return contentTypeBasic;
|
||||
}
|
||||
//no access
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetTreeNodeUrl<TController>(IContentBase source)
|
||||
where TController : ContentTreeControllerBase
|
||||
{
|
||||
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
|
||||
if (umbracoContext == null) return null;
|
||||
|
||||
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
|
||||
return urlHelper.GetUmbracoApiService<TController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
|
||||
}
|
||||
|
||||
public string GetMemberTreeNodeUrl(IContentBase source)
|
||||
{
|
||||
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
|
||||
if (umbracoContext == null) return null;
|
||||
|
||||
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
|
||||
return urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
|
||||
}
|
||||
|
||||
public IEnumerable<ContentApp> GetContentApps(IContentBase source)
|
||||
{
|
||||
var apps = _contentAppDefinitions.GetContentAppsFor(source).ToArray();
|
||||
|
||||
// localize content app names
|
||||
foreach (var app in apps)
|
||||
{
|
||||
var localizedAppName = _localizedTextService.Localize($"apps/{app.Alias}");
|
||||
if (localizedAppName.Equals($"[{app.Alias}]", StringComparison.OrdinalIgnoreCase) == false)
|
||||
{
|
||||
app.Name = localizedAppName;
|
||||
}
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,11 +55,18 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
public void SetMaps(Mapper mapper)
|
||||
{
|
||||
mapper.Define<IContent, ContentPropertyCollectionDto>((source, context) => new ContentPropertyCollectionDto(), Map);
|
||||
mapper.Define<IContent, ContentItemDisplay>((source, context) => new ContentItemDisplay(), Map);
|
||||
mapper.Define<IContent, ContentVariantDisplay>((source, context) => new ContentVariantDisplay(), Map);
|
||||
mapper.Define<IContent, ContentItemBasic<ContentPropertyBasic>>((source, context) => new ContentItemBasic<ContentPropertyBasic>(), Map);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(IContent source, ContentPropertyCollectionDto target, MapperContext context)
|
||||
{
|
||||
target.Properties = source.Properties.Select(context.Mapper.Map<ContentPropertyDto>);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -AllowPreview -Errors -PersistedContent
|
||||
private void Map(IContent source, ContentItemDisplay target, MapperContext context)
|
||||
{
|
||||
@@ -120,7 +127,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Owner = _commonMapper.GetOwner(source, context.Mapper);
|
||||
target.ParentId = source.ParentId;
|
||||
target.Path = source.Path;
|
||||
target.Properties = context.Mapper.Map<IEnumerable<ContentPropertyBasic>>(source.Properties);
|
||||
target.Properties = source.Properties.Select(context.Mapper.Map<ContentPropertyBasic>);
|
||||
target.SortOrder = source.SortOrder;
|
||||
target.State = _basicStateMapper.Map(source, context);
|
||||
target.Trashed = source.Trashed;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// Assigns the PropertyEditor, Id, Alias and Value to the property
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual TDestination Map(Property property, TDestination dest, MapperContext context)
|
||||
public virtual void Map(Property property, TDestination dest, MapperContext context)
|
||||
{
|
||||
var editor = _propertyEditors[property.PropertyType.PropertyEditorAlias];
|
||||
if (editor == null)
|
||||
@@ -44,19 +44,16 @@ namespace Umbraco.Web.Models.Mapping
|
||||
editor = _propertyEditors[Constants.PropertyEditors.Aliases.Label];
|
||||
}
|
||||
|
||||
var result = new TDestination
|
||||
{
|
||||
Id = property.Id,
|
||||
Alias = property.Alias,
|
||||
PropertyEditor = editor,
|
||||
Editor = editor.Alias
|
||||
};
|
||||
dest.Id = property.Id;
|
||||
dest.Alias = property.Alias;
|
||||
dest.PropertyEditor = editor;
|
||||
dest.Editor = editor.Alias;
|
||||
|
||||
// if there's a set of property aliases specified, we will check if the current property's value should be mapped.
|
||||
// if it isn't one of the ones specified in 'includeProperties', we will just return the result without mapping the Value.
|
||||
var includedProperties = context.GetIncludedProperties();
|
||||
if (includedProperties != null && !includedProperties.Contains(property.Alias))
|
||||
return result;
|
||||
return;
|
||||
|
||||
//Get the culture from the context which will be set during the mapping operation for each property
|
||||
var culture = context.GetCulture();
|
||||
@@ -68,11 +65,10 @@ namespace Umbraco.Web.Models.Mapping
|
||||
//set the culture to null if it's an invariant property type
|
||||
culture = !property.PropertyType.VariesByCulture() ? null : culture;
|
||||
|
||||
result.Culture = culture;
|
||||
dest.Culture = culture;
|
||||
|
||||
// if no 'IncludeProperties' were specified or this property is set to be included - we will map the value and return.
|
||||
result.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, culture);
|
||||
return result;
|
||||
dest.Value = editor.GetValueEditor().ToEditor(property, DataTypeService, culture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
_textService = textService;
|
||||
}
|
||||
public override ContentPropertyDisplay Map(Property originalProp, ContentPropertyDisplay dest, MapperContext context)
|
||||
public override void Map(Property originalProp, ContentPropertyDisplay dest, MapperContext context)
|
||||
{
|
||||
var display = base.Map(originalProp, dest, context);
|
||||
base.Map(originalProp, dest, context);
|
||||
|
||||
var config = DataTypeService.GetDataType(originalProp.PropertyType.DataTypeId).Configuration;
|
||||
|
||||
@@ -32,37 +32,35 @@ namespace Umbraco.Web.Models.Mapping
|
||||
// - does it make any sense to use a IDataValueEditor without configuring it?
|
||||
|
||||
// configure the editor for display with configuration
|
||||
var valEditor = display.PropertyEditor.GetValueEditor(config);
|
||||
var valEditor = dest.PropertyEditor.GetValueEditor(config);
|
||||
|
||||
//set the display properties after mapping
|
||||
display.Alias = originalProp.Alias;
|
||||
display.Description = originalProp.PropertyType.Description;
|
||||
display.Label = originalProp.PropertyType.Name;
|
||||
display.HideLabel = valEditor.HideLabel;
|
||||
dest.Alias = originalProp.Alias;
|
||||
dest.Description = originalProp.PropertyType.Description;
|
||||
dest.Label = originalProp.PropertyType.Name;
|
||||
dest.HideLabel = valEditor.HideLabel;
|
||||
|
||||
//add the validation information
|
||||
display.Validation.Mandatory = originalProp.PropertyType.Mandatory;
|
||||
display.Validation.Pattern = originalProp.PropertyType.ValidationRegExp;
|
||||
dest.Validation.Mandatory = originalProp.PropertyType.Mandatory;
|
||||
dest.Validation.Pattern = originalProp.PropertyType.ValidationRegExp;
|
||||
|
||||
if (display.PropertyEditor == null)
|
||||
if (dest.PropertyEditor == null)
|
||||
{
|
||||
//display.Config = PreValueCollection.AsDictionary(preVals);
|
||||
//if there is no property editor it means that it is a legacy data type
|
||||
// we cannot support editing with that so we'll just render the readonly value view.
|
||||
display.View = "views/propertyeditors/readonlyvalue/readonlyvalue.html";
|
||||
dest.View = "views/propertyeditors/readonlyvalue/readonlyvalue.html";
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the property editor format the pre-values
|
||||
display.Config = display.PropertyEditor.GetConfigurationEditor().ToValueEditor(config);
|
||||
display.View = valEditor.View;
|
||||
dest.Config = dest.PropertyEditor.GetConfigurationEditor().ToValueEditor(config);
|
||||
dest.View = valEditor.View;
|
||||
}
|
||||
|
||||
//Translate
|
||||
display.Label = _textService.UmbracoDictionaryTranslate(display.Label);
|
||||
display.Description = _textService.UmbracoDictionaryTranslate(display.Description);
|
||||
|
||||
return display;
|
||||
dest.Label = _textService.UmbracoDictionaryTranslate(dest.Label);
|
||||
dest.Description = _textService.UmbracoDictionaryTranslate(dest.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,15 @@ namespace Umbraco.Web.Models.Mapping
|
||||
: base(dataTypeService, logger, propertyEditors)
|
||||
{ }
|
||||
|
||||
public override ContentPropertyDto Map(Property property, ContentPropertyDto dest, MapperContext context)
|
||||
public override void Map(Property property, ContentPropertyDto dest, MapperContext context)
|
||||
{
|
||||
var propertyDto = base.Map(property, dest, context);
|
||||
base.Map(property, dest, context);
|
||||
|
||||
propertyDto.IsRequired = property.PropertyType.Mandatory;
|
||||
propertyDto.ValidationRegExp = property.PropertyType.ValidationRegExp;
|
||||
propertyDto.Description = property.PropertyType.Description;
|
||||
propertyDto.Label = property.PropertyType.Name;
|
||||
propertyDto.DataType = DataTypeService.GetDataType(property.PropertyType.DataTypeId);
|
||||
|
||||
return propertyDto;
|
||||
dest.IsRequired = property.PropertyType.Mandatory;
|
||||
dest.ValidationRegExp = property.PropertyType.ValidationRegExp;
|
||||
dest.Description = property.PropertyType.Description;
|
||||
dest.Label = property.PropertyType.Name;
|
||||
dest.DataType = DataTypeService.GetDataType(property.PropertyType.DataTypeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,9 +383,12 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.AllowedAsRoot = source.AllowAsRoot;
|
||||
target.AllowedContentTypes = source.AllowedContentTypes.Select((t, i) => new ContentTypeSort(t, i));
|
||||
|
||||
target.Variations = ContentVariation.Nothing;
|
||||
if (!(target is IMemberType) && source.AllowCultureVariant)
|
||||
target.Variations |= ContentVariation.Culture;
|
||||
if (!(target is IMemberType))
|
||||
{
|
||||
target.Variations = ContentVariation.Nothing;
|
||||
if (source.AllowCultureVariant)
|
||||
target.Variations |= ContentVariation.Culture;
|
||||
}
|
||||
|
||||
// handle property groups and property types
|
||||
// note that ContentTypeSave has
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.ContentEditing;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
@@ -42,10 +34,17 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
public void SetMaps(Mapper mapper)
|
||||
{
|
||||
mapper.Define<IMedia, ContentPropertyCollectionDto>((source, context) => new ContentPropertyCollectionDto(), Map);
|
||||
mapper.Define<IMedia, MediaItemDisplay>((source, context) => new MediaItemDisplay(), Map);
|
||||
mapper.Define<IMedia, ContentItemBasic<ContentPropertyBasic>>((source, context) => new ContentItemBasic<ContentPropertyBasic>(), Map);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private static void Map(IMedia source, ContentPropertyCollectionDto target, MapperContext context)
|
||||
{
|
||||
target.Properties = source.Properties.Select(context.Mapper.Map<ContentPropertyDto>);
|
||||
}
|
||||
|
||||
// Umbraco.Code.MapAll -Properties -Errors -Edited -Updater -Alias -IsContainer
|
||||
private void Map(IMedia source, MediaItemDisplay target, MapperContext context)
|
||||
{
|
||||
@@ -85,7 +84,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Owner = _commonMapper.GetOwner(source, context.Mapper);
|
||||
target.ParentId = source.ParentId;
|
||||
target.Path = source.Path;
|
||||
target.Properties = context.Mapper.Map<IEnumerable<ContentPropertyBasic>>(source.Properties);
|
||||
target.Properties = source.Properties.Select(context.Mapper.Map<ContentPropertyBasic>);
|
||||
target.SortOrder = source.SortOrder;
|
||||
target.State = null;
|
||||
target.Trashed = source.Trashed;
|
||||
@@ -101,88 +100,4 @@ namespace Umbraco.Web.Models.Mapping
|
||||
return parent != null && (parent.ContentType.IsContainer || _mediaTypeService.HasContainerInPath(parent.Path));
|
||||
}
|
||||
}
|
||||
|
||||
// fixme temp + rename
|
||||
internal class CommonMapper
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
private readonly ContentAppFactoryCollection _contentAppDefinitions;
|
||||
private readonly ILocalizedTextService _localizedTextService;
|
||||
|
||||
public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService)
|
||||
{
|
||||
_userService = userService;
|
||||
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_contentAppDefinitions = contentAppDefinitions;
|
||||
_localizedTextService = localizedTextService;
|
||||
}
|
||||
|
||||
public UserProfile GetOwner(IContentBase source, Mapper mapper)
|
||||
{
|
||||
var profile = source.GetCreatorProfile(_userService);
|
||||
return profile == null ? null : mapper.Map<IProfile, UserProfile>(profile);
|
||||
}
|
||||
|
||||
public UserProfile GetCreator(IContent source, Mapper mapper)
|
||||
{
|
||||
var profile = source.GetWriterProfile(_userService);
|
||||
return profile == null ? null : mapper.Map<IProfile, UserProfile>(profile);
|
||||
}
|
||||
|
||||
public ContentTypeBasic GetContentType(IContentBase source, Mapper mapper)
|
||||
{
|
||||
// TODO: We can resolve the UmbracoContext from the IValueResolver options!
|
||||
// OMG
|
||||
if (HttpContext.Current != null && Composing.Current.UmbracoContext != null && Composing.Current.UmbracoContext.Security.CurrentUser != null
|
||||
&& Composing.Current.UmbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
|
||||
{
|
||||
var contentType = _contentTypeBaseServiceProvider.GetContentTypeOf(source);
|
||||
var contentTypeBasic = mapper.Map<IContentTypeComposition, ContentTypeBasic>(contentType);
|
||||
|
||||
return contentTypeBasic;
|
||||
}
|
||||
//no access
|
||||
return null;
|
||||
}
|
||||
|
||||
public string GetTreeNodeUrl<TController>(IContentBase source)
|
||||
where TController : ContentTreeControllerBase
|
||||
{
|
||||
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
|
||||
if (umbracoContext == null) return null;
|
||||
|
||||
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
|
||||
return urlHelper.GetUmbracoApiService<TController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
|
||||
}
|
||||
|
||||
public string GetMemberTreeNodeUrl(IContentBase source)
|
||||
{
|
||||
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
|
||||
if (umbracoContext == null) return null;
|
||||
|
||||
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
|
||||
return urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
|
||||
}
|
||||
|
||||
public IEnumerable<ContentApp> GetContentApps(IContentBase source)
|
||||
{
|
||||
var apps = _contentAppDefinitions.GetContentAppsFor(source).ToArray();
|
||||
|
||||
// localize content app names
|
||||
foreach (var app in apps)
|
||||
{
|
||||
var localizedAppName = _localizedTextService.Localize($"apps/{app.Alias}");
|
||||
if (localizedAppName.Equals($"[{app.Alias}]", StringComparison.OrdinalIgnoreCase) == false)
|
||||
{
|
||||
app.Name = localizedAppName;
|
||||
}
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,14 +105,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// <returns></returns>
|
||||
protected virtual List<ContentPropertyDisplay> MapProperties(IContentBase content, List<Property> properties, MapperContext context)
|
||||
{
|
||||
//we need to map this way to pass the context through, I don't like it but we'll see what AutoMapper says: https://github.com/AutoMapper/AutoMapper/issues/2588
|
||||
var result = context.Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(
|
||||
properties.OrderBy(prop => prop.PropertyType.SortOrder),
|
||||
null,
|
||||
context)
|
||||
.ToList();
|
||||
|
||||
return result;
|
||||
// must pass the context through
|
||||
return properties.OrderBy(x => x.PropertyType.SortOrder).Select(x => context.Mapper.Map<ContentPropertyDisplay>(x, context)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
mapper.Define<UserGroupSave, IUserGroup>((source, context) => new UserGroup { CreateDate = DateTime.UtcNow }, Map);
|
||||
mapper.Define<UserInvite, IUser>(Map);
|
||||
mapper.Define<IProfile, ContentEditing.UserProfile>(Map);
|
||||
mapper.Define<IProfile, ContentEditing.UserProfile>((source, context) => new ContentEditing.UserProfile(), Map);
|
||||
mapper.Define<IReadOnlyUserGroup, UserGroupBasic>((source, context) => new UserGroupBasic(), Map);
|
||||
mapper.Define<IUserGroup, UserGroupBasic>((source, context) => new UserGroupBasic(), Map);
|
||||
mapper.Define<IUserGroup, AssignedUserGroupPermissions>((source, context) => new AssignedUserGroupPermissions(), Map);
|
||||
@@ -115,8 +115,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
private void Map(UserSave source, IUser target, MapperContext context)
|
||||
{
|
||||
target.Name = source.Name;
|
||||
target.StartContentIds = source.StartContentIds;
|
||||
target.StartMediaIds = source.StartMediaIds;
|
||||
target.StartContentIds = source.StartContentIds ?? Array.Empty<int>();
|
||||
target.StartMediaIds = source.StartMediaIds ?? Array.Empty<int>();
|
||||
target.Language = source.Culture;
|
||||
target.Email = source.Email;
|
||||
target.Key = source.Key;
|
||||
|
||||
Reference in New Issue
Block a user