Gets the IsSensitive property mapped to the display object and changes the property output to show that the field contains sensitive data. Refactors the TabsAndPropertiesResolver and simplifies it a lot which also allows us to pass in an UmbracoContext which we'll need in order to determine a user's rights, etc... Refactors how the TreeNodeUrls are mapped and they now use a proper mapper. This now means we do much less in AfterMap

This commit is contained in:
Shannon
2018-01-25 14:14:12 -07:00
parent b49db0e941
commit 64628c0a9d
19 changed files with 458 additions and 288 deletions

View File

@@ -76,11 +76,11 @@ namespace Umbraco.Core.Models
/// <returns></returns> /// <returns></returns>
public bool MemberCanEditProperty(string propertyTypeAlias) public bool MemberCanEditProperty(string propertyTypeAlias)
{ {
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias)) MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
{ {
return MemberTypePropertyTypes[propertyTypeAlias].IsEditable; return propertyProfile.IsEditable;
} }
return false; return false;
} }
@@ -91,11 +91,11 @@ namespace Umbraco.Core.Models
/// <returns></returns> /// <returns></returns>
public bool MemberCanViewProperty(string propertyTypeAlias) public bool MemberCanViewProperty(string propertyTypeAlias)
{ {
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias)) MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
{ {
return MemberTypePropertyTypes[propertyTypeAlias].IsVisible; return propertyProfile.IsVisible;
} }
return false; return false;
} }
@@ -106,11 +106,11 @@ namespace Umbraco.Core.Models
/// <returns></returns> /// <returns></returns>
public bool IsSensitiveProperty(string propertyTypeAlias) public bool IsSensitiveProperty(string propertyTypeAlias)
{ {
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias)) MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
{ {
return MemberTypePropertyTypes[propertyTypeAlias].IsSensitive; return propertyProfile.IsSensitive;
} }
return false; return false;
} }
@@ -121,9 +121,10 @@ namespace Umbraco.Core.Models
/// <param name="value">Boolean value, true or false</param> /// <param name="value">Boolean value, true or false</param>
public void SetMemberCanEditProperty(string propertyTypeAlias, bool value) public void SetMemberCanEditProperty(string propertyTypeAlias, bool value)
{ {
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias)) MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
{ {
MemberTypePropertyTypes[propertyTypeAlias].IsEditable = value; propertyProfile.IsEditable = value;
} }
else else
{ {
@@ -139,9 +140,10 @@ namespace Umbraco.Core.Models
/// <param name="value">Boolean value, true or false</param> /// <param name="value">Boolean value, true or false</param>
public void SetMemberCanViewProperty(string propertyTypeAlias, bool value) public void SetMemberCanViewProperty(string propertyTypeAlias, bool value)
{ {
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias)) MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
{ {
MemberTypePropertyTypes[propertyTypeAlias].IsVisible = value; propertyProfile.IsVisible = value;
} }
else else
{ {
@@ -157,9 +159,10 @@ namespace Umbraco.Core.Models
/// <param name="value">Boolean value, true or false</param> /// <param name="value">Boolean value, true or false</param>
public void SetIsSensitiveProperty(string propertyTypeAlias, bool value) public void SetIsSensitiveProperty(string propertyTypeAlias, bool value)
{ {
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias)) MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
{ {
MemberTypePropertyTypes[propertyTypeAlias].IsSensitive = value; propertyProfile.IsSensitive = value;
} }
else else
{ {

View File

@@ -57,7 +57,7 @@ namespace Umbraco.Core.Persistence.Factories
//Add the standard PropertyType to the current list //Add the standard PropertyType to the current list
propertyTypes.Add(standardPropertyType.Value); propertyTypes.Add(standardPropertyType.Value);
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType //Internal dictionary for adding "MemberCanEdit", "VisibleOnProfile", "IsSensitive" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(standardPropertyType.Key, memberType.MemberTypePropertyTypes.Add(standardPropertyType.Key,
new MemberTypePropertyProfileAccess(false, false, false)); new MemberTypePropertyProfileAccess(false, false, false));
} }

View File

@@ -90,7 +90,8 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Select("umbracoNode.*", "cmsContentType.*", "cmsPropertyType.id AS PropertyTypeId", "cmsPropertyType.Alias", sql.Select("umbracoNode.*", "cmsContentType.*", "cmsPropertyType.id AS PropertyTypeId", "cmsPropertyType.Alias",
"cmsPropertyType.Name", "cmsPropertyType.Description", "cmsPropertyType.mandatory", "cmsPropertyType.UniqueID", "cmsPropertyType.Name", "cmsPropertyType.Description", "cmsPropertyType.mandatory", "cmsPropertyType.UniqueID",
"cmsPropertyType.validationRegExp", "cmsPropertyType.dataTypeId", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder", "cmsPropertyType.validationRegExp", "cmsPropertyType.dataTypeId", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder",
"cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId", "cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile", "cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId",
"cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile", "cmsMemberType.isSensitive",
"cmsDataType.propertyEditorAlias", "cmsDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId", "cmsDataType.propertyEditorAlias", "cmsDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId",
"cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.uniqueID AS PropertyGroupUniqueID", "cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.uniqueID AS PropertyGroupUniqueID",
"cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder", "cmsPropertyTypeGroup.contenttypeNodeId") "cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder", "cmsPropertyTypeGroup.contenttypeNodeId")
@@ -362,4 +363,4 @@ namespace Umbraco.Core.Persistence.Repositories
return Attempt<Guid>.Fail(propertyEditor); return Attempt<Guid>.Fail(propertyEditor);
} }
} }
} }

View File

@@ -221,6 +221,7 @@
<key alias="addTextBox">Add another text box</key> <key alias="addTextBox">Add another text box</key>
<key alias="removeTextBox">Remove this text box</key> <key alias="removeTextBox">Remove this text box</key>
<key alias="contentRoot">Content root</key> <key alias="contentRoot">Content root</key>
<key alias="isSensitiveValue">Your user permissions do not allow access to this property</key>
</area> </area>
<area alias="blueprints"> <area alias="blueprints">
<key alias="createBlueprintFrom">Create a new Content Template from '%0%'</key> <key alias="createBlueprintFrom">Create a new Content Template from '%0%'</key>

View File

@@ -227,6 +227,7 @@
<key alias="addTextBox">Add another text box</key> <key alias="addTextBox">Add another text box</key>
<key alias="removeTextBox">Remove this text box</key> <key alias="removeTextBox">Remove this text box</key>
<key alias="contentRoot">Content root</key> <key alias="contentRoot">Content root</key>
<key alias="isSensitiveValue">Your user permissions do not allow access to this property</key>
</area> </area>
<area alias="blueprints"> <area alias="blueprints">
<key alias="createBlueprintFrom">Create a new Content Template from '%0%'</key> <key alias="createBlueprintFrom">Create a new Content Template from '%0%'</key>

