U4-10227 Users section should start in the user tree

This commit is contained in:
Shannon
2017-08-10 17:25:16 +10:00
parent 62e467d860
commit 72495b3eaf
8 changed files with 178 additions and 68 deletions

View File

@@ -154,8 +154,16 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
}
navigationService.hideSearch();
navigationService.showTree(section.alias);
$location.path("/" + section.alias);
navigationService.showTree(section.alias);
//in some cases the section will have a custom route path specified, if there is one we'll use it
if (section.routePath) {
$location.path(section.routePath);
}
else {
$location.path(section.alias);
}
};
scope.sectionDblClick = function(section){

View File

@@ -98,14 +98,25 @@ app.config(function ($routeProvider) {
resolve: doLogout()
})
.when('/:section', {
templateUrl: function (rp) {
if (rp.section.toLowerCase() === "default" || rp.section.toLowerCase() === "umbraco" || rp.section === "")
{
rp.section = "content";
//This allows us to dynamically change the template for this route since you cannot inject services into the templateUrl method.
template: "<div ng-include='templateUrl'></div>",
//This controller will execute for this route, then we can execute some code in order to set the template Url
controller: function ($scope, $route, $routeParams, $location) {
if ($routeParams.section.toLowerCase() === "default" || $routeParams.section.toLowerCase() === "umbraco" || $routeParams.section === "") {
$routeParams.section = "content";
}
//TODO: Here we could run some extra logic to check if the dashboard we are navigating
//to has any content to show and if not it could redirect to the first tree root path.
//BUT! this would mean that we'd need a server side call to check this data....
//Instead we already have this data in the sections returned from the sectionResource but we
//don't want to cache data in a resource so we'd have to create a sectionService which would rely
//on the userService, then we update the umbsections.directive to use the sectionService and when the
//sectionService requests the sections, it caches the result against the current user. Then we can
//use the sectionService here to do the redirection.
rp.url = "dashboard.aspx?app=" + rp.section;
return 'views/common/dashboard.html';
$routeParams.url = "dashboard.aspx?app=" + $routeParams.section;
$scope.templateUrl = 'views/common/dashboard.html';
},
resolve: canRoute(true)
})
@@ -121,15 +132,11 @@ app.config(function ($routeProvider) {
})
.when('/:section/:tree/:method', {
templateUrl: function (rp) {
//if there is no method registered for this then show the dashboard
if (!rp.method)
return "views/common/dashboard.html";
//NOTE: This current isn't utilized by anything but does open up some cool opportunities for
// us since we'll be able to have specialized views for individual sections which is something
// we've never had before. So could utilize this for a new dashboard model when we get native
// angular dashboards working. Perhaps a normal section dashboard would list out the registered
// dashboards (as tabs if we wanted) and each tab could actually be a route link to one of these views?
return ('views/' + rp.tree + '/' + rp.method + '.html');
},
resolve: canRoute(true)

View File

@@ -19,7 +19,6 @@ using Umbraco.Core.Logging;
namespace Umbraco.Web.Editors
{
//we need to fire up the controller like this to enable loading of remote css directly from this controller
[PluginController("UmbracoApi")]
[ValidationFilter]
@@ -124,54 +123,8 @@ namespace Umbraco.Web.Editors
[ValidateAngularAntiForgeryToken]
public IEnumerable<Tab<DashboardControl>> GetDashboard(string section)
{
var tabs = new List<Tab<DashboardControl>>();
var i = 1;
// The dashboard config can contain more than one area inserted by a package.
foreach( var dashboardSection in UmbracoConfig.For.DashboardSettings().Sections.Where(x => x.Areas.Contains(section)))
{
//we need to validate access to this section
if (DashboardSecurity.AuthorizeAccess(dashboardSection, Security.CurrentUser, Services.SectionService) == false)
continue;
//User is authorized
foreach (var tab in dashboardSection.Tabs)
{
//we need to validate access to this tab
if (DashboardSecurity.AuthorizeAccess(tab, Security.CurrentUser, Services.SectionService) == false)
continue;
var dashboardControls = new List<DashboardControl>();
foreach (var control in tab.Controls)
{
if (DashboardSecurity.AuthorizeAccess(control, Security.CurrentUser, Services.SectionService) == false)
continue;
var dashboardControl = new DashboardControl();
var controlPath = control.ControlPath.Trim();
dashboardControl.Path = IOHelper.FindFile(controlPath);
if (controlPath.ToLowerInvariant().EndsWith(".ascx".ToLowerInvariant()))
dashboardControl.ServerSide = true;
dashboardControls.Add(dashboardControl);
}
tabs.Add(new Tab<DashboardControl>
{
Id = i,
Alias = tab.Caption.ToSafeAlias(),
IsActive = i == 1,
Label = tab.Caption,
Properties = dashboardControls
});
i++;
}
}
//In case there are no tabs or a user doesn't have access the empty tabs list is returned
return tabs;
var dashboardHelper = new DashboardHelper(Services.SectionService);
return dashboardHelper.GetDashboard(section, Security.CurrentUser);
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Editors
{
internal class DashboardHelper
{
private readonly ISectionService _sectionService;
public DashboardHelper(ISectionService sectionService)
{
if (sectionService == null) throw new ArgumentNullException("sectionService");
_sectionService = sectionService;
}
/// <summary>
/// Returns the dashboard models per section for the current user and it's access
/// </summary>
/// <param name="currentUser"></param>
/// <returns></returns>
public IDictionary<string, IEnumerable<Tab<DashboardControl>>> GetDashboards(IUser currentUser)
{
var result = new Dictionary<string, IEnumerable<Tab<DashboardControl>>>();
foreach (var section in _sectionService.GetSections())
{
result[section.Alias] = GetDashboard(section.Alias, currentUser);
}
return result;
}
/// <summary>
/// Returns the dashboard model for the given section based on the current user and it's access
/// </summary>
/// <param name="section"></param>
/// <param name="currentUser"></param>
/// <returns></returns>
public IEnumerable<Tab<DashboardControl>> GetDashboard(string section, IUser currentUser)
{
var tabs = new List<Tab<DashboardControl>>();
var i = 1;
// The dashboard config can contain more than one area inserted by a package.
foreach (var dashboardSection in UmbracoConfig.For.DashboardSettings().Sections.Where(x => x.Areas.Contains(section)))
{
//we need to validate access to this section
if (DashboardSecurity.AuthorizeAccess(dashboardSection, currentUser, _sectionService) == false)
continue;
//User is authorized
foreach (var tab in dashboardSection.Tabs)
{
//we need to validate access to this tab
if (DashboardSecurity.AuthorizeAccess(tab, currentUser, _sectionService) == false)
continue;
var dashboardControls = new List<DashboardControl>();
foreach (var control in tab.Controls)
{
if (DashboardSecurity.AuthorizeAccess(control, currentUser, _sectionService) == false)
continue;
var dashboardControl = new DashboardControl();
var controlPath = control.ControlPath.Trim();
dashboardControl.Path = IOHelper.FindFile(controlPath);
if (controlPath.ToLowerInvariant().EndsWith(".ascx".ToLowerInvariant()))
dashboardControl.ServerSide = true;
dashboardControls.Add(dashboardControl);
}
tabs.Add(new Tab<DashboardControl>
{
Id = i,
Alias = tab.Caption.ToSafeAlias(),
IsActive = i == 1,
Label = tab.Caption,
Properties = dashboardControls
});
i++;
}
}
//In case there are no tabs or a user doesn't have access the empty tabs list is returned
return tabs;
}
}
}

View File

@@ -5,6 +5,8 @@ using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using System.Linq;
using System.Net.Http.Formatting;
using Umbraco.Web.Trees;
namespace Umbraco.Web.Editors
{
@@ -15,9 +17,45 @@ namespace Umbraco.Web.Editors
public class SectionController : UmbracoAuthorizedJsonController
{
public IEnumerable<Section> GetSections()
{
var sections = Services.SectionService.GetAllowedSections(UmbracoUser.Id);
return sections.Select(Mapper.Map<Core.Models.Section, Section>);
{
var sections = Services.SectionService.GetAllowedSections(Security.GetUserId());
var sectionModels = sections.Select(Mapper.Map<Core.Models.Section, Section>).ToArray();
//Check if there are empty dashboards or dashboards that will end up empty based on the current user's access
//and add the meta data about them
var dashboardHelper = new DashboardHelper(Services.SectionService);
//this is a bit nasty since we'll be proxying via the app tree controller but we sort of have to do that
//since tree's by nature are controllers and require request contextual data.
var appTreeController = new ApplicationTreeController
{
ControllerContext = ControllerContext
};
var dashboards = dashboardHelper.GetDashboards(Security.CurrentUser);
//now we can add metadata for each section so that the UI knows if there's actually anything at all to render for
//a dashboard for a given section, then the UI can deal with it accordingly (i.e. redirect to the first tree)
foreach (var section in sectionModels)
{
var hasDashboards = false;
IEnumerable<Tab<DashboardControl>> dashboardsForSection;
if (dashboards.TryGetValue(section.Alias, out dashboardsForSection))
{
if (dashboardsForSection.Any())
hasDashboards = true;
}
if (hasDashboards == false)
{
//get the first tree in the section and get it's root node route path
var sectionTrees = appTreeController.GetApplicationTrees(section.Alias, null, null).Result;
section.RoutePath = sectionTrees.IsContainer == false
? sectionTrees.RoutePath
: sectionTrees.Children[0].RoutePath;
}
}
return sectionModels;
}
public IEnumerable<Section> GetAllSections()

View File

@@ -23,6 +23,13 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "alias")]
public string Alias { get; set; }
/// <summary>
/// In some cases a custom route path can be specified so that when clicking on a section it goes to this
/// path instead of the normal dashboard path
/// </summary>
[DataMember(Name = "routePath")]
public string RoutePath { get; set; }
}
}

View File

@@ -40,7 +40,7 @@ namespace Umbraco.Web.Trees
var rootId = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
//find all tree definitions that have the current application alias
var appTrees = ApplicationContext.Current.Services.ApplicationTreeService.GetApplicationTrees(application, onlyInitialized).ToArray();
var appTrees = Services.ApplicationTreeService.GetApplicationTrees(application, onlyInitialized).ToArray();
if (string.IsNullOrEmpty(tree) == false || appTrees.Length == 1)
{

View File

@@ -320,6 +320,7 @@
<Compile Include="Cache\UserCacheRefresher.cs" />
<Compile Include="Editors\BackOfficeNotificationsController.cs" />
<Compile Include="Editors\BackOfficeServerVariables.cs" />
<Compile Include="Editors\DashboardHelper.cs" />
<Compile Include="Editors\EditorValidationResolver.cs" />
<Compile Include="Editors\EditorValidator.cs" />
<Compile Include="Editors\FromJsonPathAttribute.cs" />