Moves the grid configuration to a config class so it can be re-used. Updates the BackOfficeController to use the new config classes. Creates a new Grid property value converter (which can be overridden by user's ones) which merges the grid config values at runtime so we are not storing stale grid config values with the actual property value. Now we need to ensure that the grid doesn't post or persist these config values since they don't belong there.

This commit is contained in:
Shannon
2015-06-16 15:04:31 +02:00
parent fd6caf5cee
commit 1c0188351c
12 changed files with 289 additions and 47 deletions

View File

@@ -0,0 +1,16 @@
using System.IO;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Configuration.Grid
{
class GridConfig : IGridConfig
{
public GridConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug)
{
EditorsConfig = new GridEditorsConfig(logger, runtimeCache, appPlugins, configFolder, isDebug);
}
public IGridEditorsConfig EditorsConfig { get; private set; }
}
}

View File

@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Configuration.Grid
{
class GridEditorsConfig : IGridEditorsConfig
{
private readonly ILogger _logger;
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly DirectoryInfo _appPlugins;
private readonly DirectoryInfo _configFolder;
private readonly bool _isDebug;
public GridEditorsConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug)
{
_logger = logger;
_runtimeCache = runtimeCache;
_appPlugins = appPlugins;
_configFolder = configFolder;
_isDebug = isDebug;
}
public IEnumerable<IGridEditorConfig> Editors
{
get
{
Func<List<GridEditor>> getResult = () =>
{
var editors = new List<GridEditor>();
var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js");
if (File.Exists(gridConfig))
{
try
{
var arr = JArray.Parse(File.ReadAllText(gridConfig));
//ensure the contents parse correctly to objects
var parsed = ManifestParser.GetGridEditors(arr);
editors.AddRange(parsed);
}
catch (Exception ex)
{
_logger.Error<GridEditorsConfig>("Could not parse the contents of grid.editors.config.js into a JSON array", ex);
}
}
var parser = new ManifestParser(_appPlugins, _runtimeCache);
var builder = new ManifestBuilder(_runtimeCache, parser);
foreach (var gridEditor in builder.GridEditors)
{
//no duplicates! (based on alias)
if (editors.Contains(gridEditor) == false)
{
editors.Add(gridEditor);
}
}
return editors;
};
//cache the result if debugging is disabled
var result = _isDebug
? getResult()
: _runtimeCache.GetCacheItem<List<GridEditor>>(
typeof(GridEditorsConfig) + "Editors",
() => getResult(),
TimeSpan.FromMinutes(10));
return result;
}
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Core.Configuration.Grid
{
public interface IGridConfig
{
IGridEditorsConfig EditorsConfig { get; }
}
}

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
namespace Umbraco.Core.Configuration.Grid
{
public interface IGridEditorConfig
{
string Name { get; }
string Alias { get; }
string View { get; }
string Render { get; }
IDictionary<string, object> Config { get; }
}
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration.Grid
{
public interface IGridEditorsConfig
{
IEnumerable<IGridEditorConfig> Editors { get; }
}
}

View File

@@ -2,10 +2,13 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.BaseRest;
using Umbraco.Core.Configuration.Dashboard;
using Umbraco.Core.Configuration.Grid;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
@@ -67,6 +70,7 @@ namespace Umbraco.Core.Configuration
private IDashboardSection _dashboardSection;
private IUmbracoSettingsSection _umbracoSettings;
private IBaseRestSection _baseRestExtensions;
private IGridConfig _gridConfig;
/// <summary>
/// Gets the IDashboardSection
@@ -140,6 +144,28 @@ namespace Umbraco.Core.Configuration
return _baseRestExtensions;
}
/// <summary>
/// Only for testing
/// </summary>
/// <param name="value"></param>
public void SetGridConfig(IGridConfig value)
{
_gridConfig = value;
}
/// <summary>
/// Gets the IGridConfig
/// </summary>
public IGridConfig GridConfig(ILogger logger, IRuntimeCacheProvider runtimeCache, DirectoryInfo appPlugins, DirectoryInfo configFolder, bool isDebug)
{
if (_gridConfig == null)
{
_gridConfig = new GridConfig(logger, runtimeCache, appPlugins, configFolder, isDebug);
}
return _gridConfig;
}
//TODO: Add other configurations here !
}
}

