diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index e3ccbe156e..8f396db956 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNet.Identity; @@ -22,6 +23,9 @@ namespace Umbraco.Core.Models.Identity Culture = Configuration.GlobalSettings.DefaultUILanguage; } + private int[] _allStartContentIds; + private int[] _allStartMediaIds; + public virtual async Task GenerateUserIdentityAsync(BackOfficeUserManager manager) { // NOTE the authenticationType must match the umbraco one @@ -112,5 +116,21 @@ namespace Umbraco.Core.Models.Identity if (callback == null) throw new ArgumentNullException("callback"); _getLogins = callback; } + + /// + /// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups + /// + public int[] AllStartContentIds + { + get { return _allStartContentIds ?? (_allStartContentIds = StartContentIds.Concat(Groups.Where(x => x.StartContentId.HasValue).Select(x => x.StartContentId.Value)).Distinct().ToArray()); } + } + + /// + /// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups + /// + public int[] AllStartMediaIds + { + get { return _allStartMediaIds ?? (_allStartMediaIds = StartMediaIds.Concat(Groups.Where(x => x.StartMediaId.HasValue).Select(x => x.StartMediaId.Value)).Distinct().ToArray()); } + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs b/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs index 5898cb6dfa..b6d5a899d2 100644 --- a/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs +++ b/src/Umbraco.Core/Models/Identity/IdentityModelMappings.cs @@ -35,9 +35,9 @@ namespace Umbraco.Core.Models.Identity .ForMember(detail => detail.Roles, opt => opt.MapFrom(user => user.Groups)) .ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name)) //When mapping to UserData which is used in the authcookie we want ALL start nodes including ones defined on the groups - .ForMember(detail => detail.StartContentNodes, opt => opt.MapFrom(user => user.GetCombinedStartContentIds())) + .ForMember(detail => detail.StartContentNodes, opt => opt.MapFrom(user => user.AllStartContentIds)) //When mapping to UserData which is used in the authcookie we want ALL start nodes including ones defined on the groups - .ForMember(detail => detail.StartMediaNodes, opt => opt.MapFrom(user => user.GetCombinedStartMediaIds())) + .ForMember(detail => detail.StartMediaNodes, opt => opt.MapFrom(user => user.AllStartMediaIds)) .ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.UserName)) .ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.Culture)) .ForMember(detail => detail.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp)); diff --git a/src/Umbraco.Core/Models/Membership/IReadOnlyUserGroup.cs b/src/Umbraco.Core/Models/Membership/IReadOnlyUserGroup.cs index b590cd3543..beffc5862d 100644 --- a/src/Umbraco.Core/Models/Membership/IReadOnlyUserGroup.cs +++ b/src/Umbraco.Core/Models/Membership/IReadOnlyUserGroup.cs @@ -10,8 +10,8 @@ namespace Umbraco.Core.Models.Membership string Name { get; } string Icon { get; } int Id { get; } - int StartContentId { get; } - int StartMediaId { get; } + int? StartContentId { get; } + int? StartMediaId { get; } /// /// The alias diff --git a/src/Umbraco.Core/Models/Membership/IUser.cs b/src/Umbraco.Core/Models/Membership/IUser.cs index 0363791741..70cb135f50 100644 --- a/src/Umbraco.Core/Models/Membership/IUser.cs +++ b/src/Umbraco.Core/Models/Membership/IUser.cs @@ -45,6 +45,16 @@ namespace Umbraco.Core.Models.Membership /// /// Will hold the media file system relative path of the users custom avatar if they uploaded one /// - string Avatar { get; set; } + string Avatar { get; set; } + + /// + /// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups + /// + int[] AllStartContentIds { get; } + + /// + /// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups + /// + int[] AllStartMediaIds { get; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/IUserGroup.cs b/src/Umbraco.Core/Models/Membership/IUserGroup.cs index 5e1bc0c4cc..0282073a2e 100644 --- a/src/Umbraco.Core/Models/Membership/IUserGroup.cs +++ b/src/Umbraco.Core/Models/Membership/IUserGroup.cs @@ -7,8 +7,8 @@ namespace Umbraco.Core.Models.Membership { string Alias { get; set; } - int StartContentId { get; set; } - int StartMediaId { get; set; } + int? StartContentId { get; set; } + int? StartMediaId { get; set; } /// /// The icon diff --git a/src/Umbraco.Core/Models/Membership/ReadOnlyUserGroup.cs b/src/Umbraco.Core/Models/Membership/ReadOnlyUserGroup.cs index e2b8508497..b2a7349e81 100644 --- a/src/Umbraco.Core/Models/Membership/ReadOnlyUserGroup.cs +++ b/src/Umbraco.Core/Models/Membership/ReadOnlyUserGroup.cs @@ -5,22 +5,24 @@ namespace Umbraco.Core.Models.Membership { public class ReadOnlyUserGroup : IReadOnlyUserGroup, IEquatable { - public ReadOnlyUserGroup(int id, string name, string icon, int startContentId, int startMediaId, string @alias, IEnumerable allowedSections) + public ReadOnlyUserGroup(int id, string name, string icon, int? startContentId, int? startMediaId, string @alias, IEnumerable allowedSections) { Name = name; Icon = icon; Id = id; - StartContentId = startContentId; - StartMediaId = startMediaId; Alias = alias; AllowedSections = allowedSections; + + //Zero is invalid and will be treated as Null + StartContentId = startContentId == 0 ? null : startContentId; + StartMediaId = startMediaId == 0 ? null : startMediaId; } public int Id { get; private set; } public string Name { get; private set; } public string Icon { get; private set; } - public int StartContentId { get; private set; } - public int StartMediaId { get; private set; } + public int? StartContentId { get; private set; } + public int? StartMediaId { get; private set; } public string Alias { get; private set; } public IEnumerable AllowedSections { get; private set; } diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 2047d4346a..fb6161b994 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -117,6 +117,8 @@ namespace Umbraco.Core.Models.Membership private DateTime _lastLockoutDate; private bool _defaultToLiveEditing; + private int[] _allStartContentIds; + private int[] _allStartMediaIds; private static readonly Lazy Ps = new Lazy(); @@ -297,6 +299,24 @@ namespace Umbraco.Core.Models.Membership set { SetPropertyValueAndDetectChanges(value, ref _avatar, Ps.Value.AvatarSelector); } } + /// + /// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups + /// + [IgnoreDataMember] + public int[] AllStartContentIds + { + get { return _allStartContentIds ?? (_allStartContentIds = StartContentIds.Concat(Groups.Where(x => x.StartContentId.HasValue).Select(x => x.StartContentId.Value)).Distinct().ToArray()); } + } + + /// + /// Returns all start node Ids assigned to the user based on both the explicit start node ids assigned to the user and any start node Ids assigned to it's user groups + /// + [IgnoreDataMember] + public int[] AllStartMediaIds + { + get { return _allStartMediaIds ?? (_allStartMediaIds = StartMediaIds.Concat(Groups.Where(x => x.StartMediaId.HasValue).Select(x => x.StartMediaId.Value)).Distinct().ToArray()); } + } + /// /// Gets or sets the session timeout. /// diff --git a/src/Umbraco.Core/Models/Membership/UserGroup.cs b/src/Umbraco.Core/Models/Membership/UserGroup.cs index fff7fac5ea..f48a7b6275 100644 --- a/src/Umbraco.Core/Models/Membership/UserGroup.cs +++ b/src/Umbraco.Core/Models/Membership/UserGroup.cs @@ -14,8 +14,8 @@ namespace Umbraco.Core.Models.Membership [DataContract(IsReference = true)] internal class UserGroup : Entity, IUserGroup { - private int _startContentId; - private int _startMediaId; + private int? _startContentId; + private int? _startMediaId; private string _alias; private string _icon; private string _name; @@ -30,8 +30,8 @@ namespace Umbraco.Core.Models.Membership public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo(x => x.Alias); public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo>(x => x.Permissions); public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo(x => x.Icon); - public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartContentId); - public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartMediaId); + public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartContentId); + public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo(x => x.StartMediaId); //Custom comparer for enumerable public readonly DelegateEqualityComparer> StringEnumerableComparer = @@ -67,14 +67,14 @@ namespace Umbraco.Core.Models.Membership } [DataMember] - public int StartMediaId + public int? StartMediaId { get { return _startMediaId; } set { SetPropertyValueAndDetectChanges(value, ref _startMediaId, Ps.Value.StartMediaIdSelector); } } [DataMember] - public int StartContentId + public int? StartContentId { get { return _startContentId; } set { SetPropertyValueAndDetectChanges(value, ref _startContentId, Ps.Value.StartContentIdSelector); } diff --git a/src/Umbraco.Core/Models/Rdbms/UserGroupDto.cs b/src/Umbraco.Core/Models/Rdbms/UserGroupDto.cs index 88071dec02..fdad78bfcd 100644 --- a/src/Umbraco.Core/Models/Rdbms/UserGroupDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/UserGroupDto.cs @@ -51,11 +51,11 @@ namespace Umbraco.Core.Models.Rdbms [Column("startContentId")] [NullSetting(NullSetting = NullSettings.Null)] - public int StartContentId { get; set; } + public int? StartContentId { get; set; } [Column("startMediaId")] [NullSetting(NullSetting = NullSettings.Null)] - public int StartMediaId { get; set; } + public int? StartMediaId { get; set; } [ResultColumn] public List UserGroup2AppDtos { get; set; } diff --git a/src/Umbraco.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs index 2dc70df275..9c2931ad73 100644 --- a/src/Umbraco.Core/Models/UserExtensions.cs +++ b/src/Umbraco.Core/Models/UserExtensions.cs @@ -12,43 +12,7 @@ using Umbraco.Core.Services; namespace Umbraco.Core.Models { public static class UserExtensions - { - /// - /// Returns all of the user's assigned start node ids based on ids assigned directly to the IUser object and it's groups - /// - /// - public static IEnumerable GetCombinedStartContentIds(this IUser user) - { - return user.StartContentIds.Concat(user.Groups.Select(x => x.StartContentId)).Distinct(); - } - - /// - /// Returns all of the user's assigned start node ids based on ids assigned directly to the BackOfficeIdentityUser object and it's groups - /// - /// - public static IEnumerable GetCombinedStartContentIds(this BackOfficeIdentityUser user) - { - return user.StartContentIds.Concat(user.Groups.Select(x => x.StartContentId)).Distinct(); - } - - /// - /// Returns all of the user's assigned start node ids based on ids assigned directly to the IUser object and it's groups - /// - /// - public static IEnumerable GetCombinedStartMediaIds(this IUser user) - { - return user.StartMediaIds.Concat(user.Groups.Select(x => x.StartMediaId)).Distinct(); - } - - /// - /// Returns all of the user's assigned start node ids based on ids assigned directly to the BackOfficeIdentityUser object and it's groups - /// - /// - public static IEnumerable GetCombinedStartMediaIds(this BackOfficeIdentityUser user) - { - return user.StartMediaIds.Concat(user.Groups.Select(x => x.StartMediaId)).Distinct(); - } - + { /// /// Tries to lookup the user's gravatar to see if the endpoint can be reached, if so it returns the valid URL /// @@ -153,7 +117,7 @@ namespace Umbraco.Core.Models { if (user == null) throw new ArgumentNullException("user"); if (content == null) throw new ArgumentNullException("content"); - return HasPathAccess(content.Path, user.GetCombinedStartContentIds().ToArray(), Constants.System.RecycleBinContent); + return HasPathAccess(content.Path, user.AllStartContentIds, Constants.System.RecycleBinContent); } internal static bool HasPathAccess(string path, int[] startNodeIds, int recycleBinId) @@ -197,7 +161,7 @@ namespace Umbraco.Core.Models { if (user == null) throw new ArgumentNullException("user"); if (media == null) throw new ArgumentNullException("media"); - return HasPathAccess(media.Path, user.GetCombinedStartMediaIds().ToArray(), Constants.System.RecycleBinMedia); + return HasPathAccess(media.Path, user.AllStartMediaIds, Constants.System.RecycleBinMedia); } /// diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 6cf0282438..8f8731bb66 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -802,12 +802,12 @@ namespace Umbraco.Web.Editors var hasPathAccess = (nodeId == Constants.System.Root) ? UserExtensions.HasPathAccess( Constants.System.Root.ToInvariantString(), - user.GetCombinedStartContentIds().ToArray(), + user.AllStartContentIds, Constants.System.RecycleBinContent) : (nodeId == Constants.System.RecycleBinContent) ? UserExtensions.HasPathAccess( Constants.System.RecycleBinContent.ToInvariantString(), - user.GetCombinedStartContentIds().ToArray(), + user.AllStartContentIds, Constants.System.RecycleBinContent) : user.HasPathAccess(contentItem); diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index 4438a4d9dc..119a7e7ed0 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -667,14 +667,14 @@ namespace Umbraco.Web.Editors type = "media"; AddExamineSearchFrom(searchFrom, sb); - AddExamineUserStartNode(Security.CurrentUser.GetCombinedStartMediaIds().ToArray(), sb); + AddExamineUserStartNode(Security.CurrentUser.AllStartMediaIds, sb); break; case UmbracoEntityTypes.Document: type = "content"; AddExamineSearchFrom(searchFrom, sb); - AddExamineUserStartNode(Security.CurrentUser.GetCombinedStartContentIds().ToArray(), sb); + AddExamineUserStartNode(Security.CurrentUser.AllStartContentIds, sb); break; default: diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 9c96a865ca..ed4b1c2f63 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -887,12 +887,12 @@ namespace Umbraco.Web.Editors var hasPathAccess = (nodeId == Constants.System.Root) ? UserExtensions.HasPathAccess( Constants.System.Root.ToInvariantString(), - user.GetCombinedStartMediaIds().ToArray(), + user.AllStartMediaIds, Constants.System.RecycleBinMedia) : (nodeId == Constants.System.RecycleBinMedia) ? UserExtensions.HasPathAccess( Constants.System.RecycleBinMedia.ToInvariantString(), - user.GetCombinedStartMediaIds().ToArray(), + user.AllStartMediaIds, Constants.System.RecycleBinMedia) : user.HasPathAccess(media); diff --git a/src/Umbraco.Web/Trees/ContentTreeController.cs b/src/Umbraco.Web/Trees/ContentTreeController.cs index d9bfbbab8d..b97f0d6bb0 100644 --- a/src/Umbraco.Web/Trees/ContentTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTreeController.cs @@ -64,7 +64,7 @@ namespace Umbraco.Web.Trees private int[] _userStartNodes; protected override int[] UserStartNodes { - get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.GetCombinedStartContentIds().ToArray()); } + get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.AllStartContentIds); } } /// diff --git a/src/Umbraco.Web/Trees/MediaTreeController.cs b/src/Umbraco.Web/Trees/MediaTreeController.cs index 5f36c3de20..61264e8af8 100644 --- a/src/Umbraco.Web/Trees/MediaTreeController.cs +++ b/src/Umbraco.Web/Trees/MediaTreeController.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web.Trees private int[] _userStartNodes; protected override int[] UserStartNodes { - get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.GetCombinedStartMediaIds().ToArray()); } + get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.AllStartMediaIds); } } /// diff --git a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs index 7429e52897..ffd6bf362e 100644 --- a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingContentAttribute.cs @@ -47,7 +47,7 @@ namespace Umbraco.Web.WebApi.Filters protected override int[] GetUserStartNodes(IUser user) { - return user.GetCombinedStartContentIds().ToArray(); + return user.AllStartContentIds; } protected override int RecycleBinId diff --git a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs index 6e8c411db7..1ceeb133f3 100644 --- a/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs @@ -41,7 +41,7 @@ namespace Umbraco.Web.WebApi.Filters protected virtual int[] GetUserStartNodes(IUser user) { - return user.GetCombinedStartMediaIds().ToArray(); + return user.AllStartMediaIds; } protected virtual int RecycleBinId diff --git a/src/umbraco.businesslogic/BasePages/BasePage.cs b/src/umbraco.businesslogic/BasePages/BasePage.cs index d708ce78a3..379854406f 100644 --- a/src/umbraco.businesslogic/BasePages/BasePage.cs +++ b/src/umbraco.businesslogic/BasePages/BasePage.cs @@ -295,8 +295,8 @@ namespace umbraco.BasePages RealName = u.Name, //currently we only have one user type! Roles = u.GetGroups(), - StartContentNodes = u.UserEntity.GetCombinedStartContentIds().ToArray(), - StartMediaNodes = u.UserEntity.GetCombinedStartMediaIds().ToArray(), + StartContentNodes = u.UserEntity.AllStartContentIds, + StartMediaNodes = u.UserEntity.AllStartMediaIds, Username = u.LoginName, Culture = ui.Culture(u)