Compare commits
350 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b3867d9d55 | |||
| 834aeee107 | |||
| f3643747b3 | |||
| ee83c02424 | |||
| 355a5e0eb4 | |||
| 44e567aa34 | |||
| 8c5f253b41 | |||
| 7b99e55148 | |||
| ba27eff5cf | |||
| 01d5a12039 | |||
| 6d4d26009f | |||
| 857a8b163d | |||
| acbe82f4c8 | |||
| 3bfd9b71e2 | |||
| ef714ac258 | |||
| 975816ddd7 | |||
| 8831860174 | |||
| fbf3015de4 | |||
| be587b2064 | |||
| 347c2e8238 | |||
| f5fde0f19e | |||
| c12bdaacbf | |||
| 1c4b262c57 | |||
| 90d591e5a8 | |||
| ad121bd758 | |||
| 8d67e39e9a | |||
| bd8e344736 | |||
| 014eba971e | |||
| a5fb2d2025 | |||
| 40311f8590 | |||
| a0c51fb212 | |||
| b306e41560 | |||
| e8d6daf59a | |||
| a0966be565 | |||
| ba064ba4f5 | |||
| 1da2c00f0a | |||
| 71d076aba2 | |||
| c7ec1deee6 | |||
| d7d58644e5 | |||
| 56669b5c84 | |||
| 41b8294ce3 | |||
| aed6ef28e6 | |||
| 339ae32c3d | |||
| 7d990a2cbb | |||
| b98812b119 | |||
| fafd045ed2 | |||
| acf63fc74d | |||
| 85565f2c5f | |||
| ac6625a80c | |||
| 6d7b439aec | |||
| 9fffdb407a | |||
| 9170061810 | |||
| a7da3d741f | |||
| 255bd10296 | |||
| 4fca0bb735 | |||
| f7aaad86c5 | |||
| 4c443b9e2e | |||
| b0121c44b1 | |||
| be9d8e7da7 | |||
| d129989c3d | |||
| 2870ce5e0a | |||
| da1e2680cb | |||
| cd2ce2486a | |||
| 5d4f2ec697 | |||
| c2cb85f1cd | |||
| 37d3692cd0 | |||
| f4b2ff93fc | |||
| 5ea6ebcc66 | |||
| f6ac64f705 | |||
| fcfb107653 | |||
| f829bb8023 | |||
| 23702ee4dc | |||
| 5c2b0647f3 | |||
| c7a725ad94 | |||
| 5c6a9480a6 | |||
| c1be8e3f00 | |||
| d8dbda8e94 | |||
| a0ab7ace07 | |||
| 7c27189e2e | |||
| 76cbfdb787 | |||
| 56545ad7f1 | |||
| 832dc7f4a5 | |||
| 62dc68e7b2 | |||
| 348c79d841 | |||
| 994c6eed50 | |||
| 9614740410 | |||
| 62e6168e03 | |||
| b6d762c279 | |||
| ab93c4ff2d | |||
| 473c39f7c4 | |||
| 811aea7898 | |||
| 07358eb46d | |||
| 067af64dff | |||
| cb428bb288 | |||
| b69c981100 | |||
| 1709879b14 | |||
| cff5046a9e | |||
| 9f6da2ca4b | |||
| 0c8b0edcda | |||
| 68f9e89a32 | |||
| fecadeec51 | |||
| d3b675a213 | |||
| 316ab6becb | |||
| 9a45bda430 | |||
| 7c11943836 | |||
| 94d2a5cbad | |||
| 99cabe564d | |||
| b0488d2d94 | |||
| 600c8ebbbf | |||
| 3bf43d7ce3 | |||
| 15b1d35c17 | |||
| 872db5877f | |||
| 977c1d9585 | |||
| 46f4984add | |||
| e39e132feb | |||
| 17b479275e | |||
| 9927ff3c86 | |||
| 81077c2681 | |||
| f4593778cb | |||
| 16f6bbcbd4 | |||
| c597da8f97 | |||
| 5775a8b614 | |||
| cc4a7653e5 | |||
| 5b546cc425 | |||
| 7f5f304d2d | |||
| 0827ced915 | |||
| 9c252131f7 | |||
| dec042fce4 | |||
| 8eafadc29b | |||
| c5347a97ce | |||
| 8a19cd4bbc | |||
| 2797011fb0 | |||
| 1307ee7ced | |||
| e0059f1fad | |||
| fd5b5b67bf | |||
| 7ba4c2f353 | |||
| 0381c55ce7 | |||
| 88d9e3321c | |||
| 05f479a58f | |||
| d8180604e8 | |||
| e6a8ba84aa | |||
| 39d93a7ace | |||
| 5ddf21f09f | |||
| 7b3ab72105 | |||
| 1f64ae4682 | |||
| 120f4c3096 | |||
| e59d75f4f9 | |||
| e3b2d427a4 | |||
| 22f54394fb | |||
| 57c368f70d | |||
| 14a056f4f4 | |||
| 580de6befe | |||
| 0120dc6ea3 | |||
| 79cd312912 | |||
| 9b36bc4097 | |||
| 9f346e6ee2 | |||
| 3ea9504620 | |||
| 86db972188 | |||
| 6d12eea789 | |||
| 68174bc7df | |||
| 5ca9600c98 | |||
| 87b3fb5539 | |||
| 4be6a48fb2 | |||
| 53731049de | |||
| 7fd6bfa163 | |||
| 4b2ce522fe | |||
| d0eddbb9a2 | |||
| 938abab9d6 | |||
| 5faa71187d | |||
| c069f262dc | |||
| ac79fe7a77 | |||
| 9f42e6a607 | |||
| 3f8fe334b2 | |||
| 096004db13 | |||
| 202f2d2e27 | |||
| aaab14be3e | |||
| 1c87176d80 | |||
| c17dbbe141 | |||
| 1dde60a1d5 | |||
| 04967143d8 | |||
| 70fb48d94a | |||
| 760d1d7daa | |||
| 3135353a1a | |||
| 1565ff1661 | |||
| bc55d96cde | |||
| 3d2379d582 | |||
| 73e907291b | |||
| 49c76c744e | |||
| 8967061758 | |||
| eff8075102 | |||
| 849feb0683 | |||
| a182c9b1ee | |||
| 17675d389e | |||
| f30aefb614 | |||
| a1722f268c | |||
| 864d83f8f7 | |||
| 2f978e96d4 | |||
| dccc6238e0 | |||
| 0687125343 | |||
| de36edfd58 | |||
| 2842a56356 | |||
| 661246b5f5 | |||
| 457474ecf9 | |||
| 5f67b3a9c1 | |||
| a3547a79e8 | |||
| c6467b355d | |||
| e2ef186dd1 | |||
| 0ccc40bf52 | |||
| ebc21a1cc7 | |||
| 30067d92ae | |||
| 342f924e8f | |||
| ba12efd285 | |||
| ed3efe9bee | |||
| 47a7c08686 | |||
| 5191dbf011 | |||
| 8d9ae085aa | |||
| 161d6505eb | |||
| c292f7ff03 | |||
| 17860fb8c7 | |||
| eb642dc611 | |||
| bc99d074a9 | |||
| d536bebdbe | |||
| 3639d952d5 | |||
| 7c79cf318e | |||
| 6ad1607685 | |||
| c1ed2b9f45 | |||
| 2c5eeaeac8 | |||
| a74a0c343e | |||
| 4eb897ccff | |||
| 20dc77c330 | |||
| 4c79863130 | |||
| 9ec95c7aa2 | |||
| 38bfd07883 | |||
| ce15b7c7c4 | |||
| b090de3cde | |||
| dbd74f5273 | |||
| e87f8b14be | |||
| fb14a4987c | |||
| a471e7d25e | |||
| fef9248b51 | |||
| a8e2798add | |||
| 6af1057ad7 | |||
| 983144c3f9 | |||
| c451498975 | |||
| 8579b5a89b | |||
| 1ad4414026 | |||
| d52d0819ab | |||
| 0dedd7b2d4 | |||
| ca25b3199b | |||
| 460653d078 | |||
| beb9068805 | |||
| f5a00cc3bd | |||
| 86aef126fd | |||
| 0e9d0a5a10 | |||
| a4f1b433eb | |||
| 08b386e180 | |||
| 97ae6165e4 | |||
| 8cdb61195d | |||
| 50c2d574f1 | |||
| c6cabf1239 | |||
| f07fcac13d | |||
| e2746604a1 | |||
| e9b5225676 | |||
| c2046ad173 | |||
| f080260396 | |||
| 5d1da3ada1 | |||
| 2b84f96836 | |||
| 28b669d3a3 | |||
| 225688facf | |||
| 8bc28a4d81 | |||
| e7e74840bc | |||
| ceb1260509 | |||
| 9706a0f76a | |||
| 12d79f2d08 | |||
| ef15c247c2 | |||
| d255cd115b | |||
| 19e2b1c24e | |||
| c0c9f4dfcc | |||
| 61ba78538a | |||
| cb76914a27 | |||
| 9b0d16f0ad | |||
| 3377888219 | |||
| 35645672ae | |||
| f952877d04 | |||
| 62a6a4ec92 | |||
| 943e050493 | |||
| e958ca6f89 | |||
| 0a752c8985 | |||
| b6ad19ccad | |||
| bea1d35ebf | |||
| dae8802c50 | |||
| 58cdff1d71 | |||
| d69a978870 | |||
| 93bc2dc95b | |||
| 1bcf40402c | |||
| 7b101f0b9e | |||
| dad3f31f86 | |||
| e091987f0f | |||
| 60a3cdc5ab | |||
| 03006d7698 | |||
| 8344372ae2 | |||
| d52f6b5810 | |||
| 4fa07389dd | |||
| 33b857d2c6 | |||
| 2bdbd86787 | |||
| 3d86b08e31 | |||
| 5cef71e4e6 | |||
| fe7b114083 | |||
| adc7201e86 | |||
| bb0331e9cc | |||
| 25b8c8a565 | |||
| eb390f8d80 | |||
| be93773399 | |||
| 6f0baa4a8e | |||
| a56f3b23d1 | |||
| 4feb766cc6 | |||
| 55d4457c70 | |||
| 05c85bbce5 | |||
| 2270188668 | |||
| 41e14a62c0 | |||
| a996d46b6f | |||
| e062ea8d31 | |||
| 7cf13cbf94 | |||
| afda7a5661 | |||
| 11ef00c63d | |||
| 2b54cc50ab | |||
| 99319e0b49 | |||
| f99302ac63 | |||
| 890d7d8ce3 | |||
| f039b00a44 | |||
| 34ad8dfb8d | |||
| 2c436d5ae0 | |||
| 92a0ec2964 | |||
| 760b7ad0ce | |||
| b6918253c0 | |||
| 0f969ecdd4 | |||
| 34a3389c17 | |||
| beb325eacf | |||
| 8e45bcf23f | |||
| 40dc49ed47 | |||
| 4b07305dc5 | |||
| 2514a59e93 | |||
| 6843da790c | |||
| ba1a9c3758 | |||
| 332ad6349d | |||
| 42e48426e4 | |||
| a0cc788f27 | |||
| aecf96d74d | |||
| c75938076e | |||
| cebbcb711a |
@@ -52,7 +52,7 @@
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
|
||||
|
||||
<!-- docs -->
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\net472\Umbraco.Core.xml" />
|
||||
|
||||
<!-- symbols -->
|
||||
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
|
||||
|
||||
@@ -51,14 +51,17 @@
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.ModelsBuilder.dll" target="lib\net472\Umbraco.ModelsBuilder.dll" />
|
||||
|
||||
<!-- docs -->
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\Umbraco.Web.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\Umbraco.Examine.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\net472\Umbraco.Web.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\net472\Umbraco.Web.UI.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\net472\Umbraco.Examine.xml" />
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.ModelsBuilder.xml" target="lib\net472\Umbraco.ModelsBuilder.xml" />
|
||||
|
||||
<!-- symbols -->
|
||||
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.ModelsBuilder.pdb" target="lib" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
not want this to happen as the alpha of the next major is, really, the next major already.
|
||||
-->
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.4.0, 2.999999)" />
|
||||
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.4]" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.10.0.100,4.999999)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.5.0.100,2.999999)" />
|
||||
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.1,2.999999)" />
|
||||
|
||||
@@ -4,6 +4,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging.Viewer;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PackageActions;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
@@ -66,9 +67,16 @@ namespace Umbraco.Core
|
||||
/// Gets the validators collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
internal static ManifestValueValidatorCollectionBuilder Validators(this Composition composition)
|
||||
internal static ManifestValueValidatorCollectionBuilder ManifestValueValidators(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<ManifestValueValidatorCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the manifest filter collection builder.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
public static ManifestFilterCollectionBuilder ManifestFilters(this Composition composition)
|
||||
=> composition.WithCollectionBuilder<ManifestFilterCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the components collection builder.
|
||||
/// </summary>
|
||||
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Core.Configuration.HealthChecks;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -41,7 +42,12 @@ namespace Umbraco.Core
|
||||
configs.Add(() => new CoreDebug());
|
||||
|
||||
// GridConfig depends on runtime caches, manifest parsers... and cannot be available during composition
|
||||
configs.Add<IGridConfig>(factory => new GridConfig(factory.GetInstance<ILogger>(), factory.GetInstance<AppCaches>(), configDir, factory.GetInstance<IRuntimeState>().Debug));
|
||||
configs.Add<IGridConfig>(factory => new GridConfig(
|
||||
factory.GetInstance<ILogger>(),
|
||||
factory.GetInstance<AppCaches>(),
|
||||
configDir,
|
||||
factory.GetInstance<ManifestParser>(),
|
||||
factory.GetInstance<IRuntimeState>().Debug));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using System.IO;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Grid
|
||||
{
|
||||
class GridConfig : IGridConfig
|
||||
{
|
||||
public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, bool isDebug)
|
||||
public GridConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, ManifestParser manifestParser, bool isDebug)
|
||||
{
|
||||
EditorsConfig = new GridEditorsConfig(logger, appCaches, configFolder, isDebug);
|
||||
EditorsConfig = new GridEditorsConfig(logger, appCaches, configFolder, manifestParser, isDebug);
|
||||
}
|
||||
|
||||
public IGridEditorsConfig EditorsConfig { get; }
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -15,13 +13,15 @@ namespace Umbraco.Core.Configuration.Grid
|
||||
private readonly ILogger _logger;
|
||||
private readonly AppCaches _appCaches;
|
||||
private readonly DirectoryInfo _configFolder;
|
||||
private readonly ManifestParser _manifestParser;
|
||||
private readonly bool _isDebug;
|
||||
|
||||
public GridEditorsConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, bool isDebug)
|
||||
public GridEditorsConfig(ILogger logger, AppCaches appCaches, DirectoryInfo configFolder, ManifestParser manifestParser, bool isDebug)
|
||||
{
|
||||
_logger = logger;
|
||||
_appCaches = appCaches;
|
||||
_configFolder = configFolder;
|
||||
_manifestParser = manifestParser;
|
||||
_isDebug = isDebug;
|
||||
}
|
||||
|
||||
@@ -31,9 +31,6 @@ namespace Umbraco.Core.Configuration.Grid
|
||||
{
|
||||
List<GridEditor> GetResult()
|
||||
{
|
||||
// TODO: should use the common one somehow! + ignoring _appPlugins here!
|
||||
var parser = new ManifestParser(_appCaches, Current.ManifestValidators, _logger);
|
||||
|
||||
var editors = new List<GridEditor>();
|
||||
var gridConfig = Path.Combine(_configFolder.FullName, "grid.editors.config.js");
|
||||
if (File.Exists(gridConfig))
|
||||
@@ -42,7 +39,7 @@ namespace Umbraco.Core.Configuration.Grid
|
||||
|
||||
try
|
||||
{
|
||||
editors.AddRange(parser.ParseGridEditors(sourceString));
|
||||
editors.AddRange(_manifestParser.ParseGridEditors(sourceString));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -51,7 +48,7 @@ namespace Umbraco.Core.Configuration.Grid
|
||||
}
|
||||
|
||||
// add manifest editors, skip duplicates
|
||||
foreach (var gridEditor in parser.Manifest.GridEditors)
|
||||
foreach (var gridEditor in _manifestParser.Manifest.GridEditors)
|
||||
{
|
||||
if (editors.Contains(gridEditor) == false) editors.Add(gridEditor);
|
||||
}
|
||||
|
||||
@@ -66,44 +66,44 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Determines whether the content type is invariant.
|
||||
/// </summary>
|
||||
public static bool VariesByNothing(this PublishedContentType contentType) => contentType.Variations.VariesByNothing();
|
||||
public static bool VariesByNothing(this IPublishedContentType contentType) => contentType.Variations.VariesByNothing();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the content type varies by culture.
|
||||
/// </summary>
|
||||
/// <remarks>And then it could also vary by segment.</remarks>
|
||||
public static bool VariesByCulture(this PublishedContentType contentType) => contentType.Variations.VariesByCulture();
|
||||
public static bool VariesByCulture(this IPublishedContentType contentType) => contentType.Variations.VariesByCulture();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the content type varies by segment.
|
||||
/// </summary>
|
||||
/// <remarks>And then it could also vary by culture.</remarks>
|
||||
public static bool VariesBySegment(this PublishedContentType contentType) => contentType.Variations.VariesBySegment();
|
||||
public static bool VariesBySegment(this IPublishedContentType contentType) => contentType.Variations.VariesBySegment();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the content type varies by culture and segment.
|
||||
/// </summary>
|
||||
public static bool VariesByCultureAndSegment(this PublishedContentType contentType) => contentType.Variations.VariesByCultureAndSegment();
|
||||
public static bool VariesByCultureAndSegment(this IPublishedContentType contentType) => contentType.Variations.VariesByCultureAndSegment();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the property type is invariant.
|
||||
/// </summary>
|
||||
public static bool VariesByNothing(this PublishedPropertyType propertyType) => propertyType.Variations.VariesByNothing();
|
||||
public static bool VariesByNothing(this IPublishedPropertyType propertyType) => propertyType.Variations.VariesByNothing();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the property type varies by culture.
|
||||
/// </summary>
|
||||
public static bool VariesByCulture(this PublishedPropertyType propertyType) => propertyType.Variations.VariesByCulture();
|
||||
public static bool VariesByCulture(this IPublishedPropertyType propertyType) => propertyType.Variations.VariesByCulture();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the property type varies by segment.
|
||||
/// </summary>
|
||||
public static bool VariesBySegment(this PublishedPropertyType propertyType) => propertyType.Variations.VariesBySegment();
|
||||
public static bool VariesBySegment(this IPublishedPropertyType propertyType) => propertyType.Variations.VariesBySegment();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the property type varies by culture and segment.
|
||||
/// </summary>
|
||||
public static bool VariesByCultureAndSegment(this PublishedPropertyType propertyType) => propertyType.Variations.VariesByCultureAndSegment();
|
||||
public static bool VariesByCultureAndSegment(this IPublishedPropertyType propertyType) => propertyType.Variations.VariesByCultureAndSegment();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a variation is invariant.
|
||||
|
||||
@@ -26,26 +26,26 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
/// A count of number of errors
|
||||
/// By counting Warnings with Exceptions, Errors & Fatal messages
|
||||
/// </summary>
|
||||
int GetNumberOfErrors(DateTimeOffset startDate, DateTimeOffset endDate);
|
||||
int GetNumberOfErrors(LogTimePeriod logTimePeriod);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a number of the different log level entries
|
||||
/// </summary>
|
||||
LogLevelCounts GetLogLevelCounts(DateTimeOffset startDate, DateTimeOffset endDate);
|
||||
LogLevelCounts GetLogLevelCounts(LogTimePeriod logTimePeriod);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all unique message templates and their counts
|
||||
/// </summary>
|
||||
IEnumerable<LogTemplate> GetMessageTemplates(DateTimeOffset startDate, DateTimeOffset endDate);
|
||||
IEnumerable<LogTemplate> GetMessageTemplates(LogTimePeriod logTimePeriod);
|
||||
|
||||
bool CanHandleLargeLogs { get; }
|
||||
|
||||
bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate);
|
||||
bool CheckCanOpenLogs(LogTimePeriod logTimePeriod);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the collection of logs
|
||||
/// </summary>
|
||||
PagedResult<LogMessage> GetLogs(DateTimeOffset startDate, DateTimeOffset endDate,
|
||||
PagedResult<LogMessage> GetLogs(LogTimePeriod logTimePeriod,
|
||||
int pageNumber = 1,
|
||||
int pageSize = 100,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
|
||||
public override bool CanHandleLargeLogs => false;
|
||||
|
||||
public override bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate)
|
||||
public override bool CheckCanOpenLogs(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
//Log Directory
|
||||
var logDirectory = _logsPath;
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
|
||||
//foreach full day in the range - see if we can find one or more filenames that end with
|
||||
//yyyyMMdd.json - Ends with due to MachineName in filenames - could be 1 or more due to load balancing
|
||||
for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1))
|
||||
for (var day = logTimePeriod.StartTime.Date; day.Date <= logTimePeriod.EndTime.Date; day = day.AddDays(1))
|
||||
{
|
||||
//Filename ending to search for (As could be multiple)
|
||||
var filesToFind = GetSearchPattern(day);
|
||||
@@ -57,7 +57,7 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
return $"*{day:yyyyMMdd}*.json";
|
||||
}
|
||||
|
||||
protected override IReadOnlyList<LogEvent> GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take)
|
||||
protected override IReadOnlyList<LogEvent> GetLogs(LogTimePeriod logTimePeriod, ILogFilter filter, int skip, int take)
|
||||
{
|
||||
var logs = new List<LogEvent>();
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
|
||||
//foreach full day in the range - see if we can find one or more filenames that end with
|
||||
//yyyyMMdd.json - Ends with due to MachineName in filenames - could be 1 or more due to load balancing
|
||||
for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1))
|
||||
for (var day = logTimePeriod.StartTime.Date; day.Date <= logTimePeriod.EndTime.Date; day = day.AddDays(1))
|
||||
{
|
||||
//Filename ending to search for (As could be multiple)
|
||||
var filesToFind = GetSearchPattern(day);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging.Viewer
|
||||
{
|
||||
public class LogTimePeriod
|
||||
{
|
||||
public LogTimePeriod(DateTime startTime, DateTime endTime)
|
||||
{
|
||||
StartTime = startTime;
|
||||
EndTime = endTime;
|
||||
}
|
||||
|
||||
public DateTime StartTime { get; }
|
||||
public DateTime EndTime { get; }
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,9 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
/// <summary>
|
||||
/// Get all logs from your chosen data source back as Serilog LogEvents
|
||||
/// </summary>
|
||||
protected abstract IReadOnlyList<LogEvent> GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take);
|
||||
protected abstract IReadOnlyList<LogEvent> GetLogs(LogTimePeriod logTimePeriod, ILogFilter filter, int skip, int take);
|
||||
|
||||
public abstract bool CheckCanOpenLogs(DateTimeOffset startDate, DateTimeOffset endDate);
|
||||
public abstract bool CheckCanOpenLogs(LogTimePeriod logTimePeriod);
|
||||
|
||||
public virtual IReadOnlyList<SavedLogSearch> GetSavedSearches()
|
||||
{
|
||||
@@ -82,24 +82,24 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
return searches;
|
||||
}
|
||||
|
||||
public int GetNumberOfErrors(DateTimeOffset startDate, DateTimeOffset endDate)
|
||||
public int GetNumberOfErrors(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
var errorCounter = new ErrorCounterFilter();
|
||||
GetLogs(startDate, endDate, errorCounter, 0, int.MaxValue);
|
||||
GetLogs(logTimePeriod, errorCounter, 0, int.MaxValue);
|
||||
return errorCounter.Count;
|
||||
}
|
||||
|
||||
public LogLevelCounts GetLogLevelCounts(DateTimeOffset startDate, DateTimeOffset endDate)
|
||||
public LogLevelCounts GetLogLevelCounts(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
var counter = new CountingFilter();
|
||||
GetLogs(startDate, endDate, counter, 0, int.MaxValue);
|
||||
GetLogs(logTimePeriod, counter, 0, int.MaxValue);
|
||||
return counter.Counts;
|
||||
}
|
||||
|
||||
public IEnumerable<LogTemplate> GetMessageTemplates(DateTimeOffset startDate, DateTimeOffset endDate)
|
||||
public IEnumerable<LogTemplate> GetMessageTemplates(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
var messageTemplates = new MessageTemplateFilter();
|
||||
GetLogs(startDate, endDate, messageTemplates, 0, int.MaxValue);
|
||||
GetLogs(logTimePeriod, messageTemplates, 0, int.MaxValue);
|
||||
|
||||
var templates = messageTemplates.Counts.
|
||||
Select(x => new LogTemplate { MessageTemplate = x.Key, Count = x.Value })
|
||||
@@ -108,14 +108,14 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
return templates;
|
||||
}
|
||||
|
||||
public PagedResult<LogMessage> GetLogs(DateTimeOffset startDate, DateTimeOffset endDate,
|
||||
public PagedResult<LogMessage> GetLogs(LogTimePeriod logTimePeriod,
|
||||
int pageNumber = 1, int pageSize = 100,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
string filterExpression = null,
|
||||
string[] logLevels = null)
|
||||
{
|
||||
var expression = new ExpressionFilter(filterExpression);
|
||||
var filteredLogs = GetLogs(startDate, endDate, expression, 0, int.MaxValue);
|
||||
var filteredLogs = GetLogs(logTimePeriod, expression, 0, int.MaxValue);
|
||||
|
||||
//This is user used the checkbox UI to toggle which log levels they wish to see
|
||||
//If an empty array or null - its implied all levels to be viewed
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides filtering for package manifests.
|
||||
/// </summary>
|
||||
public interface IManifestFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Filters package manifests.
|
||||
/// </summary>
|
||||
/// <param name="manifests">The package manifests.</param>
|
||||
/// <remarks>
|
||||
/// <para>It is possible to remove, change, or add manifests.</para>
|
||||
/// </remarks>
|
||||
void Filter(List<PackageManifest> manifests);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the manifest filters.
|
||||
/// </summary>
|
||||
public class ManifestFilterCollection : BuilderCollectionBase<IManifestFilter>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManifestFilterCollection"/> class.
|
||||
/// </summary>
|
||||
public ManifestFilterCollection(IEnumerable<IManifestFilter> items)
|
||||
: base(items)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Filters package manifests.
|
||||
/// </summary>
|
||||
/// <param name="manifests">The package manifests.</param>
|
||||
public void Filter(List<PackageManifest> manifests)
|
||||
{
|
||||
foreach (var filter in this)
|
||||
filter.Filter(manifests);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
{
|
||||
public class ManifestFilterCollectionBuilder : OrderedCollectionBuilderBase<ManifestFilterCollectionBuilder, ManifestFilterCollection, IManifestFilter>
|
||||
{
|
||||
protected override ManifestFilterCollectionBuilder This => this;
|
||||
|
||||
// do NOT cache this, it's only used once
|
||||
protected override Lifetime CollectionLifetime => Lifetime.Transient;
|
||||
}
|
||||
}
|
||||
@@ -22,24 +22,26 @@ namespace Umbraco.Core.Manifest
|
||||
private readonly IAppPolicyCache _cache;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ManifestValueValidatorCollection _validators;
|
||||
private readonly ManifestFilterCollection _filters;
|
||||
|
||||
private string _path;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManifestParser"/> class.
|
||||
/// </summary>
|
||||
public ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, ILogger logger)
|
||||
: this(appCaches, validators, "~/App_Plugins", logger)
|
||||
public ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, ManifestFilterCollection filters, ILogger logger)
|
||||
: this(appCaches, validators, filters, "~/App_Plugins", logger)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ManifestParser"/> class.
|
||||
/// </summary>
|
||||
private ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, string path, ILogger logger)
|
||||
private ManifestParser(AppCaches appCaches, ManifestValueValidatorCollection validators, ManifestFilterCollection filters, string path, ILogger logger)
|
||||
{
|
||||
if (appCaches == null) throw new ArgumentNullException(nameof(appCaches));
|
||||
_cache = appCaches.RuntimeCache;
|
||||
_validators = validators ?? throw new ArgumentNullException(nameof(validators));
|
||||
_filters = filters ?? throw new ArgumentNullException(nameof(filters));
|
||||
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullOrEmptyException(nameof(path));
|
||||
Path = path;
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
@@ -78,6 +80,7 @@ namespace Umbraco.Core.Manifest
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
continue;
|
||||
var manifest = ParseManifest(text);
|
||||
manifest.Source = path;
|
||||
manifests.Add(manifest);
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -86,6 +89,8 @@ namespace Umbraco.Core.Manifest
|
||||
}
|
||||
}
|
||||
|
||||
_filters.Filter(manifests);
|
||||
|
||||
return manifests;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,16 @@ namespace Umbraco.Core.Manifest
|
||||
/// </summary>
|
||||
public class PackageManifest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the source path of the manifest.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Gets the full absolute file path of the manifest,
|
||||
/// using system directory separators.</para>
|
||||
/// </remarks>
|
||||
[JsonIgnore]
|
||||
public string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the scripts listed in the manifest.
|
||||
/// </summary>
|
||||
|
||||
@@ -191,7 +191,7 @@ namespace Umbraco.Core.Mapping
|
||||
private TTarget Map<TTarget>(object source, Type sourceType, MapperContext context)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
return default;
|
||||
|
||||
var targetType = typeof(TTarget);
|
||||
|
||||
|
||||
@@ -389,7 +389,7 @@ namespace Umbraco.Core.Migrations.Install
|
||||
|
||||
private DatabaseSchemaResult ValidateSchema(IScope scope)
|
||||
{
|
||||
if (_databaseFactory.Configured == false)
|
||||
if (_databaseFactory.Initialized == false)
|
||||
return new DatabaseSchemaResult(_databaseFactory.SqlContext.SqlSyntax);
|
||||
|
||||
if (_databaseSchemaValidationResult != null)
|
||||
@@ -513,7 +513,7 @@ namespace Umbraco.Core.Migrations.Install
|
||||
|
||||
private Attempt<Result> CheckReadyForInstall()
|
||||
{
|
||||
if (_databaseFactory.Configured == false)
|
||||
if (_databaseFactory.CanConnect == false)
|
||||
{
|
||||
return Attempt.Fail(new Result
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.Entities
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Implements <see cref="IDocumentEntitySlim"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -111,52 +111,6 @@ namespace Umbraco.Core.Models.Entities
|
||||
public virtual bool IsContainer { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a lightweight property.
|
||||
/// </summary>
|
||||
public class PropertySlim
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PropertySlim"/> class.
|
||||
/// </summary>
|
||||
public PropertySlim(string editorAlias, object value)
|
||||
{
|
||||
PropertyEditorAlias = editorAlias;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property editor alias.
|
||||
/// </summary>
|
||||
public string PropertyEditorAlias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property value.
|
||||
/// </summary>
|
||||
public object Value { get; }
|
||||
|
||||
protected bool Equals(PropertySlim other)
|
||||
{
|
||||
return PropertyEditorAlias.Equals(other.PropertyEditorAlias) && Equals(Value, other.Value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != GetType()) return false;
|
||||
return Equals((PropertySlim) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (PropertyEditorAlias.GetHashCode() * 397) ^ (Value != null ? Value.GetHashCode() : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDeepCloneable
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Umbraco.Core.Models.Entities
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents a lightweight document entity, managed by the entity service.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.Core.Models.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a lightweight media entity, managed by the entity service.
|
||||
/// </summary>
|
||||
public interface IMediaEntitySlim : IContentEntitySlim
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The media file's path/url
|
||||
/// </summary>
|
||||
string MediaPath { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Models.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements <see cref="IMediaEntitySlim"/>.
|
||||
/// </summary>
|
||||
public class MediaEntitySlim : ContentEntitySlim, IMediaEntitySlim
|
||||
{
|
||||
public string MediaPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Represents a published content item.
|
||||
@@ -27,21 +26,13 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the content item.
|
||||
/// Gets the name of the content item for the current culture.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The value of this property is contextual. When the content type is multi-lingual,
|
||||
/// this is the name for the 'current' culture. Otherwise, it is the invariant name.</para>
|
||||
/// </remarks>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url segment of the content item.
|
||||
/// Gets the url segment of the content item for the current culture.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The value of this property is contextual. When the content type is multi-lingual,
|
||||
/// this is the name for the 'current' culture. Otherwise, it is the invariant url segment.</para>
|
||||
/// </remarks>
|
||||
string UrlSegment { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -94,43 +85,28 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>For published content items, this is also the date the item was published.</para>
|
||||
/// <para>This date is always global to the content item, see GetCulture().Date for the
|
||||
/// <para>This date is always global to the content item, see CultureDate() for the
|
||||
/// date each culture was published.</para>
|
||||
/// </remarks>
|
||||
DateTime UpdateDate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url of the content item.
|
||||
/// Gets the url of the content item for the current culture.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The value of this property is contextual. It depends on the 'current' request uri,
|
||||
/// if any. In addition, when the content type is multi-lingual, this is the url for the
|
||||
/// 'current' culture. Otherwise, it is the invariant url.</para>
|
||||
/// if any.</para>
|
||||
/// </remarks>
|
||||
string Url { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url of the content item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The value of this property is contextual. It depends on the 'current' request uri,
|
||||
/// if any. In addition, when the content type is multi-lingual, this is the url for the
|
||||
/// specified culture. Otherwise, it is the invariant url.</para>
|
||||
/// </remarks>
|
||||
string GetUrl(string culture = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets culture infos for a culture.
|
||||
/// </summary>
|
||||
PublishedCultureInfo GetCulture(string culture = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets culture infos.
|
||||
/// Gets available culture infos.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Contains only those culture that are available. For a published content, these are
|
||||
/// the cultures that are published. For a draft content, those that are 'available' ie
|
||||
/// have a non-empty content name.</para>
|
||||
/// <para>Does not contain the invariant culture.</para> // fixme?
|
||||
/// </remarks>
|
||||
IReadOnlyDictionary<string, PublishedCultureInfo> Cultures { get; }
|
||||
|
||||
@@ -178,11 +154,15 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
IPublishedContent Parent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children of the content item.
|
||||
/// Gets the children of the content item that are available for the current culture.
|
||||
/// </summary>
|
||||
/// <remarks>Children are sorted by their sortOrder.</remarks>
|
||||
IEnumerable<IPublishedContent> Children { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the children of the content item, regardless of whether they are available for the current culture.
|
||||
/// </summary>
|
||||
IEnumerable<IPublishedContent> ChildrenForAllCultures { get; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an <see cref="IPublishedElement"/> type.
|
||||
/// </summary>
|
||||
/// <remarks>Instances implementing the <see cref="IPublishedContentType"/> interface should be
|
||||
/// immutable, ie if the content type changes, then a new instance needs to be created.</remarks>
|
||||
public interface IPublishedContentType
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the content type identifier.
|
||||
/// </summary>
|
||||
int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content type alias.
|
||||
/// </summary>
|
||||
string Alias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content item type.
|
||||
/// </summary>
|
||||
PublishedItemType ItemType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the aliases of the content types participating in the composition.
|
||||
/// </summary>
|
||||
HashSet<string> CompositionAliases { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content variations of the content type.
|
||||
/// </summary>
|
||||
ContentVariation Variations { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this content type is for an element.
|
||||
/// </summary>
|
||||
bool IsElement { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content type properties.
|
||||
/// </summary>
|
||||
IEnumerable<IPublishedPropertyType> PropertyTypes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property type index.
|
||||
/// </summary>
|
||||
/// <remarks>The alias is case-insensitive. This is the only place where alias strings are compared.</remarks>
|
||||
int GetPropertyIndex(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property type.
|
||||
/// </summary>
|
||||
IPublishedPropertyType GetPropertyType(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property type.
|
||||
/// </summary>
|
||||
IPublishedPropertyType GetPropertyType(int index);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
/// </summary>
|
||||
/// <param name="contentType">An content type.</param>
|
||||
/// <returns>A published content type corresponding to the item type and content type.</returns>
|
||||
PublishedContentType CreateContentType(IContentTypeComposition contentType);
|
||||
IPublishedContentType CreateContentType(IContentTypeComposition contentType);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a published property type.
|
||||
@@ -18,7 +18,7 @@
|
||||
/// <param name="contentType">The published content type owning the property.</param>
|
||||
/// <param name="propertyType">A property type.</param>
|
||||
/// <remarks>Is used by <see cref="PublishedContentType"/> constructor to create property types.</remarks>
|
||||
PublishedPropertyType CreatePropertyType(PublishedContentType contentType, PropertyType propertyType);
|
||||
IPublishedPropertyType CreatePropertyType(IPublishedContentType contentType, PropertyType propertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a published property type.
|
||||
@@ -28,7 +28,7 @@
|
||||
/// <param name="dataTypeId">The datatype identifier.</param>
|
||||
/// <param name="variations">The variations.</param>
|
||||
/// <remarks>Is used by <see cref="PublishedContentType"/> constructor to create special property types.</remarks>
|
||||
PublishedPropertyType CreatePropertyType(PublishedContentType contentType, string propertyTypeAlias, int dataTypeId, ContentVariation variations);
|
||||
IPublishedPropertyType CreatePropertyType(IPublishedContentType contentType, string propertyTypeAlias, int dataTypeId, ContentVariation variations);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a published datatype.
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <summary>
|
||||
/// Gets the content type.
|
||||
/// </summary>
|
||||
PublishedContentType ContentType { get; }
|
||||
IPublishedContentType ContentType { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/// </summary>
|
||||
public interface IPublishedProperty
|
||||
{
|
||||
PublishedPropertyType PropertyType { get; }
|
||||
IPublishedPropertyType PropertyType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the alias of the property.
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a published property type.
|
||||
/// </summary>
|
||||
/// <remarks>Instances implementing the <see cref="PublishedPropertyType"/> interface should be
|
||||
/// immutable, ie if the property type changes, then a new instance needs to be created.</remarks>
|
||||
public interface IPublishedPropertyType
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the published content type containing the property type.
|
||||
/// </summary>
|
||||
IPublishedContentType ContentType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data type.
|
||||
/// </summary>
|
||||
PublishedDataType DataType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets property type alias.
|
||||
/// </summary>
|
||||
string Alias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property editor alias.
|
||||
/// </summary>
|
||||
string EditorAlias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the property is a user content property.
|
||||
/// </summary>
|
||||
/// <remarks>A non-user content property is a property that has been added to a
|
||||
/// published content type by Umbraco but does not corresponds to a user-defined
|
||||
/// published property.</remarks>
|
||||
bool IsUserProperty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content variations of the property type.
|
||||
/// </summary>
|
||||
ContentVariation Variations { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a value is an actual value, or not a value.
|
||||
/// </summary>
|
||||
/// <remarks>Used by property.HasValue and, for instance, in fallback scenarios.</remarks>
|
||||
bool? IsValue(object value, PropertyValueLevel level);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property cache level.
|
||||
/// </summary>
|
||||
PropertyCacheLevel CacheLevel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts the source value into the intermediate value.
|
||||
/// </summary>
|
||||
/// <param name="owner">The published element owning the property.</param>
|
||||
/// <param name="source">The source value.</param>
|
||||
/// <param name="preview">A value indicating whether content should be considered draft.</param>
|
||||
/// <returns>The intermediate value.</returns>
|
||||
object ConvertSourceToInter(IPublishedElement owner, object source, bool preview);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the intermediate value into the object value.
|
||||
/// </summary>
|
||||
/// <param name="owner">The published element owning the property.</param>
|
||||
/// <param name="referenceCacheLevel">The reference cache level.</param>
|
||||
/// <param name="inter">The intermediate value.</param>
|
||||
/// <param name="preview">A value indicating whether content should be considered draft.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
object ConvertInterToObject(IPublishedElement owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the intermediate value into the XPath value.
|
||||
/// </summary>
|
||||
/// <param name="owner">The published element owning the property.</param>
|
||||
/// <param name="referenceCacheLevel">The reference cache level.</param>
|
||||
/// <param name="inter">The intermediate value.</param>
|
||||
/// <param name="preview">A value indicating whether content should be considered draft.</param>
|
||||
/// <returns>The XPath value.</returns>
|
||||
/// <remarks>
|
||||
/// <para>The XPath value can be either a string or an XPathNavigator.</para>
|
||||
/// </remarks>
|
||||
object ConvertInterToXPath(IPublishedElement owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property model CLR type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The model CLR type may be a <see cref="ModelType"/> type, or may contain <see cref="ModelType"/> types.</para>
|
||||
/// <para>For the actual CLR type, see <see cref="ClrType"/>.</para>
|
||||
/// </remarks>
|
||||
Type ModelClrType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property CLR type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Returns the actual CLR type which does not contain <see cref="ModelType"/> types.</para>
|
||||
/// <para>Mapping from <see cref="ModelClrType"/> may throw if some <see cref="ModelType"/> instances
|
||||
/// could not be mapped to actual CLR types.</para>
|
||||
/// </remarks>
|
||||
Type ClrType { get; }
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,13 @@ using System.Linq;
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an <see cref="IPublishedContent"/> type.
|
||||
/// Represents an <see cref="IPublishedElement"/> type.
|
||||
/// </summary>
|
||||
/// <remarks>Instances of the <see cref="PublishedContentType"/> class are immutable, ie
|
||||
/// if the content type changes, then a new class needs to be created.</remarks>
|
||||
public class PublishedContentType
|
||||
public class PublishedContentType : IPublishedContentType
|
||||
{
|
||||
private readonly PublishedPropertyType[] _propertyTypes;
|
||||
private readonly IPublishedPropertyType[] _propertyTypes;
|
||||
|
||||
// fast alias-to-index xref containing both the raw alias and its lowercase version
|
||||
private readonly Dictionary<string, int> _indexes = new Dictionary<string, int>();
|
||||
@@ -35,11 +35,10 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedContentType"/> with specific values.
|
||||
/// This constructor is for tests and is not intended to be used directly from application code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This constructor is for tests and is not intended to be used directly from application code.</para>
|
||||
/// <para>Values are assumed to be consisted and are not checked.</para>
|
||||
/// <para>Values are assumed to be consistent and are not checked.</para>
|
||||
/// </remarks>
|
||||
public PublishedContentType(int id, string alias, PublishedItemType itemType, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes, ContentVariation variations, bool isElement = false)
|
||||
: this (id, alias, itemType, compositionAliases, variations, isElement)
|
||||
@@ -52,6 +51,20 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
InitializeIndexes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This constructor is for tests and is not intended to be used directly from application code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Values are assumed to be consistent and are not checked.</para>
|
||||
/// </remarks>
|
||||
public PublishedContentType(int id, string alias, PublishedItemType itemType, IEnumerable<string> compositionAliases, Func<IPublishedContentType, IEnumerable<IPublishedPropertyType>> propertyTypes, ContentVariation variations, bool isElement = false)
|
||||
: this(id, alias, itemType, compositionAliases, variations, isElement)
|
||||
{
|
||||
_propertyTypes = propertyTypes(this).ToArray();
|
||||
|
||||
InitializeIndexes();
|
||||
}
|
||||
|
||||
private PublishedContentType(int id, string alias, PublishedItemType itemType, IEnumerable<string> compositionAliases, ContentVariation variations, bool isElement)
|
||||
{
|
||||
Id = id;
|
||||
@@ -75,7 +88,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
// Members have properties such as IMember LastLoginDate which are plain C# properties and not content
|
||||
// properties; they are exposed as pseudo content properties, as long as a content property with the
|
||||
// same alias does not exist already.
|
||||
private void EnsureMemberProperties(List<PublishedPropertyType> propertyTypes, IPublishedContentTypeFactory factory)
|
||||
private void EnsureMemberProperties(List<IPublishedPropertyType> propertyTypes, IPublishedContentTypeFactory factory)
|
||||
{
|
||||
var aliases = new HashSet<string>(propertyTypes.Select(x => x.Alias), StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
@@ -103,44 +116,29 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
#region Content type
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content type identifier.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content type alias.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string Alias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content item type.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public PublishedItemType ItemType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the aliases of the content types participating in the composition.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public HashSet<string> CompositionAliases { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content variations of the content type.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public ContentVariation Variations { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content type properties.
|
||||
/// </summary>
|
||||
public IEnumerable<PublishedPropertyType> PropertyTypes => _propertyTypes;
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IPublishedPropertyType> PropertyTypes => _propertyTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a property type index.
|
||||
/// </summary>
|
||||
/// <remarks>The alias is case-insensitive. This is the only place where alias strings are compared.</remarks>
|
||||
/// <inheritdoc />
|
||||
public int GetPropertyIndex(string alias)
|
||||
{
|
||||
if (_indexes.TryGetValue(alias, out var index)) return index; // fastest
|
||||
@@ -150,10 +148,8 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
// virtual for unit tests
|
||||
// TODO: explain why
|
||||
/// <summary>
|
||||
/// Gets a property type.
|
||||
/// </summary>
|
||||
public virtual PublishedPropertyType GetPropertyType(string alias)
|
||||
/// <inheritdoc />
|
||||
public virtual IPublishedPropertyType GetPropertyType(string alias)
|
||||
{
|
||||
var index = GetPropertyIndex(alias);
|
||||
return GetPropertyType(index);
|
||||
@@ -161,17 +157,13 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
// virtual for unit tests
|
||||
// TODO: explain why
|
||||
/// <summary>
|
||||
/// Gets a property type.
|
||||
/// </summary>
|
||||
public virtual PublishedPropertyType GetPropertyType(int index)
|
||||
/// <inheritdoc />
|
||||
public virtual IPublishedPropertyType GetPropertyType(int index)
|
||||
{
|
||||
return index >= 0 && index < _propertyTypes.Length ? _propertyTypes[index] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this content type is for an element.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool IsElement { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -26,37 +26,46 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PublishedContentType CreateContentType(IContentTypeComposition contentType)
|
||||
public IPublishedContentType CreateContentType(IContentTypeComposition contentType)
|
||||
{
|
||||
return new PublishedContentType(contentType, this);
|
||||
}
|
||||
|
||||
// for tests
|
||||
internal PublishedContentType CreateContentType(int id, string alias, IEnumerable<PublishedPropertyType> propertyTypes, ContentVariation variations = ContentVariation.Nothing, bool isElement = false)
|
||||
/// <summary>
|
||||
/// This method is for tests and is not intended to be used directly from application code.
|
||||
/// </summary>
|
||||
/// <remarks>Values are assumed to be consisted and are not checked.</remarks>
|
||||
internal IPublishedContentType CreateContentType(int id, string alias, Func<IPublishedContentType, IEnumerable<IPublishedPropertyType>> propertyTypes, ContentVariation variations = ContentVariation.Nothing, bool isElement = false)
|
||||
{
|
||||
return new PublishedContentType(id, alias, PublishedItemType.Content, Enumerable.Empty<string>(), propertyTypes, variations, isElement);
|
||||
}
|
||||
|
||||
// for tests
|
||||
internal PublishedContentType CreateContentType(int id, string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes, ContentVariation variations = ContentVariation.Nothing, bool isElement = false)
|
||||
/// <summary>
|
||||
/// This method is for tests and is not intended to be used directly from application code.
|
||||
/// </summary>
|
||||
/// <remarks>Values are assumed to be consisted and are not checked.</remarks>
|
||||
internal IPublishedContentType CreateContentType(int id, string alias, IEnumerable<string> compositionAliases, Func<IPublishedContentType, IEnumerable<IPublishedPropertyType>> propertyTypes, ContentVariation variations = ContentVariation.Nothing, bool isElement = false)
|
||||
{
|
||||
return new PublishedContentType(id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, variations, isElement);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PublishedPropertyType CreatePropertyType(PublishedContentType contentType, PropertyType propertyType)
|
||||
public IPublishedPropertyType CreatePropertyType(IPublishedContentType contentType, PropertyType propertyType)
|
||||
{
|
||||
return new PublishedPropertyType(contentType, propertyType, _propertyValueConverters, _publishedModelFactory, this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PublishedPropertyType CreatePropertyType(PublishedContentType contentType, string propertyTypeAlias, int dataTypeId, ContentVariation variations = ContentVariation.Nothing)
|
||||
public IPublishedPropertyType CreatePropertyType(IPublishedContentType contentType, string propertyTypeAlias, int dataTypeId, ContentVariation variations = ContentVariation.Nothing)
|
||||
{
|
||||
return new PublishedPropertyType(contentType, propertyTypeAlias, dataTypeId, true, variations, _propertyValueConverters, _publishedModelFactory, this);
|
||||
}
|
||||
|
||||
// for tests
|
||||
internal PublishedPropertyType CreatePropertyType(string propertyTypeAlias, int dataTypeId, bool umbraco = false, ContentVariation variations = ContentVariation.Nothing)
|
||||
/// <summary>
|
||||
/// This method is for tests and is not intended to be used directly from application code.
|
||||
/// </summary>
|
||||
/// <remarks>Values are assumed to be consisted and are not checked.</remarks>
|
||||
internal IPublishedPropertyType CreatePropertyType(string propertyTypeAlias, int dataTypeId, bool umbraco = false, ContentVariation variations = ContentVariation.Nothing)
|
||||
{
|
||||
return new PublishedPropertyType(propertyTypeAlias, dataTypeId, umbraco, variations, _propertyValueConverters, _publishedModelFactory, this);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
#region ContentType
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual PublishedContentType ContentType => _content.ContentType;
|
||||
public virtual IPublishedContentType ContentType => _content.ContentType;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -96,12 +96,6 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <inheritdoc />
|
||||
public virtual string Url => _content.Url;
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual string GetUrl(string culture = null) => _content.GetUrl(culture);
|
||||
|
||||
/// <inheritdoc />
|
||||
public PublishedCultureInfo GetCulture(string culture = null) => _content.GetCulture(culture);
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyDictionary<string, PublishedCultureInfo> Cultures => _content.Cultures;
|
||||
|
||||
@@ -124,6 +118,9 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <inheritdoc />
|
||||
public virtual IEnumerable<IPublishedContent> Children => _content.Children;
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IEnumerable<IPublishedContent> ChildrenForAllCultures => _content.ChildrenForAllCultures;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
@@ -13,10 +13,9 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// </summary>
|
||||
public PublishedCultureInfo(string culture, string name, string urlSegment, DateTime date)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentNullOrEmptyException(nameof(culture));
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
|
||||
|
||||
Culture = culture;
|
||||
Culture = culture ?? throw new ArgumentNullException(nameof(culture));
|
||||
Name = name;
|
||||
UrlSegment = urlSegment;
|
||||
Date = date;
|
||||
@@ -30,12 +29,12 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <summary>
|
||||
/// Gets the name of the item.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
internal string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url segment of the item.
|
||||
/// </summary>
|
||||
public string UrlSegment { get; }
|
||||
internal string UrlSegment { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date associated with the culture.
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
public IPublishedElement Unwrap() => _content;
|
||||
|
||||
/// <inheritdoc />
|
||||
public PublishedContentType ContentType => _content.ContentType;
|
||||
public IPublishedContentType ContentType => _content.ContentType;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Key => _content.Key;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedPropertyBase"/> class.
|
||||
/// </summary>
|
||||
protected PublishedPropertyBase(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel)
|
||||
protected PublishedPropertyBase(IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel)
|
||||
{
|
||||
PropertyType = propertyType ?? throw new ArgumentNullException(nameof(propertyType));
|
||||
ReferenceCacheLevel = referenceCacheLevel;
|
||||
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <summary>
|
||||
/// Gets the property type.
|
||||
/// </summary>
|
||||
public PublishedPropertyType PropertyType { get; }
|
||||
public IPublishedPropertyType PropertyType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property reference cache level.
|
||||
|
||||
@@ -10,10 +10,8 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// </summary>
|
||||
/// <remarks>Instances of the <see cref="PublishedPropertyType"/> class are immutable, ie
|
||||
/// if the property type changes, then a new class needs to be created.</remarks>
|
||||
public class PublishedPropertyType
|
||||
public class PublishedPropertyType : IPublishedPropertyType
|
||||
{
|
||||
// TODO: API design review, should this be an interface?
|
||||
|
||||
private readonly IPublishedModelFactory _publishedModelFactory;
|
||||
private readonly PropertyValueConverterCollection _propertyValueConverters;
|
||||
private readonly object _locker = new object();
|
||||
@@ -32,7 +30,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <remarks>
|
||||
/// <para>The new published property type belongs to the published content type.</para>
|
||||
/// </remarks>
|
||||
public PublishedPropertyType(PublishedContentType contentType, PropertyType propertyType, PropertyValueConverterCollection propertyValueConverters, IPublishedModelFactory publishedModelFactory, IPublishedContentTypeFactory factory)
|
||||
public PublishedPropertyType(IPublishedContentType contentType, PropertyType propertyType, PropertyValueConverterCollection propertyValueConverters, IPublishedModelFactory publishedModelFactory, IPublishedContentTypeFactory factory)
|
||||
: this(propertyType.Alias, propertyType.DataTypeId, true, propertyType.Variations, propertyValueConverters, publishedModelFactory, factory)
|
||||
{
|
||||
ContentType = contentType ?? throw new ArgumentNullException(nameof(contentType));
|
||||
@@ -45,7 +43,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <para>Values are assumed to be consisted and are not checked.</para>
|
||||
/// <para>The new published property type belongs to the published content type.</para>
|
||||
/// </remarks>
|
||||
public PublishedPropertyType(PublishedContentType contentType, string propertyTypeAlias, int dataTypeId, bool isUserProperty, ContentVariation variations, PropertyValueConverterCollection propertyValueConverters, IPublishedModelFactory publishedModelFactory, IPublishedContentTypeFactory factory)
|
||||
public PublishedPropertyType(IPublishedContentType contentType, string propertyTypeAlias, int dataTypeId, bool isUserProperty, ContentVariation variations, PropertyValueConverterCollection propertyValueConverters, IPublishedModelFactory publishedModelFactory, IPublishedContentTypeFactory factory)
|
||||
: this(propertyTypeAlias, dataTypeId, isUserProperty, variations, propertyValueConverters, publishedModelFactory, factory)
|
||||
{
|
||||
ContentType = contentType ?? throw new ArgumentNullException(nameof(contentType));
|
||||
@@ -75,37 +73,22 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
#region Property type
|
||||
|
||||
/// <summary>
|
||||
/// Gets the published content type containing the property type.
|
||||
/// </summary>
|
||||
public PublishedContentType ContentType { get; internal set; } // internally set by PublishedContentType constructor
|
||||
/// <inheritdoc />
|
||||
public IPublishedContentType ContentType { get; internal set; } // internally set by PublishedContentType constructor
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data type.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public PublishedDataType DataType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets property type alias.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string Alias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property editor alias.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string EditorAlias => DataType.EditorAlias;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the property is a user content property.
|
||||
/// </summary>
|
||||
/// <remarks>A non-user content property is a property that has been added to a
|
||||
/// published content type by Umbraco but does not corresponds to a user-defined
|
||||
/// published property.</remarks>
|
||||
/// <inheritdoc />
|
||||
public bool IsUserProperty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content variations of the property type.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public ContentVariation Variations { get; }
|
||||
|
||||
#endregion
|
||||
@@ -193,10 +176,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
_modelClrType = _converter == null ? typeof (object) : _converter.GetPropertyValueType(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a value is an actual value, or not a value.
|
||||
/// </summary>
|
||||
/// <remarks>Used by property.HasValue and, for instance, in fallback scenarios.</remarks>
|
||||
/// <inheritdoc />
|
||||
public bool? IsValue(object value, PropertyValueLevel level)
|
||||
{
|
||||
if (!_initialized) Initialize();
|
||||
@@ -209,9 +189,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
return value != null && (!(value is string) || string.IsNullOrWhiteSpace((string) value) == false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property cache level.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public PropertyCacheLevel CacheLevel
|
||||
{
|
||||
get
|
||||
@@ -221,13 +199,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the source value into the intermediate value.
|
||||
/// </summary>
|
||||
/// <param name="owner">The published element owning the property.</param>
|
||||
/// <param name="source">The source value.</param>
|
||||
/// <param name="preview">A value indicating whether content should be considered draft.</param>
|
||||
/// <returns>The intermediate value.</returns>
|
||||
/// <inheritdoc />
|
||||
public object ConvertSourceToInter(IPublishedElement owner, object source, bool preview)
|
||||
{
|
||||
if (!_initialized) Initialize();
|
||||
@@ -238,14 +210,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
: source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the intermediate value into the object value.
|
||||
/// </summary>
|
||||
/// <param name="owner">The published element owning the property.</param>
|
||||
/// <param name="referenceCacheLevel">The reference cache level.</param>
|
||||
/// <param name="inter">The intermediate value.</param>
|
||||
/// <param name="preview">A value indicating whether content should be considered draft.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
/// <inheritdoc />
|
||||
public object ConvertInterToObject(IPublishedElement owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
if (!_initialized) Initialize();
|
||||
@@ -256,17 +221,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
: inter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the intermediate value into the XPath value.
|
||||
/// </summary>
|
||||
/// <param name="owner">The published element owning the property.</param>
|
||||
/// <param name="referenceCacheLevel">The reference cache level.</param>
|
||||
/// <param name="inter">The intermediate value.</param>
|
||||
/// <param name="preview">A value indicating whether content should be considered draft.</param>
|
||||
/// <returns>The XPath value.</returns>
|
||||
/// <remarks>
|
||||
/// <para>The XPath value can be either a string or an XPathNavigator.</para>
|
||||
/// </remarks>
|
||||
/// <inheritdoc />
|
||||
public object ConvertInterToXPath(IPublishedElement owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
if (!_initialized) Initialize();
|
||||
@@ -282,13 +237,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
return inter.ToString().Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property model CLR type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The model CLR type may be a <see cref="ModelType"/> type, or may contain <see cref="ModelType"/> types.</para>
|
||||
/// <para>For the actual CLR type, see <see cref="ClrType"/>.</para>
|
||||
/// </remarks>
|
||||
/// <inheritdoc />
|
||||
public Type ModelClrType
|
||||
{
|
||||
get
|
||||
@@ -298,14 +247,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property CLR type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Returns the actual CLR type which does not contain <see cref="ModelType"/> types.</para>
|
||||
/// <para>Mapping from <see cref="ModelClrType"/> may throw if some <see cref="ModelType"/> instances
|
||||
/// could not be mapped to actual CLR types.</para>
|
||||
/// </remarks>
|
||||
/// <inheritdoc />
|
||||
public Type ClrType
|
||||
{
|
||||
get
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
public override object GetXPathValue(string culture = null, string segment = null)
|
||||
=> string.IsNullOrEmpty(culture) & string.IsNullOrEmpty(segment) ? _xpathValue.Value : null;
|
||||
|
||||
public RawValueProperty(PublishedPropertyType propertyType, IPublishedElement content, object sourceValue, bool isPreviewing = false)
|
||||
public RawValueProperty(IPublishedPropertyType propertyType, IPublishedElement content, object sourceValue, bool isPreviewing = false)
|
||||
: base(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored
|
||||
{
|
||||
if (propertyType.Variations != ContentVariation.Nothing)
|
||||
|
||||
+7
-7
@@ -1,14 +1,14 @@
|
||||
namespace Umbraco.Web.Routing
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the type of urls that the url provider should produce, Auto is the default
|
||||
/// Specifies the type of urls that the url provider should produce, Auto is the default.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The <c>Relative</c> option can lead to invalid results when combined with hostnames, but it is the only way to reproduce
|
||||
/// the true, pre-4.10, always-relative behavior of Umbraco.</para>
|
||||
/// </remarks>
|
||||
public enum UrlProviderMode
|
||||
public enum UrlMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that the url provider should do what it has been configured to do.
|
||||
/// </summary>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the url provider should produce relative urls exclusively.
|
||||
@@ -10,22 +10,35 @@ namespace Umbraco.Core.Persistence
|
||||
/// <summary>
|
||||
/// Creates a new database.
|
||||
/// </summary>
|
||||
/// <remarks>The new database must be disposed after being used.</remarks>
|
||||
/// <remarks>
|
||||
/// <para>The new database must be disposed after being used.</para>
|
||||
/// <para>Creating a database causes the factory to initialize if it is not already initialized.</para>
|
||||
/// </remarks>
|
||||
IUmbracoDatabase CreateDatabase();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the database factory is configured.
|
||||
/// Gets a value indicating whether the database factory is configured, i.e. whether
|
||||
/// its connection string and provider name have been set. The factory may however not
|
||||
/// be initialized (see <see cref="Initialized"/>).
|
||||
/// </summary>
|
||||
bool Configured { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the database factory is initialized, i.e. whether
|
||||
/// its internal state is ready and it has been possible to connect to the database.
|
||||
/// </summary>
|
||||
bool Initialized { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the connection string.
|
||||
/// </summary>
|
||||
/// <remarks>Throws if the factory is not configured.</remarks>
|
||||
/// <remarks>May return <c>null</c> if the database factory is not configured.</remarks>
|
||||
string ConnectionString { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the database can connect.
|
||||
/// Gets a value indicating whether the database factory is configured (see <see cref="Configured"/>),
|
||||
/// and it is possible to connect to the database. The factory may however not be initialized (see
|
||||
/// <see cref="Initialized"/>).
|
||||
/// </summary>
|
||||
bool CanConnect { get; }
|
||||
|
||||
@@ -37,6 +50,9 @@ namespace Umbraco.Core.Persistence
|
||||
/// <summary>
|
||||
/// Gets the Sql context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Getting the Sql context causes the factory to initialize if it is not already initialized.</para>
|
||||
/// </remarks>
|
||||
ISqlContext SqlContext { get; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -232,6 +232,14 @@ namespace Umbraco.Core.Persistence
|
||||
using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction) { BulkCopyTimeout = 10000, DestinationTableName = tableName })
|
||||
using (var bulkReader = new PocoDataDataReader<T, SqlServerSyntaxProvider>(records, pocoData, syntax))
|
||||
{
|
||||
//we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared
|
||||
//to the order in which they are declared in the model then this will not work, so instead we will add column mappings by name so that this explicitly uses
|
||||
//the names instead of their ordering.
|
||||
foreach(var col in bulkReader.ColumnMappings)
|
||||
{
|
||||
copy.ColumnMappings.Add(col.DestinationColumn, col.DestinationColumn);
|
||||
}
|
||||
|
||||
copy.WriteToServer(bulkReader);
|
||||
return bulkReader.RecordsAffected;
|
||||
}
|
||||
|
||||
@@ -140,10 +140,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
while (templateDtoIx < templateDtos.Count && templateDtos[templateDtoIx].ContentTypeNodeId == contentType.Id)
|
||||
{
|
||||
var allowedDto = templateDtos[templateDtoIx];
|
||||
templateDtoIx++;
|
||||
if (!templates.TryGetValue(allowedDto.TemplateNodeId, out var template)) continue;
|
||||
allowedTemplates.Add(template);
|
||||
templateDtoIx++;
|
||||
|
||||
|
||||
if (allowedDto.IsDefault)
|
||||
defaultTemplateId = template.Id;
|
||||
}
|
||||
|
||||
@@ -75,6 +75,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
dtos = page.Items;
|
||||
totalRecords = page.TotalItems;
|
||||
}
|
||||
else if (isMedia)
|
||||
{
|
||||
var page = Database.Page<MediaEntityDto>(pageIndexToFetch, pageSize, sql);
|
||||
dtos = page.Items;
|
||||
totalRecords = page.TotalItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
var page = Database.Page<BaseDto>(pageIndexToFetch, pageSize, sql);
|
||||
@@ -87,10 +93,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (isContent)
|
||||
BuildVariants(entities.Cast<DocumentEntitySlim>());
|
||||
|
||||
// TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
|
||||
if (isMedia)
|
||||
BuildProperties(entities, dtos.ToList());
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
@@ -112,14 +114,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return cdtos.Count == 0 ? null : BuildVariants(BuildDocumentEntity(cdtos[0]));
|
||||
}
|
||||
|
||||
var dto = Database.FirstOrDefault<BaseDto>(sql);
|
||||
var dto = isMedia
|
||||
? Database.FirstOrDefault<MediaEntityDto>(sql)
|
||||
: Database.FirstOrDefault<BaseDto>(sql);
|
||||
|
||||
if (dto == null) return null;
|
||||
|
||||
var entity = BuildEntity(false, isMedia, dto);
|
||||
|
||||
if (isMedia)
|
||||
BuildProperties(entity, dto);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -162,7 +164,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
: PerformGetAll(objectType);
|
||||
}
|
||||
|
||||
private IEnumerable<IEntitySlim> GetEntities(Sql<ISqlContext> sql, bool isContent, bool isMedia, bool loadMediaProperties)
|
||||
private IEnumerable<IEntitySlim> GetEntities(Sql<ISqlContext> sql, bool isContent, bool isMedia)
|
||||
{
|
||||
//isContent is going to return a 1:M result now with the variants so we need to do different things
|
||||
if (isContent)
|
||||
@@ -174,15 +176,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
: BuildVariants(cdtos.Select(BuildDocumentEntity)).ToList();
|
||||
}
|
||||
|
||||
var dtos = Database.Fetch<BaseDto>(sql);
|
||||
if (dtos.Count == 0) return Enumerable.Empty<IEntitySlim>();
|
||||
var dtos = isMedia
|
||||
? (IEnumerable<BaseDto>)Database.Fetch<MediaEntityDto>(sql)
|
||||
: Database.Fetch<BaseDto>(sql);
|
||||
|
||||
var entities = dtos.Select(x => BuildEntity(false, isMedia, x)).ToArray();
|
||||
|
||||
// TODO: See https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
|
||||
if (isMedia && loadMediaProperties)
|
||||
BuildProperties(entities, dtos);
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
@@ -192,7 +191,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var isMedia = objectType == Constants.ObjectTypes.Media;
|
||||
|
||||
var sql = GetFullSqlForEntityType(isContent, isMedia, objectType, filter);
|
||||
return GetEntities(sql, isContent, isMedia, true);
|
||||
return GetEntities(sql, isContent, isMedia);
|
||||
}
|
||||
|
||||
public IEnumerable<TreeEntityPath> GetAllPaths(Guid objectType, params int[] ids)
|
||||
@@ -238,22 +237,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
sql = translator.Translate();
|
||||
sql = AddGroupBy(isContent, isMedia, sql, true);
|
||||
|
||||
return GetEntities(sql, isContent, isMedia, true);
|
||||
}
|
||||
|
||||
// TODO: See https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
|
||||
internal IEnumerable<IEntitySlim> GetMediaByQueryWithoutPropertyData(IQuery<IUmbracoEntity> query)
|
||||
{
|
||||
var isContent = false;
|
||||
var isMedia = true;
|
||||
|
||||
var sql = GetBaseWhere(isContent, isMedia, false, null, Constants.ObjectTypes.Media);
|
||||
|
||||
var translator = new SqlTranslator<IUmbracoEntity>(sql, query);
|
||||
sql = translator.Translate();
|
||||
sql = AddGroupBy(isContent, isMedia, sql, true);
|
||||
|
||||
return GetEntities(sql, isContent, isMedia, false);
|
||||
return GetEntities(sql, isContent, isMedia);
|
||||
}
|
||||
|
||||
public UmbracoObjectTypes GetObjectType(int id)
|
||||
@@ -280,41 +264,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return Database.ExecuteScalar<int>(sql) > 0;
|
||||
}
|
||||
|
||||
// TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
|
||||
private void BuildProperties(EntitySlim entity, BaseDto dto)
|
||||
{
|
||||
var pdtos = Database.Fetch<PropertyDataDto>(GetPropertyData(dto.VersionId));
|
||||
foreach (var pdto in pdtos)
|
||||
BuildProperty(entity, pdto);
|
||||
}
|
||||
|
||||
// TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
|
||||
private void BuildProperties(EntitySlim[] entities, List<BaseDto> dtos)
|
||||
{
|
||||
var versionIds = dtos.Select(x => x.VersionId).Distinct().ToList();
|
||||
var pdtos = Database.FetchByGroups<PropertyDataDto, int>(versionIds, 2000, GetPropertyData);
|
||||
|
||||
var xentity = entities.ToDictionary(x => x.Id, x => x); // nodeId -> entity
|
||||
var xdto = dtos.ToDictionary(x => x.VersionId, x => x.NodeId); // versionId -> nodeId
|
||||
foreach (var pdto in pdtos)
|
||||
{
|
||||
var nodeId = xdto[pdto.VersionId];
|
||||
var entity = xentity[nodeId];
|
||||
BuildProperty(entity, pdto);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
|
||||
private void BuildProperty(EntitySlim entity, PropertyDataDto pdto)
|
||||
{
|
||||
// explain ?!
|
||||
var value = string.IsNullOrWhiteSpace(pdto.TextValue)
|
||||
? pdto.VarcharValue
|
||||
: pdto.TextValue.ConvertToJsonIfPossible();
|
||||
|
||||
entity.AdditionalData[pdto.PropertyTypeDto.Alias] = new EntitySlim.PropertySlim(pdto.PropertyTypeDto.DataTypeDto.EditorAlias, value);
|
||||
}
|
||||
|
||||
private DocumentEntitySlim BuildVariants(DocumentEntitySlim entity)
|
||||
=> BuildVariants(new[] { entity }).First();
|
||||
|
||||
@@ -400,31 +349,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return AddGroupBy(isContent, isMedia, sql, true);
|
||||
}
|
||||
|
||||
private Sql<ISqlContext> GetPropertyData(int versionId)
|
||||
{
|
||||
return Sql()
|
||||
.Select<PropertyDataDto>(r => r.Select(x => x.PropertyTypeDto, r1 => r1.Select(x => x.DataTypeDto)))
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id)
|
||||
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((left, right) => left.DataTypeId == right.NodeId)
|
||||
.Where<PropertyDataDto>(x => x.VersionId == versionId);
|
||||
}
|
||||
|
||||
private Sql<ISqlContext> GetPropertyData(IEnumerable<int> versionIds)
|
||||
{
|
||||
return Sql()
|
||||
.Select<PropertyDataDto>(r => r.Select(x => x.PropertyTypeDto, r1 => r1.Select(x => x.DataTypeDto)))
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id)
|
||||
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((left, right) => left.DataTypeId == right.NodeId)
|
||||
.WhereIn<PropertyDataDto>(x => x.VersionId, versionIds)
|
||||
.OrderBy<PropertyDataDto>(x => x.VersionId);
|
||||
}
|
||||
|
||||
// gets the base SELECT + FROM [+ filter] sql
|
||||
// always from the 'current' content version
|
||||
protected Sql<ISqlContext> GetBase(bool isContent, bool isMedia, Action<Sql<ISqlContext>> filter, bool isCount = false)
|
||||
{
|
||||
{
|
||||
var sql = Sql();
|
||||
|
||||
if (isCount)
|
||||
@@ -448,6 +376,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
sql
|
||||
.AndSelect<DocumentDto>(x => x.Published, x => x.Edited);
|
||||
}
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
sql
|
||||
.AndSelect<MediaVersionDto>(x => Alias(x.Path, "MediaPath"));
|
||||
}
|
||||
}
|
||||
|
||||
sql
|
||||
@@ -467,6 +401,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.InnerJoin<DocumentDto>().On<NodeDto, DocumentDto>((left, right) => left.NodeId == right.NodeId);
|
||||
}
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
sql
|
||||
.InnerJoin<MediaVersionDto>().On<ContentVersionDto, MediaVersionDto>((left, right) => left.Id == right.Id);
|
||||
}
|
||||
|
||||
//Any LeftJoin statements need to come last
|
||||
if (isCount == false)
|
||||
{
|
||||
@@ -536,6 +476,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.AndBy<DocumentDto>(x => x.Published, x => x.Edited);
|
||||
}
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
sql
|
||||
.AndBy<MediaVersionDto>(x => Alias(x.Path, "MediaPath"));
|
||||
}
|
||||
|
||||
|
||||
if (isContent || isMedia)
|
||||
sql
|
||||
@@ -566,23 +512,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
#region Classes
|
||||
|
||||
[ExplicitColumns]
|
||||
internal class UmbracoPropertyDto
|
||||
{
|
||||
[Column("propertyEditorAlias")]
|
||||
public string PropertyEditorAlias { get; set; }
|
||||
|
||||
[Column("propertyTypeAlias")]
|
||||
public string PropertyAlias { get; set; }
|
||||
|
||||
[Column("varcharValue")]
|
||||
public string VarcharValue { get; set; }
|
||||
|
||||
[Column("textValue")]
|
||||
public string TextValue { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The DTO used to fetch results for a content item with its variation info
|
||||
/// </summary>
|
||||
@@ -594,6 +523,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
public bool Edited { get; set; }
|
||||
}
|
||||
|
||||
private class MediaEntityDto : BaseDto
|
||||
{
|
||||
public string MediaPath { get; set; }
|
||||
}
|
||||
|
||||
public class VariantInfoDto
|
||||
{
|
||||
public int NodeId { get; set; }
|
||||
@@ -645,7 +579,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (isContent)
|
||||
return BuildDocumentEntity(dto);
|
||||
if (isMedia)
|
||||
return BuildContentEntity(dto);
|
||||
return BuildMediaEntity(dto);
|
||||
|
||||
// EntitySlim does not track changes
|
||||
var entity = new EntitySlim();
|
||||
@@ -678,11 +612,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
entity.ContentTypeThumbnail = dto.Thumbnail;
|
||||
}
|
||||
|
||||
private static EntitySlim BuildContentEntity(BaseDto dto)
|
||||
private MediaEntitySlim BuildMediaEntity(BaseDto dto)
|
||||
{
|
||||
// EntitySlim does not track changes
|
||||
var entity = new ContentEntitySlim();
|
||||
var entity = new MediaEntitySlim();
|
||||
BuildContentEntity(entity, dto);
|
||||
|
||||
if (dto is MediaEntityDto contentDto)
|
||||
{
|
||||
// fill in the media info
|
||||
entity.MediaPath = contentDto.MediaPath;
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
if (uniqueing)
|
||||
{
|
||||
if (name.NumPos > 0 && name.Name.StartsWith(nodeName) && name.NumVal == uniqueNumber)
|
||||
if (name.NumPos > 0 && name.Name.InvariantStartsWith(nodeName) && name.NumVal == uniqueNumber)
|
||||
uniqueNumber++;
|
||||
else
|
||||
break;
|
||||
|
||||
@@ -411,8 +411,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return;
|
||||
|
||||
//now the user association
|
||||
RemoveAllUsersFromGroup(entity.UserGroup.Id);
|
||||
AddUsersToGroup(entity.UserGroup.Id, entity.UserIds);
|
||||
RefreshUsersInGroup(entity.UserGroup.Id, entity.UserIds);
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(UserGroupWithUsers entity)
|
||||
@@ -424,8 +423,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return;
|
||||
|
||||
//now the user association
|
||||
RemoveAllUsersFromGroup(entity.UserGroup.Id);
|
||||
AddUsersToGroup(entity.UserGroup.Id, entity.UserIds);
|
||||
RefreshUsersInGroup(entity.UserGroup.Id, entity.UserIds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a set of users to a group, first removing any that exist
|
||||
/// </summary>
|
||||
/// <param name="groupId">Id of group</param>
|
||||
/// <param name="userIds">Ids of users</param>
|
||||
private void RefreshUsersInGroup(int groupId, int[] userIds)
|
||||
{
|
||||
RemoveAllUsersFromGroup(groupId);
|
||||
AddUsersToGroup(groupId, userIds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -444,7 +453,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// <param name="userIds">Ids of users</param>
|
||||
private void AddUsersToGroup(int groupId, int[] userIds)
|
||||
{
|
||||
// TODO: Check if the user exists?
|
||||
foreach (var userId in userIds)
|
||||
{
|
||||
var dto = new User2UserGroupDto
|
||||
|
||||
@@ -28,7 +28,8 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
private readonly Lazy<IMapperCollection> _mappers;
|
||||
private readonly ILogger _logger;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
|
||||
private object _lock = new object();
|
||||
|
||||
private DatabaseFactory _npocoDatabaseFactory;
|
||||
private IPocoDataFactory _pocoDataFactory;
|
||||
@@ -36,12 +37,13 @@ namespace Umbraco.Core.Persistence
|
||||
private string _providerName;
|
||||
private DbProviderFactory _dbProviderFactory;
|
||||
private DatabaseType _databaseType;
|
||||
private bool _serverVersionDetected;
|
||||
private ISqlSyntaxProvider _sqlSyntax;
|
||||
private RetryPolicy _connectionRetryPolicy;
|
||||
private RetryPolicy _commandRetryPolicy;
|
||||
private NPoco.MapperCollection _pocoMappers;
|
||||
private SqlContext _sqlContext;
|
||||
private bool _upgrading;
|
||||
private bool _initialized;
|
||||
|
||||
#region Constructors
|
||||
|
||||
@@ -106,36 +108,30 @@ namespace Umbraco.Core.Persistence
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Configured { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ConnectionString
|
||||
public bool Configured
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureConfigured();
|
||||
return _connectionString;
|
||||
lock (_lock)
|
||||
{
|
||||
return !_connectionString.IsNullOrWhiteSpace() && !_providerName.IsNullOrWhiteSpace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CanConnect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Configured || !DbConnectionExtensions.IsConnectionAvailable(_connectionString, _providerName)) return false;
|
||||
public bool Initialized => Volatile.Read(ref _initialized);
|
||||
|
||||
if (_serverVersionDetected) return true;
|
||||
/// <inheritdoc />
|
||||
public string ConnectionString => _connectionString;
|
||||
|
||||
if (_databaseType.IsSqlServer())
|
||||
DetectSqlServerVersion();
|
||||
_serverVersionDetected = true;
|
||||
/// <inheritdoc />
|
||||
public bool CanConnect =>
|
||||
// actually tries to connect to the database (regardless of configured/initialized)
|
||||
!_connectionString.IsNullOrWhiteSpace() && !_providerName.IsNullOrWhiteSpace() &&
|
||||
DbConnectionExtensions.IsConnectionAvailable(_connectionString, _providerName);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DetectSqlServerVersion()
|
||||
private void UpdateSqlServerDatabaseType()
|
||||
{
|
||||
// replace NPoco database type by a more efficient one
|
||||
|
||||
@@ -171,7 +167,15 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ISqlContext SqlContext { get; private set; }
|
||||
public ISqlContext SqlContext
|
||||
{
|
||||
get
|
||||
{
|
||||
// must be initialized to have a context
|
||||
EnsureInitialized();
|
||||
return _sqlContext;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ConfigureForUpgrade()
|
||||
@@ -182,63 +186,79 @@ namespace Umbraco.Core.Persistence
|
||||
/// <inheritdoc />
|
||||
public void Configure(string connectionString, string providerName)
|
||||
{
|
||||
try
|
||||
if (connectionString.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(connectionString));
|
||||
if (providerName.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(providerName));
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
|
||||
_logger.Debug<UmbracoDatabaseFactory>("Configuring.");
|
||||
|
||||
if (Configured) throw new InvalidOperationException("Already configured.");
|
||||
|
||||
if (connectionString.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(connectionString));
|
||||
if (providerName.IsNullOrWhiteSpace()) throw new ArgumentNullException(nameof(providerName));
|
||||
if (Volatile.Read(ref _initialized))
|
||||
throw new InvalidOperationException("Already initialized.");
|
||||
|
||||
_connectionString = connectionString;
|
||||
_providerName = providerName;
|
||||
|
||||
_connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(_connectionString);
|
||||
_commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(_connectionString);
|
||||
|
||||
_dbProviderFactory = DbProviderFactories.GetFactory(_providerName);
|
||||
if (_dbProviderFactory == null)
|
||||
throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\".");
|
||||
_databaseType = DatabaseType.Resolve(_dbProviderFactory.GetType().Name, _providerName);
|
||||
if (_databaseType == null)
|
||||
throw new Exception($"Can't find an NPoco database type for provider name \"{_providerName}\".");
|
||||
|
||||
_sqlSyntax = GetSqlSyntaxProvider(_providerName);
|
||||
if (_sqlSyntax == null)
|
||||
throw new Exception($"Can't find a sql syntax provider for provider name \"{_providerName}\".");
|
||||
|
||||
// ensure we have only 1 set of mappers, and 1 PocoDataFactory, for all database
|
||||
// so that everything NPoco is properly cached for the lifetime of the application
|
||||
_pocoMappers = new NPoco.MapperCollection { new PocoMapper() };
|
||||
var factory = new FluentPocoDataFactory(GetPocoDataFactoryResolver);
|
||||
_pocoDataFactory = factory;
|
||||
var config = new FluentConfig(xmappers => factory);
|
||||
|
||||
// create the database factory
|
||||
_npocoDatabaseFactory = DatabaseFactory.Config(x => x
|
||||
.UsingDatabase(CreateDatabaseInstance) // creating UmbracoDatabase instances
|
||||
.WithFluentConfig(config)); // with proper configuration
|
||||
|
||||
if (_npocoDatabaseFactory == null) throw new NullReferenceException("The call to UmbracoDatabaseFactory.Config yielded a null UmbracoDatabaseFactory instance.");
|
||||
|
||||
SqlContext = new SqlContext(_sqlSyntax, _databaseType, _pocoDataFactory, _mappers);
|
||||
|
||||
_logger.Debug<UmbracoDatabaseFactory>("Configured.");
|
||||
Configured = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_lock.IsWriteLockHeld)
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
// rest to be lazy-initialized
|
||||
}
|
||||
|
||||
private void EnsureInitialized()
|
||||
{
|
||||
LazyInitializer.EnsureInitialized(ref _sqlContext, ref _initialized, ref _lock, Initialize);
|
||||
}
|
||||
|
||||
private SqlContext Initialize()
|
||||
{
|
||||
_logger.Debug<UmbracoDatabaseFactory>("Initializing.");
|
||||
|
||||
if (_connectionString.IsNullOrWhiteSpace()) throw new InvalidOperationException("The factory has not been configured with a proper connection string.");
|
||||
if (_providerName.IsNullOrWhiteSpace()) throw new InvalidOperationException("The factory has not been configured with a proper provider name.");
|
||||
|
||||
// cannot initialize without being able to talk to the database
|
||||
if (!DbConnectionExtensions.IsConnectionAvailable(_connectionString, _providerName))
|
||||
throw new Exception("Cannot connect to the database.");
|
||||
|
||||
_connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(_connectionString);
|
||||
_commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(_connectionString);
|
||||
|
||||
_dbProviderFactory = DbProviderFactories.GetFactory(_providerName);
|
||||
if (_dbProviderFactory == null)
|
||||
throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\".");
|
||||
_databaseType = DatabaseType.Resolve(_dbProviderFactory.GetType().Name, _providerName);
|
||||
if (_databaseType == null)
|
||||
throw new Exception($"Can't find an NPoco database type for provider name \"{_providerName}\".");
|
||||
|
||||
_sqlSyntax = GetSqlSyntaxProvider(_providerName);
|
||||
if (_sqlSyntax == null)
|
||||
throw new Exception($"Can't find a sql syntax provider for provider name \"{_providerName}\".");
|
||||
|
||||
if (_databaseType.IsSqlServer())
|
||||
UpdateSqlServerDatabaseType();
|
||||
|
||||
// ensure we have only 1 set of mappers, and 1 PocoDataFactory, for all database
|
||||
// so that everything NPoco is properly cached for the lifetime of the application
|
||||
_pocoMappers = new NPoco.MapperCollection { new PocoMapper() };
|
||||
var factory = new FluentPocoDataFactory(GetPocoDataFactoryResolver);
|
||||
_pocoDataFactory = factory;
|
||||
var config = new FluentConfig(xmappers => factory);
|
||||
|
||||
// create the database factory
|
||||
_npocoDatabaseFactory = DatabaseFactory.Config(x => x
|
||||
.UsingDatabase(CreateDatabaseInstance) // creating UmbracoDatabase instances
|
||||
.WithFluentConfig(config)); // with proper configuration
|
||||
|
||||
if (_npocoDatabaseFactory == null)
|
||||
throw new NullReferenceException("The call to UmbracoDatabaseFactory.Config yielded a null UmbracoDatabaseFactory instance.");
|
||||
|
||||
_logger.Debug<UmbracoDatabaseFactory>("Initialized.");
|
||||
|
||||
return new SqlContext(_sqlSyntax, _databaseType, _pocoDataFactory, _mappers);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUmbracoDatabase CreateDatabase()
|
||||
{
|
||||
// must be initialized to create a database
|
||||
EnsureInitialized();
|
||||
return (IUmbracoDatabase) _npocoDatabaseFactory.GetDatabase();
|
||||
}
|
||||
|
||||
@@ -260,22 +280,6 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
}
|
||||
|
||||
// ensures that the database is configured, else throws
|
||||
private void EnsureConfigured()
|
||||
{
|
||||
_lock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
if (Configured == false)
|
||||
throw new InvalidOperationException("Not configured.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_lock.IsReadLockHeld)
|
||||
_lock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
// method used by NPoco's UmbracoDatabaseFactory to actually create the database instance
|
||||
private UmbracoDatabase CreateDatabaseInstance()
|
||||
{
|
||||
@@ -292,7 +296,7 @@ namespace Umbraco.Core.Persistence
|
||||
//var db = _umbracoDatabaseAccessor.UmbracoDatabase;
|
||||
//_umbracoDatabaseAccessor.UmbracoDatabase = null;
|
||||
//db?.Dispose();
|
||||
Configured = false;
|
||||
Volatile.Write(ref _initialized, false);
|
||||
}
|
||||
|
||||
// during tests, the thread static var can leak between tests
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </summary>
|
||||
/// <param name="propertyType">The property type.</param>
|
||||
/// <returns>A value indicating whether the converter supports a property type.</returns>
|
||||
bool IsConverter(PublishedPropertyType propertyType);
|
||||
bool IsConverter(IPublishedPropertyType propertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a value is an actual value, or not a value.
|
||||
@@ -36,14 +36,14 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <returns>The CLR type of values returned by the converter.</returns>
|
||||
/// <remarks>Some of the CLR types may be generated, therefore this method cannot directly return
|
||||
/// a Type object (which may not exist yet). In which case it needs to return a ModelType instance.</remarks>
|
||||
Type GetPropertyValueType(PublishedPropertyType propertyType);
|
||||
Type GetPropertyValueType(IPublishedPropertyType propertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property cache level.
|
||||
/// </summary>
|
||||
/// <param name="propertyType">The property type.</param>
|
||||
/// <returns>The property cache level.</returns>
|
||||
PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType);
|
||||
PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a property source value to an intermediate value.
|
||||
@@ -64,7 +64,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// strings, and xml-whitespace strings appropriately, ie it should know whether to preserve
|
||||
/// white spaces.</para>
|
||||
/// </remarks>
|
||||
object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview);
|
||||
object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a property intermediate value to an Object value.
|
||||
@@ -83,7 +83,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// passed to eg a PublishedFragment constructor. It is used by the fragment and the properties to manage
|
||||
/// the cache levels of property values. It is not meant to be used by the converter.</para>
|
||||
/// </remarks>
|
||||
object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
|
||||
object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a property intermediate value to an XPath value.
|
||||
@@ -107,6 +107,6 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// passed to eg a PublishedFragment constructor. It is used by the fragment and the properties to manage
|
||||
/// the cache levels of property values. It is not meant to be used by the converter.</para>
|
||||
/// </remarks>
|
||||
object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
|
||||
object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </summary>
|
||||
public abstract class PropertyValueConverterBase : IPropertyValueConverter
|
||||
{
|
||||
public virtual bool IsConverter(PublishedPropertyType propertyType)
|
||||
public virtual bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> false;
|
||||
|
||||
public virtual bool? IsValue(object value, PropertyValueLevel level)
|
||||
@@ -30,19 +30,19 @@ namespace Umbraco.Core.PropertyEditors
|
||||
return value != null && (!(value is string) || string.IsNullOrWhiteSpace((string) value) == false);
|
||||
}
|
||||
|
||||
public virtual Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public virtual Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (object);
|
||||
|
||||
public virtual PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public virtual PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Snapshot;
|
||||
|
||||
public virtual object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public virtual object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
=> source;
|
||||
|
||||
public virtual object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public virtual object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
=> inter;
|
||||
|
||||
public virtual object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public virtual object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
=> inter?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,16 +9,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class CheckboxListValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.CheckBoxList);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (IEnumerable<string>);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
{
|
||||
var sourceString = source?.ToString() ?? string.Empty;
|
||||
|
||||
|
||||
@@ -8,16 +8,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class ColorPickerValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.ColorPicker);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> UseLabel(propertyType) ? typeof(PickedColor) : typeof(string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
var useLabel = UseLabel(propertyType);
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
return ssource;
|
||||
}
|
||||
|
||||
private bool UseLabel(PublishedPropertyType propertyType)
|
||||
private bool UseLabel(IPublishedPropertyType propertyType)
|
||||
{
|
||||
return ConfigurationEditor.ConfigurationAs<ColorPickerConfiguration>(propertyType.DataType.Configuration).UseLabel;
|
||||
}
|
||||
|
||||
@@ -8,16 +8,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class DatePickerValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.DateTime);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (DateTime);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return DateTime.MinValue;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
|
||||
// default ConvertSourceToObject just returns source ie a DateTime value
|
||||
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a DateTime already
|
||||
return XmlConvert.ToString((DateTime) inter, XmlDateTimeSerializationMode.Unspecified);
|
||||
|
||||
@@ -7,16 +7,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class DecimalValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> Constants.PropertyEditors.Aliases.Decimal.Equals(propertyType.EditorAlias);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (decimal);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class EmailAddressValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.EmailAddress);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
{
|
||||
return source?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
@@ -28,16 +28,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.Grid);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (JToken);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return null;
|
||||
var sourceString = source.ToString();
|
||||
|
||||
@@ -14,19 +14,19 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
public class ImageCropperValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.ImageCropper);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (ImageCropperValue);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return null;
|
||||
var sourceString = source.ToString();
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class IntegerValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> Constants.PropertyEditors.Aliases.Integer.Equals(propertyType.EditorAlias);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (int);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
return source.TryConvertTo<int>().Result;
|
||||
}
|
||||
|
||||
@@ -31,19 +31,19 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
/// </summary>
|
||||
/// <param name="propertyType"></param>
|
||||
/// <returns></returns>
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
{
|
||||
return _propertyEditors.TryGet(propertyType.EditorAlias, out var editor)
|
||||
&& editor.GetValueEditor().ValueType.InvariantEquals(ValueTypes.Json);
|
||||
}
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (JToken);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return null;
|
||||
var sourceString = source.ToString();
|
||||
|
||||
@@ -16,10 +16,10 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class LabelValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> Constants.PropertyEditors.Aliases.Label.Equals(propertyType.EditorAlias);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
{
|
||||
var valueType = ConfigurationEditor.ConfigurationAs<LabelConfiguration>(propertyType.DataType.Configuration);
|
||||
switch (valueType.ValueType)
|
||||
@@ -40,10 +40,10 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
}
|
||||
}
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
var valueType = ConfigurationEditor.ConfigurationAs<LabelConfiguration>(propertyType.DataType.Configuration);
|
||||
switch (valueType.ValueType)
|
||||
|
||||
@@ -7,17 +7,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class MarkdownEditorValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> Constants.PropertyEditors.Aliases.MarkdownEditor.Equals(propertyType.EditorAlias);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (IHtmlString);
|
||||
|
||||
// PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// in xml a string is: string
|
||||
// in the database a string is: string
|
||||
@@ -25,13 +25,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
return source;
|
||||
}
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a string (or null) already
|
||||
return new HtmlString(inter == null ? string.Empty : (string) inter);
|
||||
}
|
||||
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a string (or null) already
|
||||
return inter?.ToString() ?? string.Empty;
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class MemberGroupPickerValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.MemberGroupPicker);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
return source?.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
+5
-5
@@ -9,18 +9,18 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class MultipleTextStringValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> Constants.PropertyEditors.Aliases.MultipleTextstring.Equals(propertyType.EditorAlias);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (IEnumerable<string>);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
private static readonly string[] NewLineDelimiters = { "\r\n", "\r", "\n" };
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// data is (both in database and xml):
|
||||
// <keyFeatureList>
|
||||
@@ -58,7 +58,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
: values.ToArray();
|
||||
}
|
||||
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
var d = new XmlDocument();
|
||||
var e = d.CreateElement("values");
|
||||
|
||||
@@ -22,16 +22,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
Constants.PropertyEditors.Aliases.MultiNodeTreePicker
|
||||
};
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> Aliases.Contains(propertyType.EditorAlias);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
return source?.ToString();
|
||||
}
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class RadioButtonListValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.RadioButtonList);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
var attempt = source.TryConvertTo<string>();
|
||||
|
||||
|
||||
@@ -18,16 +18,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
_dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService));
|
||||
}
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.Slider);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> IsRangeDataType(propertyType.DataType.Id) ? typeof (Range<decimal>) : typeof (decimal);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
{
|
||||
if (source == null)
|
||||
return null;
|
||||
|
||||
@@ -19,16 +19,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
_dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService));
|
||||
}
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.Tags);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (IEnumerable<string>);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return Array.Empty<string>();
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
return source.ToString().Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
{
|
||||
return (string[]) source;
|
||||
}
|
||||
|
||||
@@ -13,16 +13,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
Constants.PropertyEditors.Aliases.TextArea
|
||||
};
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> PropertyTypeAliases.Contains(propertyType.EditorAlias);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// in xml a string is: string
|
||||
// in the database a string is: string
|
||||
@@ -30,13 +30,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
return source;
|
||||
}
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a string (or null) already
|
||||
return inter ?? string.Empty;
|
||||
}
|
||||
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a string (or null) already
|
||||
return inter;
|
||||
|
||||
@@ -10,17 +10,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class TinyMceValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce;
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (IHtmlString);
|
||||
|
||||
// PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// in xml a string is: string
|
||||
// in the database a string is: string
|
||||
@@ -28,13 +28,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
return source;
|
||||
}
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a string (or null) already
|
||||
return new HtmlString(inter == null ? string.Empty : (string)inter);
|
||||
}
|
||||
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a string (or null) already
|
||||
return inter;
|
||||
|
||||
@@ -9,16 +9,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class UploadPropertyConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.UploadField);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
public override object ConvertIntermediateToObject(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview)
|
||||
{
|
||||
return source?.ToString() ?? "";
|
||||
}
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class YesNoValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
public override bool IsConverter(IPublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias == Constants.PropertyEditors.Aliases.Boolean;
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
public override Type GetPropertyValueType(IPublishedPropertyType propertyType)
|
||||
=> typeof (bool);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// in xml a boolean is: string
|
||||
// in the database a boolean is: string "1" or "0" or empty
|
||||
@@ -49,7 +49,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
|
||||
// default ConvertSourceToObject just returns source ie a boolean value
|
||||
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
public override object ConvertIntermediateToXPath(IPublishedElement owner, IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a boolean already
|
||||
return (bool)inter ? "1" : "0";
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static class PublishedContentExtensions
|
||||
{
|
||||
private static IVariationContextAccessor VariationContextAccessor => Current.VariationContextAccessor;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the content has a culture.
|
||||
/// </summary>
|
||||
/// <remarks>Culture is case-insensitive.</remarks>
|
||||
public static bool HasCulture(this IPublishedContent content, string culture)
|
||||
=> content.Cultures.ContainsKey(culture ?? string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the content is invariant, or has a culture.
|
||||
/// </summary>
|
||||
/// <remarks>Culture is case-insensitive.</remarks>
|
||||
public static bool IsInvariantOrHasCulture(this IPublishedContent content, string culture)
|
||||
=> !content.ContentType.VariesByCulture() || content.Cultures.ContainsKey(culture ?? "");
|
||||
|
||||
/// <summary>
|
||||
/// Filters a sequence of <see cref="IPublishedContent"/> to return invariant items, and items that are published for the specified culture.
|
||||
/// </summary>
|
||||
/// <param name="contents">The content items.</param>
|
||||
/// <param name="culture">The specific culture to filter for. If null is used the current culture is used. (Default is null).</param>
|
||||
internal static IEnumerable<T> WhereIsInvariantOrHasCulture<T>(this IEnumerable<T> contents, string culture = null)
|
||||
where T : class, IPublishedContent
|
||||
{
|
||||
if (contents == null) throw new ArgumentNullException(nameof(contents));
|
||||
|
||||
culture = culture ?? Current.VariationContextAccessor.VariationContext?.Culture ?? "";
|
||||
|
||||
// either does not vary by culture, or has the specified culture
|
||||
return contents.Where(x => !x.ContentType.VariesByCulture() || HasCulture(x, culture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the content item.
|
||||
/// </summary>
|
||||
/// <param name="content">The content item.</param>
|
||||
/// <param name="culture">The specific culture to get the name for. If null is used the current culture is used (Default is null).</param>
|
||||
public static string Name(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
// invariant has invariant value (whatever the requested culture)
|
||||
if (!content.ContentType.VariesByCulture())
|
||||
return content.Cultures.TryGetValue("", out var invariantInfos) ? invariantInfos.Name : null;
|
||||
|
||||
// handle context culture for variant
|
||||
if (culture == null)
|
||||
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
|
||||
|
||||
// get
|
||||
return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.Name : null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url segment of the content item.
|
||||
/// </summary>
|
||||
/// <param name="content">The content item.</param>
|
||||
/// <param name="culture">The specific culture to get the url segment for. If null is used the current culture is used (Default is null).</param>
|
||||
public static string UrlSegment(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
// invariant has invariant value (whatever the requested culture)
|
||||
if (!content.ContentType.VariesByCulture())
|
||||
return content.Cultures.TryGetValue("", out var invariantInfos) ? invariantInfos.UrlSegment : null;
|
||||
|
||||
// handle context culture for variant
|
||||
if (culture == null)
|
||||
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
|
||||
|
||||
// get
|
||||
return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.UrlSegment : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the culture date of the content item.
|
||||
/// </summary>
|
||||
/// <param name="content">The content item.</param>
|
||||
/// <param name="culture">The specific culture to get the name for. If null is used the current culture is used (Default is null).</param>
|
||||
public static DateTime CultureDate(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
// invariant has invariant value (whatever the requested culture)
|
||||
if (!content.ContentType.VariesByCulture())
|
||||
return content.UpdateDate;
|
||||
|
||||
// handle context culture for variant
|
||||
if (culture == null)
|
||||
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
|
||||
|
||||
// get
|
||||
return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.Date : DateTime.MinValue;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children of the content item.
|
||||
/// </summary>
|
||||
/// <param name="content">The content item.</param>
|
||||
/// <param name="culture">The specific culture to get the url children for. If null is used the current culture is used (Default is null).</param>
|
||||
/// <remarks>
|
||||
/// <para>Gets children that are available for the specified culture.</para>
|
||||
/// <para>Children are sorted by their sortOrder.</para>
|
||||
/// <para>The '*' culture and supported and returns everything.</para>
|
||||
/// </remarks>
|
||||
public static IEnumerable<IPublishedContent> Children(this IPublishedContent content, string culture = null)
|
||||
{
|
||||
// invariant has invariant value (whatever the requested culture)
|
||||
if (!content.ContentType.VariesByCulture() && culture != "*")
|
||||
culture = "";
|
||||
|
||||
// handle context culture for variant
|
||||
if (culture == null)
|
||||
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
|
||||
|
||||
var children = content.ChildrenForAllCultures;
|
||||
return culture == "*"
|
||||
? children
|
||||
: children.Where(x => x.IsInvariantOrHasCulture(culture));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ namespace Umbraco.Core.Runtime
|
||||
composition.RegisterUnique<ManifestParser>();
|
||||
|
||||
// register our predefined validators
|
||||
composition.WithCollectionBuilder<ManifestValueValidatorCollectionBuilder>()
|
||||
composition.ManifestValueValidators()
|
||||
.Add<RequiredValidator>()
|
||||
.Add<RegexValidator>()
|
||||
.Add<DelimitedValueValidator>()
|
||||
@@ -66,6 +66,9 @@ namespace Umbraco.Core.Runtime
|
||||
.Add<IntegerValidator>()
|
||||
.Add<DecimalValidator>();
|
||||
|
||||
// register the manifest filter collection builder (collection is empty by default)
|
||||
composition.ManifestFilters();
|
||||
|
||||
// properties and parameters derive from data editors
|
||||
composition.WithCollectionBuilder<DataEditorCollectionBuilder>()
|
||||
.Add(() => composition.TypeLoader.GetDataEditors());
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace Umbraco.Core.Services.Changes
|
||||
{
|
||||
internal static class TreeChangeExtensions
|
||||
public static class TreeChangeExtensions
|
||||
{
|
||||
public static TreeChange<TItem>.EventArgs ToEventArgs<TItem>(this IEnumerable<TreeChange<TItem>> changes)
|
||||
internal static TreeChange<TItem>.EventArgs ToEventArgs<TItem>(this IEnumerable<TreeChange<TItem>> changes)
|
||||
{
|
||||
return new TreeChange<TItem>.EventArgs(changes);
|
||||
}
|
||||
|
||||
@@ -15,92 +15,40 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="id">The identifier of the entity.</param>
|
||||
IEntitySlim Get(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier of the entity.</param>
|
||||
/// <param name="full">A value indicating whether to load a light entity, or the full entity.</param>
|
||||
/// <remarks>Returns either a <see cref="IEntitySlim"/>, or an actual entity, depending on <paramref name="full"/>.</remarks>
|
||||
IUmbracoEntity Get(int id, bool full);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key of the entity.</param>
|
||||
IEntitySlim Get(Guid key);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key of the entity.</param>
|
||||
/// <param name="full">A value indicating whether to load a light entity, or the full entity.</param>
|
||||
/// <remarks>Returns either a <see cref="IEntitySlim"/>, or an actual entity, depending on <paramref name="full"/>.</remarks>
|
||||
IUmbracoEntity Get(Guid key, bool full);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier of the entity.</param>
|
||||
/// <param name="objectType">The object type of the entity.</param>
|
||||
IEntitySlim Get(int id, UmbracoObjectTypes objectType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier of the entity.</param>
|
||||
/// <param name="objectType">The object type of the entity.</param>
|
||||
/// <param name="full">A value indicating whether to load a light entity, or the full entity.</param>
|
||||
/// <remarks>Returns either a <see cref="IEntitySlim"/>, or an actual entity, depending on <paramref name="full"/>.</remarks>
|
||||
IUmbracoEntity Get(int id, UmbracoObjectTypes objectType, bool full);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key of the entity.</param>
|
||||
/// <param name="objectType">The object type of the entity.</param>
|
||||
IEntitySlim Get(Guid key, UmbracoObjectTypes objectType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key of the entity.</param>
|
||||
/// <param name="objectType">The object type of the entity.</param>
|
||||
/// <param name="full">A value indicating whether to load a light entity, or the full entity.</param>
|
||||
/// <remarks>Returns either a <see cref="IEntitySlim"/>, or an actual entity, depending on <paramref name="full"/>.</remarks>
|
||||
IUmbracoEntity Get(Guid key, UmbracoObjectTypes objectType, bool full);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type used to determine the object type of the entity.</typeparam>
|
||||
/// <param name="id">The identifier of the entity.</param>
|
||||
IEntitySlim Get<T>(int id) where T : IUmbracoEntity;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type used to determine the object type of the entity.</typeparam>
|
||||
/// <param name="id">The identifier of the entity.</param>
|
||||
/// <param name="full">A value indicating whether to load a light entity, or the full entity.</param>
|
||||
/// <remarks>Returns either a <see cref="IEntitySlim"/>, or an actual entity, depending on <paramref name="full"/>.</remarks>
|
||||
IUmbracoEntity Get<T>(int id, bool full) where T : IUmbracoEntity;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type used to determine the object type of the entity.</typeparam>
|
||||
/// <param name="key">The unique key of the entity.</param>
|
||||
IEntitySlim Get<T>(Guid key) where T : IUmbracoEntity;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type used to determine the object type of the entity.</typeparam>
|
||||
/// <param name="key">The unique key of the entity.</param>
|
||||
/// <param name="full">A value indicating whether to load a light entity, or the full entity.</param>
|
||||
/// <remarks>Returns either a <see cref="IEntitySlim"/>, or an actual entity, depending on <paramref name="full"/>.</remarks>
|
||||
IUmbracoEntity Get<T>(Guid key, bool full) where T : IUmbracoEntity;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether an entity exists.
|
||||
/// </summary>
|
||||
|
||||
@@ -142,52 +142,43 @@ namespace Umbraco.Core.Services
|
||||
/// Gets the Child object from a Relation as an <see cref="IUmbracoEntity"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve child object from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An <see cref="IUmbracoEntity"/></returns>
|
||||
IUmbracoEntity GetChildEntityFromRelation(IRelation relation, bool loadBaseType = false);
|
||||
IUmbracoEntity GetChildEntityFromRelation(IRelation relation);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent object from a Relation as an <see cref="IUmbracoEntity"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve parent object from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An <see cref="IUmbracoEntity"/></returns>
|
||||
IUmbracoEntity GetParentEntityFromRelation(IRelation relation, bool loadBaseType = false);
|
||||
IUmbracoEntity GetParentEntityFromRelation(IRelation relation);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent and Child objects from a Relation as a <see cref="Tuple"/>"/> with <see cref="IUmbracoEntity"/>.
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve parent and child object from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>Returns a Tuple with Parent (item1) and Child (item2)</returns>
|
||||
Tuple<IUmbracoEntity, IUmbracoEntity> GetEntitiesFromRelation(IRelation relation, bool loadBaseType = false);
|
||||
Tuple<IUmbracoEntity, IUmbracoEntity> GetEntitiesFromRelation(IRelation relation);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve child objects from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
|
||||
IEnumerable<IUmbracoEntity> GetChildEntitiesFromRelations(IEnumerable<IRelation> relations, bool loadBaseType = false);
|
||||
IEnumerable<IUmbracoEntity> GetChildEntitiesFromRelations(IEnumerable<IRelation> relations);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve parent objects from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
|
||||
IEnumerable<IUmbracoEntity> GetParentEntitiesFromRelations(IEnumerable<IRelation> relations,
|
||||
bool loadBaseType = false);
|
||||
IEnumerable<IUmbracoEntity> GetParentEntitiesFromRelations(IEnumerable<IRelation> relations);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent and Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve parent and child objects from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An enumerable list of <see cref="Tuple"/> with <see cref="IUmbracoEntity"/></returns>
|
||||
IEnumerable<Tuple<IUmbracoEntity, IUmbracoEntity>> GetEntitiesFromRelations(
|
||||
IEnumerable<IRelation> relations,
|
||||
bool loadBaseType = false);
|
||||
IEnumerable<Tuple<IUmbracoEntity, IUmbracoEntity>> GetEntitiesFromRelations(IEnumerable<IRelation> relations);
|
||||
|
||||
/// <summary>
|
||||
/// Relates two objects by their entity Ids.
|
||||
|
||||
@@ -757,6 +757,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished)
|
||||
throw new InvalidOperationException("Cannot save (un)publishing content, use the dedicated SavePublished method.");
|
||||
|
||||
if (content.Name != null && content.Name.Length > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
@@ -870,6 +875,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
throw new NotSupportedException($"Culture \"{culture}\" is not supported by invariant content types.");
|
||||
}
|
||||
|
||||
if(content.Name != null && content.Name.Length > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
scope.WriteLock(Constants.Locks.ContentTree);
|
||||
@@ -900,6 +910,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
if (cultures == null) throw new ArgumentNullException(nameof(cultures));
|
||||
|
||||
if (content.Name != null && content.Name.Length > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
scope.WriteLock(Constants.Locks.ContentTree);
|
||||
@@ -1680,12 +1695,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
const int pageSize = 500;
|
||||
var page = 0;
|
||||
var total = long.MaxValue;
|
||||
while (page * pageSize < total)
|
||||
while (total > 0)
|
||||
{
|
||||
//get descendants - ordered from deepest to shallowest
|
||||
var descendants = GetPagedDescendants(content.Id, page, pageSize, out total, ordering: Ordering.By("Path", Direction.Descending));
|
||||
var descendants = GetPagedDescendants(content.Id, 0, pageSize, out total, ordering: Ordering.By("Path", Direction.Descending));
|
||||
foreach (var c in descendants)
|
||||
DoDelete(c);
|
||||
}
|
||||
@@ -1911,11 +1925,10 @@ namespace Umbraco.Core.Services.Implement
|
||||
paths[content.Id] = (parent == null ? (parentId == Constants.System.RecycleBinContent ? "-1,-20" : Constants.System.RootString) : parent.Path) + "," + content.Id;
|
||||
|
||||
const int pageSize = 500;
|
||||
var page = 0;
|
||||
var total = long.MaxValue;
|
||||
while (page * pageSize < total)
|
||||
while (total > 0)
|
||||
{
|
||||
var descendants = GetPagedDescendantsLocked(originalPath, page++, pageSize, out total, null, Ordering.By("Path", Direction.Ascending));
|
||||
var descendants = GetPagedDescendantsLocked(originalPath, 0, pageSize, out total, null, Ordering.By("Path", Direction.Ascending));
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
moves.Add(Tuple.Create(descendant, descendant.Path)); // capture original path
|
||||
|
||||
@@ -7,11 +7,9 @@ using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Services.Implement
|
||||
@@ -19,30 +17,25 @@ namespace Umbraco.Core.Services.Implement
|
||||
public class EntityService : ScopeRepositoryService, IEntityService
|
||||
{
|
||||
private readonly IEntityRepository _entityRepository;
|
||||
private readonly Dictionary<string, (UmbracoObjectTypes ObjectType, Func<int, IUmbracoEntity> GetById, Func<Guid, IUmbracoEntity> GetByKey)> _objectTypes;
|
||||
private readonly Dictionary<string, UmbracoObjectTypes> _objectTypes;
|
||||
private IQuery<IUmbracoEntity> _queryRootEntity;
|
||||
private readonly IdkMap _idkMap;
|
||||
|
||||
public EntityService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory,
|
||||
IContentService contentService, IContentTypeService contentTypeService,
|
||||
IMediaService mediaService, IMediaTypeService mediaTypeService,
|
||||
IDataTypeService dataTypeService,
|
||||
IMemberService memberService, IMemberTypeService memberTypeService, IdkMap idkMap,
|
||||
IEntityRepository entityRepository)
|
||||
public EntityService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IdkMap idkMap, IEntityRepository entityRepository)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_idkMap = idkMap;
|
||||
_entityRepository = entityRepository;
|
||||
|
||||
_objectTypes = new Dictionary<string, (UmbracoObjectTypes, Func<int, IUmbracoEntity>, Func<Guid, IUmbracoEntity>)>
|
||||
_objectTypes = new Dictionary<string, UmbracoObjectTypes>
|
||||
{
|
||||
{ typeof (IDataType).FullName, (UmbracoObjectTypes.DataType, dataTypeService.GetDataType, dataTypeService.GetDataType) },
|
||||
{ typeof (IContent).FullName, (UmbracoObjectTypes.Document, contentService.GetById, contentService.GetById) },
|
||||
{ typeof (IContentType).FullName, (UmbracoObjectTypes.DocumentType, contentTypeService.Get, contentTypeService.Get) },
|
||||
{ typeof (IMedia).FullName, (UmbracoObjectTypes.Media, mediaService.GetById, mediaService.GetById) },
|
||||
{ typeof (IMediaType).FullName, (UmbracoObjectTypes.MediaType, mediaTypeService.Get, mediaTypeService.Get) },
|
||||
{ typeof (IMember).FullName, (UmbracoObjectTypes.Member, memberService.GetById, memberService.GetByKey) },
|
||||
{ typeof (IMemberType).FullName, (UmbracoObjectTypes.MemberType, memberTypeService.Get, memberTypeService.Get) },
|
||||
{ typeof (IDataType).FullName, UmbracoObjectTypes.DataType },
|
||||
{ typeof (IContent).FullName, UmbracoObjectTypes.Document },
|
||||
{ typeof (IContentType).FullName, UmbracoObjectTypes.DocumentType },
|
||||
{ typeof (IMedia).FullName, UmbracoObjectTypes.Media },
|
||||
{ typeof (IMediaType).FullName, UmbracoObjectTypes.MediaType },
|
||||
{ typeof (IMember).FullName, UmbracoObjectTypes.Member },
|
||||
{ typeof (IMemberType).FullName, UmbracoObjectTypes.MemberType },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,162 +47,68 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
#endregion
|
||||
|
||||
// gets the getters, throws if not supported
|
||||
private (UmbracoObjectTypes ObjectType, Func<int, IUmbracoEntity> GetById, Func<Guid, IUmbracoEntity> GetByKey) GetGetters(Type type)
|
||||
// gets the object type, throws if not supported
|
||||
private UmbracoObjectTypes GetObjectType(Type type)
|
||||
{
|
||||
if (type?.FullName == null || !_objectTypes.TryGetValue(type.FullName, out var getters))
|
||||
if (type?.FullName == null || !_objectTypes.TryGetValue(type.FullName, out var objType))
|
||||
throw new NotSupportedException($"Type \"{type?.FullName ?? "<null>"}\" is not supported here.");
|
||||
return getters;
|
||||
return objType;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEntitySlim Get(int id)
|
||||
{
|
||||
return (IEntitySlim) Get(id, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUmbracoEntity Get(int id, bool full)
|
||||
{
|
||||
if (!full)
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
// get the light entity
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _entityRepository.Get(id);
|
||||
}
|
||||
return _entityRepository.Get(id);
|
||||
}
|
||||
|
||||
// get the full entity
|
||||
var objectType = GetObjectType(id);
|
||||
var entityType = objectType.GetClrType();
|
||||
var getters = GetGetters(entityType);
|
||||
return getters.GetById(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEntitySlim Get(Guid key)
|
||||
{
|
||||
return (IEntitySlim) Get(key, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUmbracoEntity Get(Guid key, bool full)
|
||||
{
|
||||
if (!full)
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
// get the light entity
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _entityRepository.Get(key);
|
||||
}
|
||||
return _entityRepository.Get(key);
|
||||
}
|
||||
|
||||
// get the full entity
|
||||
var objectType = GetObjectType(key);
|
||||
var entityType = objectType.GetClrType();
|
||||
var getters = GetGetters(entityType);
|
||||
return getters.GetByKey(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IEntitySlim Get(int id, UmbracoObjectTypes objectType)
|
||||
{
|
||||
return (IEntitySlim) Get(id, objectType, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IUmbracoEntity Get(int id, UmbracoObjectTypes objectType, bool full)
|
||||
{
|
||||
if (!full)
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
// get the light entity
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _entityRepository.Get(id, objectType.GetGuid());
|
||||
}
|
||||
return _entityRepository.Get(id, objectType.GetGuid());
|
||||
}
|
||||
|
||||
// get the full entity
|
||||
var entityType = objectType.GetClrType();
|
||||
var getters = GetGetters(entityType);
|
||||
return getters.GetById(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEntitySlim Get(Guid key, UmbracoObjectTypes objectType)
|
||||
{
|
||||
return (IEntitySlim) Get(key, objectType, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUmbracoEntity Get(Guid key, UmbracoObjectTypes objectType, bool full)
|
||||
{
|
||||
if (!full)
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
// get the light entity
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _entityRepository.Get(key, objectType.GetGuid());
|
||||
}
|
||||
return _entityRepository.Get(key, objectType.GetGuid());
|
||||
}
|
||||
|
||||
// get the full entity
|
||||
var entityType = objectType.GetClrType();
|
||||
var getters = GetGetters(entityType);
|
||||
return getters.GetByKey(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IEntitySlim Get<T>(int id)
|
||||
where T : IUmbracoEntity
|
||||
{
|
||||
return (IEntitySlim) Get<T>(id, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IUmbracoEntity Get<T>(int id, bool full)
|
||||
where T : IUmbracoEntity
|
||||
{
|
||||
if (!full)
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
// get the light entity
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _entityRepository.Get(id);
|
||||
}
|
||||
return _entityRepository.Get(id);
|
||||
}
|
||||
|
||||
// get the full entity
|
||||
var entityType = typeof (T);
|
||||
var getters = GetGetters(entityType);
|
||||
return getters.GetById(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IEntitySlim Get<T>(Guid key)
|
||||
where T : IUmbracoEntity
|
||||
{
|
||||
return (IEntitySlim) Get<T>(key, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUmbracoEntity Get<T>(Guid key, bool full)
|
||||
where T : IUmbracoEntity
|
||||
{
|
||||
if (!full)
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
// get the light entity
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
return _entityRepository.Get(key);
|
||||
}
|
||||
return _entityRepository.Get(key);
|
||||
}
|
||||
|
||||
// get the full entity
|
||||
var entityType = typeof (T);
|
||||
var getters = GetGetters(entityType);
|
||||
return getters.GetByKey(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -240,8 +139,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
where T : IUmbracoEntity
|
||||
{
|
||||
var entityType = typeof (T);
|
||||
var getters = GetGetters(entityType);
|
||||
var objectType = getters.ObjectType;
|
||||
var objectType = GetObjectType(entityType);
|
||||
var objectTypeId = objectType.GetGuid();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -261,7 +159,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
if (entityType == null)
|
||||
throw new NotSupportedException($"Type \"{objectType}\" is not supported here.");
|
||||
|
||||
GetGetters(entityType);
|
||||
GetObjectType(entityType);
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
@@ -277,7 +175,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
public virtual IEnumerable<IEntitySlim> GetAll(Guid objectType, params int[] ids)
|
||||
{
|
||||
var entityType = ObjectTypes.GetClrType(objectType);
|
||||
GetGetters(entityType);
|
||||
GetObjectType(entityType);
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
@@ -290,8 +188,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
where T : IUmbracoEntity
|
||||
{
|
||||
var entityType = typeof (T);
|
||||
var getters = GetGetters(entityType);
|
||||
var objectType = getters.ObjectType;
|
||||
var objectType = GetObjectType(entityType);
|
||||
var objectTypeId = objectType.GetGuid();
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
@@ -304,7 +201,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
public IEnumerable<IEntitySlim> GetAll(UmbracoObjectTypes objectType, Guid[] keys)
|
||||
{
|
||||
var entityType = objectType.GetClrType();
|
||||
GetGetters(entityType);
|
||||
GetObjectType(entityType);
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
@@ -316,7 +213,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
public virtual IEnumerable<IEntitySlim> GetAll(Guid objectType, params Guid[] keys)
|
||||
{
|
||||
var entityType = ObjectTypes.GetClrType(objectType);
|
||||
GetGetters(entityType);
|
||||
GetObjectType(entityType);
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
@@ -377,22 +274,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of children by the parent's Id and UmbracoObjectType without adding property data
|
||||
/// </summary>
|
||||
/// <param name="parentId">Id of the parent to retrieve children for</param>
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
internal IEnumerable<IEntitySlim> GetMediaChildrenWithoutPropertyData(int parentId)
|
||||
{
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
var query = Query<IUmbracoEntity>().Where(x => x.ParentId == parentId);
|
||||
|
||||
// TODO: see https://github.com/umbraco/Umbraco-CMS/pull/3460#issuecomment-434903930 we need to not load any property data at all for media
|
||||
return ((EntityRepository)_entityRepository).GetMediaByQueryWithoutPropertyData(query);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IEnumerable<IEntitySlim> GetDescendants(int id)
|
||||
{
|
||||
@@ -578,7 +459,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
public virtual IEnumerable<TreeEntityPath> GetAllPaths(UmbracoObjectTypes objectType, params int[] ids)
|
||||
{
|
||||
var entityType = objectType.GetClrType();
|
||||
GetGetters(entityType);
|
||||
GetObjectType(entityType);
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
@@ -590,7 +471,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
public virtual IEnumerable<TreeEntityPath> GetAllPaths(UmbracoObjectTypes objectType, params Guid[] keys)
|
||||
{
|
||||
var entityType = objectType.GetClrType();
|
||||
GetGetters(entityType);
|
||||
GetObjectType(entityType);
|
||||
|
||||
using (ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
var mediaType = GetMediaType(mediaTypeAlias);
|
||||
if (mediaType == null)
|
||||
throw new ArgumentException("No media type with that alias.", nameof(mediaTypeAlias)); // causes rollback // causes rollback
|
||||
throw new ArgumentException("No media type with that alias.", nameof(mediaTypeAlias)); // causes rollback
|
||||
|
||||
var media = new Models.Media(name, parent, mediaType);
|
||||
CreateMedia(scope, media, parent, userId, false);
|
||||
@@ -227,13 +227,13 @@ namespace Umbraco.Core.Services.Implement
|
||||
// locking the media tree secures media types too
|
||||
scope.WriteLock(Constants.Locks.MediaTree);
|
||||
|
||||
var mediaType = GetMediaType(mediaTypeAlias); // + locks // + locks
|
||||
var mediaType = GetMediaType(mediaTypeAlias); // + locks
|
||||
if (mediaType == null)
|
||||
throw new ArgumentException("No media type with that alias.", nameof(mediaTypeAlias)); // causes rollback // causes rollback
|
||||
throw new ArgumentException("No media type with that alias.", nameof(mediaTypeAlias)); // causes rollback
|
||||
|
||||
var parent = parentId > 0 ? GetById(parentId) : null; // + locks // + locks
|
||||
var parent = parentId > 0 ? GetById(parentId) : null; // + locks
|
||||
if (parentId > 0 && parent == null)
|
||||
throw new ArgumentException("No media with that id.", nameof(parentId)); // causes rollback // causes rollback
|
||||
throw new ArgumentException("No media with that id.", nameof(parentId)); // causes rollback
|
||||
|
||||
var media = parentId > 0 ? new Models.Media(name, parent, mediaType) : new Models.Media(name, parentId, mediaType);
|
||||
CreateMedia(scope, media, parent, userId, true);
|
||||
@@ -261,9 +261,9 @@ namespace Umbraco.Core.Services.Implement
|
||||
// locking the media tree secures media types too
|
||||
scope.WriteLock(Constants.Locks.MediaTree);
|
||||
|
||||
var mediaType = GetMediaType(mediaTypeAlias); // + locks // + locks
|
||||
var mediaType = GetMediaType(mediaTypeAlias); // + locks
|
||||
if (mediaType == null)
|
||||
throw new ArgumentException("No media type with that alias.", nameof(mediaTypeAlias)); // causes rollback // causes rollback
|
||||
throw new ArgumentException("No media type with that alias.", nameof(mediaTypeAlias)); // causes rollback
|
||||
|
||||
var media = new Models.Media(name, parent, mediaType);
|
||||
CreateMedia(scope, media, parent, userId, true);
|
||||
@@ -645,8 +645,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
// poor man's validation?
|
||||
// poor man's validation?
|
||||
|
||||
if (string.IsNullOrWhiteSpace(media.Name))
|
||||
throw new ArgumentException("Media has no name.", nameof(media));
|
||||
|
||||
@@ -934,7 +932,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
var parent = parentId == Constants.System.Root ? null : GetById(parentId);
|
||||
if (parentId != Constants.System.Root && (parent == null || parent.Trashed))
|
||||
throw new InvalidOperationException("Parent does not exist or is trashed."); // causes rollback // causes rollback
|
||||
throw new InvalidOperationException("Parent does not exist or is trashed."); // causes rollback
|
||||
|
||||
var moveEventInfo = new MoveEventInfo<IMedia>(media, media.Path, parentId);
|
||||
var moveEventArgs = new MoveEventArgs<IMedia>(true, evtMsgs, moveEventInfo);
|
||||
@@ -947,12 +945,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
// if media was trashed, and since we're not moving to the recycle bin,
|
||||
// indicate that the trashed status should be changed to false, else just
|
||||
// leave it unchanged
|
||||
// if media was trashed, and since we're not moving to the recycle bin,
|
||||
|
||||
// indicate that the trashed status should be changed to false, else just
|
||||
|
||||
// leave it unchanged
|
||||
|
||||
var trashed = media.Trashed ? false : (bool?) null;
|
||||
|
||||
PerformMoveLocked(media, parentId, parent, userId, moves, trashed);
|
||||
@@ -1042,17 +1034,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
scope.WriteLock(Constants.Locks.MediaTree);
|
||||
|
||||
// no idea what those events are for, keep a simplified version
|
||||
|
||||
// v7 EmptyingRecycleBin and EmptiedRecycleBin events are greatly simplified since
|
||||
// each deleted items will have its own deleting/deleted events. so, files and such
|
||||
// are managed by Delete, and not here.
|
||||
|
||||
// no idea what those events are for, keep a simplified version
|
||||
// v7 EmptyingRecycleBin and EmptiedRecycleBin events are greatly simplified since
|
||||
// each deleted items will have its own deleting/deleted events. so, files and such
|
||||
|
||||
// emptying the recycle bin means deleting whatever is in there - do it properly!
|
||||
// are managed by Delete, and not here.
|
||||
// no idea what those events are for, keep a simplified version
|
||||
var args = new RecycleBinEventArgs(nodeObjectType, evtMsgs);
|
||||
|
||||
if (scope.Events.DispatchCancelable(EmptyingRecycleBin, this, args))
|
||||
@@ -1113,11 +1099,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
// if the current sort order equals that of the media we don't
|
||||
// need to update it, so just increment the sort order and continue.
|
||||
// if the current sort order equals that of the media we don't
|
||||
|
||||
// else update
|
||||
// need to update it, so just increment the sort order and continue.
|
||||
// save
|
||||
if (media.SortOrder == sortOrder)
|
||||
{
|
||||
sortOrder++;
|
||||
|
||||
@@ -285,39 +285,36 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// Gets the Child object from a Relation as an <see cref="IUmbracoEntity"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve child object from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An <see cref="IUmbracoEntity"/></returns>
|
||||
public IUmbracoEntity GetChildEntityFromRelation(IRelation relation, bool loadBaseType = false)
|
||||
public IUmbracoEntity GetChildEntityFromRelation(IRelation relation)
|
||||
{
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
|
||||
return _entityService.Get(relation.ChildId, objectType, loadBaseType);
|
||||
return _entityService.Get(relation.ChildId, objectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent object from a Relation as an <see cref="IUmbracoEntity"/>
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve parent object from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An <see cref="IUmbracoEntity"/></returns>
|
||||
public IUmbracoEntity GetParentEntityFromRelation(IRelation relation, bool loadBaseType = false)
|
||||
public IUmbracoEntity GetParentEntityFromRelation(IRelation relation)
|
||||
{
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
|
||||
return _entityService.Get(relation.ParentId, objectType, loadBaseType);
|
||||
return _entityService.Get(relation.ParentId, objectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Parent and Child objects from a Relation as a <see cref="Tuple"/>"/> with <see cref="IUmbracoEntity"/>.
|
||||
/// </summary>
|
||||
/// <param name="relation">Relation to retrieve parent and child object from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>Returns a Tuple with Parent (item1) and Child (item2)</returns>
|
||||
public Tuple<IUmbracoEntity, IUmbracoEntity> GetEntitiesFromRelation(IRelation relation, bool loadBaseType = false)
|
||||
public Tuple<IUmbracoEntity, IUmbracoEntity> GetEntitiesFromRelation(IRelation relation)
|
||||
{
|
||||
var childObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
|
||||
var parentObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
|
||||
|
||||
var child = _entityService.Get(relation.ChildId, childObjectType, loadBaseType);
|
||||
var parent = _entityService.Get(relation.ParentId, parentObjectType, loadBaseType);
|
||||
var child = _entityService.Get(relation.ChildId, childObjectType);
|
||||
var parent = _entityService.Get(relation.ParentId, parentObjectType);
|
||||
|
||||
return new Tuple<IUmbracoEntity, IUmbracoEntity>(parent, child);
|
||||
}
|
||||
@@ -326,14 +323,13 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// Gets the Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve child objects from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetChildEntitiesFromRelations(IEnumerable<IRelation> relations, bool loadBaseType = false)
|
||||
public IEnumerable<IUmbracoEntity> GetChildEntitiesFromRelations(IEnumerable<IRelation> relations)
|
||||
{
|
||||
foreach (var relation in relations)
|
||||
{
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
|
||||
yield return _entityService.Get(relation.ChildId, objectType, loadBaseType);
|
||||
yield return _entityService.Get(relation.ChildId, objectType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,14 +337,13 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// Gets the Parent objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve parent objects from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetParentEntitiesFromRelations(IEnumerable<IRelation> relations, bool loadBaseType = false)
|
||||
public IEnumerable<IUmbracoEntity> GetParentEntitiesFromRelations(IEnumerable<IRelation> relations)
|
||||
{
|
||||
foreach (var relation in relations)
|
||||
{
|
||||
var objectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
|
||||
yield return _entityService.Get(relation.ParentId, objectType, loadBaseType);
|
||||
yield return _entityService.Get(relation.ParentId, objectType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,17 +351,16 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// Gets the Parent and Child objects from a list of Relations as a list of <see cref="IUmbracoEntity"/> objects.
|
||||
/// </summary>
|
||||
/// <param name="relations">List of relations to retrieve parent and child objects from</param>
|
||||
/// <param name="loadBaseType">Optional bool to load the complete object graph when set to <c>False</c></param>
|
||||
/// <returns>An enumerable list of <see cref="Tuple"/> with <see cref="IUmbracoEntity"/></returns>
|
||||
public IEnumerable<Tuple<IUmbracoEntity, IUmbracoEntity>> GetEntitiesFromRelations(IEnumerable<IRelation> relations, bool loadBaseType = false)
|
||||
public IEnumerable<Tuple<IUmbracoEntity, IUmbracoEntity>> GetEntitiesFromRelations(IEnumerable<IRelation> relations)
|
||||
{
|
||||
foreach (var relation in relations)
|
||||
{
|
||||
var childObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ChildObjectType);
|
||||
var parentObjectType = ObjectTypes.GetUmbracoObjectType(relation.RelationType.ParentObjectType);
|
||||
|
||||
var child = _entityService.Get(relation.ChildId, childObjectType, loadBaseType);
|
||||
var parent = _entityService.Get(relation.ParentId, parentObjectType, loadBaseType);
|
||||
var child = _entityService.Get(relation.ChildId, childObjectType);
|
||||
var parent = _entityService.Get(relation.ParentId, parentObjectType);
|
||||
|
||||
yield return new Tuple<IUmbracoEntity, IUmbracoEntity>(parent, child);
|
||||
}
|
||||
|
||||
@@ -83,10 +83,10 @@ namespace Umbraco.Core.Services
|
||||
internal static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text)
|
||||
{
|
||||
var cultureDictionary = CultureDictionary;
|
||||
return UmbracoDictionaryTranslate(text, cultureDictionary);
|
||||
return manager.UmbracoDictionaryTranslate(text, cultureDictionary);
|
||||
}
|
||||
|
||||
private static string UmbracoDictionaryTranslate(string text, ICultureDictionary cultureDictionary)
|
||||
private static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text, ICultureDictionary cultureDictionary)
|
||||
{
|
||||
if (text == null)
|
||||
return null;
|
||||
@@ -95,7 +95,14 @@ namespace Umbraco.Core.Services
|
||||
return text;
|
||||
|
||||
text = text.Substring(1);
|
||||
return cultureDictionary[text].IfNullOrWhiteSpace(text);
|
||||
var value = cultureDictionary[text];
|
||||
if (value.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = manager.Localize(text.Replace('_', '/'));
|
||||
return value.StartsWith("[") ? text : value;
|
||||
}
|
||||
|
||||
private static ICultureDictionary CultureDictionary
|
||||
|
||||
@@ -218,6 +218,10 @@
|
||||
<Compile Include="Composing\TypeHelper.cs" />
|
||||
<Compile Include="Composing\TypeLoader.cs" />
|
||||
<Compile Include="IO\MediaPathSchemes\UniqueMediaPathScheme.cs" />
|
||||
<Compile Include="Logging\Viewer\LogTimePeriod.cs" />
|
||||
<Compile Include="Manifest\IManifestFilter.cs" />
|
||||
<Compile Include="Manifest\ManifestFilterCollection.cs" />
|
||||
<Compile Include="Manifest\ManifestFilterCollectionBuilder.cs" />
|
||||
<Compile Include="Mapping\MapperContext.cs" />
|
||||
<Compile Include="Migrations\Upgrade\Common\DeleteKeysAndIndexes.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\ContentPickerPreValueMigrator.cs" />
|
||||
@@ -249,7 +253,13 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_1_0\ConvertTinyMceAndGridMediaUrlsToLocalLink.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\FixLanguageIsoCodeLength.cs" />
|
||||
<Compile Include="Models\CultureImpact.cs" />
|
||||
<Compile Include="Models\Entities\IMediaEntitySlim.cs" />
|
||||
<Compile Include="Models\Entities\MediaEntitySlim.cs" />
|
||||
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedContentType.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedPropertyType.cs" />
|
||||
<Compile Include="PublishedContentExtensions.cs" />
|
||||
<Compile Include="Models\PublishedContent\UrlMode.cs" />
|
||||
<Compile Include="Persistence\Dtos\PropertyTypeCommonDto.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\ContentTypeCommonRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\IContentTypeCommonRepository.cs" />
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Security;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
|
||||
//TODO: This needs to be changed:
|
||||
// * Authentication cannot happen in a filter, only Authorization
|
||||
// * The filter must be an AuthorizationFilter, not an ActionFilter
|
||||
// * Authorization must be done using the Umbraco logic - it is very specific for claim checking for ASP.Net Identity
|
||||
// * Theoretically this shouldn't be required whatsoever because when we authenticate a request that has Basic Auth (i.e. for
|
||||
// VS to work, it will add the correct Claims to the Identity and it will automatically be authorized.
|
||||
//
|
||||
// we *do* have POC supporting ASP.NET identity, however they require some config on the server
|
||||
// we'll keep using this quick-and-dirty method for the time being
|
||||
|
||||
public class ApiBasicAuthFilter : System.Web.Http.Filters.ActionFilterAttribute // use the http one, not mvc, with api controllers!
|
||||
{
|
||||
private static readonly char[] Separator = ":".ToCharArray();
|
||||
private readonly string _section;
|
||||
|
||||
public ApiBasicAuthFilter(string section)
|
||||
{
|
||||
_section = section;
|
||||
}
|
||||
|
||||
public override void OnActionExecuting(HttpActionContext actionContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = Authenticate(actionContext.Request);
|
||||
if (user == null || !user.AllowedSections.Contains(_section))
|
||||
{
|
||||
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// // note - would that be a proper way to pass data to the controller?
|
||||
// // see http://stevescodingblog.co.uk/basic-authentication-with-asp-net-webapi/
|
||||
// actionContext.ControllerContext.RouteData.Values["umbraco-user"] = user;
|
||||
//}
|
||||
|
||||
base.OnActionExecuting(actionContext);
|
||||
}
|
||||
catch
|
||||
{
|
||||
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
|
||||
}
|
||||
}
|
||||
|
||||
private static IUser Authenticate(HttpRequestMessage request)
|
||||
{
|
||||
var ah = request.Headers.Authorization;
|
||||
if (ah == null || ah.Scheme != "Basic")
|
||||
return null;
|
||||
|
||||
var token = ah.Parameter;
|
||||
var credentials = Encoding.ASCII
|
||||
.GetString(Convert.FromBase64String(token))
|
||||
.Split(Separator);
|
||||
if (credentials.Length != 2)
|
||||
return null;
|
||||
|
||||
var username = ApiClient.DecodeTokenElement(credentials[0]);
|
||||
var password = ApiClient.DecodeTokenElement(credentials[1]);
|
||||
|
||||
var providerKey = UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider;
|
||||
var provider = Membership.Providers[providerKey];
|
||||
if (provider == null || !provider.ValidateUser(username, password))
|
||||
return null;
|
||||
var user = Current.Services.UserService.GetByUsername(username);
|
||||
if (!user.IsApproved || user.IsLockedOut)
|
||||
return null;
|
||||
return user;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
public class ApiClient
|
||||
{
|
||||
private readonly string _url;
|
||||
private readonly string _user;
|
||||
private readonly string _password;
|
||||
|
||||
private readonly JsonMediaTypeFormatter _formatter;
|
||||
private readonly MediaTypeFormatter[] _formatters;
|
||||
|
||||
// fixme hardcoded?
|
||||
// could be options - but we cannot "discover" them as the API client runs outside of the web app
|
||||
// in addition, anything that references the controller forces API clients to reference Umbraco.Core
|
||||
private const string ApiControllerUrl = "/Umbraco/BackOffice/ModelsBuilder/ModelsBuilderApi/";
|
||||
|
||||
public ApiClient(string url, string user, string password)
|
||||
{
|
||||
_url = url.TrimEnd('/');
|
||||
_user = user;
|
||||
_password = password;
|
||||
|
||||
_formatter = new JsonMediaTypeFormatter();
|
||||
_formatters = new MediaTypeFormatter[] { _formatter };
|
||||
}
|
||||
|
||||
private void SetBaseAddress(HttpClient client, string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.BaseAddress = new Uri(url);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new UriFormatException($"Invalid URI: the format of the URI \"{url}\" could not be determined.");
|
||||
}
|
||||
}
|
||||
|
||||
public void ValidateClientVersion()
|
||||
{
|
||||
// FIXME - add proxys support
|
||||
|
||||
var hch = new HttpClientHandler();
|
||||
|
||||
using (var client = new HttpClient(hch))
|
||||
{
|
||||
SetBaseAddress(client, _url);
|
||||
Authorize(client);
|
||||
|
||||
var data = new ValidateClientVersionData
|
||||
{
|
||||
ClientVersion = ApiVersion.Current.Version,
|
||||
MinServerVersionSupportingClient = ApiVersion.Current.MinServerVersionSupportingClient,
|
||||
};
|
||||
|
||||
var result = client.PostAsync(_url + ApiControllerUrl + nameof(ModelsBuilderApiController.ValidateClientVersion),
|
||||
data, _formatter).Result;
|
||||
|
||||
// this is not providing enough details in case of an error - do our own reporting
|
||||
//result.EnsureSuccessStatusCode();
|
||||
EnsureSuccess(result);
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary<string, string> GetModels(Dictionary<string, string> ourFiles, string modelsNamespace)
|
||||
{
|
||||
// FIXME - add proxys support
|
||||
|
||||
var hch = new HttpClientHandler();
|
||||
|
||||
//hch.Proxy = new WebProxy("path.to.proxy", 8888);
|
||||
//hch.UseProxy = true;
|
||||
|
||||
using (var client = new HttpClient(hch))
|
||||
{
|
||||
SetBaseAddress(client, _url);
|
||||
Authorize(client);
|
||||
|
||||
var data = new GetModelsData
|
||||
{
|
||||
Namespace = modelsNamespace,
|
||||
ClientVersion = ApiVersion.Current.Version,
|
||||
MinServerVersionSupportingClient = ApiVersion.Current.MinServerVersionSupportingClient,
|
||||
Files = ourFiles
|
||||
};
|
||||
|
||||
var result = client.PostAsync(_url + ApiControllerUrl + nameof(ModelsBuilderApiController.GetModels),
|
||||
data, _formatter).Result;
|
||||
|
||||
// this is not providing enough details in case of an error - do our own reporting
|
||||
//result.EnsureSuccessStatusCode();
|
||||
EnsureSuccess(result);
|
||||
|
||||
var genFiles = result.Content.ReadAsAsync<IDictionary<string, string>>(_formatters).Result;
|
||||
return genFiles;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureSuccess(HttpResponseMessage result)
|
||||
{
|
||||
if (result.IsSuccessStatusCode) return;
|
||||
|
||||
var text = result.Content.ReadAsStringAsync().Result;
|
||||
throw new Exception($"Response status code does not indicate success ({result.StatusCode})\n{text}");
|
||||
}
|
||||
|
||||
private void Authorize(HttpClient client)
|
||||
{
|
||||
AuthorizeBasic(client);
|
||||
}
|
||||
|
||||
// fixme - for the time being, we don't cache the token and we auth on each API call
|
||||
// not used at the moment
|
||||
/*
|
||||
private void AuthorizeIdentity(HttpClient client)
|
||||
{
|
||||
var formData = new FormUrlEncodedContent(new[]
|
||||
{
|
||||
new KeyValuePair<string, string>("grant_type", "password"),
|
||||
new KeyValuePair<string, string>("userName", _user),
|
||||
new KeyValuePair<string, string>("password", _password),
|
||||
});
|
||||
|
||||
var result = client.PostAsync(_url + UmbracoOAuthTokenUrl, formData).Result;
|
||||
|
||||
EnsureSuccess(result);
|
||||
|
||||
var token = result.Content.ReadAsAsync<TokenData>(_formatters).Result;
|
||||
if (token.TokenType != "bearer")
|
||||
throw new Exception($"Received invalid token type \"{token.TokenType}\", expected \"bearer\".");
|
||||
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
|
||||
}
|
||||
*/
|
||||
|
||||
private void AuthorizeBasic(HttpClient client)
|
||||
{
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
|
||||
Convert.ToBase64String(Encoding.UTF8.GetBytes(EncodeTokenElement(_user) + ':' + EncodeTokenElement(_password))));
|
||||
}
|
||||
|
||||
public static string EncodeTokenElement(string s)
|
||||
{
|
||||
return s.Replace("%", "%a").Replace(":", "%b");
|
||||
}
|
||||
|
||||
public static string DecodeTokenElement(string s)
|
||||
{
|
||||
return s.Replace("%b", ":").Replace("%a", "%");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Umbraco.ModelsBuilder.Building;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
internal static class ApiHelper
|
||||
{
|
||||
public static Dictionary<string, string> GetModels(UmbracoServices umbracoServices, string modelsNamespace, IDictionary<string, string> files)
|
||||
{
|
||||
var typeModels = umbracoServices.GetAllTypes();
|
||||
|
||||
var parseResult = new CodeParser().ParseWithReferencedAssemblies(files);
|
||||
var builder = new TextBuilder(typeModels, parseResult, modelsNamespace);
|
||||
|
||||
var models = new Dictionary<string, string>();
|
||||
foreach (var typeModel in builder.GetModelsToGenerate())
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
builder.Generate(sb, typeModel);
|
||||
models[typeModel.ClrName] = sb.ToString();
|
||||
}
|
||||
return models;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Semver;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
@@ -8,81 +9,28 @@ namespace Umbraco.ModelsBuilder.Api
|
||||
/// </summary>
|
||||
public class ApiVersion
|
||||
{
|
||||
#region Configure
|
||||
|
||||
// indicate the minimum version of the client API that is supported by this server's API.
|
||||
// eg our Version = 4.8 but we support connections from VSIX down to version 3.2
|
||||
// => as a server, we accept connections from client down to version ...
|
||||
private static readonly Version MinClientVersionSupportedByServerConst = new Version(3, 0, 0, 0);
|
||||
|
||||
// indicate the minimum version of the server that can support the client API
|
||||
// eg our Version = 4.8 and we know we're compatible with website server down to version 3.2
|
||||
// => as a client, we tell the server down to version ... that it should accept us
|
||||
private static readonly Version MinServerVersionSupportingClientConst = new Version(3, 0, 0, 0);
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiVersion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="executingVersion">The currently executing version.</param>
|
||||
/// <param name="minClientVersionSupportedByServer">The min client version supported by the server.</param>
|
||||
/// <param name="minServerVersionSupportingClient">An opt min server version supporting the client.</param>
|
||||
internal ApiVersion(Version executingVersion, Version minClientVersionSupportedByServer, Version minServerVersionSupportingClient = null)
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
internal ApiVersion(SemVersion executingVersion)
|
||||
{
|
||||
if (executingVersion == null) throw new ArgumentNullException(nameof(executingVersion));
|
||||
if (minClientVersionSupportedByServer == null) throw new ArgumentNullException(nameof(minClientVersionSupportedByServer));
|
||||
|
||||
Version = executingVersion;
|
||||
MinClientVersionSupportedByServer = minClientVersionSupportedByServer;
|
||||
MinServerVersionSupportingClient = minServerVersionSupportingClient;
|
||||
Version = executingVersion ?? throw new ArgumentNullException(nameof(executingVersion));
|
||||
}
|
||||
|
||||
private static SemVersion CurrentAssemblyVersion
|
||||
=> SemVersion.Parse(Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently executing API version.
|
||||
/// </summary>
|
||||
public static ApiVersion Current { get; }
|
||||
= new ApiVersion(Assembly.GetExecutingAssembly().GetName().Version,
|
||||
MinClientVersionSupportedByServerConst, MinServerVersionSupportingClientConst);
|
||||
= new ApiVersion(CurrentAssemblyVersion);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the executing version of the API.
|
||||
/// </summary>
|
||||
public Version Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the min client version supported by the server.
|
||||
/// </summary>
|
||||
public Version MinClientVersionSupportedByServer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the min server version supporting the client.
|
||||
/// </summary>
|
||||
public Version MinServerVersionSupportingClient { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the API server is compatible with a client.
|
||||
/// </summary>
|
||||
/// <param name="clientVersion">The client version.</param>
|
||||
/// <param name="minServerVersionSupportingClient">An opt min server version supporting the client.</param>
|
||||
/// <remarks>
|
||||
/// <para>A client is compatible with a server if the client version is greater-or-equal _minClientVersionSupportedByServer
|
||||
/// (ie client can be older than server, up to a point) AND the client version is lower-or-equal the server version
|
||||
/// (ie client cannot be more recent than server) UNLESS the server .</para>
|
||||
/// </remarks>
|
||||
public bool IsCompatibleWith(Version clientVersion, Version minServerVersionSupportingClient = null)
|
||||
{
|
||||
// client cannot be older than server's min supported version
|
||||
if (clientVersion < MinClientVersionSupportedByServer)
|
||||
return false;
|
||||
|
||||
// if we know about this client (client is older than server), it is supported
|
||||
if (clientVersion <= Version) // if we know about this client (client older than server)
|
||||
return true;
|
||||
|
||||
// if we don't know about this client (client is newer than server),
|
||||
// give server a chance to tell client it is, indeed, ok to support it
|
||||
return minServerVersionSupportingClient != null && minServerVersionSupportingClient <= Version;
|
||||
}
|
||||
public SemVersion Version { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
[DataContract]
|
||||
public class GetModelsData : ValidateClientVersionData
|
||||
{
|
||||
[DataMember]
|
||||
public string Namespace { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public IDictionary<string, string> Files { get; set; }
|
||||
|
||||
public override bool IsValid => base.IsValid && Files != null;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
// read http://umbraco.com/follow-us/blog-archive/2014/1/17/heads-up,-breaking-change-coming-in-702-and-62.aspx
|
||||
// read http://our.umbraco.org/forum/developers/api-questions/43025-Web-API-authentication
|
||||
// UmbracoAuthorizedApiController :: /Umbraco/BackOffice/Zbu/ModelsBuilderApi/GetTypeModels
|
||||
// UmbracoApiController :: /Umbraco/Zbu/ModelsBuilderApi/GetTypeModels ?? UNLESS marked with isbackoffice
|
||||
//
|
||||
// BEWARE! the controller url is hard-coded in ModelsBuilderApi and needs to be in sync!
|
||||
|
||||
[PluginController(ControllerArea)]
|
||||
[IsBackOffice]
|
||||
//[UmbracoApplicationAuthorize(Constants.Applications.Developer)] // see ApiBasicAuthFilter - that one would be for ASP.NET identity
|
||||
public class ModelsBuilderApiController : UmbracoApiController // UmbracoAuthorizedApiController - for ASP.NET identity
|
||||
{
|
||||
public const string ControllerArea = "ModelsBuilder";
|
||||
|
||||
private readonly UmbracoServices _umbracoServices;
|
||||
|
||||
public ModelsBuilderApiController(UmbracoServices umbracoServices)
|
||||
{
|
||||
_umbracoServices = umbracoServices;
|
||||
}
|
||||
|
||||
// invoked by the API
|
||||
[System.Web.Http.HttpPost] // use the http one, not mvc, with api controllers!
|
||||
[ApiBasicAuthFilter("developer")] // have to use our own, non-cookie-based, auth
|
||||
public HttpResponseMessage ValidateClientVersion(ValidateClientVersionData data)
|
||||
{
|
||||
if (!UmbracoConfig.For.ModelsBuilder().ApiServer)
|
||||
return Request.CreateResponse(HttpStatusCode.Forbidden, "API server does not want to talk to you.");
|
||||
|
||||
if (!ModelState.IsValid || data == null || !data.IsValid)
|
||||
return Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid data.");
|
||||
|
||||
var checkResult = CheckVersion(data.ClientVersion, data.MinServerVersionSupportingClient);
|
||||
return (checkResult.Success
|
||||
? Request.CreateResponse(HttpStatusCode.OK, "OK", Configuration.Formatters.JsonFormatter)
|
||||
: checkResult.Result);
|
||||
}
|
||||
|
||||
// invoked by the API
|
||||
[System.Web.Http.HttpPost] // use the http one, not mvc, with api controllers!
|
||||
[ApiBasicAuthFilter("developer")] // have to use our own, non-cookie-based, auth
|
||||
public HttpResponseMessage GetModels(GetModelsData data)
|
||||
{
|
||||
if (!UmbracoConfig.For.ModelsBuilder().ApiServer)
|
||||
return Request.CreateResponse(HttpStatusCode.Forbidden, "API server does not want to talk to you.");
|
||||
|
||||
if (!ModelState.IsValid || data == null || !data.IsValid)
|
||||
return Request.CreateResponse(HttpStatusCode.BadRequest, "Invalid data.");
|
||||
|
||||
var checkResult = CheckVersion(data.ClientVersion, data.MinServerVersionSupportingClient);
|
||||
if (!checkResult.Success)
|
||||
return checkResult.Result;
|
||||
|
||||
var models = ApiHelper.GetModels(_umbracoServices, data.Namespace, data.Files);
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK, models, Configuration.Formatters.JsonFormatter);
|
||||
}
|
||||
|
||||
private Attempt<HttpResponseMessage> CheckVersion(Version clientVersion, Version minServerVersionSupportingClient)
|
||||
{
|
||||
if (clientVersion == null)
|
||||
return Attempt<HttpResponseMessage>.Fail(Request.CreateResponse(HttpStatusCode.Forbidden,
|
||||
$"API version conflict: client version (<null>) is not compatible with server version({ApiVersion.Current.Version})."));
|
||||
|
||||
// minServerVersionSupportingClient can be null
|
||||
var isOk = ApiVersion.Current.IsCompatibleWith(clientVersion, minServerVersionSupportingClient);
|
||||
var response = isOk ? null : Request.CreateResponse(HttpStatusCode.Forbidden,
|
||||
$"API version conflict: client version ({clientVersion}) is not compatible with server version({ApiVersion.Current.Version}).");
|
||||
|
||||
return Attempt<HttpResponseMessage>.If(isOk, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
[DataContract]
|
||||
class TokenData
|
||||
{
|
||||
[DataMember(Name = "access_token")]
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
[DataMember(Name = "token_type")]
|
||||
public string TokenType { get; set; }
|
||||
|
||||
[DataMember(Name = "expires_in")]
|
||||
public int ExpiresIn { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
[DataContract]
|
||||
public class ValidateClientVersionData
|
||||
{
|
||||
// issues 32, 34... problems when serializing versions
|
||||
//
|
||||
// make sure System.Version objects are transfered as strings
|
||||
// depending on the JSON serializer version, it looks like versions are causing issues
|
||||
// see
|
||||
// http://stackoverflow.com/questions/13170386/why-system-version-in-json-string-does-not-deserialize-correctly
|
||||
//
|
||||
// if the class is marked with [DataContract] then only properties marked with [DataMember]
|
||||
// are serialized and the rest is ignored, see
|
||||
// http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization
|
||||
|
||||
[DataMember]
|
||||
public string ClientVersionString
|
||||
{
|
||||
get { return VersionToString(ClientVersion); }
|
||||
set { ClientVersion = ParseVersion(value, false, "client"); }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string MinServerVersionSupportingClientString
|
||||
{
|
||||
get { return VersionToString(MinServerVersionSupportingClient); }
|
||||
set { MinServerVersionSupportingClient = ParseVersion(value, true, "minServer"); }
|
||||
}
|
||||
|
||||
// not serialized
|
||||
public Version ClientVersion { get; set; }
|
||||
public Version MinServerVersionSupportingClient { get; set; }
|
||||
|
||||
private static string VersionToString(Version version)
|
||||
{
|
||||
return version?.ToString() ?? "0.0.0.0";
|
||||
}
|
||||
|
||||
private static Version ParseVersion(string value, bool canBeNull, string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value) && canBeNull)
|
||||
return null;
|
||||
|
||||
Version version;
|
||||
if (Version.TryParse(value, out version))
|
||||
return version;
|
||||
|
||||
throw new ArgumentException($"Failed to parse \"{value}\" as {name} version.");
|
||||
}
|
||||
|
||||
public virtual bool IsValid => ClientVersion != null;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
|
||||
@@ -25,7 +26,8 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
private readonly IList<TypeModel> _typeModels;
|
||||
|
||||
protected Dictionary<string, string> ModelsMap { get; } = new Dictionary<string, string>();
|
||||
protected ParseResult ParseResult { get; }
|
||||
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
// the list of assemblies that will be 'using' by default
|
||||
protected readonly IList<string> TypesUsing = new List<string>
|
||||
@@ -58,7 +60,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// <returns>The models to generate, ie those that are not ignored.</returns>
|
||||
public IEnumerable<TypeModel> GetModelsToGenerate()
|
||||
{
|
||||
return _typeModels.Where(x => !x.IsContentIgnored);
|
||||
return _typeModels;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,27 +74,25 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// and the result of code parsing.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
/// <param name="parseResult">The result of code parsing.</param>
|
||||
protected Builder(IList<TypeModel> typeModels, ParseResult parseResult)
|
||||
{
|
||||
_typeModels = typeModels ?? throw new ArgumentNullException(nameof(typeModels));
|
||||
ParseResult = parseResult ?? throw new ArgumentNullException(nameof(parseResult));
|
||||
|
||||
Prepare();
|
||||
}
|
||||
protected Builder(IList<TypeModel> typeModels)
|
||||
: this(typeModels, null)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Builder"/> class with a list of models to generate,
|
||||
/// the result of code parsing, and a models namespace.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
/// <param name="parseResult">The result of code parsing.</param>
|
||||
/// <param name="modelsNamespace">The models namespace.</param>
|
||||
protected Builder(IList<TypeModel> typeModels, ParseResult parseResult, string modelsNamespace)
|
||||
: this(typeModels, parseResult)
|
||||
protected Builder(IList<TypeModel> typeModels, string modelsNamespace)
|
||||
{
|
||||
_typeModels = typeModels ?? throw new ArgumentNullException(nameof(typeModels));
|
||||
|
||||
// can be null or empty, we'll manage
|
||||
ModelsNamespace = modelsNamespace;
|
||||
|
||||
// but we want it to prepare
|
||||
Prepare();
|
||||
}
|
||||
|
||||
// for unit tests only
|
||||
@@ -108,49 +108,9 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// </remarks>
|
||||
private void Prepare()
|
||||
{
|
||||
var pureLive = UmbracoConfig.For.ModelsBuilder().ModelsMode == ModelsMode.PureLive;
|
||||
TypeModel.MapModelTypes(_typeModels, ModelsNamespace);
|
||||
|
||||
// mark IsContentIgnored models that we discovered should be ignored
|
||||
// then propagate / ignore children of ignored contents
|
||||
// ignore content = don't generate a class for it, don't generate children
|
||||
foreach (var typeModel in _typeModels.Where(x => ParseResult.IsIgnored(x.Alias)))
|
||||
typeModel.IsContentIgnored = true;
|
||||
foreach (var typeModel in _typeModels.Where(x => !x.IsContentIgnored && x.EnumerateBaseTypes().Any(xx => xx.IsContentIgnored)))
|
||||
typeModel.IsContentIgnored = true;
|
||||
|
||||
// handle model renames
|
||||
foreach (var typeModel in _typeModels.Where(x => ParseResult.IsContentRenamed(x.Alias)))
|
||||
{
|
||||
typeModel.ClrName = ParseResult.ContentClrName(typeModel.Alias);
|
||||
typeModel.IsRenamed = true;
|
||||
ModelsMap[typeModel.Alias] = typeModel.ClrName;
|
||||
}
|
||||
|
||||
// handle implement
|
||||
foreach (var typeModel in _typeModels.Where(x => ParseResult.HasContentImplement(x.Alias)))
|
||||
{
|
||||
typeModel.HasImplement = true;
|
||||
}
|
||||
|
||||
// mark OmitBase models that we discovered already have a base class
|
||||
foreach (var typeModel in _typeModels.Where(x => ParseResult.HasContentBase(ParseResult.ContentClrName(x.Alias) ?? x.ClrName)))
|
||||
typeModel.HasBase = true;
|
||||
|
||||
foreach (var typeModel in _typeModels)
|
||||
{
|
||||
// mark IsRemoved properties that we discovered should be ignored
|
||||
// ie is marked as ignored on type, or on any parent type
|
||||
var tm = typeModel;
|
||||
foreach (var property in typeModel.Properties
|
||||
.Where(property => tm.EnumerateBaseTypes(true).Any(x => ParseResult.IsPropertyIgnored(ParseResult.ContentClrName(x.Alias) ?? x.ClrName, property.Alias))))
|
||||
{
|
||||
property.IsIgnored = true;
|
||||
}
|
||||
|
||||
// handle property renames
|
||||
foreach (var property in typeModel.Properties)
|
||||
property.ClrName = ParseResult.PropertyClrName(ParseResult.ContentClrName(typeModel.Alias) ?? typeModel.ClrName, property.Alias) ?? property.ClrName;
|
||||
}
|
||||
var pureLive = Config.ModelsMode == ModelsMode.PureLive;
|
||||
|
||||
// for the first two of these two tests,
|
||||
// always throw, even in purelive: cannot happen unless ppl start fidling with attributes to rename
|
||||
@@ -158,22 +118,22 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
// for the last one, don't throw in purelive, see comment
|
||||
|
||||
// ensure we have no duplicates type names
|
||||
foreach (var xx in _typeModels.Where(x => !x.IsContentIgnored).GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
|
||||
foreach (var xx in _typeModels.GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
|
||||
throw new InvalidOperationException($"Type name \"{xx.Key}\" is used"
|
||||
+ $" for types with alias {string.Join(", ", xx.Select(x => x.ItemType + ":\"" + x.Alias + "\""))}. Names have to be unique."
|
||||
+ " Consider using an attribute to assign different names to conflicting types.");
|
||||
|
||||
// ensure we have no duplicates property names
|
||||
foreach (var typeModel in _typeModels.Where(x => !x.IsContentIgnored))
|
||||
foreach (var xx in typeModel.Properties.Where(x => !x.IsIgnored).GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
|
||||
foreach (var typeModel in _typeModels)
|
||||
foreach (var xx in typeModel.Properties.GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
|
||||
throw new InvalidOperationException($"Property name \"{xx.Key}\" in type {typeModel.ItemType}:\"{typeModel.Alias}\""
|
||||
+ $" is used for properties with alias {string.Join(", ", xx.Select(x => "\"" + x.Alias + "\""))}. Names have to be unique."
|
||||
+ " Consider using an attribute to assign different names to conflicting properties.");
|
||||
|
||||
// ensure content & property type don't have identical name (csharp hates it)
|
||||
foreach (var typeModel in _typeModels.Where(x => !x.IsContentIgnored))
|
||||
foreach (var typeModel in _typeModels)
|
||||
{
|
||||
foreach (var xx in typeModel.Properties.Where(x => !x.IsIgnored && x.ClrName == typeModel.ClrName))
|
||||
foreach (var xx in typeModel.Properties.Where(x => x.ClrName == typeModel.ClrName))
|
||||
{
|
||||
if (!pureLive)
|
||||
throw new InvalidOperationException($"The model class for content type with alias \"{typeModel.Alias}\" is named \"{xx.ClrName}\"."
|
||||
@@ -204,7 +164,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
// collect all the (non-removed) types implemented at parent level
|
||||
// ie the parent content types and the mixins content types, recursively
|
||||
var parentImplems = new List<TypeModel>();
|
||||
if (typeModel.BaseType != null && !typeModel.BaseType.IsContentIgnored)
|
||||
if (typeModel.BaseType != null)
|
||||
TypeModel.CollectImplems(parentImplems, typeModel.BaseType);
|
||||
|
||||
// interfaces we must declare we implement (initially empty)
|
||||
@@ -212,7 +172,6 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
// and except those that are already declared at the parent level
|
||||
// in other words, DeclaringInterfaces is "local mixins"
|
||||
var declaring = typeModel.MixinTypes
|
||||
.Where(x => !x.IsContentIgnored)
|
||||
.Except(parentImplems);
|
||||
typeModel.DeclaringInterfaces.AddRange(declaring);
|
||||
|
||||
@@ -227,43 +186,16 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
typeModel.ImplementingInterfaces.AddRange(mixinImplems.Except(parentImplems));
|
||||
}
|
||||
|
||||
// register using types
|
||||
foreach (var usingNamespace in ParseResult.UsingNamespaces)
|
||||
// ensure elements don't inherit from non-elements
|
||||
foreach (var typeModel in _typeModels.Where(x => x.IsElement))
|
||||
{
|
||||
if (!TypesUsing.Contains(usingNamespace))
|
||||
TypesUsing.Add(usingNamespace);
|
||||
if (typeModel.BaseType != null && !typeModel.BaseType.IsElement)
|
||||
throw new Exception($"Cannot generate model for type '{typeModel.Alias}' because it is an element type, but its parent type '{typeModel.BaseType.Alias}' is not.");
|
||||
|
||||
var errs = typeModel.MixinTypes.Where(x => !x.IsElement).ToList();
|
||||
if (errs.Count > 0)
|
||||
throw new Exception($"Cannot generate model for type '{typeModel.Alias}' because it is an element type, but it is composed of {string.Join(", ", errs.Select(x => "'" + x.Alias + "'"))} which {(errs.Count == 1 ? "is" : "are")} not.");
|
||||
}
|
||||
|
||||
// discover static mixin methods
|
||||
foreach (var typeModel in _typeModels)
|
||||
typeModel.StaticMixinMethods.AddRange(ParseResult.StaticMixinMethods(typeModel.ClrName));
|
||||
|
||||
// handle ctor
|
||||
foreach (var typeModel in _typeModels.Where(x => ParseResult.HasCtor(x.ClrName)))
|
||||
typeModel.HasCtor = true;
|
||||
}
|
||||
|
||||
private SemanticModel _ambiguousSymbolsModel;
|
||||
private int _ambiguousSymbolsPos;
|
||||
|
||||
// internal for tests
|
||||
internal void PrepareAmbiguousSymbols()
|
||||
{
|
||||
var codeBuilder = new StringBuilder();
|
||||
foreach (var t in TypesUsing)
|
||||
codeBuilder.AppendFormat("using {0};\n", t);
|
||||
|
||||
codeBuilder.AppendFormat("namespace {0}\n{{ }}\n", GetModelsNamespace());
|
||||
|
||||
var compiler = new Compiler();
|
||||
SyntaxTree[] trees;
|
||||
var compilation = compiler.GetCompilation("MyCompilation", new Dictionary<string, string> { { "code", codeBuilder.ToString() } }, out trees);
|
||||
var tree = trees[0];
|
||||
_ambiguousSymbolsModel = compilation.GetSemanticModel(tree);
|
||||
|
||||
var namespaceSyntax = tree.GetRoot().DescendantNodes().OfType<NamespaceDeclarationSyntax>().First();
|
||||
//var namespaceSymbol = model.GetDeclaredSymbol(namespaceSyntax);
|
||||
_ambiguousSymbolsPos = namespaceSyntax.OpenBraceToken.SpanStart;
|
||||
}
|
||||
|
||||
// looking for a simple symbol eg 'Umbraco' or 'String'
|
||||
@@ -273,20 +205,10 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
// - 1 symbol is found BUT not matching (implicitely ambiguous)
|
||||
protected bool IsAmbiguousSymbol(string symbol, string match)
|
||||
{
|
||||
if (_ambiguousSymbolsModel == null)
|
||||
PrepareAmbiguousSymbols();
|
||||
if (_ambiguousSymbolsModel == null)
|
||||
throw new Exception("Could not prepare ambiguous symbols.");
|
||||
var symbols = _ambiguousSymbolsModel.LookupNamespacesAndTypes(_ambiguousSymbolsPos, null, symbol);
|
||||
|
||||
if (symbols.Length > 1) return true;
|
||||
if (symbols.Length == 0) return false; // what else?
|
||||
|
||||
// only 1 - ensure it matches
|
||||
var found = symbols[0].ToDisplayString();
|
||||
var pos = found.IndexOf('<'); // generic?
|
||||
if (pos > 0) found = found.Substring(0, pos); // strip
|
||||
return found != match; // and compare
|
||||
// cannot figure out is a symbol is ambiguous without Roslyn
|
||||
// so... let's say everything is ambiguous - code won't be
|
||||
// pretty but it'll work
|
||||
return true;
|
||||
}
|
||||
|
||||
internal string ModelsNamespaceForTests;
|
||||
@@ -296,25 +218,17 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
if (ModelsNamespaceForTests != null)
|
||||
return ModelsNamespaceForTests;
|
||||
|
||||
// code attribute overrides everything
|
||||
if (ParseResult.HasModelsNamespace)
|
||||
return ParseResult.ModelsNamespace;
|
||||
|
||||
// if builder was initialized with a namespace, use that one
|
||||
if (!string.IsNullOrWhiteSpace(ModelsNamespace))
|
||||
return ModelsNamespace;
|
||||
|
||||
// default
|
||||
// fixme - should NOT reference config here, should make ModelsNamespace mandatory
|
||||
return UmbracoConfig.For.ModelsBuilder().ModelsNamespace;
|
||||
return Config.ModelsNamespace;
|
||||
}
|
||||
|
||||
protected string GetModelsBaseClassName(TypeModel type)
|
||||
{
|
||||
// code attribute overrides everything
|
||||
if (ParseResult.HasModelsBaseClassName)
|
||||
return ParseResult.ModelsBaseClassName;
|
||||
|
||||
// default
|
||||
return type.IsElement ? "PublishedElementModel" : "PublishedContentModel";
|
||||
}
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
{
|
||||
// NOTE
|
||||
// See nodes in Builder.cs class - that one does not work, is not complete,
|
||||
// and was just some sort of experiment...
|
||||
|
||||
/// <summary>
|
||||
/// Implements a builder that works by using CodeDom
|
||||
/// </summary>
|
||||
internal class CodeDomBuilder : Builder
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CodeDomBuilder"/> class with a list of models to generate.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
public CodeDomBuilder(IList<TypeModel> typeModels)
|
||||
: base(typeModels, null)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a generated model to a code namespace.
|
||||
/// </summary>
|
||||
/// <param name="ns">The code namespace.</param>
|
||||
/// <param name="typeModel">The model to generate.</param>
|
||||
public void Generate(CodeNamespace ns, TypeModel typeModel)
|
||||
{
|
||||
// what about USING?
|
||||
// what about references?
|
||||
|
||||
if (typeModel.IsMixin)
|
||||
{
|
||||
var i = new CodeTypeDeclaration("I" + typeModel.ClrName)
|
||||
{
|
||||
IsInterface = true,
|
||||
IsPartial = true,
|
||||
Attributes = MemberAttributes.Public
|
||||
};
|
||||
i.BaseTypes.Add(typeModel.BaseType == null ? "IPublishedContent" : "I" + typeModel.BaseType.ClrName);
|
||||
|
||||
foreach (var mixinType in typeModel.DeclaringInterfaces)
|
||||
i.BaseTypes.Add(mixinType.ClrName);
|
||||
|
||||
i.Comments.Add(new CodeCommentStatement($"Mixin content Type {typeModel.Id} with alias \"{typeModel.Alias}\""));
|
||||
|
||||
foreach (var propertyModel in typeModel.Properties)
|
||||
{
|
||||
var p = new CodeMemberProperty
|
||||
{
|
||||
Name = propertyModel.ClrName,
|
||||
Type = new CodeTypeReference(propertyModel.ModelClrType),
|
||||
Attributes = MemberAttributes.Public,
|
||||
HasGet = true,
|
||||
HasSet = false
|
||||
};
|
||||
i.Members.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
var c = new CodeTypeDeclaration(typeModel.ClrName)
|
||||
{
|
||||
IsClass = true,
|
||||
IsPartial = true,
|
||||
Attributes = MemberAttributes.Public
|
||||
};
|
||||
|
||||
c.BaseTypes.Add(typeModel.BaseType == null ? "PublishedContentModel" : typeModel.BaseType.ClrName);
|
||||
|
||||
// if it's a missing it implements its own interface
|
||||
if (typeModel.IsMixin)
|
||||
c.BaseTypes.Add("I" + typeModel.ClrName);
|
||||
|
||||
// write the mixins, if any, as interfaces
|
||||
// only if not a mixin because otherwise the interface already has them
|
||||
if (typeModel.IsMixin == false)
|
||||
foreach (var mixinType in typeModel.DeclaringInterfaces)
|
||||
c.BaseTypes.Add("I" + mixinType.ClrName);
|
||||
|
||||
foreach (var mixin in typeModel.MixinTypes)
|
||||
c.BaseTypes.Add("I" + mixin.ClrName);
|
||||
|
||||
c.Comments.Add(new CodeCommentStatement($"Content Type {typeModel.Id} with alias \"{typeModel.Alias}\""));
|
||||
|
||||
foreach (var propertyModel in typeModel.Properties)
|
||||
{
|
||||
var p = new CodeMemberProperty
|
||||
{
|
||||
Name = propertyModel.ClrName,
|
||||
Type = new CodeTypeReference(propertyModel.ModelClrType),
|
||||
Attributes = MemberAttributes.Public,
|
||||
HasGet = true,
|
||||
HasSet = false
|
||||
};
|
||||
p.GetStatements.Add(new CodeMethodReturnStatement( // return
|
||||
new CodeMethodInvokeExpression(
|
||||
new CodeMethodReferenceExpression(
|
||||
new CodeThisReferenceExpression(), // this
|
||||
"Value", // .Value
|
||||
new[] // <T>
|
||||
{
|
||||
new CodeTypeReference(propertyModel.ModelClrType)
|
||||
}),
|
||||
new CodeExpression[] // ("alias")
|
||||
{
|
||||
new CodePrimitiveExpression(propertyModel.Alias)
|
||||
})));
|
||||
c.Members.Add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements code parsing.
|
||||
/// </summary>
|
||||
/// <remarks>Parses user's code and look for generator's instructions.</remarks>
|
||||
internal class CodeParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses a set of file.
|
||||
/// </summary>
|
||||
/// <param name="files">A set of (filename,content) representing content to parse.</param>
|
||||
/// <returns>The result of the code parsing.</returns>
|
||||
/// <remarks>The set of files is a dictionary of name, content.</remarks>
|
||||
public ParseResult Parse(IDictionary<string, string> files)
|
||||
{
|
||||
return Parse(files, Enumerable.Empty<PortableExecutableReference>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a set of file.
|
||||
/// </summary>
|
||||
/// <param name="files">A set of (filename,content) representing content to parse.</param>
|
||||
/// <param name="references">Assemblies to reference in compilations.</param>
|
||||
/// <returns>The result of the code parsing.</returns>
|
||||
/// <remarks>The set of files is a dictionary of name, content.</remarks>
|
||||
public ParseResult Parse(IDictionary<string, string> files, IEnumerable<PortableExecutableReference> references)
|
||||
{
|
||||
SyntaxTree[] trees;
|
||||
var compiler = new Compiler { References = references };
|
||||
var compilation = compiler.GetCompilation("Umbraco.ModelsBuilder.Generated", files, out trees);
|
||||
|
||||
var disco = new ParseResult();
|
||||
foreach (var tree in trees)
|
||||
Parse(disco, compilation, tree);
|
||||
|
||||
return disco;
|
||||
}
|
||||
|
||||
public ParseResult ParseWithReferencedAssemblies(IDictionary<string, string> files)
|
||||
{
|
||||
return Parse(files, ReferencedAssemblies.References);
|
||||
}
|
||||
|
||||
private static void Parse(ParseResult disco, CSharpCompilation compilation, SyntaxTree tree)
|
||||
{
|
||||
var model = compilation.GetSemanticModel(tree);
|
||||
|
||||
//we quite probably have errors but that is normal
|
||||
//var diags = model.GetDiagnostics();
|
||||
|
||||
var classDecls = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>();
|
||||
foreach (var classSymbol in classDecls.Select(x => model.GetDeclaredSymbol(x)))
|
||||
{
|
||||
ParseClassSymbols(disco, classSymbol);
|
||||
|
||||
var baseClassSymbol = classSymbol.BaseType;
|
||||
if (baseClassSymbol != null)
|
||||
//disco.SetContentBaseClass(SymbolDisplay.ToDisplayString(classSymbol), SymbolDisplay.ToDisplayString(baseClassSymbol));
|
||||
disco.SetContentBaseClass(classSymbol.Name, baseClassSymbol.Name);
|
||||
|
||||
var interfaceSymbols = classSymbol.Interfaces;
|
||||
disco.SetContentInterfaces(classSymbol.Name, //SymbolDisplay.ToDisplayString(classSymbol),
|
||||
interfaceSymbols.Select(x => x.Name)); //SymbolDisplay.ToDisplayString(x)));
|
||||
|
||||
var hasCtor = classSymbol.Constructors
|
||||
.Any(x =>
|
||||
{
|
||||
if (x.IsStatic) return false;
|
||||
if (x.Parameters.Length != 1) return false;
|
||||
var type1 = x.Parameters[0].Type;
|
||||
var type2 = typeof (IPublishedContent);
|
||||
return type1.ToDisplayString() == type2.FullName;
|
||||
});
|
||||
|
||||
if (hasCtor)
|
||||
disco.SetHasCtor(classSymbol.Name);
|
||||
|
||||
foreach (var propertySymbol in classSymbol.GetMembers().Where(x => x is IPropertySymbol))
|
||||
ParsePropertySymbols(disco, classSymbol, propertySymbol);
|
||||
|
||||
foreach (var staticMethodSymbol in classSymbol.GetMembers().Where(x => x is IMethodSymbol))
|
||||
ParseMethodSymbol(disco, classSymbol, staticMethodSymbol);
|
||||
}
|
||||
|
||||
var interfaceDecls = tree.GetRoot().DescendantNodes().OfType<InterfaceDeclarationSyntax>();
|
||||
foreach (var interfaceSymbol in interfaceDecls.Select(x => model.GetDeclaredSymbol(x)))
|
||||
{
|
||||
ParseClassSymbols(disco, interfaceSymbol);
|
||||
|
||||
var interfaceSymbols = interfaceSymbol.Interfaces;
|
||||
disco.SetContentInterfaces(interfaceSymbol.Name, //SymbolDisplay.ToDisplayString(interfaceSymbol),
|
||||
interfaceSymbols.Select(x => x.Name)); // SymbolDisplay.ToDisplayString(x)));
|
||||
}
|
||||
|
||||
ParseAssemblySymbols(disco, compilation.Assembly);
|
||||
}
|
||||
|
||||
private static void ParseClassSymbols(ParseResult disco, ISymbol symbol)
|
||||
{
|
||||
foreach (var attrData in symbol.GetAttributes())
|
||||
{
|
||||
var attrClassSymbol = attrData.AttributeClass;
|
||||
|
||||
// handle errors
|
||||
if (attrClassSymbol is IErrorTypeSymbol) continue;
|
||||
if (attrData.AttributeConstructor == null) continue;
|
||||
|
||||
var attrClassName = SymbolDisplay.ToDisplayString(attrClassSymbol);
|
||||
switch (attrClassName)
|
||||
{
|
||||
case "Umbraco.ModelsBuilder.IgnorePropertyTypeAttribute":
|
||||
var propertyAliasToIgnore = (string)attrData.ConstructorArguments[0].Value;
|
||||
disco.SetIgnoredProperty(symbol.Name /*SymbolDisplay.ToDisplayString(symbol)*/, propertyAliasToIgnore);
|
||||
break;
|
||||
case "Umbraco.ModelsBuilder.RenamePropertyTypeAttribute":
|
||||
var propertyAliasToRename = (string)attrData.ConstructorArguments[0].Value;
|
||||
var propertyRenamed = (string)attrData.ConstructorArguments[1].Value;
|
||||
disco.SetRenamedProperty(symbol.Name /*SymbolDisplay.ToDisplayString(symbol)*/, propertyAliasToRename, propertyRenamed);
|
||||
break;
|
||||
// that one causes all sorts of issues with references to Umbraco.Core in Roslyn
|
||||
//case "Umbraco.Core.Models.PublishedContent.PublishedContentModelAttribute":
|
||||
// var contentAliasToRename = (string)attrData.ConstructorArguments[0].Value;
|
||||
// disco.SetRenamedContent(contentAliasToRename, symbol.Name /*SymbolDisplay.ToDisplayString(symbol)*/);
|
||||
// break;
|
||||
case "Umbraco.ModelsBuilder.ImplementContentTypeAttribute":
|
||||
var contentAliasToRename = (string)attrData.ConstructorArguments[0].Value;
|
||||
disco.SetRenamedContent(contentAliasToRename, symbol.Name, true /*SymbolDisplay.ToDisplayString(symbol)*/);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParsePropertySymbols(ParseResult disco, ISymbol classSymbol, ISymbol symbol)
|
||||
{
|
||||
foreach (var attrData in symbol.GetAttributes())
|
||||
{
|
||||
var attrClassSymbol = attrData.AttributeClass;
|
||||
|
||||
// handle errors
|
||||
if (attrClassSymbol is IErrorTypeSymbol) continue;
|
||||
if (attrData.AttributeConstructor == null) continue;
|
||||
|
||||
var attrClassName = SymbolDisplay.ToDisplayString(attrClassSymbol);
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (attrClassName)
|
||||
{
|
||||
case "Umbraco.ModelsBuilder.ImplementPropertyTypeAttribute":
|
||||
var propertyAliasToIgnore = (string)attrData.ConstructorArguments[0].Value;
|
||||
disco.SetIgnoredProperty(classSymbol.Name /*SymbolDisplay.ToDisplayString(classSymbol)*/, propertyAliasToIgnore);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParseAssemblySymbols(ParseResult disco, ISymbol symbol)
|
||||
{
|
||||
foreach (var attrData in symbol.GetAttributes())
|
||||
{
|
||||
var attrClassSymbol = attrData.AttributeClass;
|
||||
|
||||
// handle errors
|
||||
if (attrClassSymbol is IErrorTypeSymbol) continue;
|
||||
if (attrData.AttributeConstructor == null) continue;
|
||||
|
||||
var attrClassName = SymbolDisplay.ToDisplayString(attrClassSymbol);
|
||||
switch (attrClassName)
|
||||
{
|
||||
case "Umbraco.ModelsBuilder.IgnoreContentTypeAttribute":
|
||||
var contentAliasToIgnore = (string)attrData.ConstructorArguments[0].Value;
|
||||
// see notes in IgnoreContentTypeAttribute
|
||||
//var ignoreContent = (bool)attrData.ConstructorArguments[1].Value;
|
||||
//var ignoreMixin = (bool)attrData.ConstructorArguments[1].Value;
|
||||
//var ignoreMixinProperties = (bool)attrData.ConstructorArguments[1].Value;
|
||||
disco.SetIgnoredContent(contentAliasToIgnore /*, ignoreContent, ignoreMixin, ignoreMixinProperties*/);
|
||||
break;
|
||||
|
||||
case "Umbraco.ModelsBuilder.RenameContentTypeAttribute":
|
||||
var contentAliasToRename = (string) attrData.ConstructorArguments[0].Value;
|
||||
var contentRenamed = (string)attrData.ConstructorArguments[1].Value;
|
||||
disco.SetRenamedContent(contentAliasToRename, contentRenamed, false);
|
||||
break;
|
||||
|
||||
case "Umbraco.ModelsBuilder.ModelsBaseClassAttribute":
|
||||
var modelsBaseClass = (INamedTypeSymbol) attrData.ConstructorArguments[0].Value;
|
||||
if (modelsBaseClass is IErrorTypeSymbol)
|
||||
throw new Exception($"Invalid base class type \"{modelsBaseClass.Name}\".");
|
||||
disco.SetModelsBaseClassName(SymbolDisplay.ToDisplayString(modelsBaseClass));
|
||||
break;
|
||||
|
||||
case "Umbraco.ModelsBuilder.ModelsNamespaceAttribute":
|
||||
var modelsNamespace= (string) attrData.ConstructorArguments[0].Value;
|
||||
disco.SetModelsNamespace(modelsNamespace);
|
||||
break;
|
||||
|
||||
case "Umbraco.ModelsBuilder.ModelsUsingAttribute":
|
||||
var usingNamespace = (string)attrData.ConstructorArguments[0].Value;
|
||||
disco.SetUsingNamespace(usingNamespace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParseMethodSymbol(ParseResult disco, ISymbol classSymbol, ISymbol symbol)
|
||||
{
|
||||
var methodSymbol = symbol as IMethodSymbol;
|
||||
|
||||
if (methodSymbol == null
|
||||
|| !methodSymbol.IsStatic
|
||||
|| methodSymbol.IsGenericMethod
|
||||
|| methodSymbol.ReturnsVoid
|
||||
|| methodSymbol.IsExtensionMethod
|
||||
|| methodSymbol.Parameters.Length != 1)
|
||||
return;
|
||||
|
||||
var returnType = methodSymbol.ReturnType;
|
||||
var paramSymbol = methodSymbol.Parameters[0];
|
||||
var paramType = paramSymbol.Type;
|
||||
|
||||
// cannot do this because maybe the param type is ISomething and we don't have
|
||||
// that type yet - will be generated - so cannot put any condition on it really
|
||||
//const string iPublishedContent = "Umbraco.Core.Models.IPublishedContent";
|
||||
//var implements = paramType.AllInterfaces.Any(x => x.ToDisplayString() == iPublishedContent);
|
||||
//if (!implements)
|
||||
// return;
|
||||
|
||||
disco.SetStaticMixinMethod(classSymbol.Name, methodSymbol.Name, returnType.Name, paramType.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
{
|
||||
// main Roslyn compiler
|
||||
internal class Compiler
|
||||
{
|
||||
private readonly LanguageVersion _languageVersion;
|
||||
|
||||
public Compiler()
|
||||
: this(UmbracoConfig.For.ModelsBuilder().LanguageVersion)
|
||||
{ }
|
||||
|
||||
public Compiler(LanguageVersion languageVersion)
|
||||
{
|
||||
_languageVersion = languageVersion;
|
||||
References = ReferencedAssemblies.References;
|
||||
Debug = HttpContext.Current != null && HttpContext.Current.IsDebuggingEnabled;
|
||||
}
|
||||
|
||||
// gets or sets the references
|
||||
public IEnumerable<PortableExecutableReference> References { get; set; }
|
||||
|
||||
public bool Debug { get; set; }
|
||||
|
||||
// gets a compilation
|
||||
public CSharpCompilation GetCompilation(string assemblyName, IDictionary<string, string> files)
|
||||
{
|
||||
SyntaxTree[] trees;
|
||||
return GetCompilation(assemblyName, files, out trees);
|
||||
}
|
||||
|
||||
// gets a compilation
|
||||
// used by CodeParser to get a "compilation" of the existing files
|
||||
public CSharpCompilation GetCompilation(string assemblyName, IDictionary<string, string> files, out SyntaxTree[] trees)
|
||||
{
|
||||
var options = new CSharpParseOptions(_languageVersion);
|
||||
trees = files.Select(x =>
|
||||
{
|
||||
var text = x.Value;
|
||||
var tree = CSharpSyntaxTree.ParseText(text, /*options:*/ options);
|
||||
var diagnostic = tree.GetDiagnostics().FirstOrDefault(y => y.Severity == DiagnosticSeverity.Error);
|
||||
if (diagnostic != null)
|
||||
ThrowExceptionFromDiagnostic(x.Key, x.Value, diagnostic);
|
||||
return tree;
|
||||
}).ToArray();
|
||||
|
||||
var refs = References;
|
||||
|
||||
var compilationOptions = new CSharpCompilationOptions(
|
||||
OutputKind.DynamicallyLinkedLibrary,
|
||||
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default,
|
||||
optimizationLevel: Debug ? OptimizationLevel.Debug : OptimizationLevel.Release
|
||||
);
|
||||
var compilation = CSharpCompilation.Create(
|
||||
assemblyName,
|
||||
/*syntaxTrees:*/ trees,
|
||||
/*references:*/ refs,
|
||||
compilationOptions);
|
||||
|
||||
return compilation;
|
||||
}
|
||||
|
||||
// compile files into a Dll
|
||||
// used by ModelsBuilderBackOfficeController in [Live]Dll mode, to compile the models to disk
|
||||
public void Compile(string assemblyName, IDictionary<string, string> files, string binPath)
|
||||
{
|
||||
var assemblyPath = Path.Combine(binPath, assemblyName + ".dll");
|
||||
using (var stream = new FileStream(assemblyPath, FileMode.Create))
|
||||
{
|
||||
Compile(assemblyName, files, stream);
|
||||
}
|
||||
|
||||
// this is how we'd create the pdb:
|
||||
/*
|
||||
var pdbPath = Path.Combine(binPath, assemblyName + ".pdb");
|
||||
|
||||
// create the compilation
|
||||
var compilation = GetCompilation(assemblyName, files);
|
||||
|
||||
// check diagnostics for errors (not warnings)
|
||||
foreach (var diag in compilation.GetDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error))
|
||||
ThrowExceptionFromDiagnostic(files, diag);
|
||||
|
||||
// emit
|
||||
var result = compilation.Emit(assemblyPath, pdbPath);
|
||||
if (result.Success) return;
|
||||
|
||||
// deal with errors
|
||||
var diagnostic = result.Diagnostics.First(x => x.Severity == DiagnosticSeverity.Error);
|
||||
ThrowExceptionFromDiagnostic(files, diagnostic);
|
||||
*/
|
||||
}
|
||||
|
||||
// compile files into an assembly
|
||||
public Assembly Compile(string assemblyName, IDictionary<string, string> files)
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
Compile(assemblyName, files, stream);
|
||||
return Assembly.Load(stream.GetBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
// compile one file into an assembly
|
||||
public Assembly Compile(string assemblyName, string path, string code)
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
Compile(assemblyName, new Dictionary<string, string> { { path, code } }, stream);
|
||||
return Assembly.Load(stream.GetBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
// compiles files into a stream
|
||||
public void Compile(string assemblyName, IDictionary<string, string> files, Stream stream)
|
||||
{
|
||||
// create the compilation
|
||||
var compilation = GetCompilation(assemblyName, files);
|
||||
|
||||
// check diagnostics for errors (not warnings)
|
||||
foreach (var diag in compilation.GetDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error))
|
||||
ThrowExceptionFromDiagnostic(files, diag);
|
||||
|
||||
// emit
|
||||
var result = compilation.Emit(stream);
|
||||
if (result.Success) return;
|
||||
|
||||
// deal with errors
|
||||
var diagnostic = result.Diagnostics.First(x => x.Severity == DiagnosticSeverity.Error);
|
||||
ThrowExceptionFromDiagnostic(files, diagnostic);
|
||||
}
|
||||
|
||||
// compiles one file into a stream
|
||||
public void Compile(string assemblyName, string path, string code, Stream stream)
|
||||
{
|
||||
Compile(assemblyName, new Dictionary<string, string> { { path, code } }, stream);
|
||||
}
|
||||
|
||||
private static void ThrowExceptionFromDiagnostic(IDictionary<string, string> files, Diagnostic diagnostic)
|
||||
{
|
||||
var message = diagnostic.GetMessage();
|
||||
if (diagnostic.Location == Location.None)
|
||||
throw new CompilerException(message);
|
||||
|
||||
var position = diagnostic.Location.GetLineSpan().StartLinePosition.Line + 1;
|
||||
var path = diagnostic.Location.SourceTree.FilePath;
|
||||
var code = files.ContainsKey(path) ? files[path] : string.Empty;
|
||||
throw new CompilerException(message, path, code, position);
|
||||
}
|
||||
|
||||
private static void ThrowExceptionFromDiagnostic(string path, string code, Diagnostic diagnostic)
|
||||
{
|
||||
var message = diagnostic.GetMessage();
|
||||
if (diagnostic.Location == Location.None)
|
||||
throw new CompilerException(message);
|
||||
|
||||
var position = diagnostic.Location.GetLineSpan().StartLinePosition.Line + 1;
|
||||
throw new CompilerException(message, path, code, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
{
|
||||
public class CompilerException : Exception
|
||||
{
|
||||
public CompilerException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public CompilerException(string message, string path, string sourceCode, int line)
|
||||
: base(message)
|
||||
{
|
||||
Path = path;
|
||||
SourceCode = sourceCode;
|
||||
Line = line;
|
||||
}
|
||||
|
||||
public string Path { get; } = string.Empty;
|
||||
|
||||
public string SourceCode { get; } = string.Empty;
|
||||
|
||||
public int Line { get; } = -1;
|
||||
}
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the result of a code parsing.
|
||||
/// </summary>
|
||||
internal class ParseResult
|
||||
{
|
||||
// "alias" is the umbraco alias
|
||||
// content "name" is the complete name eg Foo.Bar.Name
|
||||
// property "name" is just the local name
|
||||
|
||||
// see notes in IgnoreContentTypeAttribute
|
||||
|
||||
private readonly HashSet<string> _ignoredContent
|
||||
= new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
//private readonly HashSet<string> _ignoredMixin
|
||||
// = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
//private readonly HashSet<string> _ignoredMixinProperties
|
||||
// = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
private readonly Dictionary<string, string> _renamedContent
|
||||
= new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
private readonly HashSet<string> _withImplementContent
|
||||
= new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
private readonly Dictionary<string, HashSet<string>> _ignoredProperty
|
||||
= new Dictionary<string, HashSet<string>>();
|
||||
private readonly Dictionary<string, Dictionary<string, string>> _renamedProperty
|
||||
= new Dictionary<string, Dictionary<string, string>>();
|
||||
private readonly Dictionary<string, string> _contentBase
|
||||
= new Dictionary<string, string>();
|
||||
private readonly Dictionary<string, string[]> _contentInterfaces
|
||||
= new Dictionary<string, string[]>();
|
||||
private readonly List<string> _usingNamespaces
|
||||
= new List<string>();
|
||||
private readonly Dictionary<string, List<StaticMixinMethodInfo>> _staticMixins
|
||||
= new Dictionary<string, List<StaticMixinMethodInfo>>();
|
||||
private readonly HashSet<string> _withCtor
|
||||
= new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
public static readonly ParseResult Empty = new ParseResult();
|
||||
|
||||
private class StaticMixinMethodInfo
|
||||
{
|
||||
public StaticMixinMethodInfo(string contentName, string methodName, string returnType, string paramType)
|
||||
{
|
||||
ContentName = contentName;
|
||||
MethodName = methodName;
|
||||
//ReturnType = returnType;
|
||||
//ParamType = paramType;
|
||||
}
|
||||
|
||||
// short name eg Type1
|
||||
public string ContentName { get; private set; }
|
||||
|
||||
// short name eg GetProp1
|
||||
public string MethodName { get; private set; }
|
||||
|
||||
// those types cannot be FQ because when parsing, some of them
|
||||
// might not exist since we're generating them... and so prob.
|
||||
// that info is worthless - not using it anyway at the moment...
|
||||
|
||||
//public string ReturnType { get; private set; }
|
||||
//public string ParamType { get; private set; }
|
||||
}
|
||||
|
||||
#region Declare
|
||||
|
||||
// content with that alias should not be generated
|
||||
// alias can end with a * (wildcard)
|
||||
public void SetIgnoredContent(string contentAlias /*, bool ignoreContent, bool ignoreMixin, bool ignoreMixinProperties*/)
|
||||
{
|
||||
//if (ignoreContent)
|
||||
_ignoredContent.Add(contentAlias);
|
||||
//if (ignoreMixin)
|
||||
// _ignoredMixin.Add(contentAlias);
|
||||
//if (ignoreMixinProperties)
|
||||
// _ignoredMixinProperties.Add(contentAlias);
|
||||
}
|
||||
|
||||
// content with that alias should be generated with a different name
|
||||
public void SetRenamedContent(string contentAlias, string contentName, bool withImplement)
|
||||
{
|
||||
_renamedContent[contentAlias] = contentName;
|
||||
if (withImplement)
|
||||
_withImplementContent.Add(contentAlias);
|
||||
}
|
||||
|
||||
// property with that alias should not be generated
|
||||
// applies to content name and any content that implements it
|
||||
// here, contentName may be an interface
|
||||
// alias can end with a * (wildcard)
|
||||
public void SetIgnoredProperty(string contentName, string propertyAlias)
|
||||
{
|
||||
HashSet<string> ignores;
|
||||
if (!_ignoredProperty.TryGetValue(contentName, out ignores))
|
||||
ignores = _ignoredProperty[contentName] = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
ignores.Add(propertyAlias);
|
||||
}
|
||||
|
||||
// property with that alias should be generated with a different name
|
||||
// applies to content name and any content that implements it
|
||||
// here, contentName may be an interface
|
||||
public void SetRenamedProperty(string contentName, string propertyAlias, string propertyName)
|
||||
{
|
||||
Dictionary<string, string> renames;
|
||||
if (!_renamedProperty.TryGetValue(contentName, out renames))
|
||||
renames = _renamedProperty[contentName] = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
|
||||
renames[propertyAlias] = propertyName;
|
||||
}
|
||||
|
||||
// content with that name has a base class so no need to generate one
|
||||
public void SetContentBaseClass(string contentName, string baseName)
|
||||
{
|
||||
if (baseName.ToLowerInvariant() != "object")
|
||||
_contentBase[contentName] = baseName;
|
||||
}
|
||||
|
||||
// content with that name implements the interfaces
|
||||
public void SetContentInterfaces(string contentName, IEnumerable<string> interfaceNames)
|
||||
{
|
||||
_contentInterfaces[contentName] = interfaceNames.ToArray();
|
||||
}
|
||||
|
||||
public void SetModelsBaseClassName(string modelsBaseClassName)
|
||||
{
|
||||
ModelsBaseClassName = modelsBaseClassName;
|
||||
}
|
||||
|
||||
public void SetModelsNamespace(string modelsNamespace)
|
||||
{
|
||||
ModelsNamespace = modelsNamespace;
|
||||
}
|
||||
|
||||
public void SetUsingNamespace(string usingNamespace)
|
||||
{
|
||||
_usingNamespaces.Add(usingNamespace);
|
||||
}
|
||||
|
||||
public void SetStaticMixinMethod(string contentName, string methodName, string returnType, string paramType)
|
||||
{
|
||||
if (!_staticMixins.ContainsKey(contentName))
|
||||
_staticMixins[contentName] = new List<StaticMixinMethodInfo>();
|
||||
|
||||
_staticMixins[contentName].Add(new StaticMixinMethodInfo(contentName, methodName, returnType, paramType));
|
||||
}
|
||||
|
||||
public void SetHasCtor(string contentName)
|
||||
{
|
||||
_withCtor.Add(contentName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Query
|
||||
|
||||
public bool IsIgnored(string contentAlias)
|
||||
{
|
||||
return IsContentOrMixinIgnored(contentAlias, _ignoredContent);
|
||||
}
|
||||
|
||||
//public bool IsMixinIgnored(string contentAlias)
|
||||
//{
|
||||
// return IsContentOrMixinIgnored(contentAlias, _ignoredMixin);
|
||||
//}
|
||||
|
||||
//public bool IsMixinPropertiesIgnored(string contentAlias)
|
||||
//{
|
||||
// return IsContentOrMixinIgnored(contentAlias, _ignoredMixinProperties);
|
||||
//}
|
||||
|
||||
private static bool IsContentOrMixinIgnored(string contentAlias, HashSet<string> ignored)
|
||||
{
|
||||
if (ignored.Contains(contentAlias)) return true;
|
||||
return ignored
|
||||
.Where(x => x.EndsWith("*"))
|
||||
.Select(x => x.Substring(0, x.Length - 1))
|
||||
.Any(x => contentAlias.StartsWith(x, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
public bool HasContentBase(string contentName)
|
||||
{
|
||||
return _contentBase.ContainsKey(contentName);
|
||||
}
|
||||
|
||||
public bool IsContentRenamed(string contentAlias)
|
||||
{
|
||||
return _renamedContent.ContainsKey(contentAlias);
|
||||
}
|
||||
|
||||
public bool HasContentImplement(string contentAlias)
|
||||
{
|
||||
return _withImplementContent.Contains(contentAlias);
|
||||
}
|
||||
|
||||
public string ContentClrName(string contentAlias)
|
||||
{
|
||||
string name;
|
||||
return (_renamedContent.TryGetValue(contentAlias, out name)) ? name : null;
|
||||
}
|
||||
|
||||
public bool IsPropertyIgnored(string contentName, string propertyAlias)
|
||||
{
|
||||
HashSet<string> ignores;
|
||||
if (_ignoredProperty.TryGetValue(contentName, out ignores))
|
||||
{
|
||||
if (ignores.Contains(propertyAlias)) return true;
|
||||
if (ignores
|
||||
.Where(x => x.EndsWith("*"))
|
||||
.Select(x => x.Substring(0, x.Length - 1))
|
||||
.Any(x => propertyAlias.StartsWith(x, StringComparison.InvariantCultureIgnoreCase)))
|
||||
return true;
|
||||
}
|
||||
string baseName;
|
||||
if (_contentBase.TryGetValue(contentName, out baseName)
|
||||
&& IsPropertyIgnored(baseName, propertyAlias)) return true;
|
||||
string[] interfaceNames;
|
||||
if (_contentInterfaces.TryGetValue(contentName, out interfaceNames)
|
||||
&& interfaceNames.Any(interfaceName => IsPropertyIgnored(interfaceName, propertyAlias))) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public string PropertyClrName(string contentName, string propertyAlias)
|
||||
{
|
||||
Dictionary<string, string> renames;
|
||||
string name;
|
||||
if (_renamedProperty.TryGetValue(contentName, out renames)
|
||||
&& renames.TryGetValue(propertyAlias, out name)) return name;
|
||||
string baseName;
|
||||
if (_contentBase.TryGetValue(contentName, out baseName)
|
||||
&& null != (name = PropertyClrName(baseName, propertyAlias))) return name;
|
||||
string[] interfaceNames;
|
||||
if (_contentInterfaces.TryGetValue(contentName, out interfaceNames)
|
||||
&& null != (name = interfaceNames
|
||||
.Select(interfaceName => PropertyClrName(interfaceName, propertyAlias))
|
||||
.FirstOrDefault(x => x != null))) return name;
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool HasModelsBaseClassName
|
||||
{
|
||||
get { return !string.IsNullOrWhiteSpace(ModelsBaseClassName); }
|
||||
}
|
||||
|
||||
public string ModelsBaseClassName { get; private set; }
|
||||
|
||||
public bool HasModelsNamespace
|
||||
{
|
||||
get { return !string.IsNullOrWhiteSpace(ModelsNamespace); }
|
||||
}
|
||||
|
||||
public string ModelsNamespace { get; private set; }
|
||||
|
||||
public IEnumerable<string> UsingNamespaces
|
||||
{
|
||||
get { return _usingNamespaces; }
|
||||
}
|
||||
|
||||
public IEnumerable<string> StaticMixinMethods(string contentName)
|
||||
{
|
||||
return _staticMixins.ContainsKey(contentName)
|
||||
? _staticMixins[contentName].Select(x => x.MethodName)
|
||||
: Enumerable.Empty<string>() ;
|
||||
}
|
||||
|
||||
public bool HasCtor(string contentName)
|
||||
{
|
||||
return _withCtor.Contains(contentName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -41,11 +41,6 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// </summary>
|
||||
public string ClrTypeName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this property should be excluded from generation.
|
||||
/// </summary>
|
||||
public bool IsIgnored;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the generation errors for the property.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,8 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.ModelsBuilder.Api;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
@@ -19,9 +20,8 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// and the result of code parsing.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
/// <param name="parseResult">The result of code parsing.</param>
|
||||
public TextBuilder(IList<TypeModel> typeModels, ParseResult parseResult)
|
||||
: base(typeModels, parseResult)
|
||||
public TextBuilder(IList<TypeModel> typeModels)
|
||||
: base(typeModels)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
@@ -29,21 +29,22 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// the result of code parsing, and a models namespace.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
/// <param name="parseResult">The result of code parsing.</param>
|
||||
/// <param name="modelsNamespace">The models namespace.</param>
|
||||
public TextBuilder(IList<TypeModel> typeModels, ParseResult parseResult, string modelsNamespace)
|
||||
: base(typeModels, parseResult, modelsNamespace)
|
||||
public TextBuilder(IList<TypeModel> typeModels, string modelsNamespace)
|
||||
: base(typeModels, modelsNamespace)
|
||||
{ }
|
||||
|
||||
// internal for unit tests only
|
||||
internal TextBuilder()
|
||||
{ }
|
||||
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a generated model to a string builder.
|
||||
/// </summary>
|
||||
/// <param name="sb">The string builder.</param>
|
||||
/// <param name="typeModel">The model to generate.</param>
|
||||
/// Outputs a generated model to a string builder.
|
||||
/// </summary>
|
||||
/// <param name="sb">The string builder.</param>
|
||||
/// <param name="typeModel">The model to generate.</param>
|
||||
public void Generate(StringBuilder sb, TypeModel typeModel)
|
||||
{
|
||||
WriteHeader(sb);
|
||||
@@ -97,6 +98,20 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
TextHeaderWriter.WriteHeader(sb);
|
||||
}
|
||||
|
||||
// writes an attribute that identifies code generated by a tool
|
||||
// (helps reduce warnings, tools such as FxCop use it)
|
||||
// see https://github.com/zpqrtbnk/Zbu.ModelsBuilder/issues/107
|
||||
// see https://docs.microsoft.com/en-us/dotnet/api/system.codedom.compiler.generatedcodeattribute
|
||||
// see https://blogs.msdn.microsoft.com/codeanalysis/2007/04/27/correct-usage-of-the-compilergeneratedattribute-and-the-generatedcodeattribute/
|
||||
//
|
||||
// note that the blog post above clearly states that "Nor should it be applied at the type level if the type being generated is a partial class."
|
||||
// and since our models are partial classes, we have to apply the attribute against the individual members, not the class itself.
|
||||
//
|
||||
private static void WriteGeneratedCodeAttribute(StringBuilder sb, string tabs)
|
||||
{
|
||||
sb.AppendFormat("{0}[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Umbraco.ModelsBuilder\", \"{1}\")]\n", tabs, ApiVersion.Current.Version);
|
||||
}
|
||||
|
||||
private void WriteContentType(StringBuilder sb, TypeModel type)
|
||||
{
|
||||
string sep;
|
||||
@@ -104,11 +119,11 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
if (type.IsMixin)
|
||||
{
|
||||
// write the interface declaration
|
||||
sb.AppendFormat("\t// Mixin content Type {0} with alias \"{1}\"\n", type.Id, type.Alias);
|
||||
sb.AppendFormat("\t// Mixin Content Type with alias \"{0}\"\n", type.Alias);
|
||||
if (!string.IsNullOrWhiteSpace(type.Name))
|
||||
sb.AppendFormat("\t/// <summary>{0}</summary>\n", XmlCommentString(type.Name));
|
||||
sb.AppendFormat("\tpublic partial interface I{0}", type.ClrName);
|
||||
var implements = type.BaseType == null || type.BaseType.IsContentIgnored
|
||||
var implements = type.BaseType == null
|
||||
? (type.HasBase ? null : (type.IsElement ? "PublishedElement" : "PublishedContent"))
|
||||
: type.BaseType.ClrName;
|
||||
if (implements != null)
|
||||
@@ -126,7 +141,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
// write the properties - only the local (non-ignored) ones, we're an interface
|
||||
var more = false;
|
||||
foreach (var prop in type.Properties.Where(x => !x.IsIgnored).OrderBy(x => x.ClrName))
|
||||
foreach (var prop in type.Properties.OrderBy(x => x.ClrName))
|
||||
{
|
||||
if (more) sb.Append("\n");
|
||||
more = true;
|
||||
@@ -137,8 +152,6 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
}
|
||||
|
||||
// write the class declaration
|
||||
if (type.IsRenamed)
|
||||
sb.AppendFormat("\t// Content Type {0} with alias \"{1}\"\n", type.Id, type.Alias);
|
||||
if (!string.IsNullOrWhiteSpace(type.Name))
|
||||
sb.AppendFormat("\t/// <summary>{0}</summary>\n", XmlCommentString(type.Name));
|
||||
// cannot do it now. see note in ImplementContentTypeAttribute
|
||||
@@ -148,7 +161,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
sb.AppendFormat("\tpublic partial class {0}", type.ClrName);
|
||||
var inherits = type.HasBase
|
||||
? null // has its own base already
|
||||
: (type.BaseType == null || type.BaseType.IsContentIgnored
|
||||
: (type.BaseType == null
|
||||
? GetModelsBaseClassName(type)
|
||||
: type.BaseType.ClrName);
|
||||
if (inherits != null)
|
||||
@@ -178,22 +191,25 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
// as 'new' since parent has its own - or maybe not - disable warning
|
||||
sb.Append("\t\t// helpers\n");
|
||||
sb.Append("#pragma warning disable 0109 // new is redundant\n");
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
sb.AppendFormat("\t\tpublic new const string ModelTypeAlias = \"{0}\";\n",
|
||||
type.Alias);
|
||||
var itemType = type.IsElement ? TypeModel.ItemTypes.Content : type.ItemType; // fixme
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
sb.AppendFormat("\t\tpublic new const PublishedItemType ModelItemType = PublishedItemType.{0};\n",
|
||||
itemType);
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
sb.Append("\t\tpublic new static PublishedContentType GetModelContentType()\n");
|
||||
sb.Append("\t\t\t=> PublishedModelUtility.GetModelContentType(ModelItemType, ModelTypeAlias);\n");
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
sb.AppendFormat("\t\tpublic static PublishedPropertyType GetModelPropertyType<TValue>(Expression<Func<{0}, TValue>> selector)\n",
|
||||
type.ClrName);
|
||||
sb.Append("\t\t\t=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(), selector);\n");
|
||||
sb.Append("#pragma warning restore 0109\n\n");
|
||||
|
||||
// write the ctor
|
||||
if (!type.HasCtor)
|
||||
sb.AppendFormat("\t\t// ctor\n\t\tpublic {0}(IPublished{1} content)\n\t\t\t: base(content)\n\t\t{{ }}\n\n",
|
||||
type.ClrName, type.IsElement ? "Element" : "Content");
|
||||
sb.AppendFormat("\t\t// ctor\n\t\tpublic {0}(IPublished{1} content)\n\t\t\t: base(content)\n\t\t{{ }}\n\n",
|
||||
type.ClrName, type.IsElement ? "Element" : "Content");
|
||||
|
||||
// write the properties
|
||||
sb.Append("\t\t// properties\n");
|
||||
@@ -205,10 +221,10 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
private void WriteContentTypeProperties(StringBuilder sb, TypeModel type)
|
||||
{
|
||||
var staticMixinGetters = UmbracoConfig.For.ModelsBuilder().StaticMixinGetters;
|
||||
var staticMixinGetters = true;
|
||||
|
||||
// write the properties
|
||||
foreach (var prop in type.Properties.Where(x => !x.IsIgnored).OrderBy(x => x.ClrName))
|
||||
foreach (var prop in type.Properties.OrderBy(x => x.ClrName))
|
||||
WriteProperty(sb, type, prop, staticMixinGetters && type.IsMixin ? type.ClrName : null);
|
||||
|
||||
// no need to write the parent properties since we inherit from the parent
|
||||
@@ -217,7 +233,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
// write the mixins properties
|
||||
foreach (var mixinType in type.ImplementingInterfaces.OrderBy(x => x.ClrName))
|
||||
foreach (var prop in mixinType.Properties.Where(x => !x.IsIgnored).OrderBy(x => x.ClrName))
|
||||
foreach (var prop in mixinType.Properties.OrderBy(x => x.ClrName))
|
||||
if (staticMixinGetters)
|
||||
WriteMixinProperty(sb, prop, mixinType.ClrName);
|
||||
else
|
||||
@@ -242,6 +258,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
sb.Append("\t\t///</summary>\n");
|
||||
}
|
||||
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
sb.AppendFormat("\t\t[ImplementPropertyType(\"{0}\")]\n", property.Alias);
|
||||
|
||||
sb.Append("\t\tpublic ");
|
||||
@@ -256,7 +273,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
private static string MixinStaticGetterName(string clrName)
|
||||
{
|
||||
return string.Format(UmbracoConfig.For.ModelsBuilder().StaticMixinGetterPattern, clrName);
|
||||
return string.Format("Get{0}", clrName);
|
||||
}
|
||||
|
||||
private void WriteProperty(StringBuilder sb, TypeModel type, PropertyModel property, string mixinClrName = null)
|
||||
@@ -300,6 +317,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
sb.Append("\t\t///</summary>\n");
|
||||
}
|
||||
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
sb.AppendFormat("\t\t[ImplementPropertyType(\"{0}\")]\n", property.Alias);
|
||||
|
||||
if (mixinStatic)
|
||||
@@ -343,6 +361,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
if (!string.IsNullOrWhiteSpace(property.Name))
|
||||
sb.AppendFormat("\t\t/// <summary>Static getter for {0}</summary>\n", XmlCommentString(property.Name));
|
||||
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
sb.Append("\t\tpublic static ");
|
||||
WriteClrType(sb, property.ClrTypeName);
|
||||
sb.AppendFormat(" {0}(I{1} that) => that.Value",
|
||||
@@ -397,6 +416,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(property.Name))
|
||||
sb.AppendFormat("\t\t/// <summary>{0}</summary>\n", XmlCommentString(property.Name));
|
||||
WriteGeneratedCodeAttribute(sb, "\t\t");
|
||||
sb.Append("\t\t");
|
||||
WriteClrType(sb, property.ClrTypeName);
|
||||
sb.AppendFormat(" {0} {{ get; }}\n",
|
||||
@@ -461,7 +481,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
s = Regex.Replace(s, @"\{(.*)\}\[\*\]", m => ModelsMap[m.Groups[1].Value + "[]"]);
|
||||
|
||||
// takes care eg of "System.Int32" vs. "int"
|
||||
if (TypesMap.TryGetValue(s.ToLowerInvariant(), out string typeName))
|
||||
if (TypesMap.TryGetValue(s, out string typeName))
|
||||
{
|
||||
sb.Append(typeName);
|
||||
return;
|
||||
@@ -481,6 +501,11 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
typeName = typeName.Substring(p + 1);
|
||||
typeUsing = x;
|
||||
}
|
||||
else if (x == ModelsNamespace) // that one is used by default
|
||||
{
|
||||
typeName = typeName.Substring(p + 1);
|
||||
typeUsing = ModelsNamespace;
|
||||
}
|
||||
}
|
||||
|
||||
// nested types *after* using
|
||||
@@ -531,24 +556,24 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
return s.Replace('<', '{').Replace('>', '}').Replace('\r', ' ').Replace('\n', ' ');
|
||||
}
|
||||
|
||||
private static readonly IDictionary<string, string> TypesMap = new Dictionary<string, string>
|
||||
private static readonly IDictionary<string, string> TypesMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "system.int16", "short" },
|
||||
{ "system.int32", "int" },
|
||||
{ "system.int64", "long" },
|
||||
{ "system.string", "string" },
|
||||
{ "system.object", "object" },
|
||||
{ "system.boolean", "bool" },
|
||||
{ "system.void", "void" },
|
||||
{ "system.char", "char" },
|
||||
{ "system.byte", "byte" },
|
||||
{ "system.uint16", "ushort" },
|
||||
{ "system.uint32", "uint" },
|
||||
{ "system.uint64", "ulong" },
|
||||
{ "system.sbyte", "sbyte" },
|
||||
{ "system.single", "float" },
|
||||
{ "system.double", "double" },
|
||||
{ "system.decimal", "decimal" }
|
||||
{ "System.Int16", "short" },
|
||||
{ "System.Int32", "int" },
|
||||
{ "System.Int64", "long" },
|
||||
{ "System.String", "string" },
|
||||
{ "System.Object", "object" },
|
||||
{ "System.Boolean", "bool" },
|
||||
{ "System.Void", "void" },
|
||||
{ "System.Char", "char" },
|
||||
{ "System.Byte", "byte" },
|
||||
{ "System.UInt16", "ushort" },
|
||||
{ "System.UInt32", "uint" },
|
||||
{ "System.UInt64", "ulong" },
|
||||
{ "System.SByte", "sbyte" },
|
||||
{ "System.Single", "float" },
|
||||
{ "System.Double", "double" },
|
||||
{ "System.Decimal", "decimal" }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
{
|
||||
@@ -88,16 +89,6 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// or because the existing user's code declares a base class for this model.</remarks>
|
||||
public bool HasBase;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this model has been renamed.
|
||||
/// </summary>
|
||||
public bool IsRenamed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this model has [ImplementContentType] already.
|
||||
/// </summary>
|
||||
public bool HasImplement;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this model is used as a mixin by another model.
|
||||
/// </summary>
|
||||
@@ -108,16 +99,6 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// </summary>
|
||||
public bool IsParent;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this model should be excluded from generation.
|
||||
/// </summary>
|
||||
public bool IsContentIgnored;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the ctor is already defined in a partial.
|
||||
/// </summary>
|
||||
public bool HasCtor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is an element.
|
||||
/// </summary>
|
||||
@@ -181,11 +162,11 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// <remarks>Includes the specified type.</remarks>
|
||||
internal static void CollectImplems(ICollection<TypeModel> types, TypeModel type)
|
||||
{
|
||||
if (!type.IsContentIgnored && types.Contains(type) == false)
|
||||
if (types.Contains(type) == false)
|
||||
types.Add(type);
|
||||
if (type.BaseType != null && !type.BaseType.IsContentIgnored)
|
||||
if (type.BaseType != null)
|
||||
CollectImplems(types, type.BaseType);
|
||||
foreach (var mixin in type.MixinTypes.Where(x => !x.IsContentIgnored))
|
||||
foreach (var mixin in type.MixinTypes)
|
||||
CollectImplems(types, mixin);
|
||||
}
|
||||
|
||||
@@ -204,5 +185,21 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
typeModel = typeModel.BaseType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps ModelType.
|
||||
/// </summary>
|
||||
public static void MapModelTypes(IList<TypeModel> typeModels, string ns)
|
||||
{
|
||||
var hasNs = !string.IsNullOrWhiteSpace(ns);
|
||||
var map = typeModels.ToDictionary(x => x.Alias, x => hasNs ? (ns + "." + x.ClrName) : x.ClrName);
|
||||
foreach (var typeModel in typeModels)
|
||||
{
|
||||
foreach (var propertyModel in typeModel.Properties)
|
||||
{
|
||||
propertyModel.ClrTypeName = ModelType.MapToName(propertyModel.ModelClrType, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="UmbracoConfig"/> class.
|
||||
/// </summary>
|
||||
public static class ConfigsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the models builder configuration.
|
||||
/// </summary>
|
||||
/// <remarks>Getting the models builder configuration freezes its state,
|
||||
/// and any attempt at modifying the configuration using the Setup method
|
||||
/// will be ignored.</remarks>
|
||||
public static Config ModelsBuilder(this Configs configs)
|
||||
=> configs.GetConfig<Config>();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.Hosting;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Configuration
|
||||
@@ -14,40 +12,13 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
/// </summary>
|
||||
public class Config
|
||||
{
|
||||
private static Config _value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration - internal so that the UmbracoConfig extension
|
||||
/// can get the value to initialize its own value. Either a value has
|
||||
/// been provided via the Setup method, or a new instance is created, which
|
||||
/// will load settings from the config file.
|
||||
/// </summary>
|
||||
internal static Config Value => _value ?? new Config();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the configuration programmatically.
|
||||
/// </summary>
|
||||
/// <param name="config">The configuration.</param>
|
||||
/// <remarks>
|
||||
/// <para>Once the configuration has been accessed via the UmbracoConfig extension,
|
||||
/// it cannot be changed anymore, and using this method will achieve nothing.</para>
|
||||
/// <para>For tests, see UmbracoConfigExtensions.ResetConfig().</para>
|
||||
/// </remarks>
|
||||
public static void Setup(Config config)
|
||||
{
|
||||
_value = config;
|
||||
}
|
||||
|
||||
internal const string DefaultStaticMixinGetterPattern = "Get{0}";
|
||||
internal const LanguageVersion DefaultLanguageVersion = LanguageVersion.CSharp6;
|
||||
internal const string DefaultModelsNamespace = "Umbraco.Web.PublishedModels";
|
||||
internal const ClrNameSource DefaultClrNameSource = ClrNameSource.Alias; // for legacy reasons
|
||||
internal const string DefaultModelsDirectory = "~/App_Data/Models";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Config"/> class.
|
||||
/// </summary>
|
||||
private Config()
|
||||
public Config()
|
||||
{
|
||||
const string prefix = "Umbraco.ModelsBuilder.";
|
||||
|
||||
@@ -56,10 +27,7 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
Enable = ConfigurationManager.AppSettings[prefix + "Enable"] == "true";
|
||||
|
||||
// ensure defaults are initialized for tests
|
||||
StaticMixinGetterPattern = DefaultStaticMixinGetterPattern;
|
||||
LanguageVersion = DefaultLanguageVersion;
|
||||
ModelsNamespace = DefaultModelsNamespace;
|
||||
ClrNameSource = DefaultClrNameSource;
|
||||
ModelsDirectory = HostingEnvironment.IsHosted
|
||||
? HostingEnvironment.MapPath(DefaultModelsDirectory)
|
||||
: DefaultModelsDirectory.TrimStart("~/");
|
||||
@@ -80,12 +48,6 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
case nameof(ModelsMode.PureLive):
|
||||
ModelsMode = ModelsMode.PureLive;
|
||||
break;
|
||||
case nameof(ModelsMode.Dll):
|
||||
ModelsMode = ModelsMode.Dll;
|
||||
break;
|
||||
case nameof(ModelsMode.LiveDll):
|
||||
ModelsMode = ModelsMode.LiveDll;
|
||||
break;
|
||||
case nameof(ModelsMode.AppData):
|
||||
ModelsMode = ModelsMode.AppData;
|
||||
break;
|
||||
@@ -94,17 +56,15 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
break;
|
||||
default:
|
||||
throw new ConfigurationErrorsException($"ModelsMode \"{modelsMode}\" is not a valid mode."
|
||||
+ " Note that modes are case-sensitive.");
|
||||
+ " Note that modes are case-sensitive. Possible values are: " + string.Join(", ", Enum.GetNames(typeof(ModelsMode))));
|
||||
}
|
||||
}
|
||||
|
||||
// default: false
|
||||
EnableApi = ConfigurationManager.AppSettings[prefix + "EnableApi"].InvariantEquals("true");
|
||||
AcceptUnsafeModelsDirectory = ConfigurationManager.AppSettings[prefix + "AcceptUnsafeModelsDirectory"].InvariantEquals("true");
|
||||
|
||||
// default: true
|
||||
EnableFactory = !ConfigurationManager.AppSettings[prefix + "EnableFactory"].InvariantEquals("false");
|
||||
StaticMixinGetters = !ConfigurationManager.AppSettings[prefix + "StaticMixinGetters"].InvariantEquals("false");
|
||||
FlagOutOfDateModels = !ConfigurationManager.AppSettings[prefix + "FlagOutOfDateModels"].InvariantEquals("false");
|
||||
|
||||
// default: initialized above with DefaultModelsNamespace const
|
||||
@@ -112,45 +72,6 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
ModelsNamespace = value;
|
||||
|
||||
// default: initialized above with DefaultStaticMixinGetterPattern const
|
||||
value = ConfigurationManager.AppSettings[prefix + "StaticMixinGetterPattern"];
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
StaticMixinGetterPattern = value;
|
||||
|
||||
// default: initialized above with DefaultLanguageVersion const
|
||||
value = ConfigurationManager.AppSettings[prefix + "LanguageVersion"];
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
LanguageVersion lv;
|
||||
if (!Enum.TryParse(value, true, out lv))
|
||||
throw new ConfigurationErrorsException($"Invalid language version \"{value}\".");
|
||||
LanguageVersion = lv;
|
||||
}
|
||||
|
||||
// default: initialized above with DefaultClrNameSource const
|
||||
value = ConfigurationManager.AppSettings[prefix + "ClrNameSource"];
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case nameof(ClrNameSource.Nothing):
|
||||
ClrNameSource = ClrNameSource.Nothing;
|
||||
break;
|
||||
case nameof(ClrNameSource.Alias):
|
||||
ClrNameSource = ClrNameSource.Alias;
|
||||
break;
|
||||
case nameof(ClrNameSource.RawAlias):
|
||||
ClrNameSource = ClrNameSource.RawAlias;
|
||||
break;
|
||||
case nameof(ClrNameSource.Name):
|
||||
ClrNameSource = ClrNameSource.Name;
|
||||
break;
|
||||
default:
|
||||
throw new ConfigurationErrorsException($"ClrNameSource \"{value}\" is not a valid source."
|
||||
+ " Note that sources are case-sensitive.");
|
||||
}
|
||||
}
|
||||
|
||||
// default: initialized above with DefaultModelsDirectory const
|
||||
value = ConfigurationManager.AppSettings[prefix + "ModelsDirectory"];
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
@@ -186,14 +107,9 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
public Config(
|
||||
bool enable = false,
|
||||
ModelsMode modelsMode = ModelsMode.Nothing,
|
||||
bool enableApi = true,
|
||||
string modelsNamespace = null,
|
||||
bool enableFactory = true,
|
||||
LanguageVersion languageVersion = DefaultLanguageVersion,
|
||||
bool staticMixinGetters = true,
|
||||
string staticMixinGetterPattern = null,
|
||||
bool flagOutOfDateModels = true,
|
||||
ClrNameSource clrNameSource = DefaultClrNameSource,
|
||||
string modelsDirectory = null,
|
||||
bool acceptUnsafeModelsDirectory = false,
|
||||
int debugLevel = 0)
|
||||
@@ -201,14 +117,9 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
Enable = enable;
|
||||
ModelsMode = modelsMode;
|
||||
|
||||
EnableApi = enableApi;
|
||||
ModelsNamespace = string.IsNullOrWhiteSpace(modelsNamespace) ? DefaultModelsNamespace : modelsNamespace;
|
||||
EnableFactory = enableFactory;
|
||||
LanguageVersion = languageVersion;
|
||||
StaticMixinGetters = staticMixinGetters;
|
||||
StaticMixinGetterPattern = string.IsNullOrWhiteSpace(staticMixinGetterPattern) ? DefaultStaticMixinGetterPattern : staticMixinGetterPattern;
|
||||
FlagOutOfDateModels = flagOutOfDateModels;
|
||||
ClrNameSource = clrNameSource;
|
||||
ModelsDirectory = string.IsNullOrWhiteSpace(modelsDirectory) ? DefaultModelsDirectory : modelsDirectory;
|
||||
AcceptUnsafeModelsDirectory = acceptUnsafeModelsDirectory;
|
||||
DebugLevel = debugLevel;
|
||||
@@ -259,27 +170,6 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
/// </summary>
|
||||
public ModelsMode ModelsMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to serve the API.
|
||||
/// </summary>
|
||||
public bool ApiServer => EnableApi && ApiInstalled && IsDebug;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to enable the API.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Default value is <c>true</c>.</para>
|
||||
/// <para>The API is used by the Visual Studio extension and the console tool to talk to Umbraco
|
||||
/// and retrieve the content types. It needs to be enabled so the extension & tool can work.</para>
|
||||
/// </remarks>
|
||||
public bool EnableApi { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the API is installed.
|
||||
/// </summary>
|
||||
// fixme - this is now always true as the API is part of Core
|
||||
public bool ApiInstalled => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether system.web/compilation/@debug is true.
|
||||
/// </summary>
|
||||
@@ -304,24 +194,6 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
/// <remarks>Default value is <c>true</c> because no factory is enabled by default in Umbraco.</remarks>
|
||||
public bool EnableFactory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Roslyn parser language version.
|
||||
/// </summary>
|
||||
/// <remarks>Default value is <c>CSharp6</c>.</remarks>
|
||||
public LanguageVersion LanguageVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to generate static mixin getters.
|
||||
/// </summary>
|
||||
/// <remarks>Default value is <c>false</c> for backward compat reaons.</remarks>
|
||||
public bool StaticMixinGetters { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string pattern for mixin properties static getter name.
|
||||
/// </summary>
|
||||
/// <remarks>Default value is "GetXxx". Standard string format.</remarks>
|
||||
public string StaticMixinGetterPattern { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether we should flag out-of-date models.
|
||||
/// </summary>
|
||||
@@ -330,11 +202,6 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
/// generated through the dashboard, the files is cleared. Default value is <c>false</c>.</remarks>
|
||||
public bool FlagOutOfDateModels { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CLR name source.
|
||||
/// </summary>
|
||||
public ClrNameSource ClrNameSource { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the models directory.
|
||||
/// </summary>
|
||||
|
||||
@@ -31,22 +31,6 @@
|
||||
/// </summary>
|
||||
/// <remarks>Generation can be triggered from the dashboard. The app does not restart.
|
||||
/// Models are not compiled and thus are not available to the project.</remarks>
|
||||
LiveAppData,
|
||||
|
||||
/// <summary>
|
||||
/// Generates models in AppData and compiles them into a Dll into ~/bin (the app restarts).
|
||||
/// When: generation is triggered.
|
||||
/// </summary>
|
||||
/// <remarks>Generation can be triggered from the dashboard. The app does restart. Models
|
||||
/// are available to the entire project.</remarks>
|
||||
Dll,
|
||||
|
||||
/// <summary>
|
||||
/// Generates models in AppData and compiles them into a Dll into ~/bin (the app restarts).
|
||||
/// When: a content type change occurs, or generation is triggered.
|
||||
/// </summary>
|
||||
/// <remarks>Generation can be triggered from the dashboard. The app does restart. Models
|
||||
/// are available to the entire project.</remarks>
|
||||
LiveDll
|
||||
LiveAppData
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user