View File

@@ -34,6 +34,9 @@ namespace Umbraco.Web.Models.ContentEditing
public bool HideLabel { get; set; } public bool HideLabel { get; set; }
[DataMember(Name = "validation")] [DataMember(Name = "validation")]
public PropertyTypeValidation Validation { get; set; } public PropertyTypeValidation Validation { get; set; }
[DataMember(Name = "isSensitiveData")]
public bool IsSensitive { get; set; }
} }
} }

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoMapper;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models.Mapping
{
internal static class AutoMapperExtensions
{
/// <summary>
/// This maps an object and passes in the current <see cref="UmbracoContext"/> so the mapping logic can use it
/// </summary>
/// <typeparam name="TIn"></typeparam>
/// <typeparam name="TOut"></typeparam>
/// <param name="obj"></param>
/// <param name="umbCtx"></param>
/// <returns></returns>
public static TOut MapWithUmbracoContext<TIn, TOut>(TIn obj, UmbracoContext umbCtx)
{
return Mapper.Map<TIn, TOut>(obj, opt => opt.Items["UmbracoContext"] = umbCtx);
}
/// <summary>
/// Returns an <see cref="UmbracoContext"/> from the mapping options
/// </summary>
/// <param name="res"></param>
/// <returns></returns>
/// <remarks>
/// If an UmbracoContext is not found in the mapping options, it will try to retrieve it from the singleton
/// </remarks>
public static UmbracoContext GetUmbracoContext(this ResolutionResult res)
{
//get the context from the mapping options set during a mapping operation
object umbCtx;
if (res.Context.Options.Items.TryGetValue("UmbracoContext", out umbCtx))
{
var umbracoContext = umbCtx as UmbracoContext;
if (umbracoContext != null) return umbracoContext;
}
//return the singleton (this could be null)
return UmbracoContext.Current;
}
}
}

View File

@@ -47,7 +47,7 @@ namespace Umbraco.Web.Models.Mapping
: content.GetContentUrls(UmbracoContext.Current))) : content.GetContentUrls(UmbracoContext.Current)))
.ForMember(display => display.Properties, expression => expression.Ignore()) .ForMember(display => display.Properties, expression => expression.Ignore())
.ForMember(display => display.AllowPreview, expression => expression.Ignore()) .ForMember(display => display.AllowPreview, expression => expression.Ignore())
.ForMember(display => display.TreeNodeUrl, expression => expression.Ignore()) .ForMember(display => display.TreeNodeUrl, opt => opt.ResolveUsing(new ContentTreeNodeUrlResolver<IContent, ContentTreeController>()))
.ForMember(display => display.Notifications, expression => expression.Ignore()) .ForMember(display => display.Notifications, expression => expression.Ignore())
.ForMember(display => display.Errors, expression => expression.Ignore()) .ForMember(display => display.Errors, expression => expression.Ignore())
.ForMember(display => display.Alias, expression => expression.Ignore()) .ForMember(display => display.Alias, expression => expression.Ignore())
@@ -101,16 +101,9 @@ namespace Umbraco.Web.Models.Mapping
ILocalizedTextService localizedText, IContentTypeService contentTypeService) ILocalizedTextService localizedText, IContentTypeService contentTypeService)
{ {
// map the IsChildOfListView (this is actually if it is a descendant of a list view!) // map the IsChildOfListView (this is actually if it is a descendant of a list view!)
//TODO: STOP using these extension methods, they are not testable and require singletons to be setup
var parent = content.Parent(); var parent = content.Parent();
display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path)); display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path));
//map the tree node url
if (HttpContext.Current != null)
{
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
var url = urlHelper.GetUmbracoApiService<ContentTreeController>(controller => controller.GetTreeNode(display.Id.ToString(), null));
display.TreeNodeUrl = url;
}
//set default template if template isn't set //set default template if template isn't set
if (string.IsNullOrEmpty(display.TemplateAlias)) if (string.IsNullOrEmpty(display.TemplateAlias))
@@ -122,8 +115,6 @@ namespace Umbraco.Web.Models.Mapping
{ {
TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, localizedText); TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, localizedText);
} }
TabsAndPropertiesResolver.MapGenericProperties(content, display, localizedText);
} }
/// <summary> /// <summary>
@@ -134,9 +125,7 @@ namespace Umbraco.Web.Models.Mapping
{ {
protected override ContentTypeBasic ResolveCore(IContent source) protected override ContentTypeBasic ResolveCore(IContent source)
{ {
//TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons //TODO: We can resolve the UmbracoContext from the IValueResolver options!
//If this is a web request and there's a user signed in and the
// user has access to the settings section, we will
if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings))) && UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{ {
@@ -194,4 +183,4 @@ namespace Umbraco.Web.Models.Mapping
} }
} }
} }
} }

View File

@@ -16,9 +16,9 @@ namespace Umbraco.Web.Models.Mapping
internal class ContentPropertyBasicConverter<T> : TypeConverter<Property, T> internal class ContentPropertyBasicConverter<T> : TypeConverter<Property, T>
where T : ContentPropertyBasic, new() where T : ContentPropertyBasic, new()
{ {
protected Lazy<IDataTypeService> DataTypeService { get; private set; } protected IDataTypeService DataTypeService { get; private set; }
public ContentPropertyBasicConverter(Lazy<IDataTypeService> dataTypeService) public ContentPropertyBasicConverter(IDataTypeService dataTypeService)
{ {
DataTypeService = dataTypeService; DataTypeService = dataTypeService;
} }
@@ -42,7 +42,7 @@ namespace Umbraco.Web.Models.Mapping
var result = new T var result = new T
{ {
Id = property.Id, Id = property.Id,
Value = editor.ValueEditor.ConvertDbToEditor(property, property.PropertyType, DataTypeService.Value), Value = editor.ValueEditor.ConvertDbToEditor(property, property.PropertyType, DataTypeService),
Alias = property.Alias, Alias = property.Alias,
PropertyEditor = editor, PropertyEditor = editor,
Editor = editor.Alias Editor = editor.Alias
@@ -51,4 +51,4 @@ namespace Umbraco.Web.Models.Mapping
return result; return result;
} }
} }
} }

View File

