diff --git a/src/Umbraco.Deploy.Contrib/DataTypeConfigurationConnectors/DocTypeGridEditorDataTypeConfigurationConnector.cs b/src/Umbraco.Deploy.Contrib/DataTypeConfigurationConnectors/DocTypeGridEditorDataTypeConfigurationConnector.cs new file mode 100644 index 0000000..e55cddf --- /dev/null +++ b/src/Umbraco.Deploy.Contrib/DataTypeConfigurationConnectors/DocTypeGridEditorDataTypeConfigurationConnector.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core; +using Umbraco.Core.Configuration.Grid; +using Umbraco.Core.Deploy; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Deploy.Connectors.DataTypeConfigurationConnectors; +using Umbraco.Deploy.Core; +using Umbraco.Web.PropertyEditors; + +namespace Umbraco.Deploy.Contrib.DataTypeConfigurationConnectors +{ + /// + /// Implements a Grid layout data type configuration connector supporting DocTypeGridEditor. + /// + public class DocTypeGridEditorDataTypeConfigurationConnector : DataTypeConfigurationConnectorBase2 + { + private readonly IGridConfig _gridConfig; + private readonly IContentTypeService _contentTypeService; + + /// + public override IEnumerable PropertyEditorAliases { get; } = new[] + { + Constants.PropertyEditors.Aliases.Grid + }; + + /// + /// Initializes a new instance of the class. + /// + /// The grid configuration. + /// The content type service. + public DocTypeGridEditorDataTypeConfigurationConnector(IGridConfig gridConfig, IContentTypeService contentTypeService) + { + _gridConfig = gridConfig; + _contentTypeService = contentTypeService; + } + + /// + public override string ToArtifact(IDataType dataType, ICollection dependencies, IContextCache contextCache) + { + if (dataType.ConfigurationAs() is GridConfiguration gridConfiguration && + gridConfiguration.Items?.ToObject() is GridConfigurationItems gridConfigurationItems) + { + // Get all element types (when needed) + var allElementTypes = new Lazy>(() => _contentTypeService.GetAll().Where(x => x.IsElement).ToList()); + + // Process DTGE editors + foreach (var gridEditor in GetGridEditors(gridConfigurationItems).Where(IsDocTypeGridEditor)) + { + if (gridEditor.Config.TryGetValue("allowedDocTypes", out var allowedDocTypesConfig) && + allowedDocTypesConfig is JArray allowedDocTypes && + allowedDocTypes.Count > 0) + { + string[] docTypes = allowedDocTypes.Values().WhereNotNull().ToArray(); + + // Use regex matching + AddDependencies(dependencies, allElementTypes.Value.Where(x => docTypes.Any(y => Regex.IsMatch(x.Alias, y)))); + } + else + { + // Add all element types as dependencies and stop processing + AddDependencies(dependencies, allElementTypes.Value); + break; + } + } + } + + return base.ToArtifact(dataType, dependencies, contextCache); + } + + private static void AddDependencies(ICollection dependencies, IEnumerable contentTypes) + { + foreach (var contentType in contentTypes) + { + dependencies.Add(new ArtifactDependency(contentType.GetUdi(), true, ArtifactDependencyMode.Exist)); + } + } + + /// + /// Gets the grid editors used within the grid configuration. + /// + /// The grid configuration items. + /// + /// The used grid editors (returns all editors if any of the areas allows all editors). + /// + protected virtual IEnumerable GetGridEditors(GridConfigurationItems gridConfigurationItems) + { + foreach (var gridEditor in _gridConfig.EditorsConfig.Editors) + { + if (IsAllowedGridEditor(gridConfigurationItems, gridEditor.Alias)) + { + yield return gridEditor; + } + } + } + + /// + /// Determines whether the grid editor alias is allowed in the specified grid configuration. + /// + /// The grid configuration items. + /// The alias. + /// + /// true if the grid editor alias is allowed in the specified grid configuration; otherwise, false. + /// + protected static bool IsAllowedGridEditor(GridConfigurationItems gridConfigurationItems, string alias) + => gridConfigurationItems.Layouts.Any(x => x.Areas.Any(y => y.AllowAll || y.Allowed.Contains(alias))); + + /// + /// Determines whether the grid editor is the DTGE. + /// + /// The grid editor. + /// + /// true if the grid editor is the DTGE; otherwise, false. + /// + protected static bool IsDocTypeGridEditor(IGridEditorConfig gridEditor) + => !string.IsNullOrEmpty(gridEditor.View) && gridEditor.View.Contains("doctypegrideditor"); + + /// + /// The grid configuration items. + /// + protected sealed class GridConfigurationItems + { + /// + /// Gets or sets the row configurations. + /// + /// + /// The row configurations. + /// + [JsonProperty("layouts")] + public GridConfigurationLayout[] Layouts { get; set; } = Array.Empty(); + } + + /// + /// The grid row configuration. + /// + protected sealed class GridConfigurationLayout + { + /// + /// Gets or sets the areas. + /// + /// + /// The areas. + /// + [JsonProperty("areas")] + public GridConfigurationLayoutArea[] Areas { get; set; } = Array.Empty(); + } + + /// + /// The grid row configuration area. + /// + protected sealed class GridConfigurationLayoutArea + { + /// + /// Gets or sets a value indicating whether all grid editors are allowed. + /// + /// + /// true if all grid editors are allowed; otherwise, false. + /// + /// + /// Defaults to true. + /// + [JsonProperty("allowAll")] + public bool AllowAll { get; set; } = true; + + /// + /// Gets or sets the allowed grid editor aliases. + /// + /// + /// The allowed grid editor aliases. + /// + [JsonProperty("allowed")] + public string[] Allowed { get; set; } = Array.Empty(); + } + } +}