View File

@@ -1,9 +1,10 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Umbraco.Core.Configuration.Grid;
namespace Umbraco.Core.PropertyEditors
{
internal class GridEditor
internal class GridEditor : IGridEditorConfig
{
public GridEditor()
{

View File

@@ -0,0 +1,112 @@
using System;
using System.IO;
using System.Linq;
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.Grid;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
[PropertyValueType(typeof(JToken))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class GridValueConverter : JsonValueConverter
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.GridAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();
if (sourceString.DetectIsJson())
{
try
{
var obj = JsonConvert.DeserializeObject<JObject>(sourceString);
//so we have the grid json... we need to merge in the grid's configuration values with the values
// we've saved in the database so that when the front end gets this value, it is up-to-date.
//TODO: Change all singleton access to use ctor injection in v8!!!
//TODO: That would mean that property value converters would need to be request lifespan, hrm....
var gridConfig = UmbracoConfig.For.GridConfig(
ApplicationContext.Current.ProfilingLogger.Logger,
ApplicationContext.Current.ApplicationCache.RuntimeCache,
new DirectoryInfo(HttpContext.Current.Server.MapPath(SystemDirectories.AppPlugins)),
new DirectoryInfo(HttpContext.Current.Server.MapPath(SystemDirectories.Config)),
HttpContext.Current.IsDebuggingEnabled);
var sections = GetArray(obj, "sections");
foreach (var section in sections.Cast<JObject>())
{
var rows = GetArray(section, "rows");
foreach (var row in rows.Cast<JObject>())
{
var areas = GetArray(row, "areas");
foreach (var area in areas.Cast<JObject>())
{
var controls = GetArray(area, "controls");
foreach (var control in controls.Cast<JObject>())
{
var editor = control.Value<JObject>("editor");
if (editor != null)
{
var alias = editor.Value<string>("alias");
if (alias.IsNullOrWhiteSpace() == false)
{
//find the alias in config
var found = gridConfig.EditorsConfig.Editors.FirstOrDefault(x => x.Alias == alias);
if (found != null)
{
//add/replace the editor value with the one from config
var serialized = new JObject();
serialized["name"] = found.Name;
serialized["alias"] = found.Alias;
serialized["view"] = found.View;
serialized["render"] = found.Render;
serialized["config"] = JObject.FromObject(found.Config);
control["editor"] = serialized;
}
}
}
}
}
}
}
return obj;
}
catch (Exception ex)
{
LogHelper.Error<JsonValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
}
}
//it's not json, just return the string
return sourceString;
}
private JArray GetArray(JObject obj, string propertyName)
{
JToken token;
if (obj.TryGetValue(propertyName, out token))
{
var asArray = token as JArray;
return asArray ?? new JArray();
}
return new JArray();
}
}
}

View File

@@ -204,6 +204,11 @@
<Compile Include="Configuration\FileSystemProviderElement.cs" />
<Compile Include="Configuration\FileSystemProviderElementCollection.cs" />
<Compile Include="Configuration\FileSystemProvidersSection.cs" />
<Compile Include="Configuration\Grid\GridConfig.cs" />
<Compile Include="Configuration\Grid\GridEditorsConfig.cs" />
<Compile Include="Configuration\Grid\IGridConfig.cs" />
<Compile Include="Configuration\Grid\IGridEditorConfig.cs" />
<Compile Include="Configuration\Grid\IGridEditorsConfig.cs" />
<Compile Include="Configuration\UmbracoConfig.cs" />
<Compile Include="Configuration\UmbracoConfigurationSection.cs" />
<Compile Include="Configuration\UmbracoSettings\AppCodeFileExtensionsCollection.cs" />
@@ -403,6 +408,7 @@
<Compile Include="Persistence\Repositories\RepositoryCacheOptions.cs" />
<Compile Include="Persistence\Repositories\TaskRepository.cs" />
<Compile Include="Persistence\Repositories\TaskTypeRepository.cs" />
<Compile Include="PropertyEditors\ValueConverters\GridValueConverter.cs" />
<Compile Include="Security\BackOfficeClaimsIdentityFactory.cs" />
<Compile Include="Security\BackOfficeUserManager.cs" />
<Compile Include="Security\BackOfficeUserStore.cs" />

View File

@@ -163,48 +163,14 @@ namespace Umbraco.Web.Editors
[HttpGet]
public JsonNetResult GetGridConfig()
{
Func<List<GridEditor>> getResult = () =>
{
var editors = new List<GridEditor>();
var gridConfig = Server.MapPath("~/Config/grid.editors.config.js");
if (System.IO.File.Exists(gridConfig))
{
try
{
var arr = JArray.Parse(System.IO.File.ReadAllText(gridConfig));
//ensure the contents parse correctly to objects
var parsed = ManifestParser.GetGridEditors(arr);
editors.AddRange(parsed);
}
catch (Exception ex)
{
LogHelper.Error<BackOfficeController>("Could not parse the contents of grid.editors.config.js into a JSON array", ex);
}
}
var gridConfig = UmbracoConfig.For.GridConfig(
Logger,
ApplicationContext.ApplicationCache.RuntimeCache,
new DirectoryInfo(Server.MapPath(SystemDirectories.AppPlugins)),
new DirectoryInfo(Server.MapPath(SystemDirectories.Config)),
HttpContext.IsDebuggingEnabled);
var plugins = new DirectoryInfo(Server.MapPath("~/App_Plugins"));
var parser = new ManifestParser(plugins, ApplicationContext.ApplicationCache.RuntimeCache);
var builder = new ManifestBuilder(ApplicationContext.ApplicationCache.RuntimeCache, parser);
foreach (var gridEditor in builder.GridEditors)
{
//no duplicates! (based on alias)
if (editors.Contains(gridEditor) == false)
{
editors.Add(gridEditor);
}
}
return editors;
};
//cache the result if debugging is disabled
var result = HttpContext.IsDebuggingEnabled
? getResult()
: ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<List<GridEditor>>(
typeof(BackOfficeController) + "GetGridConfig",
() => getResult(),
new TimeSpan(0, 10, 0));
return new JsonNetResult { Data = result, Formatting = Formatting.Indented };
return new JsonNetResult { Data = gridConfig.EditorsConfig.Editors, Formatting = Formatting.Indented };
}
/// <summary>

View File

@@ -20,7 +20,7 @@ namespace Umbraco.Web
public static MvcHtmlString GetGridHtml(this HtmlHelper html, IPublishedProperty property, string framework = "bootstrap3")
{
var asString = property.Value as string;
if (asString.IsNullOrWhiteSpace()) return new MvcHtmlString(string.Empty);
if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty);
var view = "Grid/" + framework;
return html.Partial(view, property.Value);
@@ -56,7 +56,7 @@ namespace Umbraco.Web
public static MvcHtmlString GetGridHtml(this IPublishedProperty property, HtmlHelper html, string framework = "bootstrap3")
{
var asString = property.Value as string;
if (asString.IsNullOrWhiteSpace()) return new MvcHtmlString(string.Empty);
if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty);
var view = "Grid/" + framework;
return html.Partial(view, property.Value);
@@ -91,7 +91,7 @@ namespace Umbraco.Web
public static MvcHtmlString GetGridHtml(this IPublishedProperty property, string framework = "bootstrap3")
{
var asString = property.Value as string;
if (asString.IsNullOrWhiteSpace()) return new MvcHtmlString(string.Empty);
if (asString != null && string.IsNullOrEmpty(asString)) return new MvcHtmlString(string.Empty);
var htmlHelper = CreateHtmlHelper(property.Value);
return htmlHelper.GetGridHtml(property, framework);

View File

@@ -56,7 +56,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
}
catch (Exception ex)
{
LogHelper.Error<JsonValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
LogHelper.Error<RelatedLinksEditorValueConvertor>("Could not parse the string " + sourceString + " to a json object", ex);
}
}
@@ -95,7 +95,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
}
catch (Exception ex)
{
LogHelper.Error<JsonValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
LogHelper.Error<RelatedLinksEditorValueConvertor>("Could not parse the string " + sourceString + " to a json object", ex);
}
}