manifest dashboard code
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -13,19 +15,20 @@ namespace Umbraco.Core.Manifest
|
||||
/// </summary>
|
||||
internal class ManifestBuilder
|
||||
{
|
||||
private readonly IRuntimeCacheProvider _cache;
|
||||
private readonly IRuntimeCacheProvider _runtimeCache;
|
||||
private readonly ManifestParser _parser;
|
||||
|
||||
public ManifestBuilder(IRuntimeCacheProvider cache, ManifestParser parser)
|
||||
{
|
||||
_cache = cache;
|
||||
_runtimeCache = cache;
|
||||
_parser = parser;
|
||||
}
|
||||
|
||||
private const string GridEditorsKey = "grideditors";
|
||||
private const string PropertyEditorsKey = "propertyeditors";
|
||||
private const string ParameterEditorsKey = "parametereditors";
|
||||
|
||||
public const string GridEditorsKey = "gridEditors";
|
||||
public const string PropertyEditorsKey = "propertyEditors";
|
||||
public const string ParameterEditorsKey = "parameterEditors";
|
||||
public const string DashboardsKey = "dashboards";
|
||||
|
||||
/// <summary>
|
||||
/// Returns all grid editors found in the manfifests
|
||||
/// </summary>
|
||||
@@ -33,7 +36,7 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cache.GetCacheItem<IEnumerable<GridEditor>>(
|
||||
return _runtimeCache.GetCacheItem<IEnumerable<GridEditor>>(
|
||||
typeof (ManifestBuilder) + GridEditorsKey,
|
||||
() =>
|
||||
{
|
||||
@@ -58,7 +61,7 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cache.GetCacheItem<IEnumerable<PropertyEditor>>(
|
||||
return _runtimeCache.GetCacheItem<IEnumerable<PropertyEditor>>(
|
||||
typeof(ManifestBuilder) + PropertyEditorsKey,
|
||||
() =>
|
||||
{
|
||||
@@ -83,7 +86,7 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cache.GetCacheItem<IEnumerable<ParameterEditor>>(
|
||||
return _runtimeCache.GetCacheItem<IEnumerable<ParameterEditor>>(
|
||||
typeof (ManifestBuilder) + ParameterEditorsKey,
|
||||
() =>
|
||||
{
|
||||
@@ -98,7 +101,104 @@ namespace Umbraco.Core.Manifest
|
||||
return editors;
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all dashboards found in the manfifests
|
||||
/// </summary>
|
||||
internal IDictionary<string, Section> Dashboards
|
||||
{
|
||||
get
|
||||
{
|
||||
//TODO: Need to integrate the security with the manifest dashboards
|
||||
|
||||
return _runtimeCache.GetCacheItem<IDictionary<string, Section>>(
|
||||
typeof(ManifestBuilder) + DashboardsKey,
|
||||
() =>
|
||||
{
|
||||
var dashboards = new Dictionary<string, Section>();
|
||||
foreach (var manifest in _parser.GetManifests())
|
||||
{
|
||||
if (manifest.Dashboards != null)
|
||||
{
|
||||
var converted = manifest.Dashboards.ToDictionary(x => x.Key, x => x.Value.ToObject<Section>());
|
||||
foreach (var item in converted)
|
||||
{
|
||||
Section existing;
|
||||
if (dashboards.TryGetValue(item.Key, out existing))
|
||||
{
|
||||
foreach (var area in item.Value.Areas)
|
||||
{
|
||||
if (existing.Areas.Contains(area, StringComparer.InvariantCultureIgnoreCase) == false)
|
||||
existing.Areas.Add(area);
|
||||
}
|
||||
|
||||
//merge
|
||||
foreach (var tab in item.Value.Tabs)
|
||||
{
|
||||
Tab existingTab;
|
||||
if (existing.Tabs.TryGetValue(tab.Key, out existingTab))
|
||||
{
|
||||
//merge
|
||||
foreach (var control in tab.Value.Controls)
|
||||
{
|
||||
existingTab.Controls.Add(control);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
existing.Tabs[tab.Key] = tab.Value;
|
||||
}
|
||||
}
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
dashboards[item.Key] = item.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dashboards;
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
}
|
||||
|
||||
#region Internal manifest models
|
||||
internal class Section
|
||||
{
|
||||
public Section()
|
||||
{
|
||||
Areas = new List<string>();
|
||||
Tabs = new Dictionary<string, Tab>();
|
||||
}
|
||||
[JsonProperty("areas")]
|
||||
public List<string> Areas { get; set; }
|
||||
[JsonProperty("tabs")]
|
||||
public IDictionary<string, Tab> Tabs { get; set; }
|
||||
}
|
||||
|
||||
internal class Tab
|
||||
{
|
||||
public Tab()
|
||||
{
|
||||
Controls = new List<Control>();
|
||||
Index = int.MaxValue; //default so we can check if this value has been explicitly set
|
||||
}
|
||||
[JsonProperty("controls")]
|
||||
public List<Control> Controls { get; set; }
|
||||
[JsonProperty("index")]
|
||||
public int Index { get; set; }
|
||||
}
|
||||
|
||||
internal class Control
|
||||
{
|
||||
[JsonProperty("path")]
|
||||
public string Path { get; set; }
|
||||
[JsonProperty("caption")]
|
||||
public string Caption { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,26 +185,33 @@ namespace Umbraco.Core.Manifest
|
||||
}
|
||||
|
||||
//validate the property editors section
|
||||
var propEditors = deserialized.Properties().Where(x => x.Name == "propertyEditors").ToArray();
|
||||
var propEditors = deserialized.Properties().Where(x => x.Name == ManifestBuilder.PropertyEditorsKey).ToArray();
|
||||
if (propEditors.Length > 1)
|
||||
{
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'propertyEditors' element");
|
||||
}
|
||||
|
||||
//validate the parameterEditors section
|
||||
var paramEditors = deserialized.Properties().Where(x => x.Name == "parameterEditors").ToArray();
|
||||
var paramEditors = deserialized.Properties().Where(x => x.Name == ManifestBuilder.ParameterEditorsKey).ToArray();
|
||||
if (paramEditors.Length > 1)
|
||||
{
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'parameterEditors' element");
|
||||
}
|
||||
|
||||
//validate the gridEditors section
|
||||
var gridEditors = deserialized.Properties().Where(x => x.Name == "gridEditors").ToArray();
|
||||
var gridEditors = deserialized.Properties().Where(x => x.Name == ManifestBuilder.GridEditorsKey).ToArray();
|
||||
if (gridEditors.Length > 1)
|
||||
{
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'gridEditors' element");
|
||||
}
|
||||
|
||||
//validate the dashboards section
|
||||
var dashboards = deserialized.Properties().Where(x => x.Name == "dashboards").ToArray();
|
||||
if (dashboards.Length > 1)
|
||||
{
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'dashboards' element");
|
||||
}
|
||||
|
||||
var jConfig = init.Any() ? (JArray)deserialized["javascript"] : new JArray();
|
||||
ReplaceVirtualPaths(jConfig);
|
||||
|
||||
@@ -212,9 +219,9 @@ namespace Umbraco.Core.Manifest
|
||||
ReplaceVirtualPaths(cssConfig);
|
||||
|
||||
//replace virtual paths for each property editor
|
||||
if (deserialized["propertyEditors"] != null)
|
||||
if (deserialized[ManifestBuilder.PropertyEditorsKey] != null)
|
||||
{
|
||||
foreach (JObject p in deserialized["propertyEditors"])
|
||||
foreach (JObject p in deserialized[ManifestBuilder.PropertyEditorsKey])
|
||||
{
|
||||
if (p["editor"] != null)
|
||||
{
|
||||
@@ -228,9 +235,9 @@ namespace Umbraco.Core.Manifest
|
||||
}
|
||||
|
||||
//replace virtual paths for each property editor
|
||||
if (deserialized["gridEditors"] != null)
|
||||
if (deserialized[ManifestBuilder.GridEditorsKey] != null)
|
||||
{
|
||||
foreach (JObject p in deserialized["gridEditors"])
|
||||
foreach (JObject p in deserialized[ManifestBuilder.GridEditorsKey])
|
||||
{
|
||||
if (p["view"] != null)
|
||||
{
|
||||
@@ -247,9 +254,10 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
JavaScriptInitialize = jConfig,
|
||||
StylesheetInitialize = cssConfig,
|
||||
PropertyEditors = propEditors.Any() ? (JArray)deserialized["propertyEditors"] : new JArray(),
|
||||
ParameterEditors = paramEditors.Any() ? (JArray)deserialized["parameterEditors"] : new JArray(),
|
||||
GridEditors = gridEditors.Any() ? (JArray)deserialized["gridEditors"] : new JArray()
|
||||
PropertyEditors = propEditors.Any() ? (JArray)deserialized[ManifestBuilder.PropertyEditorsKey] : new JArray(),
|
||||
ParameterEditors = paramEditors.Any() ? (JArray)deserialized[ManifestBuilder.ParameterEditorsKey] : new JArray(),
|
||||
GridEditors = gridEditors.Any() ? (JArray)deserialized[ManifestBuilder.GridEditorsKey] : new JArray(),
|
||||
Dashboards = dashboards.Any() ? deserialized[ManifestBuilder.DashboardsKey].ToObject<IDictionary<string, JObject>>() : new Dictionary<string, JObject>()
|
||||
};
|
||||
result.Add(manifest);
|
||||
}
|
||||
@@ -353,4 +361,4 @@ namespace Umbraco.Core.Manifest
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
{
|
||||
@@ -26,10 +27,15 @@ namespace Umbraco.Core.Manifest
|
||||
/// The json array of parameter editors
|
||||
/// </summary>
|
||||
public JArray ParameterEditors { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The json array of grid editors
|
||||
/// </summary>
|
||||
public JArray GridEditors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary of dashboards
|
||||
/// </summary>
|
||||
public IDictionary<string, JObject> Dashboards { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,8 +123,8 @@ namespace Umbraco.Web.Editors
|
||||
[ValidateAngularAntiForgeryToken]
|
||||
public IEnumerable<Tab<DashboardControl>> GetDashboard(string section)
|
||||
{
|
||||
var dashboardHelper = new DashboardHelper(Services.SectionService);
|
||||
return dashboardHelper.GetDashboard(section, Security.CurrentUser);
|
||||
var dashboardHelper = new DashboardHelper(ApplicationContext);
|
||||
return dashboardHelper.GetDashboard(section, Security.CurrentUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
@@ -12,12 +15,12 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
internal class DashboardHelper
|
||||
{
|
||||
private readonly ISectionService _sectionService;
|
||||
private readonly ApplicationContext _appContext;
|
||||
|
||||
public DashboardHelper(ISectionService sectionService)
|
||||
public DashboardHelper(ApplicationContext appContext)
|
||||
{
|
||||
if (sectionService == null) throw new ArgumentNullException("sectionService");
|
||||
_sectionService = sectionService;
|
||||
if (appContext == null) throw new ArgumentNullException("appContext");
|
||||
_appContext = appContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -28,7 +31,7 @@ namespace Umbraco.Web.Editors
|
||||
public IDictionary<string, IEnumerable<Tab<DashboardControl>>> GetDashboards(IUser currentUser)
|
||||
{
|
||||
var result = new Dictionary<string, IEnumerable<Tab<DashboardControl>>>();
|
||||
foreach (var section in _sectionService.GetSections())
|
||||
foreach (var section in _appContext.Services.SectionService.GetSections())
|
||||
{
|
||||
result[section.Alias] = GetDashboard(section.Alias, currentUser);
|
||||
}
|
||||
@@ -42,29 +45,64 @@ namespace Umbraco.Web.Editors
|
||||
/// <param name="currentUser"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Tab<DashboardControl>> GetDashboard(string section, IUser currentUser)
|
||||
{
|
||||
var configDashboards = GetDashboardsFromConfig(1, section, currentUser);
|
||||
var pluginDashboards = GetDashboardsFromPlugins(configDashboards.Count + 1, section, currentUser);
|
||||
|
||||
//now we need to merge them, the plugin ones would replace anything matched in the config one where the tab alias matches
|
||||
var added = new List<Tab<DashboardControl>>(); //to track the ones we'll add
|
||||
foreach (var configDashboard in configDashboards)
|
||||
{
|
||||
var matched = pluginDashboards.Where(x => string.Equals(x.Alias, configDashboard.Alias, StringComparison.InvariantCultureIgnoreCase)).ToList();
|
||||
foreach (var tab in matched)
|
||||
{
|
||||
configDashboard.Label = tab.Label; //overwrite
|
||||
configDashboard.Properties = configDashboard.Properties.Concat(tab.Properties).ToList(); //combine
|
||||
added.Add(tab); //track this
|
||||
}
|
||||
}
|
||||
|
||||
//now add the plugin dashboards to the config dashboards that have not already been added
|
||||
var toAdd = pluginDashboards.Where(pluginDashboard => added.Contains(pluginDashboard) == false).ToList();
|
||||
configDashboards.AddRange(toAdd);
|
||||
|
||||
//last thing is to re-sort and ID the tabs
|
||||
configDashboards.Sort((tab, tab1) => tab.Id > tab1.Id ? 1 : 0);
|
||||
for (var index = 0; index < configDashboards.Count; index++)
|
||||
{
|
||||
var tab = configDashboards[index];
|
||||
tab.Id = (index + 1);
|
||||
if (tab.Id == 1)
|
||||
tab.IsActive = true;
|
||||
}
|
||||
|
||||
return configDashboards;
|
||||
}
|
||||
|
||||
private List<Tab<DashboardControl>> GetDashboardsFromConfig(int startTabId, string section, IUser currentUser)
|
||||
{
|
||||
var tabs = new List<Tab<DashboardControl>>();
|
||||
var i = 1;
|
||||
var i = startTabId;
|
||||
|
||||
// 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)
|
||||
if (DashboardSecurity.AuthorizeAccess(dashboardSection, currentUser, _appContext.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, currentUser, _sectionService) == false)
|
||||
if (DashboardSecurity.AuthorizeAccess(tab, currentUser, _appContext.Services.SectionService) == false)
|
||||
continue;
|
||||
|
||||
var dashboardControls = new List<DashboardControl>();
|
||||
|
||||
foreach (var control in tab.Controls)
|
||||
{
|
||||
if (DashboardSecurity.AuthorizeAccess(control, currentUser, _sectionService) == false)
|
||||
if (DashboardSecurity.AuthorizeAccess(control, currentUser, _appContext.Services.SectionService) == false)
|
||||
continue;
|
||||
|
||||
var dashboardControl = new DashboardControl();
|
||||
@@ -81,7 +119,6 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
Id = i,
|
||||
Alias = tab.Caption.ToSafeAlias(),
|
||||
IsActive = i == 1,
|
||||
Label = tab.Caption,
|
||||
Properties = dashboardControls
|
||||
});
|
||||
@@ -93,5 +130,49 @@ namespace Umbraco.Web.Editors
|
||||
//In case there are no tabs or a user doesn't have access the empty tabs list is returned
|
||||
return tabs;
|
||||
}
|
||||
|
||||
private List<Tab<DashboardControl>> GetDashboardsFromPlugins(int startTabId, string section, IUser currentUser)
|
||||
{
|
||||
//TODO: Need to integrate the security with the manifest dashboards
|
||||
|
||||
var appPlugins = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.AppPlugins));
|
||||
var parser = new ManifestParser(appPlugins, _appContext.ApplicationCache.RuntimeCache);
|
||||
var builder = new ManifestBuilder(_appContext.ApplicationCache.RuntimeCache, parser);
|
||||
|
||||
var tabs = new List<Tab<DashboardControl>>();
|
||||
var i = startTabId;
|
||||
|
||||
foreach (var sectionDashboard in builder.Dashboards.Where(x => x.Value.Areas.InvariantContains(section)))
|
||||
{
|
||||
foreach (var tab in sectionDashboard.Value.Tabs)
|
||||
{
|
||||
var dashboardControls = new List<DashboardControl>();
|
||||
|
||||
foreach (var control in tab.Value.Controls)
|
||||
{
|
||||
var dashboardControl = new DashboardControl();
|
||||
var controlPath = control.Path.Trim();
|
||||
dashboardControl.Caption = control.Caption;
|
||||
dashboardControl.Path = IOHelper.FindFile(controlPath);
|
||||
if (controlPath.ToLowerInvariant().EndsWith(".ascx".ToLowerInvariant()))
|
||||
dashboardControl.ServerSide = true;
|
||||
|
||||
dashboardControls.Add(dashboardControl);
|
||||
}
|
||||
|
||||
tabs.Add(new Tab<DashboardControl>
|
||||
{
|
||||
//assign the Id to the value of the index if one was defined, then we'll use the Id to sort later
|
||||
Id = tab.Value.Index == int.MaxValue ? i : tab.Value.Index,
|
||||
Alias = tab.Key.ToSafeAlias(),
|
||||
Label = tab.Key,
|
||||
Properties = dashboardControls
|
||||
});
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return tabs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
//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);
|
||||
var dashboardHelper = new DashboardHelper(ApplicationContext);
|
||||
//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
|
||||
@@ -72,4 +72,4 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user