@@ -13,17 +13,19 @@ namespace Umbraco.Web.Models.Mapping
/// </summary> /// </summary>
internal class ContentPropertyDisplayConverter : ContentPropertyBasicConverter<ContentPropertyDisplay> internal class ContentPropertyDisplayConverter : ContentPropertyBasicConverter<ContentPropertyDisplay>
{ {
public ContentPropertyDisplayConverter(Lazy<IDataTypeService> dataTypeService) private readonly ILocalizedTextService _textService;
public ContentPropertyDisplayConverter(IDataTypeService dataTypeService, ILocalizedTextService textService)
: base(dataTypeService) : base(dataTypeService)
{ {
_textService = textService;
} }
protected override ContentPropertyDisplay ConvertCore(Property originalProp) protected override ContentPropertyDisplay ConvertCore(Property originalProp)
{ {
var display = base.ConvertCore(originalProp); var display = base.ConvertCore(originalProp);
var dataTypeService = DataTypeService.Value; var dataTypeService = DataTypeService;
var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(originalProp.PropertyType.DataTypeDefinitionId); var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(originalProp.PropertyType.DataTypeDefinitionId);
//configure the editor for display with the pre-values //configure the editor for display with the pre-values
@@ -54,7 +56,11 @@ namespace Umbraco.Web.Models.Mapping
display.View = valEditor.View; display.View = valEditor.View;
} }
//Translate
display.Label = _textService.UmbracoDictionaryTranslate(display.Label);
display.Description = _textService.UmbracoDictionaryTranslate(display.Description);
return display; return display;
} }
} }
} }

View File

@@ -12,7 +12,7 @@ namespace Umbraco.Web.Models.Mapping
/// </summary> /// </summary>
internal class ContentPropertyDtoConverter : ContentPropertyBasicConverter<ContentPropertyDto> internal class ContentPropertyDtoConverter : ContentPropertyBasicConverter<ContentPropertyDto>
{ {
public ContentPropertyDtoConverter(Lazy<IDataTypeService> dataTypeService) public ContentPropertyDtoConverter(IDataTypeService dataTypeService)
: base(dataTypeService) : base(dataTypeService)
{ {
} }
@@ -21,7 +21,7 @@ namespace Umbraco.Web.Models.Mapping
{ {
var propertyDto = base.ConvertCore(originalProperty); var propertyDto = base.ConvertCore(originalProperty);
var dataTypeService = DataTypeService.Value; var dataTypeService = DataTypeService;
propertyDto.IsRequired = originalProperty.PropertyType.Mandatory; propertyDto.IsRequired = originalProperty.PropertyType.Mandatory;
propertyDto.ValidationRegExp = originalProperty.PropertyType.ValidationRegExp; propertyDto.ValidationRegExp = originalProperty.PropertyType.ValidationRegExp;
@@ -35,4 +35,4 @@ namespace Umbraco.Web.Models.Mapping
return propertyDto; return propertyDto;
} }
} }
} }

View File

@@ -16,8 +16,6 @@ namespace Umbraco.Web.Models.Mapping
{ {
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext) public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
{ {
var lazyDataTypeService = new Lazy<IDataTypeService>(() => applicationContext.Services.DataTypeService);
//FROM Property TO ContentPropertyBasic //FROM Property TO ContentPropertyBasic
config.CreateMap<PropertyGroup, Tab<ContentPropertyDisplay>>() config.CreateMap<PropertyGroup, Tab<ContentPropertyDisplay>>()
.ForMember(tab => tab.Label, expression => expression.MapFrom(@group => @group.Name)) .ForMember(tab => tab.Label, expression => expression.MapFrom(@group => @group.Name))
@@ -27,15 +25,15 @@ namespace Umbraco.Web.Models.Mapping
//FROM Property TO ContentPropertyBasic //FROM Property TO ContentPropertyBasic
config.CreateMap<Property, ContentPropertyBasic>() config.CreateMap<Property, ContentPropertyBasic>()
.ConvertUsing(new ContentPropertyBasicConverter<ContentPropertyBasic>(lazyDataTypeService)); .ConvertUsing(new ContentPropertyBasicConverter<ContentPropertyBasic>(applicationContext.Services.DataTypeService));
//FROM Property TO ContentPropertyDto //FROM Property TO ContentPropertyDto
config.CreateMap<Property, ContentPropertyDto>() config.CreateMap<Property, ContentPropertyDto>()
.ConvertUsing(new ContentPropertyDtoConverter(lazyDataTypeService)); .ConvertUsing(new ContentPropertyDtoConverter(applicationContext.Services.DataTypeService));
//FROM Property TO ContentPropertyDisplay //FROM Property TO ContentPropertyDisplay
config.CreateMap<Property, ContentPropertyDisplay>() config.CreateMap<Property, ContentPropertyDisplay>()
.ConvertUsing(new ContentPropertyDisplayConverter(lazyDataTypeService)); .ConvertUsing(new ContentPropertyDisplayConverter(applicationContext.Services.DataTypeService, applicationContext.Services.TextService));
} }
} }
} }

View File

@@ -0,0 +1,34 @@
using System.Web.Mvc;
using AutoMapper;
using Umbraco.Core.Models;
using Umbraco.Web.Trees;
namespace Umbraco.Web.Models.Mapping
{
/// <summary>
/// Gets the tree node url for the content or media
/// </summary>
internal class ContentTreeNodeUrlResolver<TSource, TController> : IValueResolver
where TSource : IContentBase
where TController : ContentTreeControllerBase
{
public ResolutionResult Resolve(ResolutionResult source)
{
return source.New(ResolveCore(source, (TSource)source.Value), typeof(string));
}
private string ResolveCore(ResolutionResult res, TSource source)
{
var umbCtx = res.GetUmbracoContext();
//map the tree node url
if (umbCtx != null)
{
var urlHelper = new UrlHelper(umbCtx.HttpContext.Request.RequestContext);
var url = urlHelper.GetUmbracoApiService<TController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
return url;
}
return null;
}
}
}

View File

@@ -19,9 +19,7 @@ namespace Umbraco.Web.Models.Mapping
{ {
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext) public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
{ {
var lazyDataTypeService = new Lazy<IDataTypeService>(() => applicationContext.Services.DataTypeService); config.CreateMap<PropertyEditor, PropertyEditorBasic>();
config.CreateMap<PropertyEditor, PropertyEditorBasic>();
//just maps the standard properties, does not map the value! //just maps the standard properties, does not map the value!
config.CreateMap<PreValueField, PreValueFieldDisplay>() config.CreateMap<PreValueField, PreValueFieldDisplay>()
@@ -67,7 +65,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.DataType, content.Key))) .ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.DataType, content.Key)))
.ForMember(display => display.AvailableEditors, expression => expression.ResolveUsing(new AvailablePropertyEditorsResolver(UmbracoConfig.For.UmbracoSettings().Content))) .ForMember(display => display.AvailableEditors, expression => expression.ResolveUsing(new AvailablePropertyEditorsResolver(UmbracoConfig.For.UmbracoSettings().Content)))
.ForMember(display => display.PreValues, expression => expression.ResolveUsing( .ForMember(display => display.PreValues, expression => expression.ResolveUsing(
new PreValueDisplayResolver(lazyDataTypeService))) new PreValueDisplayResolver(applicationContext.Services.DataTypeService)))
.ForMember(display => display.SelectedEditor, expression => expression.MapFrom( .ForMember(display => display.SelectedEditor, expression => expression.MapFrom(
definition => definition.PropertyEditorAlias.IsNullOrWhiteSpace() ? null : definition.PropertyEditorAlias)) definition => definition.PropertyEditorAlias.IsNullOrWhiteSpace() ? null : definition.PropertyEditorAlias))
.ForMember(x => x.HasPrevalues, expression => expression.Ignore()) .ForMember(x => x.HasPrevalues, expression => expression.Ignore())
@@ -90,7 +88,7 @@ namespace Umbraco.Web.Models.Mapping
config.CreateMap<IDataTypeDefinition, IEnumerable<PreValueFieldDisplay>>() config.CreateMap<IDataTypeDefinition, IEnumerable<PreValueFieldDisplay>>()
.ConvertUsing(definition => .ConvertUsing(definition =>
{ {
var resolver = new PreValueDisplayResolver(lazyDataTypeService); var resolver = new PreValueDisplayResolver(applicationContext.Services.DataTypeService);
return resolver.Convert(definition); return resolver.Convert(definition);
}); });
@@ -124,4 +122,4 @@ namespace Umbraco.Web.Models.Mapping
}); });
} }
} }
} }

