From 1c0188351cfc0abcf77d040a7e863799beb5eca2 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 16 Jun 2015 15:04:31 +0200 Subject: [PATCH] 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. --- .../Configuration/Grid/GridConfig.cs | 16 +++ .../Configuration/Grid/GridEditorsConfig.cs | 78 ++++++++++++ .../Configuration/Grid/IGridConfig.cs | 14 +++ .../Configuration/Grid/IGridEditorConfig.cs | 14 +++ .../Configuration/Grid/IGridEditorsConfig.cs | 9 ++ .../Configuration/UmbracoConfig.cs | 26 ++++ .../PropertyEditors/GridEditor.cs | 3 +- .../ValueConverters/GridValueConverter.cs | 112 ++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 6 + .../Editors/BackOfficeController.cs | 48 ++------ src/Umbraco.Web/GridTemplateExtensions.cs | 6 +- .../RelatedLinksEditorValueConvertor.cs | 4 +- 12 files changed, 289 insertions(+), 47 deletions(-) create mode 100644 src/Umbraco.Core/Configuration/Grid/GridConfig.cs create mode 100644 src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs create mode 100644 src/Umbraco.Core/Configuration/Grid/IGridConfig.cs create mode 100644 src/Umbraco.Core/Configuration/Grid/IGridEditorConfig.cs create mode 100644 src/Umbraco.Core/Configuration/Grid/IGridEditorsConfig.cs create mode 100644 src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs diff --git a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs new file mode 100644 index 0000000000..334124a4e5 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs @@ -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; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs new file mode 100644 index 0000000000..389c620637 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs @@ -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 Editors + { + get + { + Func> getResult = () => + { + var editors = new List(); + 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("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>( + typeof(GridEditorsConfig) + "Editors", + () => getResult(), + TimeSpan.FromMinutes(10)); + + return result; + } + + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/Grid/IGridConfig.cs b/src/Umbraco.Core/Configuration/Grid/IGridConfig.cs new file mode 100644 index 0000000000..a1170c136e --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/IGridConfig.cs @@ -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; } + + } +} diff --git a/src/Umbraco.Core/Configuration/Grid/IGridEditorConfig.cs b/src/Umbraco.Core/Configuration/Grid/IGridEditorConfig.cs new file mode 100644 index 0000000000..0e64811068 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/IGridEditorConfig.cs @@ -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 Config { get; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/Grid/IGridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/IGridEditorsConfig.cs new file mode 100644 index 0000000000..64fb1a831f --- /dev/null +++ b/src/Umbraco.Core/Configuration/Grid/IGridEditorsConfig.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Umbraco.Core.Configuration.Grid +{ + public interface IGridEditorsConfig + { + IEnumerable Editors { get; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoConfig.cs b/src/Umbraco.Core/Configuration/UmbracoConfig.cs index cb82582c7e..8881c5fb2e 100644 --- a/src/Umbraco.Core/Configuration/UmbracoConfig.cs +++ b/src/Umbraco.Core/Configuration/UmbracoConfig.cs @@ -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; /// /// Gets the IDashboardSection @@ -140,6 +144,28 @@ namespace Umbraco.Core.Configuration return _baseRestExtensions; } + /// + /// Only for testing + /// + /// + public void SetGridConfig(IGridConfig value) + { + _gridConfig = value; + } + + /// + /// Gets the IGridConfig + /// + 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 ! } } \ No newline at end of file diff --git a/src/Umbraco.Core/PropertyEditors/GridEditor.cs b/src/Umbraco.Core/PropertyEditors/GridEditor.cs index 2fd24a2e99..61ea94e7dd 100644 --- a/src/Umbraco.Core/PropertyEditors/GridEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/GridEditor.cs @@ -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() { diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs new file mode 100644 index 0000000000..cfcf194246 --- /dev/null +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs @@ -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(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()) + { + var rows = GetArray(section, "rows"); + foreach (var row in rows.Cast()) + { + var areas = GetArray(row, "areas"); + foreach (var area in areas.Cast()) + { + var controls = GetArray(area, "controls"); + foreach (var control in controls.Cast()) + { + var editor = control.Value("editor"); + if (editor != null) + { + var alias = editor.Value("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("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(); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 881f757eaf..ead0e5d1e2 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -204,6 +204,11 @@ + + + + + @@ -403,6 +408,7 @@ + diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 96b56f58ca..c25d0e50c0 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -163,48 +163,14 @@ namespace Umbraco.Web.Editors [HttpGet] public JsonNetResult GetGridConfig() { - Func> getResult = () => - { - var editors = new List(); - 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("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>( - 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 }; } /// diff --git a/src/Umbraco.Web/GridTemplateExtensions.cs b/src/Umbraco.Web/GridTemplateExtensions.cs index e4af759c88..ca75552e51 100644 --- a/src/Umbraco.Web/GridTemplateExtensions.cs +++ b/src/Umbraco.Web/GridTemplateExtensions.cs @@ -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); diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs index 9d3b50f2d9..a0368db769 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksEditorValueConvertor.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } catch (Exception ex) { - LogHelper.Error("Could not parse the string " + sourceString + " to a json object", ex); + LogHelper.Error("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("Could not parse the string " + sourceString + " to a json object", ex); + LogHelper.Error("Could not parse the string " + sourceString + " to a json object", ex); } }