Port v7@2aa0dfb2c5 - WIP
This commit is contained in:
27
src/Umbraco.Web/Models/BackOfficeTour.cs
Normal file
27
src/Umbraco.Web/Models/BackOfficeTour.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A model representing a tour.
|
||||
/// </summary>
|
||||
[DataContract(Name = "tour", Namespace = "")]
|
||||
public class BackOfficeTour
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
[DataMember(Name = "group")]
|
||||
public string Group { get; set; }
|
||||
[DataMember(Name = "groupOrder")]
|
||||
public int GroupOrder { get; set; }
|
||||
[DataMember(Name = "allowDisable")]
|
||||
public bool AllowDisable { get; set; }
|
||||
[DataMember(Name = "requiredSections")]
|
||||
public List<string> RequiredSections { get; set; }
|
||||
[DataMember(Name = "steps")]
|
||||
public BackOfficeTourStep[] Steps { get; set; }
|
||||
}
|
||||
}
|
||||
30
src/Umbraco.Web/Models/BackOfficeTourFile.cs
Normal file
30
src/Umbraco.Web/Models/BackOfficeTourFile.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A model representing the file used to load a tour.
|
||||
/// </summary>
|
||||
[DataContract(Name = "tourFile", Namespace = "")]
|
||||
public class BackOfficeTourFile
|
||||
{
|
||||
/// <summary>
|
||||
/// The file name for the tour
|
||||
/// </summary>
|
||||
[DataMember(Name = "fileName")]
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The plugin folder that the tour comes from
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this is null it means it's a Core tour
|
||||
/// </remarks>
|
||||
[DataMember(Name = "pluginName")]
|
||||
public string PluginName { get; set; }
|
||||
|
||||
[DataMember(Name = "tours")]
|
||||
public IEnumerable<BackOfficeTour> Tours { get; set; }
|
||||
}
|
||||
}
|
||||
61
src/Umbraco.Web/Models/BackOfficeTourFilter.cs
Normal file
61
src/Umbraco.Web/Models/BackOfficeTourFilter.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public class BackOfficeTourFilter
|
||||
{
|
||||
public Regex PluginName { get; private set; }
|
||||
public Regex TourFileName { get; private set; }
|
||||
public Regex TourAlias { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a filter to filter out a whole plugin's tours
|
||||
/// </summary>
|
||||
/// <param name="pluginName"></param>
|
||||
/// <returns></returns>
|
||||
public static BackOfficeTourFilter FilterPlugin(Regex pluginName)
|
||||
{
|
||||
return new BackOfficeTourFilter(pluginName, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a filter to filter out a whole tour file
|
||||
/// </summary>
|
||||
/// <param name="tourFileName"></param>
|
||||
/// <returns></returns>
|
||||
public static BackOfficeTourFilter FilterFile(Regex tourFileName)
|
||||
{
|
||||
return new BackOfficeTourFilter(null, tourFileName, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a filter to filter out a tour alias, this will filter out the same alias found in all files
|
||||
/// </summary>
|
||||
/// <param name="tourAlias"></param>
|
||||
/// <returns></returns>
|
||||
public static BackOfficeTourFilter FilterAlias(Regex tourAlias)
|
||||
{
|
||||
return new BackOfficeTourFilter(null, null, tourAlias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to create a tour filter
|
||||
/// </summary>
|
||||
/// <param name="pluginName">Value to filter out tours by a plugin, can be null</param>
|
||||
/// <param name="tourFileName">Value to filter out a tour file, can be null</param>
|
||||
/// <param name="tourAlias">Value to filter out a tour alias, can be null</param>
|
||||
/// <remarks>
|
||||
/// Depending on what is null will depend on how the filter is applied.
|
||||
/// If pluginName is not NULL and it's matched then we check if tourFileName is not NULL and it's matched then we check tour alias is not NULL and then match it,
|
||||
/// if any steps is NULL then the filters upstream are applied.
|
||||
/// Example, pluginName = "hello", tourFileName="stuff", tourAlias=NULL = we will filter out the tour file "stuff" from the plugin "hello" but not from other plugins if the same file name exists.
|
||||
/// Example, tourAlias="test.*" = we will filter out all tour aliases that start with the word "test" regardless of the plugin or file name
|
||||
/// </remarks>
|
||||
public BackOfficeTourFilter(Regex pluginName, Regex tourFileName, Regex tourAlias)
|
||||
{
|
||||
PluginName = pluginName;
|
||||
TourFileName = tourFileName;
|
||||
TourAlias = tourAlias;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/Umbraco.Web/Models/BackOfficeTourStep.cs
Normal file
33
src/Umbraco.Web/Models/BackOfficeTourStep.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A model representing a step in a tour.
|
||||
/// </summary>
|
||||
[DataContract(Name = "step", Namespace = "")]
|
||||
public class BackOfficeTourStep
|
||||
{
|
||||
[DataMember(Name = "title")]
|
||||
public string Title { get; set; }
|
||||
[DataMember(Name = "content")]
|
||||
public string Content { get; set; }
|
||||
[DataMember(Name = "type")]
|
||||
public string Type { get; set; }
|
||||
[DataMember(Name = "element")]
|
||||
public string Element { get; set; }
|
||||
[DataMember(Name = "elementPreventClick")]
|
||||
public bool ElementPreventClick { get; set; }
|
||||
[DataMember(Name = "backdropOpacity")]
|
||||
public float? BackdropOpacity { get; set; }
|
||||
[DataMember(Name = "event")]
|
||||
public string Event { get; set; }
|
||||
[DataMember(Name = "view")]
|
||||
public string View { get; set; }
|
||||
[DataMember(Name = "eventElement")]
|
||||
public string EventElement { get; set; }
|
||||
[DataMember(Name = "customProperties")]
|
||||
public JObject CustomProperties { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,33 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
[DataContract(Name = "auditLog", Namespace = "")]
|
||||
public class AuditLog
|
||||
{
|
||||
[DataMember(Name = "userId", IsRequired = true)]
|
||||
[DataMember(Name = "userId")]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[DataMember(Name = "nodeId", IsRequired = true)]
|
||||
[DataMember(Name = "userName")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
[DataMember(Name = "userAvatars")]
|
||||
public string[] UserAvatars { get; set; }
|
||||
|
||||
[DataMember(Name = "nodeId")]
|
||||
public int NodeId { get; set; }
|
||||
|
||||
[DataMember(Name = "timestamp", IsRequired = true)]
|
||||
[DataMember(Name = "timestamp")]
|
||||
public DateTime Timestamp { get; set; }
|
||||
|
||||
[DataMember(Name = "logType", IsRequired = true)]
|
||||
[DataMember(Name = "logType")]
|
||||
public string LogType { get; set; }
|
||||
|
||||
[DataMember(Name = "comment", IsRequired = true)]
|
||||
[DataMember(Name = "comment")]
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A model representing a content item to be displayed in the back office
|
||||
/// </summary>
|
||||
@@ -29,6 +28,12 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "template")]
|
||||
public string TemplateAlias { get; set; }
|
||||
|
||||
[DataMember(Name = "allowedTemplates")]
|
||||
public IDictionary<string, string> AllowedTemplates { get; set; }
|
||||
|
||||
[DataMember(Name = "documentType")]
|
||||
public ContentTypeBasic DocumentType { get; set; }
|
||||
|
||||
[DataMember(Name = "urls")]
|
||||
public string[] Urls { get; set; }
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "editor", IsRequired = false)]
|
||||
public string Editor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Flags the property to denote that it can contain sensitive data
|
||||
/// </summary>
|
||||
[DataMember(Name = "isSensitive", IsRequired = false)]
|
||||
public bool IsSensitive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used internally during model mapping
|
||||
|
||||
@@ -35,5 +35,8 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
|
||||
[DataMember(Name = "validation")]
|
||||
public PropertyTypeValidation Validation { get; set; }
|
||||
|
||||
[DataMember(Name = "readonly")]
|
||||
public bool Readonly { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
26
src/Umbraco.Web/Models/ContentEditing/EditorNavigation.cs
Normal file
26
src/Umbraco.Web/Models/ContentEditing/EditorNavigation.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
/// <summary>
|
||||
/// A model representing the navigation ("apps") inside an editor in the back office
|
||||
/// </summary>
|
||||
[DataContract(Name = "user", Namespace = "")]
|
||||
public class EditorNavigation
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[DataMember(Name = "icon")]
|
||||
public string Icon { get; set; }
|
||||
|
||||
[DataMember(Name = "view")]
|
||||
public string View { get; set; }
|
||||
|
||||
[DataMember(Name = "active")]
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.Validation;
|
||||
|
||||
@@ -10,6 +10,10 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataContract(Name = "content", Namespace = "")]
|
||||
public class MediaItemDisplay : ListViewAwareContentItemDisplayBase<ContentPropertyDisplay, IMedia>
|
||||
{
|
||||
[DataMember(Name = "contentType")]
|
||||
public ContentTypeBasic ContentType { get; set; }
|
||||
|
||||
[DataMember(Name = "mediaLink")]
|
||||
public string MediaLink { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,5 +13,8 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
|
||||
[DataMember(Name = "memberCanEdit")]
|
||||
public bool MemberCanEditProperty { get; set; }
|
||||
|
||||
[DataMember(Name = "isSensitiveData")]
|
||||
public bool IsSensitiveData { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,5 +10,8 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
|
||||
[DataMember(Name = "memberCanEdit")]
|
||||
public bool MemberCanEditProperty { get; set; }
|
||||
|
||||
[DataMember(Name = "isSensitiveData")]
|
||||
public bool IsSensitiveData { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
17
src/Umbraco.Web/Models/ContentEditing/PostedFolder.cs
Normal file
17
src/Umbraco.Web/Models/ContentEditing/PostedFolder.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to create a folder with the MediaController
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class PostedFolder
|
||||
{
|
||||
[DataMember(Name = "parentId")]
|
||||
public string ParentId { get; set; }
|
||||
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,5 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// </summary>
|
||||
[DataMember(Name = "allowedSections")]
|
||||
public IEnumerable<string> AllowedSections { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,13 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
AvailableCultures = new Dictionary<string, string>();
|
||||
StartContentIds = new List<EntityBasic>();
|
||||
StartMediaIds = new List<EntityBasic>();
|
||||
Navigation = new List<EditorNavigation>();
|
||||
}
|
||||
|
||||
[DataMember(Name = "navigation")]
|
||||
[ReadOnly(true)]
|
||||
public IEnumerable<EditorNavigation> Navigation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the available cultures (i.e. to populate a drop down)
|
||||
/// The key is the culture stored in the database, the value is the Name
|
||||
|
||||
@@ -11,33 +11,34 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// </summary>
|
||||
internal class ActionButtonsResolver
|
||||
{
|
||||
private readonly Lazy<IUserService> _userService;
|
||||
|
||||
public ActionButtonsResolver(Lazy<IUserService> userService)
|
||||
public ActionButtonsResolver(IUserService userService, IContentService contentService)
|
||||
{
|
||||
_userService = userService;
|
||||
UserService = userService;
|
||||
ContentService = contentService;
|
||||
}
|
||||
|
||||
private IUserService UserService { get; }
|
||||
private IContentService ContentService { get; }
|
||||
|
||||
public IEnumerable<string> Resolve(IContent source)
|
||||
{
|
||||
//cannot check permissions without a context
|
||||
if (UmbracoContext.Current == null)
|
||||
{
|
||||
//cannot check permissions without a context
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
string path;
|
||||
if (source.HasIdentity)
|
||||
path = source.Path;
|
||||
else
|
||||
{
|
||||
var parent = ContentService.GetById(source.ParentId);
|
||||
path = parent == null ? "-1" : parent.Path;
|
||||
}
|
||||
var svc = _userService.Value;
|
||||
|
||||
var permissions = svc.GetPermissions(
|
||||
//TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is
|
||||
// with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null
|
||||
// refrence exception :(
|
||||
UmbracoContext.Current.Security.CurrentUser,
|
||||
// Here we need to do a special check since this could be new content, in which case we need to get the permissions
|
||||
// from the parent, not the existing one otherwise permissions would be coming from the root since Id is 0.
|
||||
source.HasIdentity ? source.Id : source.ParentId)
|
||||
.GetAllPermissions();
|
||||
|
||||
return permissions;
|
||||
//TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is
|
||||
// with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null
|
||||
// refrence exception :(
|
||||
return UserService.GetPermissionsForPath(UmbracoContext.Current.Security.CurrentUser, path).GetAllPermissions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
src/Umbraco.Web/Models/Mapping/AuditMapperProfile.cs
Normal file
20
src/Umbraco.Web/Models/Mapping/AuditMapperProfile.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class AuditMapperProfile : Profile
|
||||
{
|
||||
public AuditMapperProfile()
|
||||
{
|
||||
CreateMap<IAuditItem, AuditLog>()
|
||||
.ForMember(log => log.UserAvatars, expression => expression.Ignore())
|
||||
.ForMember(log => log.UserName, expression => expression.Ignore())
|
||||
.ForMember(log => log.NodeId, expression => expression.MapFrom(item => item.Id))
|
||||
.ForMember(log => log.Timestamp, expression => expression.MapFrom(item => item.CreateDate))
|
||||
.ForMember(log => log.LogType, expression => expression.MapFrom(item => item.AuditType));
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/Umbraco.Web/Models/Mapping/AutoMapperExtensions.cs
Normal file
31
src/Umbraco.Web/Models/Mapping/AutoMapperExtensions.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using AutoMapper;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Extends AutoMapper's <see cref="Mapper"/> class to handle Umbraco's context.
|
||||
/// </summary>
|
||||
internal static class ContextMapper
|
||||
{
|
||||
private const string UmbracoContextKey = "ContextMapper.UmbracoContext";
|
||||
|
||||
public static TDestination Map<TSource, TDestination>(TSource obj, UmbracoContext umbracoContext)
|
||||
=> Mapper.Map<TSource, TDestination>(obj, opt => opt.Items[UmbracoContextKey] = umbracoContext);
|
||||
|
||||
public static UmbracoContext GetUmbracoContext(this ResolutionContext resolutionContext, bool throwIfMissing = true)
|
||||
{
|
||||
if (resolutionContext.Options.Items.TryGetValue(UmbracoContextKey, out var obj) && obj is UmbracoContext umbracoContext)
|
||||
return umbracoContext;
|
||||
|
||||
// not sure this is a good idea at all
|
||||
//return Current.UmbracoContext;
|
||||
|
||||
// better fail fast
|
||||
if (throwIfMissing)
|
||||
throw new InvalidOperationException("AutoMapper ResolutionContext does not contain an UmbracoContext.");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class ContentChildOfListViewResolver : IValueResolver<IContent, ContentItemDisplay, bool>
|
||||
{
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
|
||||
public ContentChildOfListViewResolver(IContentService contentService, IContentTypeService contentTypeService)
|
||||
{
|
||||
_contentService = contentService;
|
||||
_contentTypeService = contentTypeService;
|
||||
}
|
||||
|
||||
public bool Resolve(IContent source, ContentItemDisplay destination, bool destMember, ResolutionContext context)
|
||||
{
|
||||
// map the IsChildOfListView (this is actually if it is a descendant of a list view!)
|
||||
var parent = _contentService.GetParent(source);
|
||||
return parent != null && (parent.ContentType.IsContainer || _contentTypeService.HasContainerInPath(parent.Path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class ContentUrlResolver : IValueResolver<IContent, ContentItemDisplay, string[]>
|
||||
{
|
||||
public string[] Resolve(IContent source, ContentItemDisplay destination, string[] destMember, ResolutionContext context)
|
||||
{
|
||||
var umbracoContext = context.GetUmbracoContext();
|
||||
|
||||
var urls = umbracoContext == null
|
||||
? new[] {"Cannot generate urls without a current Umbraco Context"}
|
||||
: source.GetContentUrls(umbracoContext).ToArray();
|
||||
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Declares how model mappings for content
|
||||
/// </summary>
|
||||
@@ -26,13 +33,17 @@ namespace Umbraco.Web.Models.Mapping
|
||||
// create, capture, cache
|
||||
var contentOwnerResolver = new OwnerResolver<IContent>(userService);
|
||||
var creatorResolver = new CreatorResolver(userService);
|
||||
var actionButtonsResolver = new ActionButtonsResolver(new Lazy<IUserService>(() => userService));
|
||||
var tabsAndPropertiesResolver = new TabsAndPropertiesResolver(textService);
|
||||
var actionButtonsResolver = new ActionButtonsResolver(userService, contentService);
|
||||
var tabsAndPropertiesResolver = new TabsAndPropertiesResolver<IContent, ContentItemDisplay>(textService);
|
||||
var childOfListViewResolver = new ContentChildOfListViewResolver(contentService, contentTypeService);
|
||||
var contentTypeBasicResolver = new ContentTypeBasicResolver<IContent, ContentItemDisplay>();
|
||||
var contentTreeNodeUrlResolver = new ContentTreeNodeUrlResolver<IContent, ContentTreeController>();
|
||||
var defaultTemplateResolver = new DefaultTemplateResolver();
|
||||
var contentUrlResolver = new ContentUrlResolver();
|
||||
|
||||
//FROM IContent TO ContentItemDisplay
|
||||
CreateMap<IContent, ContentItemDisplay>()
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src =>
|
||||
Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBluePrint : Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => contentOwnerResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Updater, opt => opt.ResolveUsing(src => creatorResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon))
|
||||
@@ -40,29 +51,35 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(src => src.ContentType.Name))
|
||||
.ForMember(dest => dest.IsContainer, opt => opt.MapFrom(src => src.ContentType.IsContainer))
|
||||
.ForMember(dest => dest.IsBlueprint, opt => opt.MapFrom(src => src.Blueprint))
|
||||
.ForMember(dest => dest.IsChildOfListView, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.IsChildOfListView, opt => opt.ResolveUsing(childOfListViewResolver))
|
||||
.ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed))
|
||||
.ForMember(dest => dest.PublishDate, opt => opt.MapFrom(src => src.PublishDate))
|
||||
.ForMember(dest => dest.TemplateAlias, opt => opt.MapFrom(src => src.Template.Alias))
|
||||
.ForMember(dest => dest.Urls, opt => opt.MapFrom(src =>
|
||||
UmbracoContext.Current == null
|
||||
? new[] {"Cannot generate urls without a current Umbraco Context"}
|
||||
: src.GetContentUrls(UmbracoContext.Current)))
|
||||
.ForMember(dest => dest.TemplateAlias, opt => opt.ResolveUsing(defaultTemplateResolver))
|
||||
.ForMember(dest => dest.Urls, opt => opt.ResolveUsing(contentUrlResolver))
|
||||
.ForMember(dest => dest.Properties, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.AllowPreview, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.TreeNodeUrl, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.TreeNodeUrl, opt => opt.ResolveUsing(contentTreeNodeUrlResolver))
|
||||
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Errors, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(src => tabsAndPropertiesResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.DocumentType, opt => opt.ResolveUsing(contentTypeBasicResolver))
|
||||
.ForMember(dest => dest.AllowedTemplates, opt =>
|
||||
opt.MapFrom(content => content.ContentType.AllowedTemplates
|
||||
.Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false)
|
||||
.ToDictionary(t => t.Alias, t => t.Name)))
|
||||
.ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(tabsAndPropertiesResolver))
|
||||
.ForMember(dest => dest.AllowedActions, opt => opt.ResolveUsing(src => actionButtonsResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
|
||||
.AfterMap((src, dest) => AfterMap(src, dest, dataTypeService, textService, contentTypeService, contentService));
|
||||
.AfterMap((content, display) =>
|
||||
{
|
||||
if (content.ContentType.IsContainer)
|
||||
TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, textService);
|
||||
});
|
||||
|
||||
//FROM IContent TO ContentItemBasic<ContentPropertyBasic, IContent>
|
||||
CreateMap<IContent, ContentItemBasic<ContentPropertyBasic, IContent>>()
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src =>
|
||||
Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBluePrint : Constants.UdiEntityType.Document, src.Key)))
|
||||
Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => contentOwnerResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Updater, opt => opt.ResolveUsing(src => creatorResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon))
|
||||
@@ -74,141 +91,12 @@ namespace Umbraco.Web.Models.Mapping
|
||||
//FROM IContent TO ContentItemDto<IContent>
|
||||
CreateMap<IContent, ContentItemDto<IContent>>()
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src =>
|
||||
Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBluePrint : Constants.UdiEntityType.Document, src.Key)))
|
||||
Udi.Create(src.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => contentOwnerResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Icon, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps the generic tab with custom properties for content
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="display"></param>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <param name="localizedText"></param>
|
||||
/// <param name="contentTypeService"></param>
|
||||
/// <param name="contentService"></param>
|
||||
private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService,
|
||||
ILocalizedTextService localizedText, IContentTypeService contentTypeService, IContentService contentService)
|
||||
{
|
||||
// map the IsChildOfListView (this is actually if it is a descendant of a list view!)
|
||||
var parent = content.Parent(contentService);
|
||||
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;
|
||||
}
|
||||
|
||||
//fill in the template config to be passed to the template drop down.
|
||||
var templateItemConfig = new Dictionary<string, string> {{"", localizedText.Localize("general/choose") } };
|
||||
foreach (var t in content.ContentType.AllowedTemplates
|
||||
.Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false))
|
||||
{
|
||||
templateItemConfig.Add(t.Alias, t.Name);
|
||||
}
|
||||
|
||||
if (content.ContentType.IsContainer)
|
||||
{
|
||||
TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, localizedText);
|
||||
}
|
||||
|
||||
var properties = new List<ContentPropertyDisplay>
|
||||
{
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}doctype",
|
||||
Label = localizedText.Localize("content/documentType"),
|
||||
Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName),
|
||||
View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}releasedate",
|
||||
Label = localizedText.Localize("content/releaseDate"),
|
||||
Value = display.ReleaseDate?.ToIsoString(),
|
||||
//Not editible for people without publish permission (U4-287)
|
||||
View = display.AllowedActions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture)) ? "datepicker" : Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View,
|
||||
Config = new Dictionary<string, object>
|
||||
{
|
||||
{"offsetTime", "1"}
|
||||
}
|
||||
//TODO: Fix up hard coded datepicker
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = string.Format("{0}expiredate", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
||||
Label = localizedText.Localize("content/unpublishDate"),
|
||||
Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null,
|
||||
//Not editible for people without publish permission (U4-287)
|
||||
View = display.AllowedActions.Contains(ActionPublish.Instance.Letter.ToString(CultureInfo.InvariantCulture)) ? "datepicker" : Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View,
|
||||
Config = new Dictionary<string, object>
|
||||
{
|
||||
{"offsetTime", "1"}
|
||||
}
|
||||
//TODO: Fix up hard coded datepicker
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = string.Format("{0}template", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
||||
Label = localizedText.Localize("template/template"),
|
||||
Value = display.TemplateAlias,
|
||||
View = "dropdown", //TODO: Hard coding until we make a real dropdown property editor to lookup
|
||||
Config = new Dictionary<string, object>
|
||||
{
|
||||
{"items", templateItemConfig}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TabsAndPropertiesResolver.MapGenericProperties(content, display, localizedText, properties.ToArray(),
|
||||
genericProperties =>
|
||||
{
|
||||
//TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons
|
||||
//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
|
||||
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
|
||||
{
|
||||
var currentDocumentType = contentTypeService.Get(display.ContentTypeAlias);
|
||||
var currentDocumentTypeName = currentDocumentType == null ? string.Empty : localizedText.UmbracoDictionaryTranslate(currentDocumentType.Name);
|
||||
|
||||
var currentDocumentTypeId = currentDocumentType == null ? string.Empty : currentDocumentType.Id.ToString(CultureInfo.InvariantCulture);
|
||||
//TODO: Hard coding this is not good
|
||||
var docTypeLink = string.Format("#/settings/documenttypes/edit/{0}", currentDocumentTypeId);
|
||||
|
||||
//Replace the doc type property
|
||||
var docTypeProperty = genericProperties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
|
||||
docTypeProperty.Value = new List<object>
|
||||
{
|
||||
new
|
||||
{
|
||||
linkText = currentDocumentTypeName,
|
||||
url = docTypeLink,
|
||||
target = "_self",
|
||||
icon = "icon-item-arrangement"
|
||||
}
|
||||
};
|
||||
//TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
|
||||
docTypeProperty.View = "urllist";
|
||||
}
|
||||
|
||||
// inject 'Link to document' as the first generic property
|
||||
genericProperties.Insert(0, new ContentPropertyDisplay
|
||||
{
|
||||
Alias = string.Format("{0}urls", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
||||
Label = localizedText.Localize("content/urls"),
|
||||
Value = string.Join(",", display.Urls),
|
||||
View = "urllist" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,11 @@ namespace Umbraco.Web.Models.Mapping
|
||||
internal class ContentPropertyBasicConverter<TDestination> : ITypeConverter<Property, TDestination>
|
||||
where TDestination : ContentPropertyBasic, new()
|
||||
{
|
||||
private readonly Lazy<IDataTypeService> _dataTypeService;
|
||||
protected IDataTypeService DataTypeService { get; }
|
||||
|
||||
protected IDataTypeService DataTypeService => _dataTypeService.Value;
|
||||
|
||||
public ContentPropertyBasicConverter(Lazy<IDataTypeService> dataTypeService)
|
||||
public ContentPropertyBasicConverter(IDataTypeService dataTypeService)
|
||||
{
|
||||
_dataTypeService = dataTypeService;
|
||||
DataTypeService = dataTypeService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,10 +15,13 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// </summary>
|
||||
internal class ContentPropertyDisplayConverter : ContentPropertyBasicConverter<ContentPropertyDisplay>
|
||||
{
|
||||
public ContentPropertyDisplayConverter(Lazy<IDataTypeService> dataTypeService)
|
||||
: base(dataTypeService)
|
||||
{ }
|
||||
private readonly ILocalizedTextService _textService;
|
||||
|
||||
public ContentPropertyDisplayConverter(IDataTypeService dataTypeService, ILocalizedTextService textService)
|
||||
: base(dataTypeService)
|
||||
{
|
||||
_textService = textService;
|
||||
}
|
||||
public override ContentPropertyDisplay Convert(Property originalProp, ContentPropertyDisplay dest, ResolutionContext context)
|
||||
{
|
||||
var display = base.Convert(originalProp, dest, context);
|
||||
@@ -58,6 +61,10 @@ namespace Umbraco.Web.Models.Mapping
|
||||
display.View = valEditor.View;
|
||||
}
|
||||
|
||||
//Translate
|
||||
display.Label = _textService.UmbracoDictionaryTranslate(display.Label);
|
||||
display.Description = _textService.UmbracoDictionaryTranslate(display.Description);
|
||||
|
||||
return display;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// </summary>
|
||||
internal class ContentPropertyDtoConverter : ContentPropertyBasicConverter<ContentPropertyDto>
|
||||
{
|
||||
public ContentPropertyDtoConverter(Lazy<IDataTypeService> dataTypeService)
|
||||
public ContentPropertyDtoConverter(IDataTypeService dataTypeService)
|
||||
: base(dataTypeService)
|
||||
{ }
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using AutoMapper;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
@@ -12,13 +11,11 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// </summary>
|
||||
internal class ContentPropertyMapperProfile : Profile
|
||||
{
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
|
||||
public ContentPropertyMapperProfile(IDataTypeService dataTypeService)
|
||||
public ContentPropertyMapperProfile(IDataTypeService dataTypeService, ILocalizedTextService textService)
|
||||
{
|
||||
_dataTypeService = dataTypeService;
|
||||
|
||||
var lazyDataTypeService = new Lazy<IDataTypeService>(() => _dataTypeService);
|
||||
var contentPropertyBasicConverter = new ContentPropertyBasicConverter<ContentPropertyBasic>(dataTypeService);
|
||||
var contentPropertyDtoConverter = new ContentPropertyDtoConverter(dataTypeService);
|
||||
var contentPropertyDisplayConverter = new ContentPropertyDisplayConverter(dataTypeService, textService);
|
||||
|
||||
//FROM Property TO ContentPropertyBasic
|
||||
CreateMap<PropertyGroup, Tab<ContentPropertyDisplay>>()
|
||||
@@ -28,16 +25,13 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(tab => tab.Alias, expression => expression.Ignore());
|
||||
|
||||
//FROM Property TO ContentPropertyBasic
|
||||
CreateMap<Property, ContentPropertyBasic>()
|
||||
.ConvertUsing(new ContentPropertyBasicConverter<ContentPropertyBasic>(lazyDataTypeService));
|
||||
CreateMap<Property, ContentPropertyBasic>().ConvertUsing(contentPropertyBasicConverter);
|
||||
|
||||
//FROM Property TO ContentPropertyDto
|
||||
CreateMap<Property, ContentPropertyDto>()
|
||||
.ConvertUsing(new ContentPropertyDtoConverter(lazyDataTypeService));
|
||||
CreateMap<Property, ContentPropertyDto>().ConvertUsing(contentPropertyDtoConverter);
|
||||
|
||||
//FROM Property TO ContentPropertyDisplay
|
||||
CreateMap<Property, ContentPropertyDisplay>()
|
||||
.ConvertUsing(new ContentPropertyDisplayConverter(lazyDataTypeService));
|
||||
CreateMap<Property, ContentPropertyDisplay>().ConvertUsing(contentPropertyDisplayConverter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
src/Umbraco.Web/Models/Mapping/ContentTreeNodeUrlResolver.cs
Normal file
24
src/Umbraco.Web/Models/Mapping/ContentTreeNodeUrlResolver.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
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<TSource, object, string>
|
||||
where TSource : IContentBase
|
||||
where TController : ContentTreeControllerBase
|
||||
{
|
||||
public string Resolve(TSource source, object destination, string destMember, ResolutionContext context)
|
||||
{
|
||||
var umbracoContext = context.GetUmbracoContext(throwIfMissing: false);
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs
Normal file
39
src/Umbraco.Web/Models/Mapping/ContentTypeBasicResolver.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves a <see cref="ContentTypeBasic"/> from the <see cref="IContent"/> item and checks if the current user
|
||||
/// has access to see this data
|
||||
/// </summary>
|
||||
internal class ContentTypeBasicResolver<TSource, TDestination> : IValueResolver<TSource, TDestination, ContentTypeBasic>
|
||||
where TSource : IContentBase
|
||||
{
|
||||
public ContentTypeBasic Resolve(TSource source, TDestination destination, ContentTypeBasic destMember, ResolutionContext context)
|
||||
{
|
||||
//TODO: We can resolve the UmbracoContext from the IValueResolver options!
|
||||
// OMG
|
||||
if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null
|
||||
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
|
||||
{
|
||||
ContentTypeBasic contentTypeBasic;
|
||||
if (source is IContent content)
|
||||
contentTypeBasic = Mapper.Map<ContentTypeBasic>(content.ContentType);
|
||||
else if (source is IMedia media)
|
||||
contentTypeBasic = Mapper.Map<ContentTypeBasic>(media.ContentType);
|
||||
else
|
||||
throw new NotSupportedException($"Expected TSource to be IContent or IMedia, got {typeof(TSource).Name}.");
|
||||
|
||||
return contentTypeBasic;
|
||||
}
|
||||
//no access
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,39 +14,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// </summary>
|
||||
internal class ContentTypeMapperProfile : Profile
|
||||
{
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
private readonly IFileService _fileService;
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
private readonly IMediaTypeService _mediaTypeService;
|
||||
|
||||
public ContentTypeMapperProfile(PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IFileService fileService, IContentTypeService contentTypeService, IMediaTypeService mediaTypeService)
|
||||
{
|
||||
_propertyEditors = propertyEditors;
|
||||
_dataTypeService = dataTypeService;
|
||||
_fileService = fileService;
|
||||
_contentTypeService = contentTypeService;
|
||||
_mediaTypeService = mediaTypeService;
|
||||
|
||||
// v7 creates this map twice which makes no sense, and AutoMapper 6 detects it
|
||||
// assuming the second map took over, and removing the first one for now
|
||||
/*
|
||||
CreateMap<PropertyTypeBasic, PropertyType>()
|
||||
.ConstructUsing(basic => new PropertyType(_dataTypeService.GetDataTypeDefinitionById(basic.DataTypeId)))
|
||||
.ForMember(type => type.ValidationRegExp, opt => opt.ResolveUsing(basic => basic.Validation.Pattern))
|
||||
.ForMember(type => type.Mandatory, opt => opt.ResolveUsing(basic => basic.Validation.Mandatory))
|
||||
.ForMember(type => type.Name, opt => opt.ResolveUsing(basic => basic.Label))
|
||||
.ForMember(type => type.DataTypeDefinitionId, opt => opt.ResolveUsing(basic => basic.DataTypeId))
|
||||
.ForMember(type => type.DataTypeId, opt => opt.Ignore())
|
||||
.ForMember(type => type.PropertyEditorAlias, opt => opt.Ignore())
|
||||
.ForMember(type => type.HelpText, opt => opt.Ignore())
|
||||
.ForMember(type => type.Key, opt => opt.Ignore())
|
||||
.ForMember(type => type.CreateDate, opt => opt.Ignore())
|
||||
.ForMember(type => type.UpdateDate, opt => opt.Ignore())
|
||||
.ForMember(type => type.DeletedDate, opt => opt.Ignore())
|
||||
.ForMember(type => type.HasIdentity, opt => opt.Ignore());
|
||||
*/
|
||||
|
||||
CreateMap<DocumentTypeSave, IContentType>()
|
||||
//do the base mapping
|
||||
.MapBaseContentTypeSaveToEntity<DocumentTypeSave, PropertyTypeBasic, IContentType>()
|
||||
@@ -57,13 +26,15 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
dest.AllowedTemplates = source.AllowedTemplates
|
||||
.Where(x => x != null)
|
||||
.Select(s => _fileService.GetTemplate(s))
|
||||
.Select(s => fileService.GetTemplate(s))
|
||||
.ToArray();
|
||||
|
||||
if (source.DefaultTemplate != null)
|
||||
dest.SetDefaultTemplate(_fileService.GetTemplate(source.DefaultTemplate));
|
||||
dest.SetDefaultTemplate(fileService.GetTemplate(source.DefaultTemplate));
|
||||
else
|
||||
dest.SetDefaultTemplate(null);
|
||||
|
||||
ContentTypeProfileExtensions.AfterMapContentTypeSaveToEntity(source, dest, _contentTypeService);
|
||||
ContentTypeProfileExtensions.AfterMapContentTypeSaveToEntity(source, dest, contentTypeService);
|
||||
});
|
||||
|
||||
CreateMap<MediaTypeSave, IMediaType>()
|
||||
@@ -72,7 +43,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ConstructUsing((source) => new MediaType(source.ParentId))
|
||||
.AfterMap((source, dest) =>
|
||||
{
|
||||
ContentTypeProfileExtensions.AfterMapMediaTypeSaveToEntity(source, dest, _mediaTypeService);
|
||||
ContentTypeProfileExtensions.AfterMapMediaTypeSaveToEntity(source, dest, mediaTypeService);
|
||||
});
|
||||
|
||||
CreateMap<MemberTypeSave, IMemberType>()
|
||||
@@ -81,9 +52,9 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ConstructUsing(source => new MemberType(source.ParentId))
|
||||
.AfterMap((source, dest) =>
|
||||
{
|
||||
ContentTypeProfileExtensions.AfterMapContentTypeSaveToEntity(source, dest, _contentTypeService);
|
||||
ContentTypeProfileExtensions.AfterMapContentTypeSaveToEntity(source, dest, contentTypeService);
|
||||
|
||||
//map the MemberCanEditProperty,MemberCanViewProperty
|
||||
//map the MemberCanEditProperty,MemberCanViewProperty,IsSensitiveData
|
||||
foreach (var propertyType in source.Groups.SelectMany(x => x.Properties))
|
||||
{
|
||||
var localCopy = propertyType;
|
||||
@@ -92,6 +63,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
dest.SetMemberCanEditProperty(localCopy.Alias, localCopy.MemberCanEditProperty);
|
||||
dest.SetMemberCanViewProperty(localCopy.Alias, localCopy.MemberCanViewProperty);
|
||||
dest.SetIsSensitiveProperty(localCopy.Alias, localCopy.IsSensitiveData);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -100,10 +72,10 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
CreateMap<IMemberType, MemberTypeDisplay>()
|
||||
//map base logic
|
||||
.MapBaseContentTypeEntityToDisplay<IMemberType, MemberTypeDisplay, MemberPropertyTypeDisplay>(_propertyEditors, _dataTypeService, _contentTypeService)
|
||||
.MapBaseContentTypeEntityToDisplay<IMemberType, MemberTypeDisplay, MemberPropertyTypeDisplay>(propertyEditors, dataTypeService, contentTypeService)
|
||||
.AfterMap((memberType, display) =>
|
||||
{
|
||||
//map the MemberCanEditProperty,MemberCanViewProperty
|
||||
//map the MemberCanEditProperty,MemberCanViewProperty,IsSensitiveData
|
||||
foreach (var propertyType in memberType.PropertyTypes)
|
||||
{
|
||||
var localCopy = propertyType;
|
||||
@@ -112,13 +84,14 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
displayProp.MemberCanEditProperty = memberType.MemberCanEditProperty(localCopy.Alias);
|
||||
displayProp.MemberCanViewProperty = memberType.MemberCanViewProperty(localCopy.Alias);
|
||||
displayProp.IsSensitiveData = memberType.IsSensitiveProperty(localCopy.Alias);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
CreateMap<IMediaType, MediaTypeDisplay>()
|
||||
//map base logic
|
||||
.MapBaseContentTypeEntityToDisplay<IMediaType, MediaTypeDisplay, PropertyTypeDisplay>(_propertyEditors, _dataTypeService, _contentTypeService)
|
||||
.MapBaseContentTypeEntityToDisplay<IMediaType, MediaTypeDisplay, PropertyTypeDisplay>(propertyEditors, dataTypeService, contentTypeService)
|
||||
.AfterMap((source, dest) =>
|
||||
{
|
||||
//default listview
|
||||
@@ -127,14 +100,14 @@ namespace Umbraco.Web.Models.Mapping
|
||||
if (string.IsNullOrEmpty(source.Name) == false)
|
||||
{
|
||||
var name = Constants.Conventions.DataTypes.ListViewPrefix + source.Name;
|
||||
if (_dataTypeService.GetDataType(name) != null)
|
||||
if (dataTypeService.GetDataType(name) != null)
|
||||
dest.ListViewEditorName = name;
|
||||
}
|
||||
});
|
||||
|
||||
CreateMap<IContentType, DocumentTypeDisplay>()
|
||||
//map base logic
|
||||
.MapBaseContentTypeEntityToDisplay<IContentType, DocumentTypeDisplay, PropertyTypeDisplay>(_propertyEditors, _dataTypeService, _contentTypeService)
|
||||
.MapBaseContentTypeEntityToDisplay<IContentType, DocumentTypeDisplay, PropertyTypeDisplay>(propertyEditors, dataTypeService, contentTypeService)
|
||||
.ForMember(dto => dto.AllowedTemplates, opt => opt.Ignore())
|
||||
.ForMember(dto => dto.DefaultTemplate, opt => opt.Ignore())
|
||||
.ForMember(display => display.Notifications, opt => opt.Ignore())
|
||||
@@ -152,7 +125,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
if (string.IsNullOrEmpty(source.Alias) == false)
|
||||
{
|
||||
var name = Constants.Conventions.DataTypes.ListViewPrefix + source.Alias;
|
||||
if (_dataTypeService.GetDataType(name) != null)
|
||||
if (dataTypeService.GetDataType(name) != null)
|
||||
dest.ListViewEditorName = name;
|
||||
}
|
||||
|
||||
@@ -175,7 +148,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
.ConstructUsing(propertyTypeBasic =>
|
||||
{
|
||||
var dataType = _dataTypeService.GetDataType(propertyTypeBasic.DataTypeId);
|
||||
var dataType = dataTypeService.GetDataType(propertyTypeBasic.DataTypeId);
|
||||
if (dataType == null) throw new NullReferenceException("No data type found with id " + propertyTypeBasic.DataTypeId);
|
||||
return new PropertyType(dataType, propertyTypeBasic.Alias);
|
||||
})
|
||||
@@ -226,7 +199,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
//if the dest is set and it's the same as the source, then don't change
|
||||
if (destAllowedTemplateAliases.SequenceEqual(source.AllowedTemplates) == false)
|
||||
{
|
||||
var templates = _fileService.GetTemplates(source.AllowedTemplates.ToArray());
|
||||
var templates = fileService.GetTemplates(source.AllowedTemplates.ToArray());
|
||||
dest.AllowedTemplates = source.AllowedTemplates
|
||||
.Select(x => Mapper.Map<EntityBasic>(templates.SingleOrDefault(t => t.Alias == x)))
|
||||
.WhereNotNull()
|
||||
@@ -238,7 +211,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
//if the dest is set and it's the same as the source, then don't change
|
||||
if (dest.DefaultTemplate == null || source.DefaultTemplate != dest.DefaultTemplate.Alias)
|
||||
{
|
||||
var template = _fileService.GetTemplate(source.DefaultTemplate);
|
||||
var template = fileService.GetTemplate(source.DefaultTemplate);
|
||||
dest.DefaultTemplate = template == null ? null : Mapper.Map<EntityBasic>(template);
|
||||
}
|
||||
}
|
||||
|
||||
24
src/Umbraco.Web/Models/Mapping/DefaultTemplateResolver.cs
Normal file
24
src/Umbraco.Web/Models/Mapping/DefaultTemplateResolver.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class DefaultTemplateResolver : IValueResolver<IContent, ContentItemDisplay, string>
|
||||
{
|
||||
public string Resolve(IContent source, ContentItemDisplay destination, string destMember, ResolutionContext context)
|
||||
{
|
||||
if (source == null || source.Template == null) return null;
|
||||
|
||||
var alias = source.Template.Alias;
|
||||
|
||||
//set default template if template isn't set
|
||||
if (string.IsNullOrEmpty(alias))
|
||||
alias = source.ContentType.DefaultTemplate == null
|
||||
? string.Empty
|
||||
: source.ContentType.DefaultTemplate.Alias;
|
||||
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
CreateMap<EntitySlim, EntityBasic>()
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(ObjectTypes.GetUdiType(src.NodeObjectType), src.Key)))
|
||||
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => GetContentTypeIcon(src)))
|
||||
.ForMember(dest => dest.Trashed, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed))
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.AfterMap((src, dest) =>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class MediaChildOfListViewResolver : IValueResolver<IMedia, MediaItemDisplay, bool>
|
||||
{
|
||||
private readonly IMediaService _mediaService;
|
||||
private readonly IMediaTypeService _mediaTypeService;
|
||||
|
||||
public MediaChildOfListViewResolver(IMediaService mediaService, IMediaTypeService mediaTypeService)
|
||||
{
|
||||
_mediaService = mediaService;
|
||||
_mediaTypeService = mediaTypeService;
|
||||
}
|
||||
|
||||
public bool Resolve(IMedia source, MediaItemDisplay destination, bool destMember, ResolutionContext context)
|
||||
{
|
||||
// map the IsChildOfListView (this is actually if it is a descendant of a list view!)
|
||||
var parent = _mediaService.GetParent(source);
|
||||
return parent != null && (parent.ContentType.IsContainer || _mediaTypeService.HasContainerInPath(parent.Path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using AutoMapper;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
@@ -19,11 +14,14 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// </summary>
|
||||
internal class MediaMapperProfile : Profile
|
||||
{
|
||||
public MediaMapperProfile(IUserService userService, ILocalizedTextService textService, IDataTypeService dataTypeService, IMediaService mediaService, ILogger logger)
|
||||
public MediaMapperProfile(IUserService userService, ILocalizedTextService textService, IDataTypeService dataTypeService, IMediaService mediaService, IMediaTypeService mediaTypeService, ILogger logger)
|
||||
{
|
||||
// create, capture, cache
|
||||
var mediaOwnerResolver = new OwnerResolver<IMedia>(userService);
|
||||
var tabsAndPropertiesResolver = new TabsAndPropertiesResolver(textService);
|
||||
var tabsAndPropertiesResolver = new TabsAndPropertiesResolver<IMedia, MediaItemDisplay>(textService);
|
||||
var childOfListViewResolver = new MediaChildOfListViewResolver(mediaService, mediaTypeService);
|
||||
var contentTreeNodeUrlResolver = new ContentTreeNodeUrlResolver<IMedia, MediaTreeController>();
|
||||
var mediaTypeBasicResolver = new ContentTypeBasicResolver<IMedia, MediaItemDisplay>();
|
||||
|
||||
//FROM IMedia TO MediaItemDisplay
|
||||
CreateMap<IMedia, MediaItemDisplay>()
|
||||
@@ -31,20 +29,26 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => mediaOwnerResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Icon, opt => opt.MapFrom(content => content.ContentType.Icon))
|
||||
.ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(content => content.ContentType.Alias))
|
||||
.ForMember(dest => dest.IsChildOfListView, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.IsChildOfListView, opt => opt.ResolveUsing(childOfListViewResolver))
|
||||
.ForMember(dest => dest.Trashed, opt => opt.MapFrom(content => content.Trashed))
|
||||
.ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(content => content.ContentType.Name))
|
||||
.ForMember(dest => dest.Properties, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.TreeNodeUrl, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.TreeNodeUrl, opt => opt.ResolveUsing(contentTreeNodeUrlResolver))
|
||||
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Errors, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Published, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.IsContainer, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(src => tabsAndPropertiesResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(tabsAndPropertiesResolver))
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
|
||||
.AfterMap((src, dest) => AfterMap(src, dest, dataTypeService, textService, logger, mediaService));
|
||||
.ForMember(dest => dest.ContentType, opt => opt.ResolveUsing(mediaTypeBasicResolver))
|
||||
.ForMember(dest => dest.MediaLink, opt => opt.ResolveUsing(content => string.Join(",", content.GetUrls(UmbracoConfig.For.UmbracoSettings().Content, logger))))
|
||||
.AfterMap((media, display) =>
|
||||
{
|
||||
if (media.ContentType.IsContainer)
|
||||
TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService, textService);
|
||||
});
|
||||
|
||||
//FROM IMedia TO ContentItemBasic<ContentPropertyBasic, IMedia>
|
||||
CreateMap<IMedia, ContentItemBasic<ContentPropertyBasic, IMedia>>()
|
||||
@@ -68,74 +72,5 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore());
|
||||
}
|
||||
|
||||
private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText, ILogger logger, IMediaService mediaService)
|
||||
{
|
||||
// Adapted from ContentModelMapper
|
||||
//map the IsChildOfListView (this is actually if it is a descendant of a list view!)
|
||||
var parent = media.Parent();
|
||||
display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || Current.Services.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)
|
||||
{
|
||||
TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService, localizedText);
|
||||
}
|
||||
|
||||
var genericProperties = new List<ContentPropertyDisplay>
|
||||
{
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
||||
Label = localizedText.Localize("content/mediatype"),
|
||||
Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName),
|
||||
View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View
|
||||
}
|
||||
};
|
||||
|
||||
TabsAndPropertiesResolver.MapGenericProperties(media, 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 mediaTypeLink = string.Format("#/settings/mediatypes/edit/{0}", media.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 = media.ContentType.Name,
|
||||
url = mediaTypeLink,
|
||||
target = "_self",
|
||||
icon = "icon-item-arrangement"
|
||||
}
|
||||
};
|
||||
docTypeProperty.View = "urllist";
|
||||
}
|
||||
|
||||
// inject 'Link to media' as the first generic property
|
||||
var links = media.GetUrls(UmbracoConfig.For.UmbracoSettings().Content, logger);
|
||||
if (links.Any())
|
||||
{
|
||||
var link = new ContentPropertyDisplay
|
||||
{
|
||||
Alias = string.Format("{0}urls", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
||||
Label = localizedText.Localize("media/urls"),
|
||||
Value = string.Join(",", links),
|
||||
View = "urllist"
|
||||
};
|
||||
properties.Insert(0, link);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver to map <see cref="IMember"/> properties to a collection of <see cref="ContentPropertyBasic"/>
|
||||
/// </summary>
|
||||
internal class MemberBasicPropertiesResolver : IValueResolver<IMember, MemberBasic, IEnumerable<ContentPropertyBasic>>
|
||||
{
|
||||
public IEnumerable<ContentPropertyBasic> Resolve(IMember source, MemberBasic destination, IEnumerable<ContentPropertyBasic> destMember, ResolutionContext context)
|
||||
{
|
||||
var umbracoContext = context.GetUmbracoContext();
|
||||
|
||||
var result = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyBasic>>(
|
||||
// Sort properties so items from different compositions appear in correct order (see U4-9298). Map sorted properties.
|
||||
source.Properties.OrderBy(prop => prop.PropertyType.SortOrder))
|
||||
.ToList();
|
||||
|
||||
var memberType = source.ContentType;
|
||||
|
||||
//now update the IsSensitive value
|
||||
foreach (var prop in result)
|
||||
{
|
||||
//check if this property is flagged as sensitive
|
||||
var isSensitiveProperty = memberType.IsSensitiveProperty(prop.Alias);
|
||||
//check permissions for viewing sensitive data
|
||||
if (isSensitiveProperty && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false)
|
||||
{
|
||||
//mark this property as sensitive
|
||||
prop.IsSensitive = true;
|
||||
//clear the value
|
||||
prop.Value = null;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Security;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
@@ -26,18 +18,15 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
// create, capture, cache
|
||||
var memberOwnerResolver = new OwnerResolver<IMember>(userService);
|
||||
var tabsAndPropertiesResolver = new MemberTabsAndPropertiesResolver(textService);
|
||||
var tabsAndPropertiesResolver = new MemberTabsAndPropertiesResolver(textService, memberService, userService);
|
||||
var memberProfiderFieldMappingResolver = new MemberProviderFieldResolver();
|
||||
var membershipScenarioMappingResolver = new MembershipScenarioResolver(new Lazy<IMemberTypeService>(() => memberTypeService));
|
||||
var membershipScenarioMappingResolver = new MembershipScenarioResolver(memberTypeService);
|
||||
var memberDtoPropertiesResolver = new MemberDtoPropertiesResolver();
|
||||
var memberTreeNodeUrlResolver = new MemberTreeNodeUrlResolver();
|
||||
var memberBasicPropertiesResolver = new MemberBasicPropertiesResolver();
|
||||
|
||||
//FROM MembershipUser TO MediaItemDisplay - used when using a non-umbraco membership provider
|
||||
CreateMap<MembershipUser, MemberDisplay>()
|
||||
.ConvertUsing(user =>
|
||||
{
|
||||
var member = Mapper.Map<MembershipUser, IMember>(user);
|
||||
return Mapper.Map<IMember, MemberDisplay>(member);
|
||||
});
|
||||
CreateMap<MembershipUser, MemberDisplay>().ConvertUsing<MembershipUserTypeConverter>();
|
||||
|
||||
//FROM MembershipUser TO IMember - used when using a non-umbraco membership provider
|
||||
CreateMap<MembershipUser, IMember>()
|
||||
@@ -75,7 +64,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias))
|
||||
.ForMember(dest => dest.ContentTypeName, opt => opt.MapFrom(src => src.ContentType.Name))
|
||||
.ForMember(dest => dest.Properties, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(src => tabsAndPropertiesResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(tabsAndPropertiesResolver))
|
||||
.ForMember(dest => dest.MemberProviderFieldMapping, opt => opt.ResolveUsing(src => memberProfiderFieldMappingResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.MembershipScenario, opt => opt.ResolveUsing(src => membershipScenarioMappingResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
|
||||
@@ -86,8 +75,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.IsChildOfListView, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Trashed, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.IsContainer, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.TreeNodeUrl, opt => opt.Ignore())
|
||||
.AfterMap((src, dest) => MapGenericCustomProperties(memberService, userService, src, dest, textService));
|
||||
.ForMember(dest => dest.TreeNodeUrl, opt => opt.ResolveUsing(memberTreeNodeUrlResolver));
|
||||
|
||||
//FROM IMember TO MemberBasic
|
||||
CreateMap<IMember, MemberBasic>()
|
||||
@@ -100,7 +88,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.Trashed, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Published, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore());
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.ForMember(dto => dto.Properties, expression => expression.ResolveUsing(memberBasicPropertiesResolver));
|
||||
|
||||
//FROM MembershipUser TO MemberBasic
|
||||
CreateMap<MembershipUser, MemberBasic>()
|
||||
@@ -110,7 +99,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.CreateDate, opt => opt.MapFrom(src => src.CreationDate))
|
||||
.ForMember(dest => dest.UpdateDate, opt => opt.MapFrom(src => src.LastActivityDate))
|
||||
.ForMember(dest => dest.Key, opt => opt.MapFrom(src => src.ProviderUserKey.TryConvertTo<Guid>().Result.ToString("N")))
|
||||
.ForMember(dest => dest.Owner, opt => opt.UseValue(new ContentEditing.UserProfile {Name = "Admin", UserId = 0}))
|
||||
.ForMember(dest => dest.Owner, opt => opt.UseValue(new UserProfile {Name = "Admin", UserId = 0}))
|
||||
.ForMember(dest => dest.Icon, opt => opt.UseValue("icon-user"))
|
||||
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.UserName))
|
||||
.ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email))
|
||||
@@ -148,170 +137,5 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Path, opt => opt.Ignore());
|
||||
}
|
||||
|
||||
/// <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 = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().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>
|
||||
{
|
||||
// fixme why ignoreCase, what are we doing here?!
|
||||
{"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 IUmbracoMemberTypeMembershipProvider;
|
||||
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>
|
||||
/// Returns the login property display field
|
||||
/// </summary>
|
||||
/// <param name="memberService"></param>
|
||||
/// <param name="member"></param>
|
||||
/// <param name="display"></param>
|
||||
/// <param name="localizedText"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// If the membership provider installed is the umbraco membership provider, then we will allow changing the username, however if
|
||||
/// the membership provider is a custom one, we cannot allow chaning the username because MembershipProvider's do not actually natively
|
||||
/// allow that.
|
||||
/// </remarks>
|
||||
internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, MemberDisplay display, ILocalizedTextService localizedText)
|
||||
{
|
||||
var prop = new ContentPropertyDisplay
|
||||
{
|
||||
Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
|
||||
Label = localizedText.Localize("login"),
|
||||
Value = display.Username
|
||||
};
|
||||
|
||||
var scenario = memberService.GetMembershipScenario();
|
||||
|
||||
//only allow editing if this is a new member, or if the membership provider is the umbraco one
|
||||
if (member.HasIdentity == false || scenario == MembershipScenario.NativeUmbraco)
|
||||
{
|
||||
prop.View = "textbox";
|
||||
prop.Validation.Mandatory = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
prop.View = "readonlyvalue";
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
internal static IDictionary<string, bool> GetMemberGroupValue(string username)
|
||||
{
|
||||
var userRoles = username.IsNullOrWhiteSpace() ? null : Roles.GetRolesForUser(username);
|
||||
|
||||
// create a dictionary of all roles (except internal roles) + "false"
|
||||
var result = Roles.GetAllRoles().Distinct()
|
||||
// if a role starts with __umbracoRole we won't show it as it's an internal role used for public access
|
||||
.Where(x => x.StartsWith(Constants.Conventions.Member.InternalRolePrefix) == false)
|
||||
.ToDictionary(x => x, x => false);
|
||||
|
||||
// if user has no roles, just return the dictionary
|
||||
if (userRoles == null) return result;
|
||||
|
||||
// else update the dictionary to "true" for the user roles (except internal roles)
|
||||
foreach (var userRole in userRoles.Where(x => x.StartsWith(Constants.Conventions.Member.InternalRolePrefix) == false))
|
||||
result[userRole] = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Security;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
@@ -16,44 +20,50 @@ namespace Umbraco.Web.Models.Mapping
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver
|
||||
internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver<IMember, MemberDisplay>
|
||||
{
|
||||
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)
|
||||
{
|
||||
_localizedTextService = localizedTextService;
|
||||
_memberService = memberService;
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService,
|
||||
IEnumerable<string> ignoreProperties) : base(localizedTextService, ignoreProperties)
|
||||
public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService, IEnumerable<string> ignoreProperties, IMemberService memberService, IUserService userService)
|
||||
: base(localizedTextService, ignoreProperties)
|
||||
{
|
||||
_localizedTextService = localizedTextService;
|
||||
_memberService = memberService;
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
public override IEnumerable<Tab<ContentPropertyDisplay>> Resolve(IContentBase content)
|
||||
/// <inheritdoc />
|
||||
/// <remarks>Overriden to deal with custom member properties and permissions.</remarks>
|
||||
public override IEnumerable<Tab<ContentPropertyDisplay>> Resolve(IMember source, MemberDisplay destination, IEnumerable<Tab<ContentPropertyDisplay>> destMember, ResolutionContext context)
|
||||
{
|
||||
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
|
||||
IgnoreProperties = content.PropertyTypes
|
||||
IgnoreProperties = source.PropertyTypes
|
||||
.Where(x => x.HasIdentity == false)
|
||||
.Select(x => x.Alias)
|
||||
.ToArray();
|
||||
|
||||
var result = base.Resolve(content).ToArray();
|
||||
var resolved = base.Resolve(source, destination, destMember, context);
|
||||
|
||||
if (provider.IsUmbracoMembershipProvider() == false)
|
||||
{
|
||||
//it's a generic provider so update the locked out property based on our known constant alias
|
||||
var isLockedOutProperty = result.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == Constants.Conventions.Member.IsLockedOut);
|
||||
if (isLockedOutProperty != null && isLockedOutProperty.Value.ToString() != "1")
|
||||
var isLockedOutProperty = resolved.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == Constants.Conventions.Member.IsLockedOut);
|
||||
if (isLockedOutProperty?.Value != null && isLockedOutProperty.Value.ToString() != "1")
|
||||
{
|
||||
isLockedOutProperty.View = "readonlyvalue";
|
||||
isLockedOutProperty.Value = _localizedTextService.Localize("general/no");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -62,15 +72,186 @@ namespace Umbraco.Web.Models.Mapping
|
||||
//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 :(
|
||||
// TODO: But is there a way to map the IMember.IsLockedOut to the property ? i dunno.
|
||||
var isLockedOutProperty = result.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == umbracoProvider.LockPropertyTypeAlias);
|
||||
if (isLockedOutProperty != null && isLockedOutProperty.Value.ToString() != "1")
|
||||
var isLockedOutProperty = resolved.SelectMany(x => x.Properties).FirstOrDefault(x => x.Alias == umbracoProvider.LockPropertyTypeAlias);
|
||||
if (isLockedOutProperty?.Value != null && isLockedOutProperty.Value.ToString() != "1")
|
||||
{
|
||||
isLockedOutProperty.View = "readonlyvalue";
|
||||
isLockedOutProperty.Value = _localizedTextService.Localize("general/no");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var umbracoContext = context.GetUmbracoContext();
|
||||
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}", source.ContentTypeId);
|
||||
|
||||
//Replace the doctype property
|
||||
var docTypeProperty = resolved.SelectMany(x => x.Properties)
|
||||
.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
|
||||
docTypeProperty.Value = new List<object>
|
||||
{
|
||||
new
|
||||
{
|
||||
linkText = source.ContentType.Name,
|
||||
url = memberTypeLink,
|
||||
target = "_self",
|
||||
icon = "icon-item-arrangement"
|
||||
}
|
||||
};
|
||||
docTypeProperty.View = "urllist";
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
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 = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}doctype",
|
||||
Label = _localizedTextService.Localize("content/membertype"),
|
||||
Value = _localizedTextService.UmbracoDictionaryTranslate(member.ContentType.Name),
|
||||
View = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View
|
||||
},
|
||||
GetLoginProperty(_memberService, member, _localizedTextService),
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}email",
|
||||
Label = _localizedTextService.Localize("general/email"),
|
||||
Value = member.Email,
|
||||
View = "email",
|
||||
Validation = {Mandatory = true}
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}password",
|
||||
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>
|
||||
{
|
||||
// fixme why ignoreCase, what are we doing here?!
|
||||
{"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 = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}membergroup",
|
||||
Label = _localizedTextService.Localize("content/membergroup"),
|
||||
Value = GetMemberGroupValue(member.Username),
|
||||
View = "membergroups",
|
||||
Config = new Dictionary<string, object> {{"IsRequired", true}}
|
||||
}
|
||||
};
|
||||
|
||||
return genericProperties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden to assign the IsSensitive property values
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="properties"></param>
|
||||
/// <returns></returns>
|
||||
protected override List<ContentPropertyDisplay> MapProperties(UmbracoContext umbracoContext, IContentBase content, List<Property> properties)
|
||||
{
|
||||
var result = base.MapProperties(umbracoContext, content, properties);
|
||||
var member = (IMember)content;
|
||||
var memberType = member.ContentType;
|
||||
|
||||
//now update the IsSensitive value
|
||||
foreach (var prop in result)
|
||||
{
|
||||
//check if this property is flagged as sensitive
|
||||
var isSensitiveProperty = memberType.IsSensitiveProperty(prop.Alias);
|
||||
//check permissions for viewing sensitive data
|
||||
if (isSensitiveProperty && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false)
|
||||
{
|
||||
//mark this property as sensitive
|
||||
prop.IsSensitive = true;
|
||||
//mark this property as readonly so that it does not post any data
|
||||
prop.Readonly = true;
|
||||
//replace this editor with a sensitivevalue
|
||||
prop.View = "sensitivevalue";
|
||||
//clear the value
|
||||
prop.Value = null;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the login property display field
|
||||
/// </summary>
|
||||
/// <param name="memberService"></param>
|
||||
/// <param name="member"></param>
|
||||
/// <param name="display"></param>
|
||||
/// <param name="localizedText"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// If the membership provider installed is the umbraco membership provider, then we will allow changing the username, however if
|
||||
/// the membership provider is a custom one, we cannot allow chaning the username because MembershipProvider's do not actually natively
|
||||
/// allow that.
|
||||
/// </remarks>
|
||||
internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, ILocalizedTextService localizedText)
|
||||
{
|
||||
var prop = new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}login",
|
||||
Label = localizedText.Localize("login"),
|
||||
Value = member.Username
|
||||
};
|
||||
|
||||
var scenario = memberService.GetMembershipScenario();
|
||||
|
||||
//only allow editing if this is a new member, or if the membership provider is the umbraco one
|
||||
if (member.HasIdentity == false || scenario == MembershipScenario.NativeUmbraco)
|
||||
{
|
||||
prop.View = "textbox";
|
||||
prop.Validation.Mandatory = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
prop.View = "readonlyvalue";
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
internal static IDictionary<string, bool> GetMemberGroupValue(string username)
|
||||
{
|
||||
var userRoles = username.IsNullOrWhiteSpace() ? null : Roles.GetRolesForUser(username);
|
||||
|
||||
// create a dictionary of all roles (except internal roles) + "false"
|
||||
var result = Roles.GetAllRoles().Distinct()
|
||||
// if a role starts with __umbracoRole we won't show it as it's an internal role used for public access
|
||||
.Where(x => x.StartsWith(Constants.Conventions.Member.InternalRolePrefix) == false)
|
||||
.ToDictionary(x => x, x => false);
|
||||
|
||||
// if user has no roles, just return the dictionary
|
||||
if (userRoles == null) return result;
|
||||
|
||||
// else update the dictionary to "true" for the user roles (except internal roles)
|
||||
foreach (var userRole in userRoles.Where(x => x.StartsWith(Constants.Conventions.Member.InternalRolePrefix) == false))
|
||||
result[userRole] = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
src/Umbraco.Web/Models/Mapping/MemberTreeNodeUrlResolver.cs
Normal file
23
src/Umbraco.Web/Models/Mapping/MemberTreeNodeUrlResolver.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Web.Mvc;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the tree node url for the IMember
|
||||
/// </summary>
|
||||
internal class MemberTreeNodeUrlResolver : IValueResolver<IMember, MemberDisplay, string>
|
||||
{
|
||||
public string Resolve(IMember source, MemberDisplay destination, string destMember, ResolutionContext context)
|
||||
{
|
||||
var umbracoContext = context.GetUmbracoContext(throwIfMissing: false);
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,9 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class MembershipScenarioResolver
|
||||
{
|
||||
private readonly Lazy<IMemberTypeService> _memberTypeService;
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
|
||||
public MembershipScenarioResolver(Lazy<IMemberTypeService> memberTypeService)
|
||||
public MembershipScenarioResolver(IMemberTypeService memberTypeService)
|
||||
{
|
||||
_memberTypeService = memberTypeService;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
return MembershipScenario.NativeUmbraco;
|
||||
}
|
||||
var memberType = _memberTypeService.Value.Get(Constants.Conventions.MemberTypes.DefaultAlias);
|
||||
var memberType = _memberTypeService.Get(Constants.Conventions.MemberTypes.DefaultAlias);
|
||||
return memberType != null
|
||||
? MembershipScenario.CustomProviderWithUmbracoLink
|
||||
: MembershipScenario.StandaloneCustomProvider;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Web.Security;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// A converter to go from a <see cref="MembershipUser"/> to a <see cref="MemberDisplay"/>
|
||||
/// </summary>
|
||||
internal class MembershipUserTypeConverter : ITypeConverter<MembershipUser, MemberDisplay>
|
||||
{
|
||||
public MemberDisplay Convert(MembershipUser source, MemberDisplay destination, ResolutionContext context)
|
||||
{
|
||||
//first convert to IMember
|
||||
var member = Mapper.Map<MembershipUser, IMember>(source);
|
||||
//then convert to MemberDisplay
|
||||
return ContextMapper.Map<IMember, MemberDisplay>(member, context.GetUmbracoContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
using AutoMapper;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// A model mapper used to map models for the various dashboards
|
||||
/// </summary>
|
||||
internal class DashboardMapperProfile : Profile
|
||||
internal class RedirectUrlMapperProfile : Profile
|
||||
{
|
||||
public DashboardMapperProfile()
|
||||
public RedirectUrlMapperProfile()
|
||||
{
|
||||
CreateMap<IRedirectUrl, ContentRedirectUrl>()
|
||||
.ForMember(x => x.OriginalUrl, expression => expression.MapFrom(item => UmbracoContext.Current.UrlProvider.GetUrlFromRoute(item.ContentId, item.Url)))
|
||||
.ForMember(x => x.OriginalUrl, expression => expression.MapFrom(item => Current.UmbracoContext.UrlProvider.GetUrlFromRoute(item.ContentId, item.Url)))
|
||||
.ForMember(x => x.DestinationUrl, expression => expression.Ignore())
|
||||
.ForMember(x => x.RedirectId, expression => expression.MapFrom(item => item.Key));
|
||||
}
|
||||
@@ -10,17 +10,14 @@ using Umbraco.Web.Composing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the tabs collection with properties assigned for display models
|
||||
/// </summary>
|
||||
internal class TabsAndPropertiesResolver
|
||||
internal abstract class TabsAndPropertiesResolver
|
||||
{
|
||||
private readonly ILocalizedTextService _localizedTextService;
|
||||
protected ILocalizedTextService LocalizedTextService { get; }
|
||||
protected IEnumerable<string> IgnoreProperties { get; set; }
|
||||
|
||||
public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService)
|
||||
{
|
||||
_localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService));
|
||||
LocalizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService));
|
||||
IgnoreProperties = new List<string>();
|
||||
}
|
||||
|
||||
@@ -29,87 +26,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
IgnoreProperties = ignoreProperties ?? throw new ArgumentNullException(nameof(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 labelEditor = Current.PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit].GetValueEditor().View;
|
||||
|
||||
var contentProps = new List<ContentPropertyDisplay>
|
||||
{
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}id",
|
||||
Label = "Id",
|
||||
Value = Convert.ToInt32(display.Id).ToInvariantString() + "<br/><small class='muted'>" + display.Key + "</small>",
|
||||
View = labelEditor
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}creator",
|
||||
Label = localizedTextService.Localize("content/createBy"),
|
||||
Description = localizedTextService.Localize("content/createByDesc"),
|
||||
Value = display.Owner.Name,
|
||||
View = labelEditor
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}createdate",
|
||||
Label = localizedTextService.Localize("content/createDate"),
|
||||
Description = localizedTextService.Localize("content/createDateDesc"),
|
||||
Value = display.CreateDate.ToIsoString(),
|
||||
View = labelEditor
|
||||
},
|
||||
new ContentPropertyDisplay
|
||||
{
|
||||
Alias = $"{Constants.PropertyEditors.InternalGenericPropertiesPrefix}updatedate",
|
||||
Label = localizedTextService.Localize("content/updateDate"),
|
||||
Description = localizedTextService.Localize("content/updateDateDesc"),
|
||||
Value = display.UpdateDate.ToIsoString(),
|
||||
View = labelEditor
|
||||
}
|
||||
};
|
||||
|
||||
if (customProperties != null)
|
||||
{
|
||||
//add the custom ones
|
||||
contentProps.AddRange(customProperties);
|
||||
}
|
||||
|
||||
//now add the user props
|
||||
contentProps.AddRange(currProps);
|
||||
|
||||
//callback
|
||||
onGenericPropertiesMapped?.Invoke(contentProps);
|
||||
|
||||
//re-assign
|
||||
genericProps.Properties = contentProps;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds the container (listview) tab to the document
|
||||
/// </summary>
|
||||
@@ -136,7 +53,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
dtdId = Constants.DataTypes.DefaultMembersListView;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("entityType does not match a required value");
|
||||
throw new ArgumentOutOfRangeException(nameof(entityType), "entityType does not match a required value");
|
||||
}
|
||||
|
||||
//first try to get the custom one if there is one
|
||||
@@ -220,15 +137,117 @@ namespace Umbraco.Web.Models.Mapping
|
||||
display.Tabs = tabs;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<Tab<ContentPropertyDisplay>> Resolve(IContentBase content)
|
||||
/// <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="umbracoContext"></param>
|
||||
/// <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(UmbracoContext umbracoContext, IContentBase content, List<Tab<ContentPropertyDisplay>> tabs)
|
||||
{
|
||||
// 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
|
||||
var noGroupProperties = content.GetNonGroupedProperties()
|
||||
.Where(x => IgnoreProperties.Contains(x.Alias) == false) // skip ignored
|
||||
.ToList();
|
||||
var genericproperties = MapProperties(umbracoContext, content, noGroupProperties);
|
||||
|
||||
tabs.Add(new Tab<ContentPropertyDisplay>
|
||||
{
|
||||
Id = 0,
|
||||
Label = LocalizedTextService.Localize("general/properties"),
|
||||
Alias = "Generic properties",
|
||||
Properties = genericproperties
|
||||
});
|
||||
|
||||
var genericProps = 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>();
|
||||
|
||||
var customProperties = GetCustomGenericProperties(content);
|
||||
if (customProperties != null)
|
||||
{
|
||||
//add the custom ones
|
||||
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="umbracoContext"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="properties"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual List<ContentPropertyDisplay> MapProperties(UmbracoContext umbracoContext, 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the tabs collection with properties assigned for display models
|
||||
/// </summary>
|
||||
internal class TabsAndPropertiesResolver<TSource, TDestination> : TabsAndPropertiesResolver, IValueResolver<TSource, TDestination, IEnumerable<Tab<ContentPropertyDisplay>>>
|
||||
where TSource : IContentBase
|
||||
{
|
||||
public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService)
|
||||
: base(localizedTextService)
|
||||
{ }
|
||||
|
||||
public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService, IEnumerable<string> ignoreProperties)
|
||||
: base(localizedTextService, ignoreProperties)
|
||||
{ }
|
||||
|
||||
public virtual IEnumerable<Tab<ContentPropertyDisplay>> Resolve(TSource source, TDestination destination, IEnumerable<Tab<ContentPropertyDisplay>> destMember, ResolutionContext context)
|
||||
{
|
||||
var umbracoContext = context.GetUmbracoContext();
|
||||
var tabs = new List<Tab<ContentPropertyDisplay>>();
|
||||
|
||||
// add the tabs, for properties that belong to a tab
|
||||
// need to aggregate the tabs, as content.PropertyGroups contains all the composition tabs,
|
||||
// and there might be duplicates (content does not work like contentType and there is no
|
||||
// content.CompositionPropertyGroups).
|
||||
var groupsGroupsByName = content.PropertyGroups.OrderBy(x => x.SortOrder).GroupBy(x => x.Name);
|
||||
var groupsGroupsByName = source.PropertyGroups.OrderBy(x => x.SortOrder).GroupBy(x => x.Name);
|
||||
foreach (var groupsByName in groupsGroupsByName)
|
||||
{
|
||||
var properties = new List<Property>();
|
||||
@@ -236,7 +255,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
// merge properties for groups with the same name
|
||||
foreach (var group in groupsByName)
|
||||
{
|
||||
var groupProperties = content.GetPropertiesForGroup(group)
|
||||
var groupProperties = source.GetPropertiesForGroup(group)
|
||||
.Where(x => IgnoreProperties.Contains(x.Alias) == false); // skip ignored
|
||||
|
||||
properties.AddRange(groupProperties);
|
||||
@@ -245,14 +264,12 @@ namespace Umbraco.Web.Models.Mapping
|
||||
if (properties.Count == 0)
|
||||
continue;
|
||||
|
||||
// Sort properties so items from different compositions appear in correct order (see U4-9298). Map sorted properties.
|
||||
var mappedProperties = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(properties.OrderBy(prop => prop.PropertyType.SortOrder));
|
||||
|
||||
TranslateProperties(mappedProperties);
|
||||
//map the properties
|
||||
var mappedProperties = MapProperties(umbracoContext, source, properties);
|
||||
|
||||
// add the tab
|
||||
// we need to pick an identifier... there is no "right" way...
|
||||
var g = groupsByName.FirstOrDefault(x => x.Id == content.ContentTypeId) // try local
|
||||
var g = groupsByName.FirstOrDefault(x => x.Id == source.ContentTypeId) // try local
|
||||
?? groupsByName.First(); // else pick one randomly
|
||||
var groupId = g.Id;
|
||||
var groupName = groupsByName.Key;
|
||||
@@ -260,41 +277,19 @@ namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
Id = groupId,
|
||||
Alias = groupName,
|
||||
Label = _localizedTextService.UmbracoDictionaryTranslate(groupName),
|
||||
Label = LocalizedTextService.UmbracoDictionaryTranslate(groupName),
|
||||
Properties = mappedProperties,
|
||||
IsActive = false
|
||||
});
|
||||
}
|
||||
|
||||
// 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
|
||||
var noGroupProperties = content.GetNonGroupedProperties()
|
||||
.Where(x => IgnoreProperties.Contains(x.Alias) == false); // skip ignored
|
||||
var genericproperties = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyDisplay>>(noGroupProperties).ToList();
|
||||
TranslateProperties(genericproperties);
|
||||
MapGenericProperties(umbracoContext, source, tabs);
|
||||
|
||||
tabs.Add(new Tab<ContentPropertyDisplay>
|
||||
{
|
||||
Id = 0,
|
||||
Label = _localizedTextService.Localize("general/properties"),
|
||||
Alias = "Generic properties",
|
||||
Properties = genericproperties
|
||||
});
|
||||
|
||||
// activate the first tab
|
||||
tabs.First().IsActive = true;
|
||||
// activate the first tab, if any
|
||||
if (tabs.Count > 0)
|
||||
tabs[0].IsActive = true;
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
private void TranslateProperties(IEnumerable<ContentPropertyDisplay> properties)
|
||||
{
|
||||
// Not sure whether it's a good idea to add this to the ContentPropertyDisplay mapper
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
prop.Label = _localizedTextService.UmbracoDictionaryTranslate(prop.Label);
|
||||
prop.Description = _localizedTextService.UmbracoDictionaryTranslate(prop.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
var userGroupDefaultPermissionsResolver = new UserGroupDefaultPermissionsResolver(textService, actions);
|
||||
|
||||
CreateMap<UserGroupSave, IUserGroup>()
|
||||
.ConstructUsing((UserGroupSave save) => new UserGroup { CreateDate = DateTime.Now })
|
||||
.ConstructUsing(save => new UserGroup { CreateDate = DateTime.UtcNow })
|
||||
.IgnoreEntityCommonProperties()
|
||||
.ForMember(dest => dest.Id, opt => opt.Condition(source => GetIntId(source.Id) > 0))
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(source => GetIntId(source.Id)))
|
||||
@@ -44,6 +44,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
CreateMap<UserSave, IUser>()
|
||||
.IgnoreEntityCommonProperties()
|
||||
.ForMember(dest => dest.Id, opt => opt.Condition(src => GetIntId(src.Id) > 0))
|
||||
.ForMember(detail => detail.TourData, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.SessionTimeout, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.EmailConfirmedDate, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.UserType, opt => opt.Ignore())
|
||||
@@ -75,6 +76,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
CreateMap<UserInvite, IUser>()
|
||||
.IgnoreEntityCommonProperties()
|
||||
.ForMember(dest => dest.Id, opt => opt.Ignore())
|
||||
.ForMember(detail => detail.TourData, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.StartContentIds, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.StartMediaIds, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.UserType, opt => opt.Ignore())
|
||||
@@ -200,9 +202,22 @@ namespace Umbraco.Web.Models.Mapping
|
||||
var allContentPermissions = userService.GetPermissions(@group, true)
|
||||
.ToDictionary(x => x.EntityId, x => x);
|
||||
|
||||
var contentEntities = allContentPermissions.Keys.Count == 0
|
||||
? Array.Empty<IEntitySlim>()
|
||||
: entityService.GetAll(UmbracoObjectTypes.Document, allContentPermissions.Keys.ToArray());
|
||||
IEntitySlim[] contentEntities;
|
||||
if (allContentPermissions.Keys.Count == 0)
|
||||
{
|
||||
contentEntities = Array.Empty<IEntitySlim>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// a group can end up with way more than 2000 assigned permissions,
|
||||
// so we need to break them into groups in order to avoid breaking
|
||||
// the entity service due to too many Sql parameters.
|
||||
|
||||
var list = new List<IEntitySlim>();
|
||||
foreach (var idGroup in allContentPermissions.Keys.InGroupsOf(2000))
|
||||
list.AddRange(entityService.GetAll(UmbracoObjectTypes.Document, idGroup.ToArray()));
|
||||
contentEntities = list.ToArray();
|
||||
}
|
||||
|
||||
var allAssignedPermissions = new List<AssignedContentPermissions>();
|
||||
foreach (var entity in contentEntities)
|
||||
@@ -229,10 +244,11 @@ namespace Umbraco.Web.Models.Mapping
|
||||
//Important! Currently we are never mapping to multiple UserDisplay objects but if we start doing that
|
||||
// this will cause an N+1 and we'll need to change how this works.
|
||||
CreateMap<IUser, UserDisplay>()
|
||||
.ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(userService, runtimeCache)))
|
||||
.ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetUserAvatarUrls(runtimeCache)))
|
||||
.ForMember(dest => dest.Username, opt => opt.MapFrom(user => user.Username))
|
||||
.ForMember(dest => dest.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?)user.LastLoginDate))
|
||||
.ForMember(dest => dest.UserGroups, opt => opt.MapFrom(user => user.Groups))
|
||||
.ForMember(detail => detail.Navigation, opt => opt.MapFrom(user => CreateUserEditorNavigation(textService)))
|
||||
.ForMember(
|
||||
dest => dest.CalculatedStartContentIds,
|
||||
opt => opt.MapFrom(src => GetStartNodeValues(
|
||||
@@ -278,7 +294,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
//like the load time is waiting.
|
||||
.ForMember(detail =>
|
||||
detail.Avatars,
|
||||
opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(userService, runtimeCache)))
|
||||
opt => opt.MapFrom(user => user.GetUserAvatarUrls(runtimeCache)))
|
||||
.ForMember(dest => dest.Username, opt => opt.MapFrom(user => user.Username))
|
||||
.ForMember(dest => dest.UserGroups, opt => opt.MapFrom(user => user.Groups))
|
||||
.ForMember(dest => dest.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?)user.LastLoginDate))
|
||||
@@ -298,7 +314,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore());
|
||||
|
||||
CreateMap<IUser, UserDetail>()
|
||||
.ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(userService, runtimeCache)))
|
||||
.ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetUserAvatarUrls(runtimeCache)))
|
||||
.ForMember(dest => dest.UserId, opt => opt.MapFrom(user => GetIntId(user.Id)))
|
||||
.ForMember(dest => dest.StartContentIds, opt => opt.MapFrom(user => user.CalculateContentStartNodeIds(entityService)))
|
||||
.ForMember(dest => dest.StartMediaIds, opt => opt.MapFrom(user => user.CalculateMediaStartNodeIds(entityService)))
|
||||
@@ -340,18 +356,21 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
CreateMap<IProfile, ContentEditing.UserProfile>()
|
||||
.ForMember(dest => dest.UserId, opt => opt.MapFrom(profile => GetIntId(profile.Id)));
|
||||
}
|
||||
|
||||
CreateMap<IUser, UserData>()
|
||||
.ConstructUsing((IUser user) => new UserData())
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(user => user.Id))
|
||||
.ForMember(dest => dest.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections.ToArray()))
|
||||
.ForMember(dest => dest.RealName, opt => opt.MapFrom(user => user.Name))
|
||||
.ForMember(dest => dest.Roles, opt => opt.MapFrom(user => user.Groups.Select(x => x.Alias).ToArray()))
|
||||
.ForMember(dest => dest.StartContentNodes, opt => opt.MapFrom(user => user.CalculateContentStartNodeIds(entityService)))
|
||||
.ForMember(dest => dest.StartMediaNodes, opt => opt.MapFrom(user => user.CalculateMediaStartNodeIds(entityService)))
|
||||
.ForMember(dest => dest.Username, opt => opt.MapFrom(user => user.Username))
|
||||
.ForMember(dest => dest.Culture, opt => opt.MapFrom(user => user.GetUserCulture(textService)))
|
||||
.ForMember(dest => dest.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp));
|
||||
private IEnumerable<EditorNavigation> CreateUserEditorNavigation(ILocalizedTextService textService)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new EditorNavigation
|
||||
{
|
||||
Active = true,
|
||||
Alias = "details",
|
||||
Icon = "icon-umb-users",
|
||||
Name = textService.Localize("general/user"),
|
||||
View = "views/users/views/user/details.html"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private IEnumerable<EntityBasic> GetStartNodeValues(int[] startNodeIds,
|
||||
|
||||
9
src/Umbraco.Web/Models/Trees/ExportMember.cs
Normal file
9
src/Umbraco.Web/Models/Trees/ExportMember.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Web.Models.Trees
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the export member menu item
|
||||
/// </summary>
|
||||
[ActionMenuItem("umbracoMenuActions")]
|
||||
public sealed class ExportMember : ActionMenuItem
|
||||
{ }
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace Umbraco.Web.Models.Trees
|
||||
else
|
||||
{
|
||||
// if that doesn't work, try to get the legacy confirm view
|
||||
var attempt2 = LegacyTreeDataConverter.GetLegacyConfirmView(Action, currentSection);
|
||||
var attempt2 = LegacyTreeDataConverter.GetLegacyConfirmView(Action);
|
||||
if (attempt2)
|
||||
{
|
||||
var view = attempt2.Result;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Web.Models.Trees
|
||||
/// <param name="name">The text to display for the menu item, will default to the IAction alias if not specified</param>
|
||||
internal MenuItem Add(IAction action, string name)
|
||||
{
|
||||
var item = new MenuItem(action);
|
||||
var item = new MenuItem(action, name);
|
||||
|
||||
DetectLegacyActionMenu(action.GetType(), item);
|
||||
|
||||
|
||||
60
src/Umbraco.Web/Models/UserTourStatus.cs
Normal file
60
src/Umbraco.Web/Models/UserTourStatus.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A model representing the tours a user has taken/completed
|
||||
/// </summary>
|
||||
[DataContract(Name = "userTourStatus", Namespace = "")]
|
||||
public class UserTourStatus : IEquatable<UserTourStatus>
|
||||
{
|
||||
/// <summary>
|
||||
/// The tour alias
|
||||
/// </summary>
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the tour is completed
|
||||
/// </summary>
|
||||
[DataMember(Name = "completed")]
|
||||
public bool Completed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the tour is disabled
|
||||
/// </summary>
|
||||
[DataMember(Name = "disabled")]
|
||||
public bool Disabled { get; set; }
|
||||
|
||||
public bool Equals(UserTourStatus other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return string.Equals(Alias, other.Alias);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((UserTourStatus) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Alias.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(UserTourStatus left, UserTourStatus right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(UserTourStatus left, UserTourStatus right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user