View File

@@ -33,7 +33,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.Trashed, expression => expression.MapFrom(content => content.Trashed)) .ForMember(display => display.Trashed, expression => expression.MapFrom(content => content.Trashed))
.ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name))
.ForMember(display => display.Properties, expression => expression.Ignore()) .ForMember(display => display.Properties, expression => expression.Ignore())
.ForMember(display => display.TreeNodeUrl, expression => expression.Ignore()) .ForMember(display => display.TreeNodeUrl, opt => opt.ResolveUsing(new ContentTreeNodeUrlResolver<IMedia, MediaTreeController>()))
.ForMember(display => display.Notifications, expression => expression.Ignore()) .ForMember(display => display.Notifications, expression => expression.Ignore())
.ForMember(display => display.Errors, expression => expression.Ignore()) .ForMember(display => display.Errors, expression => expression.Ignore())
.ForMember(display => display.Published, expression => expression.Ignore()) .ForMember(display => display.Published, expression => expression.Ignore())
@@ -74,23 +74,14 @@ namespace Umbraco.Web.Models.Mapping
{ {
// Adapted from ContentModelMapper // Adapted from ContentModelMapper
//map the IsChildOfListView (this is actually if it is a descendant of a list view!) //map the IsChildOfListView (this is actually if it is a descendant of a list view!)
//TODO: STOP using these extension methods, they are not testable and require singletons to be setup
var parent = media.Parent(); var parent = media.Parent();
display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path)); display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path));
//map the tree node url
if (HttpContext.Current != null)
{
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
var url = urlHelper.GetUmbracoApiService<MediaTreeController>(controller => controller.GetTreeNode(display.Id.ToString(), null));
display.TreeNodeUrl = url;
}
if (media.ContentType.IsContainer) if (media.ContentType.IsContainer)
{ {
TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService, localizedText); TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService, localizedText);
} }
TabsAndPropertiesResolver.MapGenericProperties(media, display, localizedText);
} }
/// <summary> /// <summary>
@@ -101,9 +92,7 @@ namespace Umbraco.Web.Models.Mapping
{ {
protected override ContentTypeBasic ResolveCore(IMedia source) protected override ContentTypeBasic ResolveCore(IMedia source)
{ {
//TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons //TODO: We can resolve the UmbracoContext from the IValueResolver options!
//If this is a web request and there's a user signed in and the
// user has access to the settings section, we will
if (HttpContext.Current != null && UmbracoContext.Current != null && if (HttpContext.Current != null && UmbracoContext.Current != null &&
UmbracoContext.Current.Security.CurrentUser != null UmbracoContext.Current.Security.CurrentUser != null
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants && UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Web; using System.Web;
using System.Web.Mvc;
using System.Web.Routing; using System.Web.Routing;
using System.Web.Security; using System.Web.Security;
using AutoMapper; using AutoMapper;
@@ -14,7 +13,6 @@ using Umbraco.Web.Models.ContentEditing;
using System.Linq; using System.Linq;
using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Security; using Umbraco.Core.Security;
using Umbraco.Web.Trees;
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile; using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
namespace Umbraco.Web.Models.Mapping namespace Umbraco.Web.Models.Mapping
@@ -56,9 +54,9 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(member => member.SortOrder, expression => expression.Ignore()) .ForMember(member => member.SortOrder, expression => expression.Ignore())
.ForMember(member => member.AdditionalData, expression => expression.Ignore()) .ForMember(member => member.AdditionalData, expression => expression.Ignore())
.ForMember(member => member.FailedPasswordAttempts, expression => expression.Ignore()) .ForMember(member => member.FailedPasswordAttempts, expression => expression.Ignore())
.ForMember(member => member.DeletedDate, expression => expression.Ignore()) .ForMember(member => member.DeletedDate, expression => expression.Ignore())
//TODO: Support these eventually //TODO: Support these eventually
.ForMember(member => member.PasswordQuestion, expression => expression.Ignore()) .ForMember(member => member.PasswordQuestion, expression => expression.Ignore())
.ForMember(member => member.RawPasswordAnswerValue, expression => expression.Ignore()); .ForMember(member => member.RawPasswordAnswerValue, expression => expression.Ignore());
//FROM IMember TO MediaItemDisplay //FROM IMember TO MediaItemDisplay
@@ -69,10 +67,10 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias)) .ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias))
.ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name))
.ForMember(display => display.Properties, expression => expression.Ignore()) .ForMember(display => display.Properties, expression => expression.Ignore())
.ForMember(display => display.Tabs, expression => expression.ResolveUsing(new MemberTabsAndPropertiesResolver(applicationContext.Services.TextService))) .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new MemberTabsAndPropertiesResolver(applicationContext.Services.TextService, applicationContext.Services.MemberService, applicationContext.Services.UserService)))
.ForMember(display => display.MemberProviderFieldMapping, expression => expression.ResolveUsing(new MemberProviderFieldMappingResolver())) .ForMember(display => display.MemberProviderFieldMapping, expression => expression.ResolveUsing(new MemberProviderFieldMappingResolver()))
.ForMember(display => display.MembershipScenario, .ForMember(display => display.MembershipScenario,
expression => expression.ResolveUsing(new MembershipScenarioMappingResolver(new Lazy<IMemberTypeService>(() => applicationContext.Services.MemberTypeService)))) expression => expression.ResolveUsing(new MembershipScenarioMappingResolver(applicationContext.Services.MemberTypeService)))
.ForMember(display => display.Notifications, expression => expression.Ignore()) .ForMember(display => display.Notifications, expression => expression.Ignore())
.ForMember(display => display.Errors, expression => expression.Ignore()) .ForMember(display => display.Errors, expression => expression.Ignore())
.ForMember(display => display.Published, expression => expression.Ignore()) .ForMember(display => display.Published, expression => expression.Ignore())
@@ -81,9 +79,9 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.IsChildOfListView, expression => expression.Ignore()) .ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
.ForMember(display => display.Trashed, expression => expression.Ignore()) .ForMember(display => display.Trashed, expression => expression.Ignore())
.ForMember(display => display.IsContainer, expression => expression.Ignore()) .ForMember(display => display.IsContainer, expression => expression.Ignore())
.ForMember(display => display.TreeNodeUrl, expression => expression.Ignore()) .ForMember(display => display.TreeNodeUrl, opt => opt.ResolveUsing(new MemberTreeNodeUrlResolver()))
.ForMember(display => display.HasPublishedVersion, expression => expression.Ignore()) .ForMember(display => display.HasPublishedVersion, expression => expression.Ignore());
.AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, applicationContext.Services.UserService, member, display, applicationContext.Services.TextService)); //.AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, applicationContext.Services.UserService, member, display, applicationContext.Services.TextService));
//FROM IMember TO MemberBasic //FROM IMember TO MemberBasic
config.CreateMap<IMember, MemberBasic>() config.CreateMap<IMember, MemberBasic>()
@@ -100,14 +98,14 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore()); .ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore());
//FROM MembershipUser TO MemberBasic //FROM MembershipUser TO MemberBasic
config.CreateMap<MembershipUser, MemberBasic>() config.CreateMap<MembershipUser, MemberBasic>()
//we're giving this entity an ID of 0 - we cannot really map it but it needs an id so the system knows it's not a new entity //we're giving this entity an ID of 0 - we cannot really map it but it needs an id so the system knows it's not a new entity
.ForMember(member => member.Id, expression => expression.MapFrom(user => int.MaxValue)) .ForMember(member => member.Id, expression => expression.MapFrom(user => int.MaxValue))
.ForMember(display => display.Udi, expression => expression.Ignore()) .ForMember(display => display.Udi, expression => expression.Ignore())
.ForMember(member => member.CreateDate, expression => expression.MapFrom(user => user.CreationDate)) .ForMember(member => member.CreateDate, expression => expression.MapFrom(user => user.CreationDate))
.ForMember(member => member.UpdateDate, expression => expression.MapFrom(user => user.LastActivityDate)) .ForMember(member => member.UpdateDate, expression => expression.MapFrom(user => user.LastActivityDate))
.ForMember(member => member.Key, expression => expression.MapFrom(user => user.ProviderUserKey.TryConvertTo<Guid>().Result.ToString("N"))) .ForMember(member => member.Key, expression => expression.MapFrom(user => user.ProviderUserKey.TryConvertTo<Guid>().Result.ToString("N")))
.ForMember(member => member.Owner, expression => expression.UseValue(new UserProfile {Name = "Admin", UserId = 0})) .ForMember(member => member.Owner, expression => expression.UseValue(new UserProfile { Name = "Admin", UserId = 0 }))
.ForMember(member => member.Icon, expression => expression.UseValue("icon-user")) .ForMember(member => member.Icon, expression => expression.UseValue("icon-user"))
.ForMember(member => member.Name, expression => expression.MapFrom(user => user.UserName)) .ForMember(member => member.Name, expression => expression.MapFrom(user => user.UserName))
.ForMember(member => member.Email, expression => expression.MapFrom(content => content.Email)) .ForMember(member => member.Email, expression => expression.MapFrom(content => content.Email))
@@ -137,119 +135,11 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.Properties, expression => expression.ResolveUsing(new MemberDtoPropertiesValueResolver())); .ForMember(dto => dto.Properties, expression => expression.ResolveUsing(new MemberDtoPropertiesValueResolver()));
} }
/// <summary>
/// Maps the generic tab with custom properties for content
/// </summary>
/// <param name="memberService"></param>
/// <param name="userService"></param>
/// <param name="member"></param>
/// <param name="display"></param>
/// <param name="localizedText"></param>
/// <remarks>
/// If this is a new entity and there is an approved field then we'll set it to true by default.
/// </remarks>
private static void MapGenericCustomProperties(IMemberService memberService, IUserService userService, IMember member, MemberDisplay display, ILocalizedTextService localizedText)
{
var membersProvider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
//map the tree node url
if (HttpContext.Current != null)
{
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
var url = urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(display.Key.ToString("N"), null));
display.TreeNodeUrl = url;
}
var genericProperties = new List<ContentPropertyDisplay>
{
new ContentPropertyDisplay
{
Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/membertype"),
Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName),
View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View
},
GetLoginProperty(memberService, member, display, localizedText),
new ContentPropertyDisplay
{
Alias = string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("general/email"),
Value = display.Email,
View = "email",
Validation = {Mandatory = true}
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("password"),
//NOTE: The value here is a json value - but the only property we care about is the generatedPassword one if it exists, the newPassword exists
// only when creating a new member and we want to have a generated password pre-filled.
Value = new Dictionary<string, object>
{
{"generatedPassword", member.GetAdditionalDataValueIgnoreCase("GeneratedPassword", null)},
{"newPassword", member.GetAdditionalDataValueIgnoreCase("NewPassword", null)},
},
//TODO: Hard coding this because the changepassword doesn't necessarily need to be a resolvable (real) property editor
View = "changepassword",
//initialize the dictionary with the configuration from the default membership provider
Config = new Dictionary<string, object>(membersProvider.GetConfiguration(userService))
{
//the password change toggle will only be displayed if there is already a password assigned.
{"hasPassword", member.RawPasswordValue.IsNullOrWhiteSpace() == false}
}
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}membergroup", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("content/membergroup"),
Value = GetMemberGroupValue(display.Username),
View = "membergroups",
Config = new Dictionary<string, object> {{"IsRequired", true}}
}
};
TabsAndPropertiesResolver.MapGenericProperties(member, display, localizedText, genericProperties, properties =>
{
if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{
var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", member.ContentTypeId);
//Replace the doctype property
var docTypeProperty = properties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
docTypeProperty.Value = new List<object>
{
new
{
linkText = member.ContentType.Name,
url = memberTypeLink,
target = "_self",
icon = "icon-item-arrangement"
}
};
docTypeProperty.View = "urllist";
}
});
//check if there's an approval field
var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider;
if (member.HasIdentity == false && provider != null)
{
var approvedField = provider.ApprovedPropertyTypeAlias;
var prop = display.Properties.FirstOrDefault(x => x.Alias == approvedField);
if (prop != null)
{
prop.Value = 1;
}
}
}
/// <summary> /// <summary>
/// Returns the login property display field /// Returns the login property display field
/// </summary> /// </summary>
/// <param name="memberService"></param> /// <param name="memberService"></param>
/// <param name="member"></param> /// <param name="member"></param>
/// <param name="display"></param>
/// <param name="localizedText"></param> /// <param name="localizedText"></param>
/// <returns></returns> /// <returns></returns>
/// <remarks> /// <remarks>
@@ -257,13 +147,13 @@ namespace Umbraco.Web.Models.Mapping
/// the membership provider is a custom one, we cannot allow chaning the username because MembershipProvider's do not actually natively /// the membership provider is a custom one, we cannot allow chaning the username because MembershipProvider's do not actually natively
/// allow that. /// allow that.
/// </remarks> /// </remarks>
internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, MemberDisplay display, ILocalizedTextService localizedText) internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, ILocalizedTextService localizedText)
{ {
var prop = new ContentPropertyDisplay var prop = new ContentPropertyDisplay
{ {
Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix), Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("login"), Label = localizedText.Localize("login"),
Value = display.Username Value = member.Username
}; };
var scenario = memberService.GetMembershipScenario(); var scenario = memberService.GetMembershipScenario();
@@ -329,24 +219,60 @@ namespace Umbraco.Web.Models.Mapping
/// <remarks> /// <remarks>
/// This also ensures that the IsLocked out property is readonly when the member is not locked out - this is because /// This also ensures that the IsLocked out property is readonly when the member is not locked out - this is because
/// an admin cannot actually set isLockedOut = true, they can only unlock. /// an admin cannot actually set isLockedOut = true, they can only unlock.
///
/// This also ensures that the IsSensitive property display value is set based on the configured IMemberType property type
/// </remarks> /// </remarks>
internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver, IValueResolver
{ {
private readonly ILocalizedTextService _localizedTextService; private readonly ILocalizedTextService _localizedTextService;
private readonly IMemberService _memberService;
private readonly IUserService _userService;
public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService) public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService, IMemberService memberService, IUserService userService)
: base(localizedTextService) : base(localizedTextService)
{ {
_localizedTextService = localizedTextService; _localizedTextService = localizedTextService;
_memberService = memberService;
_userService = userService;
} }
public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService, public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService,
IEnumerable<string> ignoreProperties) : base(localizedTextService, ignoreProperties) IEnumerable<string> ignoreProperties, IMemberService memberService, IUserService userService) : base(localizedTextService, ignoreProperties)
{ {
_localizedTextService = localizedTextService; _localizedTextService = localizedTextService;
_memberService = memberService;
_userService = userService;
} }
protected override IEnumerable<Tab<ContentPropertyDisplay>> ResolveCore(IContentBase content) /// <summary>
/// Explicitly implement to override behavior
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
/// <remarks>
/// This is required to get access to the <see cref="ResolutionResult"/> object which allows us access to the mapping options
/// </remarks>
ResolutionResult IValueResolver.Resolve(ResolutionResult source)
{
//call the base class logic
var result = base.Resolve(source);
var member = (IMember)source.Value;
//now we can customize the result and use the ResolutionResult options to get the UmbracoContext
var tabs = (List<Tab<ContentPropertyDisplay>>) result.Value;
//now we can customize the result with the current context, we can get the UmbracoContext from the options
CustomizeProperties(source.GetUmbracoContext(), member, tabs);
return result;
}
/// <summary>
/// Overridden to deal with custom member properties
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
protected override List<Tab<ContentPropertyDisplay>> ResolveCore(IContentBase content)
{ {
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
@@ -355,7 +281,7 @@ namespace Umbraco.Web.Models.Mapping
.Select(x => x.Alias) .Select(x => x.Alias)
.ToArray(); .ToArray();
var result = base.ResolveCore(content).ToArray(); var result = base.ResolveCore(content);
if (provider.IsUmbracoMembershipProvider() == false) if (provider.IsUmbracoMembershipProvider() == false)
{ {
@@ -366,12 +292,10 @@ namespace Umbraco.Web.Models.Mapping
isLockedOutProperty.View = "readonlyvalue"; isLockedOutProperty.View = "readonlyvalue";
isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); isLockedOutProperty.Value = _localizedTextService.Localize("general/no");
} }
return result;
} }
else else
{ {
var umbracoProvider = (IUmbracoMemberTypeMembershipProvider) provider; var umbracoProvider = (IUmbracoMemberTypeMembershipProvider)provider;
//This is kind of a hack because a developer is supposed to be allowed to set their property editor - would have been much easier //This is kind of a hack because a developer is supposed to be allowed to set their property editor - would have been much easier
// if we just had all of the membeship provider fields on the member table :( // if we just had all of the membeship provider fields on the member table :(
@@ -382,17 +306,150 @@ namespace Umbraco.Web.Models.Mapping
isLockedOutProperty.View = "readonlyvalue"; isLockedOutProperty.View = "readonlyvalue";
isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); isLockedOutProperty.Value = _localizedTextService.Localize("general/no");
} }
return result;
} }
return result;
}
protected override IEnumerable<ContentPropertyDisplay> GetCustomGenericProperties(IContentBase content)
{
var member = (IMember) content;
var membersProvider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
var genericProperties = new List<ContentPropertyDisplay>
{
new ContentPropertyDisplay
{
Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = _localizedTextService.Localize("content/membertype"),
//Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName),
Value = _localizedTextService.UmbracoDictionaryTranslate(member.ContentType.Name),
View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View
},
GetLoginProperty(_memberService, member, _localizedTextService),
new ContentPropertyDisplay
{
Alias = string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = _localizedTextService.Localize("general/email"),
Value = member.Email,
View = "email",
Validation = {Mandatory = true}
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = _localizedTextService.Localize("password"),
//NOTE: The value here is a json value - but the only property we care about is the generatedPassword one if it exists, the newPassword exists
// only when creating a new member and we want to have a generated password pre-filled.
Value = new Dictionary<string, object>
{
{"generatedPassword", member.GetAdditionalDataValueIgnoreCase("GeneratedPassword", null)},
{"newPassword", member.GetAdditionalDataValueIgnoreCase("NewPassword", null)},
},
//TODO: Hard coding this because the changepassword doesn't necessarily need to be a resolvable (real) property editor
View = "changepassword",
//initialize the dictionary with the configuration from the default membership provider
Config = new Dictionary<string, object>(membersProvider.GetConfiguration(_userService))
{
//the password change toggle will only be displayed if there is already a password assigned.
{"hasPassword", member.RawPasswordValue.IsNullOrWhiteSpace() == false}
}
},
new ContentPropertyDisplay
{
Alias = string.Format("{0}membergroup", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = _localizedTextService.Localize("content/membergroup"),
Value = GetMemberGroupValue(member.Username),
View = "membergroups",
Config = new Dictionary<string, object> {{"IsRequired", true}}
}
};
return genericProperties;
}
/// <summary>
/// Performs some customizations for the properties based on the current context
/// </summary>
/// <param name="umbracoContext"></param>
/// <param name="member"></param>
/// <param name="tabs">The current tab collection</param>
/// <remarks>
/// If this is a new entity and there is an approved field then we'll set it to true by default.
/// </remarks>
private void CustomizeProperties(UmbracoContext umbracoContext, IMember member, List<Tab<ContentPropertyDisplay>> tabs)
{
var membersProvider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
if (umbracoContext != null && umbracoContext.Security.CurrentUser != null
&& umbracoContext.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{
var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", member.ContentTypeId);
//Replace the doctype property
var docTypeProperty = tabs.SelectMany(x => x.Properties)
.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
docTypeProperty.Value = new List<object>
{
new
{
linkText = member.ContentType.Name,
url = memberTypeLink,
target = "_self",
icon = "icon-item-arrangement"
}
};
docTypeProperty.View = "urllist";
}
//check if there's an approval field
var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider;
if (member.HasIdentity == false && provider != null)
{
var approvedField = provider.ApprovedPropertyTypeAlias;
var prop = tabs.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == approvedField);
if (prop != null)
{
prop.Value = 1;
}
}
}
/// <summary>
/// Overridden to assign the IsSensitive property values
/// </summary>
/// <param name="content"></param>
/// <param name="properties"></param>
/// <returns></returns>
protected override List<ContentPropertyDisplay> MapProperties(IContentBase content, List<Property> properties)
{
var result = base.MapProperties(content, properties);
var member = (IMember)content;
var memberType = member.ContentType;
var labelPropEditor = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View;
//now update the IsSensitive value
foreach (var prop in result)
{
prop.IsSensitive = memberType.IsSensitiveProperty(prop.Alias);
//check permissions for viewing sensitive data
if (prop.IsSensitive)
{
//replace this editor with a label
prop.View = labelPropEditor;
//replace the value
prop.Value = string.Format("<em class='text-warning'>{0}</em>", _localizedTextService.Localize("content/isSensitiveValue"));
}
}
return result;
} }
} }
internal class MembershipScenarioMappingResolver : ValueResolver<IMember, MembershipScenario> internal class MembershipScenarioMappingResolver : ValueResolver<IMember, MembershipScenario>
{ {
private readonly Lazy<IMemberTypeService> _memberTypeService; private readonly IMemberTypeService _memberTypeService;
public MembershipScenarioMappingResolver(Lazy<IMemberTypeService> memberTypeService) public MembershipScenarioMappingResolver(IMemberTypeService memberTypeService)
{ {
_memberTypeService = memberTypeService; _memberTypeService = memberTypeService;
} }
@@ -405,7 +462,7 @@ namespace Umbraco.Web.Models.Mapping
{ {
return MembershipScenario.NativeUmbraco; return MembershipScenario.NativeUmbraco;
} }
var memberType = _memberTypeService.Value.Get(Constants.Conventions.MemberTypes.DefaultAlias); var memberType = _memberTypeService.Get(Constants.Conventions.MemberTypes.DefaultAlias);
return memberType != null return memberType != null
? MembershipScenario.CustomProviderWithUmbracoLink ? MembershipScenario.CustomProviderWithUmbracoLink
: MembershipScenario.StandaloneCustomProvider; : MembershipScenario.StandaloneCustomProvider;
@@ -432,7 +489,7 @@ namespace Umbraco.Web.Models.Mapping
} }
else else
{ {
var umbracoProvider = (IUmbracoMemberTypeMembershipProvider) provider; var umbracoProvider = (IUmbracoMemberTypeMembershipProvider)provider;
return new Dictionary<string, string> return new Dictionary<string, string>
{ {
@@ -444,4 +501,7 @@ namespace Umbraco.Web.Models.Mapping
} }
} }
} }
} }

