From 623d3883d2223a101fa58d8afa06377e2856954e Mon Sep 17 00:00:00 2001 From: Jamie Howarth Date: Tue, 11 Oct 2022 02:05:28 +0100 Subject: [PATCH 1/4] Basic fixes for #154 by filtering domains and redirects API to only show redirects on nodes the user has access to. Doesn't solve risky payload issues, TBD w/ @abjerner later --- .../Controllers/Api/RedirectsController.cs | 35 ++++++++++++----- .../Services/IRedirectsService.cs | 11 ++++-- .../Services/RedirectsService.cs | 38 +++++++++++++++++-- 3 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs b/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs index 4c8833e..94bbc7c 100644 --- a/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs +++ b/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs @@ -12,12 +12,16 @@ using Skybrud.Umbraco.Redirects.Models.Api; using Skybrud.Umbraco.Redirects.Models.Options; using Skybrud.Umbraco.Redirects.Services; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Web.BackOffice.Controllers; using Umbraco.Cms.Web.Common.Attributes; +using Umbraco.Cms.Web.Common.UmbracoContext; +using Umbraco.Extensions; #pragma warning disable 1591 @@ -36,6 +40,7 @@ public class RedirectsController : UmbracoAuthorizedApiController { private readonly RedirectsBackOfficeHelper _backOffice; private readonly IContentService _contentService; private readonly IMediaService _mediaService; + private readonly IUserService _userService; private readonly IUmbracoContextAccessor _umbracoContextAccessor; #region Constructors @@ -43,12 +48,14 @@ public class RedirectsController : UmbracoAuthorizedApiController { public RedirectsController(ILogger logger, IRedirectsService redirectsService, RedirectsBackOfficeHelper backOffice, IContentService contentService, IMediaService mediaService, + IUserService userService, IUmbracoContextAccessor umbracoContextAccessor) { _logger = logger; _redirects = redirectsService; _backOffice = backOffice; _contentService = contentService; _mediaService = mediaService; + _userService = userService; _umbracoContextAccessor = umbracoContextAccessor; } @@ -61,13 +68,13 @@ public RedirectsController(ILogger logger, IRedirectsServic [HttpGet] public ActionResult GetRootNodes() { - RedirectRootNode[] rootNodes = _redirects.GetRootNodes(); - - return new JsonResult(new { - total = rootNodes.Length, - items = rootNodes.Select(x => new RedirectRootNodeModel(x, _backOffice)) - }); + RedirectRootNode[] rootNodes = _redirects.GetRootNodes(GetUser()).ToArray(); + return new JsonResult(new + { + total = rootNodes.Length, + items = rootNodes.Select(x => new RedirectRootNodeModel(x, _backOffice)) + }); } [HttpPost] @@ -267,12 +274,17 @@ public ActionResult GetRedirects(int page = 1, int limit = 20, string type = nul Page = page, Limit = limit, Type = EnumUtils.ParseEnum(type, RedirectTypeFilter.All), - Text = text, - RootNodeKey = rootNodeKey + Text = text }; + + if (rootNodeKey != null) options.RootNodeKey = rootNodeKey; + + var rootKeys = _contentService.GetByIds(_redirects.GetUserAccessibleNodes(GetUser())) + .Select(p => p.Key) + .ToArray(); // Make the search for redirects via the redirects service - RedirectsSearchResult result = _redirects.GetRedirects(options); + RedirectsSearchResult result = _redirects.GetRedirects(options, rootKeys); // Map the result for the API return new JsonResult(_backOffice.Map(result)); @@ -370,6 +382,11 @@ private ActionResult Error(RedirectsException ex) { } + private IUser GetUser() + { + var currentUser = HttpContext.User.GetUmbracoIdentity(); + return _userService.GetByUsername(currentUser.Name); + } } } \ No newline at end of file diff --git a/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs b/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs index 00b69a5..091d0b7 100644 --- a/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs +++ b/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs @@ -4,6 +4,8 @@ using Skybrud.Umbraco.Redirects.Models; using Skybrud.Umbraco.Redirects.Models.Options; +using Umbraco.Cms.Core.Models.Membership; + namespace Skybrud.Umbraco.Redirects.Services { /// @@ -17,6 +19,8 @@ public interface IRedirectsService { /// An array of . RedirectDomain[] GetDomains(); + int[] GetUserAccessibleNodes(IUser umbracoUser); + /// /// Adds a new redirect with the specified . /// @@ -99,13 +103,14 @@ public interface IRedirectsService { /// The inbound URL. /// The destination URL. string GetDestinationUrl(IRedirectBase redirect, Uri uri); - + /// /// Returns a paginated list of redirects matching the specified . /// /// The options the returned redirects should match. + /// The user's root nodes that should be visible for security /// An instance of . - RedirectsSearchResult GetRedirects(RedirectsSearchOptions options); + RedirectsSearchResult GetRedirects(RedirectsSearchOptions options, Guid[] rootNodes); /// /// Returns a collection with all redirects. @@ -117,7 +122,7 @@ public interface IRedirectsService { /// Returns an array of all rode nodes configured in Umbraco. /// /// An array of representing the root nodes. - RedirectRootNode[] GetRootNodes(); + RedirectRootNode[] GetRootNodes(IUser user); /// /// Returns an array of redirects where the destination matches the specified and . diff --git a/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs b/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs index d3b8c18..15e362a 100644 --- a/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs +++ b/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using NPoco; +using NUglify.Helpers; using Skybrud.Essentials.Strings.Extensions; using Skybrud.Essentials.Time; using Skybrud.Umbraco.Redirects.Exceptions; @@ -12,6 +13,7 @@ using Skybrud.Umbraco.Redirects.Models; using Skybrud.Umbraco.Redirects.Models.Dtos; using Skybrud.Umbraco.Redirects.Models.Options; +using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; @@ -59,6 +61,26 @@ public RedirectDomain[] GetDomains() { return _domains.GetAll(false).Select(RedirectDomain.GetFromDomain).ToArray(); } + public int[] GetUserAccessibleNodes(IUser umbracoUser) + { + var rootNodeIDs = umbracoUser.StartContentIds.ToList(); + var groupRootNodes = umbracoUser.Groups + .Where(p => p.StartContentId.HasValue) + .Select(p => p.StartContentId.Value) + .ToArray(); + rootNodeIDs.AddRange(groupRootNodes); + + // JH: Admin should access all nodes + if (rootNodeIDs.Count == 1 && rootNodeIDs.Single() == -1) + { + rootNodeIDs.Clear(); + rootNodeIDs = GetDomains().Select(c => c.RootNodeId).ToList(); + } + + return rootNodeIDs.ToArray(); + + } + /// /// Deletes the specified . /// @@ -353,8 +375,9 @@ public IRedirect SaveRedirect(IRedirect redirect) { /// Returns a paginated list of redirects matching the specified . /// /// The options the returned redirects should match. + /// The user's root nodes that should be visible for security /// An instance of . - public RedirectsSearchResult GetRedirects(RedirectsSearchOptions options) { + public RedirectsSearchResult GetRedirects(RedirectsSearchOptions options, Guid[] rootNodes) { if (options == null) throw new ArgumentNullException(nameof(options)); @@ -365,7 +388,11 @@ public RedirectsSearchResult GetRedirects(RedirectsSearchOptions options) { var sql = scope.SqlContext.Sql().Select().From(); // Search by the rootNodeId - if (options.RootNodeKey != null) sql = sql.Where(x => x.RootKey == options.RootNodeKey.Value); + if (options.RootNodeKey != null) { + sql = sql.Where(x => x.RootKey == options.RootNodeKey); + } else if (rootNodes.Any()) { + sql = sql.Where(x => rootNodes.Contains(x.RootKey)); + } // Search by the type if (options.Type != RedirectTypeFilter.All) { @@ -394,6 +421,7 @@ public RedirectsSearchResult GetRedirects(RedirectsSearchOptions options) { || (x.Path.Contains(url) && x.QueryString.Contains(query)) )); + } } @@ -452,15 +480,17 @@ public IEnumerable GetAllRedirects() { /// Returns an array of all rode nodes configured in Umbraco. /// /// An array of representing the root nodes. - public RedirectRootNode[] GetRootNodes() { + public RedirectRootNode[] GetRootNodes(IUser user) + { + var rootNodeIDs = GetUserAccessibleNodes(user); // Multiple domains may be configured for a single node, so we need to group the domains before proceeding var domainsByRootNodeId = GetDomains().GroupBy(x => x.RootNodeId); return ( from domainGroup in domainsByRootNodeId let content = _contentService.GetById(domainGroup.First().RootNodeId) - where content is { Trashed: false } + where !content.Trashed && rootNodeIDs.Contains(content.Id) orderby content.Id select RedirectRootNode.GetFromContent(content, domainGroup) ).ToArray(); From 350d545612363d6e7d29fb15009364608d757e62 Mon Sep 17 00:00:00 2001 From: Jamie Howarth Date: Mon, 14 Nov 2022 20:22:42 +0000 Subject: [PATCH 2/4] This should hopefully satisfy @abjerner's API spec. Have tested on our local multi-tenant instance and all seems to work well. --- .../Config/RedirectsContentAppSettings.cs | 5 ++ .../Controllers/Api/RedirectsController.cs | 33 +++----- .../Models/RedirectRootNode.cs | 7 ++ .../Services/IRedirectsService.cs | 14 ++-- .../Services/RedirectsSearchOptions.cs | 15 +++- .../Services/RedirectsService.cs | 81 ++++++++++--------- .../Scripts/Controllers/Dashboards/Default.js | 2 +- 7 files changed, 88 insertions(+), 69 deletions(-) diff --git a/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs b/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs index de45ef2..d74e7ec 100644 --- a/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs +++ b/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs @@ -10,6 +10,11 @@ public class RedirectsContentAppSettings { /// public bool Enabled { get; set; } = true; + /// + /// Gets or sets whether the user's start nodes should filter which redirects they have access to. Default is . + /// + public bool UserStartNodes { get; set; } = false; + } } \ No newline at end of file diff --git a/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs b/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs index f1b82e6..73a2c4f 100644 --- a/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs +++ b/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Net; using Microsoft.AspNetCore.Mvc; @@ -16,6 +17,7 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Web.BackOffice.Controllers; @@ -40,7 +42,6 @@ public class RedirectsController : UmbracoAuthorizedApiController { private readonly RedirectsBackOfficeHelper _backOffice; private readonly IContentService _contentService; private readonly IMediaService _mediaService; - private readonly IUserService _userService; private readonly IUmbracoContextAccessor _umbracoContextAccessor; #region Constructors @@ -48,14 +49,12 @@ public class RedirectsController : UmbracoAuthorizedApiController { public RedirectsController(ILogger logger, IRedirectsService redirectsService, RedirectsBackOfficeHelper backOffice, IContentService contentService, IMediaService mediaService, - IUserService userService, IUmbracoContextAccessor umbracoContextAccessor) { _logger = logger; _redirects = redirectsService; _backOffice = backOffice; _contentService = contentService; _mediaService = mediaService; - _userService = userService; _umbracoContextAccessor = umbracoContextAccessor; } @@ -68,7 +67,9 @@ public RedirectsController(ILogger logger, IRedirectsServic [HttpGet] public ActionResult GetRootNodes() { - RedirectRootNode[] rootNodes = _redirects.GetRootNodes(GetUser()).ToArray(); + var rootNodes = _backOffice.Settings.ContentApp.UserStartNodes + ? _redirects.GetRootNodes(_backOffice.CurrentUser).ToArray() + : _redirects.GetRootNodes(); return new JsonResult(new { @@ -262,29 +263,27 @@ public ActionResult DeleteRedirect(Guid redirectId) { /// The maximum amount of redirects to be returned per page. /// The type of redirects that should be returned. /// The text that the returned redirects should match. - /// The root node key that the returned redirects should match. null means all redirects. means all global redirects. + /// An array of root node keys that the returned redirects should match. null means all redirects. means all global redirects. /// A list of redirects. [HttpGet] - public ActionResult GetRedirects(int page = 1, int limit = 20, string type = null, string text = null, Guid? rootNodeKey = null) { + public ActionResult GetRedirects(int page = 1, int limit = 20, string type = null, string text = null, [FromQuery]Guid[] rootNodeKeys = null) { try { + var rootKeys = _backOffice.Settings.ContentApp.UserStartNodes + ? _redirects.GetRootNodes(_backOffice.CurrentUser).Select(p => p.Key) + : _redirects.GetRootNodes().Select(p => p.Key); // Initialize the search options RedirectsSearchOptions options = new() { Page = page, Limit = limit, Type = EnumUtils.ParseEnum(type, RedirectTypeFilter.All), - Text = text + Text = text, + RootNodeKeys = (rootNodeKeys != null && rootNodeKeys.Any()) ? rootNodeKeys : rootKeys.ToArray() }; - if (rootNodeKey != null) options.RootNodeKey = rootNodeKey; - - var rootKeys = _contentService.GetByIds(_redirects.GetUserAccessibleNodes(GetUser())) - .Select(p => p.Key) - .ToArray(); - // Make the search for redirects via the redirects service - RedirectsSearchResult result = _redirects.GetRedirects(options, rootKeys); + RedirectsSearchResult result = _redirects.GetRedirects(options); // Map the result for the API return new JsonResult(_backOffice.Map(result)); @@ -381,12 +380,6 @@ private ActionResult Error(RedirectsException ex) { }; } - - private IUser GetUser() - { - var currentUser = HttpContext.User.GetUmbracoIdentity(); - return _userService.GetByUsername(currentUser.Name); - } } } \ No newline at end of file diff --git a/src/Skybrud.Umbraco.Redirects/Models/RedirectRootNode.cs b/src/Skybrud.Umbraco.Redirects/Models/RedirectRootNode.cs index 35effa3..5225fd6 100644 --- a/src/Skybrud.Umbraco.Redirects/Models/RedirectRootNode.cs +++ b/src/Skybrud.Umbraco.Redirects/Models/RedirectRootNode.cs @@ -35,6 +35,12 @@ public class RedirectRootNode { [JsonProperty("icon")] public string Icon { get; } + /// + /// Gets the path of the root node. + /// + [JsonProperty("path")] + public IEnumerable Path { get; set; } + /// /// Gets the domains asscoiated with the root node. /// @@ -44,6 +50,7 @@ private RedirectRootNode(IContent content, IEnumerable domains) Id = content.Id; Key = content.Key; Name = content.Name; + Path = content.Path.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse); Icon = content.ContentType.Icon; Domains = domains?.Select(x => x.Name).ToArray() ?? Array.Empty(); } diff --git a/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs b/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs index 3cb4abb..892f7b4 100644 --- a/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs +++ b/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs @@ -19,8 +19,6 @@ public interface IRedirectsService { /// An array of . RedirectDomain[] GetDomains(); - int[] GetUserAccessibleNodes(IUser umbracoUser); - /// /// Adds a new redirect with the specified . /// @@ -105,9 +103,8 @@ public interface IRedirectsService { /// Returns a paginated list of redirects matching the specified . /// /// The options the returned redirects should match. - /// The user's root nodes that should be visible for security /// An instance of . - RedirectsSearchResult GetRedirects(RedirectsSearchOptions options, Guid[] rootNodes); + RedirectsSearchResult GetRedirects(RedirectsSearchOptions options); /// /// Returns a collection with all redirects. @@ -119,8 +116,15 @@ public interface IRedirectsService { /// Returns an array of all rode nodes configured in Umbraco. /// /// An array of representing the root nodes. + RedirectRootNode[] GetRootNodes(); + + /// + /// Returns an array of all rode nodes configured in Umbraco. + /// + /// An object to determine access to root nodes. + /// An array of representing the root nodes. RedirectRootNode[] GetRootNodes(IUser user); - + /// /// Returns an array of redirects where the destination matches the specified and . /// diff --git a/src/Skybrud.Umbraco.Redirects/Services/RedirectsSearchOptions.cs b/src/Skybrud.Umbraco.Redirects/Services/RedirectsSearchOptions.cs index 73bbcee..89159d5 100644 --- a/src/Skybrud.Umbraco.Redirects/Services/RedirectsSearchOptions.cs +++ b/src/Skybrud.Umbraco.Redirects/Services/RedirectsSearchOptions.cs @@ -33,12 +33,19 @@ public class RedirectsSearchOptions { /// public string Text { get; set; } - /// - /// Gets or sets the key the returned redirects should match. indicates all global - /// redirects. Default is null, in which case this filter is disabled. - /// + /// + /// Gets or sets the key the returned redirects should match. indicates all global + /// redirects. Default is null, in which case this filter is disabled. + /// + [Obsolete("Obsoleted in favour of RootNodeKeys, as a user may have access to more than one root node.")] public Guid? RootNodeKey { get; set; } + /// + /// Gets or sets the key the returned redirects should match. indicates all global + /// redirects. Default is null, in which case this filter is disabled. + /// + public Guid[] RootNodeKeys { get; set; } + #endregion #region Constructors diff --git a/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs b/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs index 57fb7eb..36313a0 100644 --- a/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs +++ b/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs @@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using NPoco; -using NUglify.Helpers; using Skybrud.Essentials.Strings.Extensions; using Skybrud.Essentials.Time; using Skybrud.Umbraco.Redirects.Exceptions; @@ -61,26 +60,6 @@ public RedirectDomain[] GetDomains() { return _domains.GetAll(false).Select(RedirectDomain.GetFromDomain).ToArray(); } - public int[] GetUserAccessibleNodes(IUser umbracoUser) - { - var rootNodeIDs = umbracoUser.StartContentIds.ToList(); - var groupRootNodes = umbracoUser.Groups - .Where(p => p.StartContentId.HasValue) - .Select(p => p.StartContentId.Value) - .ToArray(); - rootNodeIDs.AddRange(groupRootNodes); - - // JH: Admin should access all nodes - if (rootNodeIDs.Count == 1 && rootNodeIDs.Single() == -1) - { - rootNodeIDs.Clear(); - rootNodeIDs = GetDomains().Select(c => c.RootNodeId).ToList(); - } - - return rootNodeIDs.ToArray(); - - } - /// /// Deletes the specified . /// @@ -376,9 +355,8 @@ public IRedirect SaveRedirect(IRedirect redirect) { /// Returns a paginated list of redirects matching the specified . /// /// The options the returned redirects should match. - /// The user's root nodes that should be visible for security /// An instance of . - public RedirectsSearchResult GetRedirects(RedirectsSearchOptions options, Guid[] rootNodes) { + public RedirectsSearchResult GetRedirects(RedirectsSearchOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); @@ -389,10 +367,10 @@ public RedirectsSearchResult GetRedirects(RedirectsSearchOptions options, Guid[] var sql = scope.SqlContext.Sql().Select().From(); // Search by the rootNodeId - if (options.RootNodeKey != null) { + if (options.RootNodeKeys != null && options.RootNodeKeys.Any()) { + sql = sql.Where(x => options.RootNodeKeys.Contains(x.RootKey)); + } else if (options.RootNodeKey != null) { sql = sql.Where(x => x.RootKey == options.RootNodeKey); - } else if (rootNodes.Any()) { - sql = sql.Where(x => rootNodes.Contains(x.RootKey)); } // Search by the type @@ -481,21 +459,46 @@ public IEnumerable GetAllRedirects() { /// Returns an array of all rode nodes configured in Umbraco. /// /// An array of representing the root nodes. - public RedirectRootNode[] GetRootNodes(IUser user) + public RedirectRootNode[] GetRootNodes() { + var domainsByRootNodeId = GetDomains().GroupBy(x => x.RootNodeId); + + return ( + from domainGroup in domainsByRootNodeId + let content = _contentService.GetById(domainGroup.First().RootNodeId) + where content is { Trashed: false } + orderby content.Id + select RedirectRootNode.GetFromContent(content, domainGroup) + ).ToArray(); + } - var rootNodeIDs = GetUserAccessibleNodes(user); - // Multiple domains may be configured for a single node, so we need to group the domains before proceeding - var domainsByRootNodeId = GetDomains().GroupBy(x => x.RootNodeId); - - return ( - from domainGroup in domainsByRootNodeId - let content = _contentService.GetById(domainGroup.First().RootNodeId) - where !content.Trashed && rootNodeIDs.Contains(content.Id) - orderby content.Id - select RedirectRootNode.GetFromContent(content, domainGroup) - ).ToArray(); - + /// + /// Returns an array of all rode nodes configured in Umbraco. + /// + /// An with potential root node access restrictions. + /// An array of representing the root nodes the user has access to. + public RedirectRootNode[] GetRootNodes(IUser user) + { + var rootNodes = GetRootNodes(); + HashSet rootNodeIds = new(); + + if (user.StartContentIds != null) + { + foreach (var rootNodeId in user.StartContentIds) + { + rootNodeIds.Add(rootNodeId); + } + } + + foreach (var group in user.Groups) + { + if (group.StartContentId != null) + { + rootNodeIds.Add(group.StartContentId.Value); + } + } + + return rootNodes.Where(rootNode => rootNodeIds.Any(x => rootNode.Path.Contains(x))).ToArray(); } /// diff --git a/src/Skybrud.Umbraco.Redirects/wwwroot/Scripts/Controllers/Dashboards/Default.js b/src/Skybrud.Umbraco.Redirects/wwwroot/Scripts/Controllers/Dashboards/Default.js index 604a4f5..7cbf000 100644 --- a/src/Skybrud.Umbraco.Redirects/wwwroot/Scripts/Controllers/Dashboards/Default.js +++ b/src/Skybrud.Umbraco.Redirects/wwwroot/Scripts/Controllers/Dashboards/Default.js @@ -113,7 +113,7 @@ // Any filters? if (vm.filters.rootNode && vm.filters.rootNode.key) { - args.rootNodeKey = vm.filters.rootNode.key; + args.rootNodeKeys = vm.filters.rootNode.key; vm.activeFilters++; } From 76e3ca960718eb9bfa0e458d460948414943a4ba Mon Sep 17 00:00:00 2001 From: Jamie Howarth Date: Mon, 14 Nov 2022 20:35:22 +0000 Subject: [PATCH 3/4] Added merged props --- .../Config/RedirectsContentAppSettings.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs b/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs index d74e7ec..01a989d 100644 --- a/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs +++ b/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs @@ -1,4 +1,6 @@ -namespace Skybrud.Umbraco.Redirects.Config { +using System.Collections.Generic; + +namespace Skybrud.Umbraco.Redirects.Config { /// /// Class with settings for the redirects content app. @@ -15,6 +17,14 @@ public class RedirectsContentAppSettings { /// public bool UserStartNodes { get; set; } = false; + /// Gets or sets a list of content types and media types where the content app should or should not be shown. + /// The format follows Umbraco's show option - eg. +content/* enables the content app for all + /// content. + /// + /// If empty, the content app will be enabled for all content and media. + /// + public HashSet Show { get; set; } = new(); + } } \ No newline at end of file From a928c173a6a1b100a0abd1a31fb8c84afa412621 Mon Sep 17 00:00:00 2001 From: Jamie Howarth Date: Mon, 14 Nov 2022 21:44:11 +0000 Subject: [PATCH 4/4] Updated with @abjerner's comments. --- .../Config/RedirectsContentAppSettings.cs | 4 +-- .../Controllers/Api/RedirectsController.cs | 6 ++-- .../Services/IRedirectsService.cs | 30 +++++++++++++++++-- .../Services/RedirectsService.cs | 29 ------------------ 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs b/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs index 01a989d..e8b6cf6 100644 --- a/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs +++ b/src/Skybrud.Umbraco.Redirects/Config/RedirectsContentAppSettings.cs @@ -13,9 +13,9 @@ public class RedirectsContentAppSettings { public bool Enabled { get; set; } = true; /// - /// Gets or sets whether the user's start nodes should filter which redirects they have access to. Default is . + /// Gets or sets whether the user's start nodes should filter which redirects they have access to. Default is . /// - public bool UserStartNodes { get; set; } = false; + public bool UseStartNodes { get; set; } = false; /// Gets or sets a list of content types and media types where the content app should or should not be shown. /// The format follows Umbraco's show option - eg. +content/* enables the content app for all diff --git a/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs b/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs index 73a2c4f..0da3a5c 100644 --- a/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs +++ b/src/Skybrud.Umbraco.Redirects/Controllers/Api/RedirectsController.cs @@ -67,8 +67,8 @@ public RedirectsController(ILogger logger, IRedirectsServic [HttpGet] public ActionResult GetRootNodes() { - var rootNodes = _backOffice.Settings.ContentApp.UserStartNodes - ? _redirects.GetRootNodes(_backOffice.CurrentUser).ToArray() + var rootNodes = _backOffice.Settings.ContentApp.UseStartNodes + ? _redirects.GetRootNodes(_backOffice.CurrentUser) : _redirects.GetRootNodes(); return new JsonResult(new @@ -269,7 +269,7 @@ public ActionResult DeleteRedirect(Guid redirectId) { public ActionResult GetRedirects(int page = 1, int limit = 20, string type = null, string text = null, [FromQuery]Guid[] rootNodeKeys = null) { try { - var rootKeys = _backOffice.Settings.ContentApp.UserStartNodes + var rootKeys = _backOffice.Settings.ContentApp.UseStartNodes ? _redirects.GetRootNodes(_backOffice.CurrentUser).Select(p => p.Key) : _redirects.GetRootNodes().Select(p => p.Key); diff --git a/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs b/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs index 892f7b4..bbb14b3 100644 --- a/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs +++ b/src/Skybrud.Umbraco.Redirects/Services/IRedirectsService.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; + using Microsoft.AspNetCore.Http; using Skybrud.Umbraco.Redirects.Models; using Skybrud.Umbraco.Redirects.Models.Options; @@ -121,9 +123,31 @@ public interface IRedirectsService { /// /// Returns an array of all rode nodes configured in Umbraco. /// - /// An object to determine access to root nodes. - /// An array of representing the root nodes. - RedirectRootNode[] GetRootNodes(IUser user); + /// An with potential root node access restrictions. + /// An array of representing the root nodes the user has access to. + RedirectRootNode[] GetRootNodes(IUser user) + { + var rootNodes = GetRootNodes(); + HashSet rootNodeIds = new(); + + if (user.StartContentIds != null) + { + foreach (var rootNodeId in user.StartContentIds) + { + rootNodeIds.Add(rootNodeId); + } + } + + foreach (var group in user.Groups) + { + if (group.StartContentId != null) + { + rootNodeIds.Add(group.StartContentId.Value); + } + } + + return rootNodes.Where(rootNode => rootNodeIds.Any(x => rootNode.Path.Contains(x))).ToArray(); + } /// /// Returns an array of redirects where the destination matches the specified and . diff --git a/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs b/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs index 36313a0..9e59352 100644 --- a/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs +++ b/src/Skybrud.Umbraco.Redirects/Services/RedirectsService.cs @@ -472,35 +472,6 @@ select RedirectRootNode.GetFromContent(content, domainGroup) ).ToArray(); } - /// - /// Returns an array of all rode nodes configured in Umbraco. - /// - /// An with potential root node access restrictions. - /// An array of representing the root nodes the user has access to. - public RedirectRootNode[] GetRootNodes(IUser user) - { - var rootNodes = GetRootNodes(); - HashSet rootNodeIds = new(); - - if (user.StartContentIds != null) - { - foreach (var rootNodeId in user.StartContentIds) - { - rootNodeIds.Add(rootNodeId); - } - } - - foreach (var group in user.Groups) - { - if (group.StartContentId != null) - { - rootNodeIds.Add(group.StartContentId.Value); - } - } - - return rootNodes.Where(rootNode => rootNodeIds.Any(x => rootNode.Path.Contains(x))).ToArray(); - } - /// /// Returns the calculated destination URL for the specified . ///