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();