View File

@@ -0,0 +1,32 @@
using System.Web.Mvc;
using AutoMapper;
using Umbraco.Core.Models;
using Umbraco.Web.Trees;
namespace Umbraco.Web.Models.Mapping
{
/// <summary>
/// Gets the tree node url for the IMember
/// </summary>
internal class MemberTreeNodeUrlResolver : IValueResolver
{
public ResolutionResult Resolve(ResolutionResult source)
{
return source.New(ResolveCore(source, (IMember)source.Value), typeof(string));
}
private string ResolveCore(ResolutionResult res, IMember source)
{
var umbCtx = res.GetUmbracoContext();
//map the tree node url
if (umbCtx != null)
{
var urlHelper = new UrlHelper(umbCtx.HttpContext.Request.RequestContext);
var url = urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
return url;
}
return null;
}
}
}

View File

@@ -13,9 +13,9 @@ namespace Umbraco.Web.Models.Mapping
{ {
internal class PreValueDisplayResolver : ValueResolver<IDataTypeDefinition, IEnumerable<PreValueFieldDisplay>> internal class PreValueDisplayResolver : ValueResolver<IDataTypeDefinition, IEnumerable<PreValueFieldDisplay>>
{ {
private readonly Lazy<IDataTypeService> _dataTypeService; private readonly IDataTypeService _dataTypeService;
public PreValueDisplayResolver(Lazy<IDataTypeService> dataTypeService) public PreValueDisplayResolver(IDataTypeService dataTypeService)
{ {
_dataTypeService = dataTypeService; _dataTypeService = dataTypeService;
} }
@@ -55,7 +55,7 @@ namespace Umbraco.Web.Models.Mapping
} }
//set up the defaults //set up the defaults
var dataTypeService = _dataTypeService.Value; var dataTypeService = _dataTypeService;
var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(source.Id); var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(source.Id);
IDictionary<string, object> dictionaryVals = preVals.FormatAsDictionary().ToDictionary(x => x.Key, x => (object)x.Value); IDictionary<string, object> dictionaryVals = preVals.FormatAsDictionary().ToDictionary(x => x.Key, x => (object)x.Value);
var result = Enumerable.Empty<PreValueFieldDisplay>().ToArray(); var result = Enumerable.Empty<PreValueFieldDisplay>().ToArray();
@@ -77,4 +77,4 @@ namespace Umbraco.Web.Models.Mapping
return Convert(source); return Convert(source);
} }
} }
} }

