diff --git a/src/Umbraco.Web/Editors/IsCurrentUserModelFilterAttribute.cs b/src/Umbraco.Web/Editors/IsCurrentUserModelFilterAttribute.cs index d5a0a4022e..f466090e65 100644 --- a/src/Umbraco.Web/Editors/IsCurrentUserModelFilterAttribute.cs +++ b/src/Umbraco.Web/Editors/IsCurrentUserModelFilterAttribute.cs @@ -20,19 +20,19 @@ namespace Umbraco.Web.Editors var objectContent = actionExecutedContext.Response.Content as ObjectContent; if (objectContent != null) { - var model = objectContent.Value as UserDisplay; + var model = objectContent.Value as UserBasic; if (model != null) { model.IsCurrentUser = (int) model.Id == user.Id; } else { - var collection = objectContent.Value as IEnumerable; + var collection = objectContent.Value as IEnumerable; if (collection != null) { - foreach (var userDisplay in collection) + foreach (var userBasic in collection) { - userDisplay.IsCurrentUser = (int) userDisplay.Id == user.Id; + userBasic.IsCurrentUser = (int) userBasic.Id == user.Id; } } else @@ -40,9 +40,9 @@ namespace Umbraco.Web.Editors var paged = objectContent.Value as UsersController.PagedUserResult; if (paged != null && paged.Items != null) { - foreach (var userDisplay in paged.Items) + foreach (var userBasic in paged.Items) { - userDisplay.IsCurrentUser = (int)userDisplay.Id == user.Id; + userBasic.IsCurrentUser = (int)userBasic.Id == user.Id; } } } diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index ac0faf96e5..9f26c51674 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -227,7 +227,7 @@ namespace Umbraco.Web.Editors var paged = new PagedUserResult(total, pageNumber, pageSize) { - Items = Mapper.Map>(result), + Items = Mapper.Map>(result), UserStates = Services.UserService.GetUserStates() }; @@ -569,7 +569,7 @@ namespace Umbraco.Web.Editors Services.TextService.Localize("speechBubbles/enableUserSuccess", new[] { users[0].Name })); } - public class PagedUserResult : PagedResult + public class PagedUserResult : PagedResult { public PagedUserResult(long totalItems, long pageNumber, long pageSize) : base(totalItems, pageNumber, pageSize) { diff --git a/src/Umbraco.Web/Models/ContentEditing/UserBasic.cs b/src/Umbraco.Web/Models/ContentEditing/UserBasic.cs index 60f00a85e7..7467955e71 100644 --- a/src/Umbraco.Web/Models/ContentEditing/UserBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/UserBasic.cs @@ -5,7 +5,12 @@ using System.Runtime.Serialization; using Umbraco.Core.Models.Membership; namespace Umbraco.Web.Models.ContentEditing -{ +{ + + + /// + /// The user model used for paging and listing users in the UI + /// [DataContract(Name = "user", Namespace = "")] [ReadOnly(true)] public class UserBasic : EntityBasic, INotificationModel @@ -13,6 +18,7 @@ namespace Umbraco.Web.Models.ContentEditing public UserBasic() { Notifications = new List(); + UserGroups = new List(); } [DataMember(Name = "username")] @@ -42,6 +48,19 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "email", IsRequired = true)] public string Email { get; set; } + /// + /// The list of group aliases assigned to the user + /// + [DataMember(Name = "userGroups")] + public IEnumerable UserGroups { get; set; } + + /// + /// This is an info flag to denote if this object is the equivalent of the currently logged in user + /// + [DataMember(Name = "isCurrentUser")] + [ReadOnly(true)] + public bool IsCurrentUser { get; set; } + /// /// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes. /// diff --git a/src/Umbraco.Web/Models/ContentEditing/UserDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/UserDisplay.cs index 095a0fe13b..4cff43e3b8 100644 --- a/src/Umbraco.Web/Models/ContentEditing/UserDisplay.cs +++ b/src/Umbraco.Web/Models/ContentEditing/UserDisplay.cs @@ -12,16 +12,13 @@ namespace Umbraco.Web.Models.ContentEditing [ReadOnly(true)] public class UserDisplay : UserBasic { - public UserDisplay() : base() + public UserDisplay() { + AvailableCultures = new Dictionary(); + StartContentIds = new List(); + StartMediaIds = new List(); } - - /// - /// The list of group aliases assigned to the user - /// - [DataMember(Name = "userGroups")] - public IEnumerable UserGroups { get; set; } - + /// /// 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 @@ -41,12 +38,6 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "resetPasswordValue")] [ReadOnly(true)] public string ResetPasswordValue { get; set; } - - /// - /// This is an info flag to denote if this object is the equivalent of the currently logged in user - /// - [DataMember(Name = "isCurrentUser")] - [ReadOnly(true)] - public bool IsCurrentUser { get; set; } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs index 4a67aa0f26..f0375855ef 100644 --- a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs @@ -142,7 +142,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(detail => detail.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(applicationContext.Services.UserService, applicationContext.ApplicationCache.RuntimeCache))) .ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.Username)) .ForMember(detail => detail.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?) user.LastLoginDate)) - .ForMember(detail => detail.UserGroups, opt => opt.Ignore()) + .ForMember(detail => detail.UserGroups, opt => opt.MapFrom(user => user.Groups)) .ForMember(detail => detail.StartContentIds, opt => opt.UseValue(Enumerable.Empty())) .ForMember(detail => detail.StartMediaIds, opt => opt.UseValue(Enumerable.Empty())) .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService))) @@ -164,10 +164,15 @@ namespace Umbraco.Web.Models.Mapping .ForMember(detail => detail.Trashed, opt => opt.Ignore()) .ForMember(detail => detail.AdditionalData, opt => opt.Ignore()) .AfterMap((user, display) => - { + { + //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. + var startContentIds = user.StartContentIds.ToArray(); if (startContentIds.Length > 0) - { + { + //TODO: Update GetAll to be able to pass in a parameter like on the normal Get to NOT load in the entire object! + var contentItems = applicationContext.Services.EntityService.GetAll(UmbracoObjectTypes.Document, startContentIds); display.StartContentIds = Mapper.Map, IEnumerable>(contentItems); } @@ -177,13 +182,17 @@ namespace Umbraco.Web.Models.Mapping var mediaItems = applicationContext.Services.EntityService.GetAll(UmbracoObjectTypes.Document, startMediaIds); display.StartMediaIds = Mapper.Map, IEnumerable>(mediaItems); } - display.UserGroups = Mapper.Map, IEnumerable>(user.Groups); - }); config.CreateMap() - .ForMember(detail => detail.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(applicationContext.Services.UserService, applicationContext.ApplicationCache.RuntimeCache))) + //Loading in the user avatar's requires an external request if they don't have a local file avatar, this means that initial load of paging may incur a cost + //Alternatively, if this is annoying the back office UI would need to be updated to request the avatars for the list of users separately so it doesn't look + //like the load time is waiting. + .ForMember(detail => + detail.Avatars, + opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(applicationContext.Services.UserService, applicationContext.ApplicationCache.RuntimeCache))) .ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.Username)) + .ForMember(detail => detail.UserGroups, opt => opt.MapFrom(user => user.Groups)) .ForMember(detail => detail.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?) user.LastLoginDate)) .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService))) .ForMember( @@ -192,6 +201,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1)) .ForMember(detail => detail.Path, opt => opt.MapFrom(user => "-1," + user.Id)) .ForMember(detail => detail.Notifications, opt => opt.Ignore()) + .ForMember(detail => detail.IsCurrentUser, opt => opt.Ignore()) .ForMember(detail => detail.Udi, opt => opt.Ignore()) .ForMember(detail => detail.Icon, opt => opt.Ignore()) .ForMember(detail => detail.Trashed, opt => opt.Ignore())