View File

@@ -16,7 +16,7 @@ namespace Umbraco.Web.Models.Mapping
/// <summary> /// <summary>
/// Creates the tabs collection with properties assigned for display models /// Creates the tabs collection with properties assigned for display models
/// </summary> /// </summary>
internal class TabsAndPropertiesResolver : ValueResolver<IContentBase, IEnumerable<Tab<ContentPropertyDisplay>>> internal class TabsAndPropertiesResolver : ValueResolver<IContentBase, List<Tab<ContentPropertyDisplay>>>
{ {
private readonly ILocalizedTextService _localizedTextService; private readonly ILocalizedTextService _localizedTextService;
protected IEnumerable<string> IgnoreProperties { get; set; } protected IEnumerable<string> IgnoreProperties { get; set; }
@@ -35,60 +35,6 @@ namespace Umbraco.Web.Models.Mapping
IgnoreProperties = ignoreProperties; IgnoreProperties = ignoreProperties;
} }
/// <summary>
/// Maps properties on to the generic properties tab
/// </summary>
/// <param name="content"></param>
/// <param name="display"></param>
/// <param name="localizedTextService"></param>
/// <param name="customProperties">
/// Any additional custom properties to assign to the generic properties tab.
/// </param>
/// <param name="onGenericPropertiesMapped"></param>
/// <remarks>
/// The generic properties tab is mapped during AfterMap and is responsible for
/// setting up the properties such as Created date, updated date, template selected, etc...
/// </remarks>
public static void MapGenericProperties<TPersisted>(
TPersisted content,
ContentItemDisplayBase<ContentPropertyDisplay, TPersisted> display,
ILocalizedTextService localizedTextService,
IEnumerable<ContentPropertyDisplay> customProperties = null,
Action<List<ContentPropertyDisplay>> onGenericPropertiesMapped = null)
where TPersisted : IContentBase
{
var genericProps = display.Tabs.Single(x => x.Id == 0);
//store the current props to append to the newly inserted ones
var currProps = genericProps.Properties.ToArray();
var contentProps = new List<ContentPropertyDisplay>();
if (customProperties != null)
{
//add the custom ones
contentProps.AddRange(customProperties);
}
//now add the user props
contentProps.AddRange(currProps);
//callback
if (onGenericPropertiesMapped != null)
{
onGenericPropertiesMapped(contentProps);
}
//re-assign
genericProps.Properties = contentProps;
//Show or hide properties tab based on wether it has or not any properties
if (genericProps.Properties.Any() == false)
{
display.Tabs = display.Tabs.Where(x => x.Id != 0);
}
}
/// <summary> /// <summary>
/// Adds the container (listview) tab to the document /// Adds the container (listview) tab to the document
/// </summary> /// </summary>
@@ -199,7 +145,7 @@ namespace Umbraco.Web.Models.Mapping
display.Tabs = tabs; display.Tabs = tabs;
} }
protected override IEnumerable<Tab<ContentPropertyDisplay>> ResolveCore(IContentBase content) protected override List<Tab<ContentPropertyDisplay>> ResolveCore(IContentBase content)
{ {
var tabs = new List<Tab<ContentPropertyDisplay>>(); var tabs = new List<Tab<ContentPropertyDisplay>>();
@@ -224,10 +170,8 @@ namespace Umbraco.Web.Models.Mapping
if (properties.Count == 0) if (properties.Count == 0)
continue; continue;
// Sort properties so items from different compositions appear in correct order (see U4-9298). Map sorted properties. //map the properties
var mappedProperties = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(properties.OrderBy(prop => prop.PropertyType.SortOrder)); var mappedProperties = MapProperties(content, properties);
TranslateProperties(mappedProperties);
// add the tab // add the tab
// we need to pick an identifier... there is no "right" way... // we need to pick an identifier... there is no "right" way...
@@ -245,12 +189,40 @@ namespace Umbraco.Web.Models.Mapping
}); });
} }
MapGenericProperties(content, tabs);
// activate the first tab
tabs[0].IsActive = true;
return tabs;
}
/// <summary>
/// Returns a collection of custom generic properties that exist on the generic properties tab
/// </summary>
/// <returns></returns>
protected virtual IEnumerable<ContentPropertyDisplay> GetCustomGenericProperties(IContentBase content)
{
return Enumerable.Empty<ContentPropertyDisplay>();
}
/// <summary>
/// Maps properties on to the generic properties tab
/// </summary>
/// <param name="content"></param>
/// <param name="tabs"></param>
/// <remarks>
/// The generic properties tab is responsible for
/// setting up the properties such as Created date, updated date, template selected, etc...
/// </remarks>
protected virtual void MapGenericProperties(IContentBase content, List<Tab<ContentPropertyDisplay>> tabs)
{
// add the generic properties tab, for properties that don't belong to a tab // add the generic properties tab, for properties that don't belong to a tab
// get the properties, map and translate them, then add the tab // get the properties, map and translate them, then add the tab
var noGroupProperties = content.GetNonGroupedProperties() var noGroupProperties = content.GetNonGroupedProperties()
.Where(x => IgnoreProperties.Contains(x.Alias) == false); // skip ignored .Where(x => IgnoreProperties.Contains(x.Alias) == false) // skip ignored
var genericproperties = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(noGroupProperties).ToList(); .ToList();
TranslateProperties(genericproperties); var genericproperties = MapProperties(content, noGroupProperties);
tabs.Add(new Tab<ContentPropertyDisplay> tabs.Add(new Tab<ContentPropertyDisplay>
{ {
@@ -260,20 +232,54 @@ namespace Umbraco.Web.Models.Mapping
Properties = genericproperties Properties = genericproperties
}); });
// activate the first tab var genericProps = tabs.Single(x => x.Id == 0);
tabs.First().IsActive = true;
return tabs; //store the current props to append to the newly inserted ones
} var currProps = genericProps.Properties.ToArray();
private void TranslateProperties(IEnumerable<ContentPropertyDisplay> properties) var contentProps = new List<ContentPropertyDisplay>();
{
// Not sure whether it's a good idea to add this to the ContentPropertyDisplay mapper var customProperties = GetCustomGenericProperties(content);
foreach (var prop in properties) if (customProperties != null)
{ {
prop.Label = _localizedTextService.UmbracoDictionaryTranslate(prop.Label); //add the custom ones
prop.Description = _localizedTextService.UmbracoDictionaryTranslate(prop.Description); contentProps.AddRange(customProperties);
}
//now add the user props
contentProps.AddRange(currProps);
//re-assign
genericProps.Properties = contentProps;
//Show or hide properties tab based on wether it has or not any properties
if (genericProps.Properties.Any() == false)
{
//loop throug the tabs, remove the one with the id of zero and exit the loop
for (var i = 0; i < tabs.Count; i++)
{
if (tabs[i].Id != 0) continue;
tabs.RemoveAt(i);
break;
}
} }
} }
/// <summary>
/// Maps a list of <see cref="Property"/> to a list of <see cref="ContentPropertyDisplay"/>
/// </summary>
/// <param name="content"></param>
/// <param name="properties"></param>
/// <returns></returns>
protected virtual List<ContentPropertyDisplay> MapProperties(IContentBase content, List<Property> properties)
{
var result = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(
// Sort properties so items from different compositions appear in correct order (see U4-9298). Map sorted properties.
properties.OrderBy(prop => prop.PropertyType.SortOrder))
.ToList();
return result;
}
} }
} }