Compare commits
145 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 78735ff349 | |||
| 1af43498d9 | |||
| 015ad64e30 | |||
| 6dbb988903 | |||
| 926acb910e | |||
| 57e3187e3a | |||
| 988d51c4c8 | |||
| 4733256ca1 | |||
| 4133a1fe76 | |||
| 37bf6fe938 | |||
| 31716e574c | |||
| 126c4cbd46 | |||
| 7cc91f71c2 | |||
| 7c52b9602c | |||
| c5f1cc15fd | |||
| d089518681 | |||
| cd6ef35bf9 | |||
| 47cdc79fcb | |||
| f7382255c2 | |||
| 2167eada0c | |||
| df11935598 | |||
| d3b4b9fe64 | |||
| 33aff7ff61 | |||
| 4d2c551b79 | |||
| 5b7ae7150f | |||
| 5bf29a907a | |||
| 96d5bdd7b2 | |||
| 7b4023fd5a | |||
| af72729905 | |||
| d5bc54cf6c | |||
| 5625102e2c | |||
| 66abd7b50c | |||
| 2a9bcf0e98 | |||
| e6484687e5 | |||
| 5da1e64bbc | |||
| 7b0979f9fd | |||
| 1a437c1c6a | |||
| 3c0565e516 | |||
| 178b1ccf40 | |||
| c03cd81c23 | |||
| 3d3647b476 | |||
| a4cac670df | |||
| c414dd06cc | |||
| 4ed746e4ef | |||
| c270d8ecac | |||
| ade9bb7324 | |||
| 4134dd16df | |||
| f81588bb13 | |||
| 09793a1744 | |||
| ba7cd48b8f | |||
| 640d2cedb9 | |||
| 0a6237af04 | |||
| 503183331f | |||
| 3effc66b2c | |||
| b64f303537 | |||
| 760f6a1647 | |||
| 0b64e34f05 | |||
| f01be09075 | |||
| 1c5ed58074 | |||
| 42d86f147f | |||
| fa4acb255b | |||
| 1885767ef1 | |||
| 80e6880bb7 | |||
| fabacd1689 | |||
| 23a7654cea | |||
| b2d019bfe1 | |||
| 9f817bf032 | |||
| 01c89bd338 | |||
| e5956e4955 | |||
| 958c3b147b | |||
| 4a33ca99ba | |||
| 568835f7e2 | |||
| 84aa861a5b | |||
| ee2ebc7d14 | |||
| 9ce996cbba | |||
| 580ba79619 | |||
| fbe184ef6e | |||
| 2f7bf413ed | |||
| 390613c796 | |||
| b3e3475bf5 | |||
| 5333b23c23 | |||
| 734086fcf5 | |||
| 12dff9bca3 | |||
| f370e738da | |||
| a018ed9e52 | |||
| 17f73b88dc | |||
| 405e9a79be | |||
| 4d90322842 | |||
| a8b5d69be0 | |||
| 5ebd90aba5 | |||
| bec909c284 | |||
| 46e0b08d65 | |||
| 7a178be031 | |||
| 9d14c9e0b7 | |||
| ef19633a90 | |||
| 80ffd026f6 | |||
| cb7300688c | |||
| 040ebfe9dd | |||
| fad33a97b2 | |||
| ac586c5207 | |||
| 8033931e31 | |||
| 8e29810598 | |||
| be96e2cf08 | |||
| 534ee67ad2 | |||
| 571a3bc257 | |||
| e7a30d0a5d | |||
| a55323176f | |||
| 1b83e0a87d | |||
| ca15f340b0 | |||
| 23b8e1cce8 | |||
| cf53ba363d | |||
| 2f309a2fd6 | |||
| 9f45d41a4a | |||
| 1994194656 | |||
| 36559b8761 | |||
| 8fe7c5599a | |||
| 4dd325cec9 | |||
| d558646d75 | |||
| afac4bb918 | |||
| 0869bf27c7 | |||
| 383a8617ce | |||
| 3865f4fb50 | |||
| 3e74bbfb45 | |||
| 966b07ba1c | |||
| 60ed6f6b20 | |||
| 903c163a57 | |||
| d4311fe4ab | |||
| eab597a2a8 | |||
| 003ee1a991 | |||
| 601d48277e | |||
| 8d12170def | |||
| d2655a9f2f | |||
| c4c2082fa9 | |||
| 40d4a8fe6a | |||
| 2898203cb9 | |||
| 5ebdfc7b1c | |||
| 31d7e58191 | |||
| ad4416f663 | |||
| b55d2a8a41 | |||
| 17a4799b97 | |||
| 4df838c20c | |||
| 4e44871671 | |||
| 1dd2c1cb91 | |||
| 6b23a8221d | |||
| db867c66a3 |
@@ -14,6 +14,7 @@
|
||||
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
|
||||
<dependencies>
|
||||
|
||||
<group targetFramework="net472">
|
||||
@@ -44,7 +45,7 @@
|
||||
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
|
||||
<dependency id="NPoco" version="[3.9.4,3.999999)" />
|
||||
</group>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
@@ -55,6 +56,6 @@
|
||||
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\net472\Umbraco.Core.xml" />
|
||||
|
||||
<!-- symbols -->
|
||||
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib\net472\Umbraco.Core.pdb" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
|
||||
<dependencies>
|
||||
|
||||
<group targetFramework="net472">
|
||||
@@ -43,7 +44,7 @@
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.9.0,4.999999)" />
|
||||
|
||||
</group>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
@@ -51,17 +52,14 @@
|
||||
<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\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" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib\net472\Umbraco.Web.pdb" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib\net472\Umbraco.Examine.pdb" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
|
||||
<dependencies>
|
||||
|
||||
<group targetFramework="net472">
|
||||
@@ -25,6 +26,7 @@
|
||||
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.1.0]" />
|
||||
<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)" />
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</configSections>
|
||||
|
||||
<system.web.webPages.razor>
|
||||
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(factoryType)" xdt:Transform="SetAttributes(factoryType)" />
|
||||
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(factoryType)" xdt:Transform="SetAttributes(factoryType)" />
|
||||
<pages pageBaseType="System.Web.Mvc.WebViewPage">
|
||||
<namespaces>
|
||||
<add namespace="Umbraco.Web.PublishedContentModels" xdt:Transform="InsertIfMissing" />
|
||||
@@ -18,13 +18,13 @@
|
||||
|
||||
<system.web>
|
||||
<pages
|
||||
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
|
||||
xdt:Locator="Match(pageParserFilterType,pageBaseType,userControlBaseType)"
|
||||
xdt:Transform="SetAttributes(pageParserFilterType,pageBaseType,userControlBaseType)">
|
||||
<controls>
|
||||
<add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" xdt:Locator="Match(namespace)" xdt:Transform="SetAttributes(assembly)" />
|
||||
<add assembly="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" xdt:Locator="Match(namespace)" xdt:Transform="SetAttributes(assembly)" />
|
||||
</controls>
|
||||
</pages>
|
||||
</system.web>
|
||||
|
||||
@@ -18,9 +18,20 @@ if ($project) {
|
||||
|
||||
# Copy umbraco and umbraco_files from package to project folder
|
||||
$umbracoFolder = Join-Path $projectPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoFolder
|
||||
New-Item -ItemType Directory -Force -Path $umbracoFolder
|
||||
$umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
|
||||
|
||||
Write-Host "copying files to $umbracoFolder ..."
|
||||
# see https://support.microsoft.com/en-us/help/954404/return-codes-that-are-used-by-the-robocopy-utility-in-windows-server-2
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e
|
||||
if (($lastexitcode -eq 1) -or ($lastexitcode -eq 3) -or ($lastexitcode -eq 5) -or ($lastexitcode -eq 7))
|
||||
{
|
||||
write-host "Copy succeeded!"
|
||||
}
|
||||
else
|
||||
{
|
||||
write-host "Copy failed with exit code:" $lastexitcode
|
||||
}
|
||||
|
||||
$copyWebconfig = $true
|
||||
$destinationWebConfig = Join-Path $projectPath "Web.config"
|
||||
@@ -40,7 +51,11 @@ if ($project) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch { }
|
||||
Catch
|
||||
{
|
||||
Write-Host "An error occurred:"
|
||||
Write-Host $_
|
||||
}
|
||||
}
|
||||
|
||||
if($copyWebconfig -eq $true)
|
||||
@@ -74,7 +89,9 @@ if ($project) {
|
||||
}
|
||||
Catch
|
||||
{
|
||||
# Not a big problem if this fails, let it go
|
||||
# Not a big problem if this fails, let it go
|
||||
# Write-Host "An error occurred:"
|
||||
# Write-Host $_
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -15,7 +15,7 @@
|
||||
[Parameter(Mandatory=$false)]
|
||||
[Alias("doc")]
|
||||
[switch] $docfx = $false,
|
||||
|
||||
|
||||
# keep the build directories, don't clear them
|
||||
[Parameter(Mandatory=$false)]
|
||||
[Alias("c")]
|
||||
@@ -392,13 +392,13 @@
|
||||
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Core.nuspec" `
|
||||
-Properties BuildTmp="$($this.BuildTemp)" `
|
||||
-Version "$($this.Version.Semver.ToString())" `
|
||||
-Symbols -SymbolPackageFormat snupkg -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
|
||||
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
|
||||
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Core." }
|
||||
|
||||
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Web.nuspec" `
|
||||
-Properties BuildTmp="$($this.BuildTemp)" `
|
||||
-Version "$($this.Version.Semver.ToString())" `
|
||||
-Symbols -SymbolPackageFormat snupkg -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
|
||||
-Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
|
||||
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Web." }
|
||||
|
||||
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.nuspec" `
|
||||
@@ -429,37 +429,37 @@
|
||||
Write-Host "Prepare Azure Gallery"
|
||||
$this.CopyFile("$($this.SolutionRoot)\build\Azure\azuregalleryrelease.ps1", $this.BuildOutput)
|
||||
})
|
||||
|
||||
|
||||
$ubuild.DefineMethod("PrepareCSharpDocs",
|
||||
{
|
||||
Write-Host "Prepare C# Documentation"
|
||||
|
||||
|
||||
$src = "$($this.SolutionRoot)\src"
|
||||
$tmp = $this.BuildTemp
|
||||
$out = $this.BuildOutput
|
||||
$DocFxJson = Join-Path -Path $src "\ApiDocs\docfx.json"
|
||||
$DocFxSiteOutput = Join-Path -Path $tmp "\_site\*.*"
|
||||
|
||||
|
||||
|
||||
#restore nuget packages
|
||||
$this.RestoreNuGet()
|
||||
# run DocFx
|
||||
$DocFx = $this.BuildEnv.DocFx
|
||||
|
||||
|
||||
& $DocFx metadata $DocFxJson
|
||||
& $DocFx build $DocFxJson
|
||||
|
||||
# zip it
|
||||
& $this.BuildEnv.Zip a -tzip -r "$out\csharp-docs.zip" $DocFxSiteOutput
|
||||
})
|
||||
|
||||
|
||||
$ubuild.DefineMethod("PrepareAngularDocs",
|
||||
{
|
||||
Write-Host "Prepare Angular Documentation"
|
||||
|
||||
|
||||
$src = "$($this.SolutionRoot)\src"
|
||||
$out = $this.BuildOutput
|
||||
|
||||
|
||||
$this.CompileBelle()
|
||||
|
||||
"Moving to Umbraco.Web.UI.Client folder"
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace Umbraco.Core.Composing
|
||||
private string _currentAssembliesHash;
|
||||
private IEnumerable<Assembly> _assemblies;
|
||||
private bool _reportedChange;
|
||||
private static string _localTempPath;
|
||||
private static string _fileBasePath;
|
||||
private readonly string _localTempPath;
|
||||
private string _fileBasePath;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
|
||||
|
||||
@@ -1,27 +1,375 @@
|
||||
namespace Umbraco.Core
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
public static class DataTypes
|
||||
{
|
||||
public const int LabelString = -92;
|
||||
//NOTE: unfortunately due to backwards compat we can't move/rename these, with the addition of the GUID
|
||||
//constants, it would make more sense to have these suffixed with "ID" or in a Subclass called "INT", for
|
||||
//now all we can do is make a subclass called Guids to put the GUID IDs.
|
||||
|
||||
public const int LabelString = System.DefaultLabelDataTypeId;
|
||||
public const int LabelInt = -91;
|
||||
public const int LabelBigint = -93;
|
||||
public const int LabelDateTime = -94;
|
||||
public const int LabelTime = -98;
|
||||
public const int LabelDecimal = -99;
|
||||
|
||||
public const int Textarea = -89;
|
||||
public const int Textbox = -88;
|
||||
public const int RichtextEditor = -87;
|
||||
public const int Boolean = -49;
|
||||
public const int DateTime = -36;
|
||||
public const int DropDownSingle = -39;
|
||||
public const int DropDownMultiple = -42;
|
||||
public const int Upload = -90;
|
||||
|
||||
public const int DefaultContentListView = -95;
|
||||
public const int DefaultMediaListView = -96;
|
||||
public const int DefaultMembersListView = -97;
|
||||
|
||||
public const int ImageCropper = 1043;
|
||||
public const int Tags = 1041;
|
||||
|
||||
public static class ReservedPreValueKeys
|
||||
{
|
||||
public const string IgnoreUserStartNodes = "ignoreUserStartNodes";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco data types as constants for easy centralized access/management.
|
||||
/// </summary>
|
||||
public static class Guids
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Content Picker as string
|
||||
/// </summary>
|
||||
public const string ContentPicker = "FD1E0DA5-5606-4862-B679-5D0CF3A52A59";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Content Picker
|
||||
/// </summary>
|
||||
public static readonly Guid ContentPickerGuid = new Guid(ContentPicker);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Member Picker as string
|
||||
/// </summary>
|
||||
public const string MemberPicker = "1EA2E01F-EBD8-4CE1-8D71-6B1149E63548";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Member Picker
|
||||
/// </summary>
|
||||
public static readonly Guid MemberPickerGuid = new Guid(MemberPicker);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Media Picker as string
|
||||
/// </summary>
|
||||
public const string MediaPicker = "135D60E0-64D9-49ED-AB08-893C9BA44AE5";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Media Picker
|
||||
/// </summary>
|
||||
public static readonly Guid MediaPickerGuid = new Guid(MediaPicker);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Multiple Media Picker as string
|
||||
/// </summary>
|
||||
public const string MultipleMediaPicker = "9DBBCBBB-2327-434A-B355-AF1B84E5010A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Multiple Media Picker
|
||||
/// </summary>
|
||||
public static readonly Guid MultipleMediaPickerGuid = new Guid(MultipleMediaPicker);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Related Links as string
|
||||
/// </summary>
|
||||
public const string RelatedLinks = "B4E3535A-1753-47E2-8568-602CF8CFEE6F";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Related Links
|
||||
/// </summary>
|
||||
public static readonly Guid RelatedLinksGuid = new Guid(RelatedLinks);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Member as string
|
||||
/// </summary>
|
||||
public const string Member = "d59be02f-1df9-4228-aa1e-01917d806cda";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Member
|
||||
/// </summary>
|
||||
public static readonly Guid MemberGuid = new Guid(Member);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Image Cropper as string
|
||||
/// </summary>
|
||||
public const string ImageCropper = "1df9f033-e6d4-451f-b8d2-e0cbc50a836f";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Image Cropper
|
||||
/// </summary>
|
||||
public static readonly Guid ImageCropperGuid = new Guid(ImageCropper);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Tags as string
|
||||
/// </summary>
|
||||
public const string Tags = "b6b73142-b9c1-4bf8-a16d-e1c23320b549";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Tags
|
||||
/// </summary>
|
||||
public static readonly Guid TagsGuid = new Guid(Tags);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for List View - Content as string
|
||||
/// </summary>
|
||||
public const string ListViewContent = "C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for List View - Content
|
||||
/// </summary>
|
||||
public static readonly Guid ListViewContentGuid = new Guid(ListViewContent);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for List View - Media as string
|
||||
/// </summary>
|
||||
public const string ListViewMedia = "3A0156C4-3B8C-4803-BDC1-6871FAA83FFF";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for List View - Media
|
||||
/// </summary>
|
||||
public static readonly Guid ListViewMediaGuid = new Guid(ListViewMedia);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for List View - Members as string
|
||||
/// </summary>
|
||||
public const string ListViewMembers = "AA2C52A0-CE87-4E65-A47C-7DF09358585D";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for List View - Members
|
||||
/// </summary>
|
||||
public static readonly Guid ListViewMembersGuid = new Guid(ListViewMembers);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Date Picker with time as string
|
||||
/// </summary>
|
||||
public const string DatePickerWithTime = "e4d66c0f-b935-4200-81f0-025f7256b89a";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Date Picker with time
|
||||
/// </summary>
|
||||
public static readonly Guid DatePickerWithTimeGuid = new Guid(DatePickerWithTime);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Approved Color as string
|
||||
/// </summary>
|
||||
public const string ApprovedColor = "0225af17-b302-49cb-9176-b9f35cab9c17";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Approved Color
|
||||
/// </summary>
|
||||
public static readonly Guid ApprovedColorGuid = new Guid(ApprovedColor);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Dropdown multiple as string
|
||||
/// </summary>
|
||||
public const string DropdownMultiple = "f38f0ac7-1d27-439c-9f3f-089cd8825a53";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Dropdown multiple
|
||||
/// </summary>
|
||||
public static readonly Guid DropdownMultipleGuid = new Guid(DropdownMultiple);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Radiobox as string
|
||||
/// </summary>
|
||||
public const string Radiobox = "bb5f57c9-ce2b-4bb9-b697-4caca783a805";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Radiobox
|
||||
/// </summary>
|
||||
public static readonly Guid RadioboxGuid = new Guid(Radiobox);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Date Picker as string
|
||||
/// </summary>
|
||||
public const string DatePicker = "5046194e-4237-453c-a547-15db3a07c4e1";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Date Picker
|
||||
/// </summary>
|
||||
public static readonly Guid DatePickerGuid = new Guid(DatePicker);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Dropdown as string
|
||||
/// </summary>
|
||||
public const string Dropdown = "0b6a45e7-44ba-430d-9da5-4e46060b9e03";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Dropdown
|
||||
/// </summary>
|
||||
public static readonly Guid DropdownGuid = new Guid(Dropdown);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Checkbox list as string
|
||||
/// </summary>
|
||||
public const string CheckboxList = "fbaf13a8-4036-41f2-93a3-974f678c312a";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Checkbox list
|
||||
/// </summary>
|
||||
public static readonly Guid CheckboxListGuid = new Guid(CheckboxList);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Checkbox as string
|
||||
/// </summary>
|
||||
public const string Checkbox = "92897bc6-a5f3-4ffe-ae27-f2e7e33dda49";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Checkbox
|
||||
/// </summary>
|
||||
public static readonly Guid CheckboxGuid = new Guid(Checkbox);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Numeric as string
|
||||
/// </summary>
|
||||
public const string Numeric = "2e6d3631-066e-44b8-aec4-96f09099b2b5";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Dropdown
|
||||
/// </summary>
|
||||
public static readonly Guid NumericGuid = new Guid(Numeric);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Richtext editor as string
|
||||
/// </summary>
|
||||
public const string RichtextEditor = "ca90c950-0aff-4e72-b976-a30b1ac57dad";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Richtext editor
|
||||
/// </summary>
|
||||
public static readonly Guid RichtextEditorGuid = new Guid(RichtextEditor);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Textstring as string
|
||||
/// </summary>
|
||||
public const string Textstring = "0cc0eba1-9960-42c9-bf9b-60e150b429ae";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Textstring
|
||||
/// </summary>
|
||||
public static readonly Guid TextstringGuid = new Guid(Textstring);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Textarea as string
|
||||
/// </summary>
|
||||
public const string Textarea = "c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Dropdown
|
||||
/// </summary>
|
||||
public static readonly Guid TextareaGuid = new Guid(Textarea);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Upload as string
|
||||
/// </summary>
|
||||
public const string Upload = "84c6b441-31df-4ffe-b67e-67d5bc3ae65a";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Upload
|
||||
/// </summary>
|
||||
public static readonly Guid UploadGuid = new Guid(Upload);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label as string
|
||||
/// </summary>
|
||||
public const string LabelString = "f0bc4bfb-b499-40d6-ba86-058885a5178c";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label string
|
||||
/// </summary>
|
||||
public static readonly Guid LabelStringGuid = new Guid(LabelString);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label as int
|
||||
/// </summary>
|
||||
public const string LabelInt = "8e7f995c-bd81-4627-9932-c40e568ec788";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label int
|
||||
/// </summary>
|
||||
public static readonly Guid LabelIntGuid = new Guid(LabelInt);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label as big int
|
||||
/// </summary>
|
||||
public const string LabelBigInt = "930861bf-e262-4ead-a704-f99453565708";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label big int
|
||||
/// </summary>
|
||||
public static readonly Guid LabelBigIntGuid = new Guid(LabelBigInt);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label as date time
|
||||
/// </summary>
|
||||
public const string LabelDateTime = "0e9794eb-f9b5-4f20-a788-93acd233a7e4";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label date time
|
||||
/// </summary>
|
||||
public static readonly Guid LabelDateTimeGuid = new Guid(LabelDateTime);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label as time
|
||||
/// </summary>
|
||||
public const string LabelTime = "a97cec69-9b71-4c30-8b12-ec398860d7e8";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label time
|
||||
/// </summary>
|
||||
public static readonly Guid LabelTimeGuid = new Guid(LabelTime);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label as decimal
|
||||
/// </summary>
|
||||
public const string LabelDecimal = "8f1ef1e1-9de4-40d3-a072-6673f631ca64";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for Label decimal
|
||||
/// </summary>
|
||||
public static readonly Guid LabelDecimalGuid = new Guid(LabelDecimal);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,39 +5,89 @@
|
||||
public static class Icons
|
||||
{
|
||||
/// <summary>
|
||||
/// System contenttype icon
|
||||
/// System default icon
|
||||
/// </summary>
|
||||
public const string ContentType = "icon-arrangement";
|
||||
public const string DefaultIcon = Content;
|
||||
|
||||
/// <summary>
|
||||
/// System datatype icon
|
||||
/// System content icon
|
||||
/// </summary>
|
||||
public const string Content = "icon-document";
|
||||
|
||||
/// <summary>
|
||||
/// System content type icon
|
||||
/// </summary>
|
||||
public const string ContentType = "icon-item-arrangement";
|
||||
|
||||
/// <summary>
|
||||
/// System data type icon
|
||||
/// </summary>
|
||||
public const string DataType = "icon-autofill";
|
||||
|
||||
/// <summary>
|
||||
/// System property editor icon
|
||||
/// System list view icon
|
||||
/// </summary>
|
||||
public const string PropertyEditor = "icon-autofill";
|
||||
public const string ListView = "icon-thumbnail-list";
|
||||
|
||||
/// <summary>
|
||||
/// System macro icon
|
||||
/// </summary>
|
||||
public const string Macro = "icon-settings-alt";
|
||||
|
||||
/// <summary>
|
||||
/// System media file icon
|
||||
/// </summary>
|
||||
public const string MediaFile = "icon-document";
|
||||
|
||||
/// <summary>
|
||||
/// System media folder icon
|
||||
/// </summary>
|
||||
public const string MediaFolder = "icon-folder";
|
||||
|
||||
/// <summary>
|
||||
/// System media image icon
|
||||
/// </summary>
|
||||
public const string MediaImage = "icon-picture";
|
||||
|
||||
/// <summary>
|
||||
/// System media type icon
|
||||
/// </summary>
|
||||
public const string MediaType = "icon-thumbnails";
|
||||
|
||||
/// <summary>
|
||||
/// System member icon
|
||||
/// </summary>
|
||||
public const string Member = "icon-user";
|
||||
|
||||
/// <summary>
|
||||
/// System member icon
|
||||
/// System member group icon
|
||||
/// </summary>
|
||||
public const string MemberGroup = "icon-users-alt";
|
||||
|
||||
/// <summary>
|
||||
/// System member type icon
|
||||
/// </summary>
|
||||
public const string MemberType = "icon-users";
|
||||
|
||||
/// <summary>
|
||||
/// System property editor icon
|
||||
/// </summary>
|
||||
public const string PropertyEditor = "icon-autofill";
|
||||
|
||||
/// <summary>
|
||||
/// System member icon
|
||||
/// </summary>
|
||||
public const string Template = "icon-layout";
|
||||
|
||||
/// <summary>
|
||||
/// System user icon
|
||||
/// </summary>
|
||||
public const string User = "icon-user";
|
||||
|
||||
/// <summary>
|
||||
/// System user group icon
|
||||
/// </summary>
|
||||
public const string UserGroup = "icon-users";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ namespace Umbraco.Core
|
||||
///</summary>
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
internal static bool IsCollectionEmpty<T>(this IReadOnlyCollection<T> list) => list == null || list.Count == 0;
|
||||
|
||||
internal static bool HasDuplicates<T>(this IEnumerable<T> items, bool includeNull)
|
||||
{
|
||||
var hs = new HashSet<T>();
|
||||
@@ -112,7 +114,6 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if all items in the other collection exist in this collection
|
||||
/// </summary>
|
||||
|
||||
@@ -101,33 +101,33 @@ namespace Umbraco.Core.Migrations.Install
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -1, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1", SortOrder = 0, UniqueId = new Guid("916724a5-173d-4619-b97e-b9de133dd6f5"), Text = "SYSTEM DATA: umbraco master root", NodeObjectType = Constants.ObjectTypes.SystemRoot, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -20, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,-20", SortOrder = 0, UniqueId = new Guid("0F582A79-1E41-4CF0-BFA0-76340651891A"), Text = "Recycle Bin", NodeObjectType = Constants.ObjectTypes.ContentRecycleBin, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -21, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,-21", SortOrder = 0, UniqueId = new Guid("BF7C7CBC-952F-4518-97A2-69E9C7B33842"), Text = "Recycle Bin", NodeObjectType = Constants.ObjectTypes.MediaRecycleBin, CreateDate = DateTime.Now });
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelString, 35, "f0bc4bfb-b499-40d6-ba86-058885a5178c", "Label");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelInt, 36, "8e7f995c-bd81-4627-9932-c40e568ec788", "Label (integer)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelBigint, 36, "930861bf-e262-4ead-a704-f99453565708", "Label (bigint)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelDateTime, 37, "0e9794eb-f9b5-4f20-a788-93acd233a7e4", "Label (datetime)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelTime, 38, "a97cec69-9b71-4c30-8b12-ec398860d7e8", "Label (time)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelDecimal, 39, "8f1ef1e1-9de4-40d3-a072-6673f631ca64", "Label (decimal)");
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -90, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-90", SortOrder = 34, UniqueId = new Guid("84c6b441-31df-4ffe-b67e-67d5bc3ae65a"), Text = "Upload", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -89, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-89", SortOrder = 33, UniqueId = new Guid("c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3"), Text = "Textarea", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -88, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-88", SortOrder = 32, UniqueId = new Guid("0cc0eba1-9960-42c9-bf9b-60e150b429ae"), Text = "Textstring", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -87, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-87", SortOrder = 4, UniqueId = new Guid("ca90c950-0aff-4e72-b976-a30b1ac57dad"), Text = "Richtext editor", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -51, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-51", SortOrder = 2, UniqueId = new Guid("2e6d3631-066e-44b8-aec4-96f09099b2b5"), Text = "Numeric", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -49, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-49", SortOrder = 2, UniqueId = new Guid("92897bc6-a5f3-4ffe-ae27-f2e7e33dda49"), Text = "True/false", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -43, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-43", SortOrder = 2, UniqueId = new Guid("fbaf13a8-4036-41f2-93a3-974f678c312a"), Text = "Checkbox list", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DropDownSingle, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DropDownSingle}", SortOrder = 2, UniqueId = new Guid("0b6a45e7-44ba-430d-9da5-4e46060b9e03"), Text = "Dropdown", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -41, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-41", SortOrder = 2, UniqueId = new Guid("5046194e-4237-453c-a547-15db3a07c4e1"), Text = "Date Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -40, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-40", SortOrder = 2, UniqueId = new Guid("bb5f57c9-ce2b-4bb9-b697-4caca783a805"), Text = "Radiobox", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DropDownMultiple, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DropDownMultiple}", SortOrder = 2, UniqueId = new Guid("f38f0ac7-1d27-439c-9f3f-089cd8825a53"), Text = "Dropdown multiple", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -37, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-37", SortOrder = 2, UniqueId = new Guid("0225af17-b302-49cb-9176-b9f35cab9c17"), Text = "Approved Color", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -36, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-36", SortOrder = 2, UniqueId = new Guid("e4d66c0f-b935-4200-81f0-025f7256b89a"), Text = "Date Picker with time", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultContentListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultContentListView}", SortOrder = 2, UniqueId = new Guid("C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Content", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMediaListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultMediaListView}", SortOrder = 2, UniqueId = new Guid("3A0156C4-3B8C-4803-BDC1-6871FAA83FFF"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Media", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMembersListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultMembersListView}", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelString, 35, Constants.DataTypes.Guids.LabelString, "Label (string)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelInt, 36, Constants.DataTypes.Guids.LabelInt, "Label (integer)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelBigint, 36, Constants.DataTypes.Guids.LabelBigInt, "Label (bigint)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelDateTime, 37, Constants.DataTypes.Guids.LabelDateTime, "Label (datetime)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelTime, 38, Constants.DataTypes.Guids.LabelTime, "Label (time)");
|
||||
InsertDataTypeNodeDto(Constants.DataTypes.LabelDecimal, 39, Constants.DataTypes.Guids.LabelDecimal, "Label (decimal)");
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Upload, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Upload}", SortOrder = 34, UniqueId = Constants.DataTypes.Guids.UploadGuid, Text = "Upload", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Textarea, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Textarea}", SortOrder = 33, UniqueId = Constants.DataTypes.Guids.TextareaGuid, Text = "Textarea", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Textbox, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Textbox}", SortOrder = 32, UniqueId = Constants.DataTypes.Guids.TextstringGuid, Text = "Textstring", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.RichtextEditor, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.RichtextEditor}", SortOrder = 4, UniqueId = Constants.DataTypes.Guids.RichtextEditorGuid, Text = "Richtext editor", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -51, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-51", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.NumericGuid, Text = "Numeric", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Boolean, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Boolean}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.CheckboxGuid, Text = "True/false", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -43, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-43", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.CheckboxListGuid, Text = "Checkbox list", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DropDownSingle, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DropDownSingle}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.DropdownGuid, Text = "Dropdown", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -41, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-41", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.DatePickerGuid, Text = "Date Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -40, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-40", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.RadioboxGuid, Text = "Radiobox", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DropDownMultiple, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DropDownMultiple}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.DropdownMultipleGuid, Text = "Dropdown multiple", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = -37, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,-37", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.ApprovedColorGuid, Text = "Approved Color", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DateTime, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DateTime}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.DatePickerWithTimeGuid, Text = "Date Picker with time", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultContentListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultContentListView}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.ListViewContentGuid, Text = Constants.Conventions.DataTypes.ListViewPrefix + "Content", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMediaListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultMediaListView}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.ListViewMediaGuid, Text = Constants.Conventions.DataTypes.ListViewPrefix + "Media", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.DefaultMembersListView, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.DefaultMembersListView}", SortOrder = 2, UniqueId = Constants.DataTypes.Guids.ListViewMembersGuid, Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1031, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1031", SortOrder = 2, UniqueId = new Guid("f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d"), Text = Constants.Conventions.MediaTypes.Folder, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1032, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1032", SortOrder = 2, UniqueId = new Guid("cc07b313-0843-4aa8-bbda-871c8da728c8"), Text = Constants.Conventions.MediaTypes.Image, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = Constants.ObjectTypes.MediaType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1041, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1041", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1043, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1043", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.Tags, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.Tags}", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = Constants.DataTypes.ImageCropper, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = $"-1,{Constants.DataTypes.ImageCropper}", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = Constants.ObjectTypes.MemberType, CreateDate = DateTime.Now });
|
||||
|
||||
//New UDI pickers with newer Ids
|
||||
@@ -155,10 +155,10 @@ namespace Umbraco.Core.Migrations.Install
|
||||
|
||||
private void CreateContentTypeData()
|
||||
{
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = "icon-folder", Thumbnail = "icon-folder", IsContainer = false, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = "icon-picture", Thumbnail = "icon-picture", AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = "icon-document", Thumbnail = "icon-document", AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 531, NodeId = 1044, Alias = Constants.Conventions.MemberTypes.DefaultAlias, Icon = "icon-user", Thumbnail = "icon-user", Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = Constants.Icons.MediaFolder, Thumbnail = Constants.Icons.MediaFolder, IsContainer = false, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = Constants.Icons.MediaImage, Thumbnail = Constants.Icons.MediaImage, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = Constants.Icons.MediaFile, Thumbnail = Constants.Icons.MediaFile, AllowAtRoot = true, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.ContentType, "pk", false, new ContentTypeDto { PrimaryKey = 531, NodeId = 1044, Alias = Constants.Conventions.MemberTypes.DefaultAlias, Icon = Constants.Icons.Member, Thumbnail = Constants.Icons.Member, Variations = (byte) ContentVariation.Nothing });
|
||||
}
|
||||
|
||||
private void CreateUserData()
|
||||
@@ -210,19 +210,19 @@ namespace Umbraco.Core.Migrations.Install
|
||||
|
||||
private void CreatePropertyTypeData()
|
||||
{
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 6, UniqueId = 6.ToGuid(), DataTypeId = 1043, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.File, Name = "Upload image", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 6, UniqueId = 6.ToGuid(), DataTypeId = Constants.DataTypes.ImageCropper, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.File, Name = "Upload image", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 7, UniqueId = 7.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Width, Name = "Width", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in pixels", Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 8, UniqueId = 8.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Height, Name = "Height", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in pixels", Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 9, UniqueId = 9.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 10, UniqueId = 10.ToGuid(), DataTypeId = -92, ContentTypeId = 1032, PropertyTypeGroupId = 3, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = -90, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "Upload file", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = Constants.DataTypes.Upload, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "Upload file", SortOrder = 0, Mandatory = true, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 25, UniqueId = 25.ToGuid(), DataTypeId = -92, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 26, UniqueId = 26.ToGuid(), DataTypeId = Constants.DataTypes.LabelBigint, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = "in bytes", Variations = (byte) ContentVariation.Nothing });
|
||||
//membership property types
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 28, UniqueId = 28.ToGuid(), DataTypeId = -89, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.Comments, Name = Constants.Conventions.Member.CommentsLabel, SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 28, UniqueId = 28.ToGuid(), DataTypeId = Constants.DataTypes.Textarea, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.Comments, Name = Constants.Conventions.Member.CommentsLabel, SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 29, UniqueId = 29.ToGuid(), DataTypeId = Constants.DataTypes.LabelInt, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.FailedPasswordAttempts, Name = Constants.Conventions.Member.FailedPasswordAttemptsLabel, SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 30, UniqueId = 30.ToGuid(), DataTypeId = -49, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsApproved, Name = Constants.Conventions.Member.IsApprovedLabel, SortOrder = 2, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 31, UniqueId = 31.ToGuid(), DataTypeId = -49, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsLockedOut, Name = Constants.Conventions.Member.IsLockedOutLabel, SortOrder = 3, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 30, UniqueId = 30.ToGuid(), DataTypeId = Constants.DataTypes.Boolean, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsApproved, Name = Constants.Conventions.Member.IsApprovedLabel, SortOrder = 2, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 31, UniqueId = 31.ToGuid(), DataTypeId = Constants.DataTypes.Boolean, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.IsLockedOut, Name = Constants.Conventions.Member.IsLockedOutLabel, SortOrder = 3, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
@@ -266,30 +266,30 @@ namespace Umbraco.Core.Migrations.Install
|
||||
const string layouts = "[" + cardLayout + "," + listLayout + "]";
|
||||
|
||||
// TODO: Check which of the DataTypeIds below doesn't exist in umbracoNode, which results in a foreign key constraint errors.
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -49, EditorAlias = Constants.PropertyEditors.Aliases.Boolean, DbType = "Integer" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Boolean, EditorAlias = Constants.PropertyEditors.Aliases.Boolean, DbType = "Integer" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -51, EditorAlias = Constants.PropertyEditors.Aliases.Integer, DbType = "Integer" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -87, EditorAlias = Constants.PropertyEditors.Aliases.TinyMce, DbType = "Ntext",
|
||||
Configuration = "{\"value\":\",code,undo,redo,cut,copy,mcepasteword,stylepicker,bold,italic,bullist,numlist,outdent,indent,mcelink,unlink,mceinsertanchor,mceimage,umbracomacro,mceinserttable,umbracoembed,mcecharmap,|1|1,2,3,|0|500,400|1049,|true|\"}" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -88, EditorAlias = Constants.PropertyEditors.Aliases.TextBox, DbType = "Nvarchar" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -89, EditorAlias = Constants.PropertyEditors.Aliases.TextArea, DbType = "Ntext" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -90, EditorAlias = Constants.PropertyEditors.Aliases.UploadField, DbType = "Nvarchar" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Textbox, EditorAlias = Constants.PropertyEditors.Aliases.TextBox, DbType = "Nvarchar" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Textarea, EditorAlias = Constants.PropertyEditors.Aliases.TextArea, DbType = "Ntext" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Upload, EditorAlias = Constants.PropertyEditors.Aliases.UploadField, DbType = "Nvarchar" });
|
||||
InsertDataTypeDto(Constants.DataTypes.LabelString, Constants.PropertyEditors.Aliases.Label, "Nvarchar", "{\"umbracoDataValueType\":\"STRING\"}");
|
||||
InsertDataTypeDto(Constants.DataTypes.LabelInt, Constants.PropertyEditors.Aliases.Label, "Integer", "{\"umbracoDataValueType\":\"INT\"}");
|
||||
InsertDataTypeDto(Constants.DataTypes.LabelBigint, Constants.PropertyEditors.Aliases.Label, "Nvarchar", "{\"umbracoDataValueType\":\"BIGINT\"}");
|
||||
InsertDataTypeDto(Constants.DataTypes.LabelDateTime, Constants.PropertyEditors.Aliases.Label, "Date", "{\"umbracoDataValueType\":\"DATETIME\"}");
|
||||
InsertDataTypeDto(Constants.DataTypes.LabelDecimal, Constants.PropertyEditors.Aliases.Label, "Decimal", "{\"umbracoDataValueType\":\"DECIMAL\"}");
|
||||
InsertDataTypeDto(Constants.DataTypes.LabelTime, Constants.PropertyEditors.Aliases.Label, "Date", "{\"umbracoDataValueType\":\"TIME\"}");
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -36, EditorAlias = Constants.PropertyEditors.Aliases.DateTime, DbType = "Date" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DateTime, EditorAlias = Constants.PropertyEditors.Aliases.DateTime, DbType = "Date" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -37, EditorAlias = Constants.PropertyEditors.Aliases.ColorPicker, DbType = "Nvarchar" });
|
||||
InsertDataTypeDto(Constants.DataTypes.DropDownSingle, Constants.PropertyEditors.Aliases.DropDownListFlexible, "Nvarchar", "{\"multiple\":false}");
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -40, EditorAlias = Constants.PropertyEditors.Aliases.RadioButtonList, DbType = "Nvarchar" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -41, EditorAlias = "Umbraco.DateTime", DbType = "Date", Configuration = "{\"format\":\"YYYY-MM-DD\"}" });
|
||||
InsertDataTypeDto(Constants.DataTypes.DropDownMultiple, Constants.PropertyEditors.Aliases.DropDownListFlexible, "Nvarchar", "{\"multiple\":true}");
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = -43, EditorAlias = Constants.PropertyEditors.Aliases.CheckBoxList, DbType = "Nvarchar" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1041, EditorAlias = Constants.PropertyEditors.Aliases.Tags, DbType = "Ntext",
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.Tags, EditorAlias = Constants.PropertyEditors.Aliases.Tags, DbType = "Ntext",
|
||||
Configuration = "{\"group\":\"default\", \"storageType\":\"Json\"}"
|
||||
});
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1043, EditorAlias = Constants.PropertyEditors.Aliases.ImageCropper, DbType = "Ntext" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.ImageCropper, EditorAlias = Constants.PropertyEditors.Aliases.ImageCropper, DbType = "Ntext" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DefaultContentListView, EditorAlias = Constants.PropertyEditors.Aliases.ListView, DbType = "Nvarchar",
|
||||
Configuration = "{\"pageSize\":100, \"orderBy\":\"updateDate\", \"orderDirection\":\"desc\", \"layouts\":" + layouts + ", \"includeProperties\":[{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1},{\"alias\":\"owner\",\"header\":\"Updated by\",\"isSystem\":1}]}" });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = Constants.DataTypes.DefaultMediaListView, EditorAlias = Constants.PropertyEditors.Aliases.ListView, DbType = "Nvarchar",
|
||||
|
||||
@@ -74,6 +74,11 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
throw new InvalidOperationException($"Version {currentVersion} cannot be migrated to {UmbracoVersion.SemanticVersion}."
|
||||
+ $" Please upgrade first to at least {minVersion}.");
|
||||
|
||||
// Force versions between 7.14.*-7.15.* into into 7.14 initial state. Because there is no db-changes,
|
||||
// and we don't want users to workaround my putting in version 7.14.0 them self.
|
||||
if (minVersion <= currentVersion && currentVersion < new SemVersion(7, 16))
|
||||
return GetInitState(minVersion);
|
||||
|
||||
// initial state is eg "{init-7.14.0}"
|
||||
return GetInitState(currentVersion);
|
||||
}
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
|
||||
{
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Upgrade, MaxLevel = RuntimeLevel.Upgrade)] // only on upgrades
|
||||
public class PreValueMigratorComposer : ICoreComposer
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.Upgrade, MaxLevel = RuntimeLevel.Upgrade)] // only on upgrades
|
||||
public class PreValueMigratorComposer : ICoreComposer
|
||||
{
|
||||
public void Compose(Composition composition)
|
||||
{
|
||||
public void Compose(Composition composition)
|
||||
{
|
||||
// do NOT add DefaultPreValueMigrator to this list!
|
||||
// it will be automatically used if nothing matches
|
||||
// do NOT add DefaultPreValueMigrator to this list!
|
||||
// it will be automatically used if nothing matches
|
||||
|
||||
composition.WithCollectionBuilder<PreValueMigratorCollectionBuilder>()
|
||||
.Append<RenamingPreValueMigrator>()
|
||||
.Append<RichTextPreValueMigrator>()
|
||||
.Append<UmbracoSliderPreValueMigrator>()
|
||||
.Append<MediaPickerPreValueMigrator>()
|
||||
.Append<ContentPickerPreValueMigrator>()
|
||||
.Append<NestedContentPreValueMigrator>()
|
||||
.Append<DecimalPreValueMigrator>()
|
||||
.Append<ListViewPreValueMigrator>()
|
||||
.Append<ValueListPreValueMigrator>();
|
||||
}
|
||||
composition.WithCollectionBuilder<PreValueMigratorCollectionBuilder>()
|
||||
.Append<RenamingPreValueMigrator>()
|
||||
.Append<RichTextPreValueMigrator>()
|
||||
.Append<UmbracoSliderPreValueMigrator>()
|
||||
.Append<MediaPickerPreValueMigrator>()
|
||||
.Append<ContentPickerPreValueMigrator>()
|
||||
.Append<NestedContentPreValueMigrator>()
|
||||
.Append<DecimalPreValueMigrator>()
|
||||
.Append<ListViewPreValueMigrator>()
|
||||
.Append<ValueListPreValueMigrator>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,20 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
.Where<DataTypeDto>(x => x.EditorAlias == toAlias));
|
||||
|
||||
if (oldCount > 0)
|
||||
throw new InvalidOperationException($"Cannot rename datatype alias \"{fromAlias}\" to \"{toAlias}\" because the target alias is already used.");
|
||||
{
|
||||
// If we throw it means that the upgrade will exit and cannot continue.
|
||||
// This will occur if a v7 site has the old "Obsolete" property editors that are already named with the `toAlias` name.
|
||||
// TODO: We should have an additional upgrade step when going from 7 -> 8 like we did with 6 -> 7 that shows a compatibility report,
|
||||
// this would include this check and then we can provide users with information on what they should do (i.e. before upgrading to v8 they will
|
||||
// need to migrate these old obsolete editors to non-obsolete editors)
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Cannot rename datatype alias \"{fromAlias}\" to \"{toAlias}\" because the target alias is already used." +
|
||||
$"This is generally because when upgrading from a v7 to v8 site, the v7 site contains Data Types that reference old and already Obsolete " +
|
||||
$"Property Editors. Before upgrading to v8, any Data Types using property editors that are named with the prefix '(Obsolete)' must be migrated " +
|
||||
$"to the non-obsolete v7 property editors of the same type.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Database.Execute(Sql()
|
||||
|
||||
@@ -35,5 +35,58 @@ namespace Umbraco.Core.Models
|
||||
|
||||
throw new InvalidCastException($"Cannot cast dataType configuration, of type {configuration.GetType().Name}, to {typeof(T).Name}.");
|
||||
}
|
||||
|
||||
private static readonly ISet<Guid> IdsOfBuildInDataTypes = new HashSet<Guid>()
|
||||
{
|
||||
Constants.DataTypes.Guids.ContentPickerGuid,
|
||||
Constants.DataTypes.Guids.MemberPickerGuid,
|
||||
Constants.DataTypes.Guids.MediaPickerGuid,
|
||||
Constants.DataTypes.Guids.MultipleMediaPickerGuid,
|
||||
Constants.DataTypes.Guids.RelatedLinksGuid,
|
||||
Constants.DataTypes.Guids.MemberGuid,
|
||||
Constants.DataTypes.Guids.ImageCropperGuid,
|
||||
Constants.DataTypes.Guids.TagsGuid,
|
||||
Constants.DataTypes.Guids.ListViewContentGuid,
|
||||
Constants.DataTypes.Guids.ListViewMediaGuid,
|
||||
Constants.DataTypes.Guids.ListViewMembersGuid,
|
||||
Constants.DataTypes.Guids.DatePickerWithTimeGuid,
|
||||
Constants.DataTypes.Guids.ApprovedColorGuid,
|
||||
Constants.DataTypes.Guids.DropdownMultipleGuid,
|
||||
Constants.DataTypes.Guids.RadioboxGuid,
|
||||
Constants.DataTypes.Guids.DatePickerGuid,
|
||||
Constants.DataTypes.Guids.DropdownGuid,
|
||||
Constants.DataTypes.Guids.CheckboxListGuid,
|
||||
Constants.DataTypes.Guids.CheckboxGuid,
|
||||
Constants.DataTypes.Guids.NumericGuid,
|
||||
Constants.DataTypes.Guids.RichtextEditorGuid,
|
||||
Constants.DataTypes.Guids.TextstringGuid,
|
||||
Constants.DataTypes.Guids.TextareaGuid,
|
||||
Constants.DataTypes.Guids.UploadGuid,
|
||||
Constants.DataTypes.Guids.LabelStringGuid,
|
||||
Constants.DataTypes.Guids.LabelDecimalGuid,
|
||||
Constants.DataTypes.Guids.LabelDateTimeGuid,
|
||||
Constants.DataTypes.Guids.LabelBigIntGuid,
|
||||
Constants.DataTypes.Guids.LabelTimeGuid,
|
||||
Constants.DataTypes.Guids.LabelDateTimeGuid,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this date type is build-in/default.
|
||||
/// </summary>
|
||||
/// <param name="dataType">The data type definition.</param>
|
||||
/// <returns></returns>
|
||||
internal static bool IsBuildInDataType(this IDataType dataType)
|
||||
{
|
||||
return IsBuildInDataType(dataType.Key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this date type is build-in/default.
|
||||
/// </summary>
|
||||
internal static bool IsBuildInDataType(Guid key)
|
||||
{
|
||||
return IdsOfBuildInDataTypes.Contains(key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,37 +81,7 @@ namespace Umbraco.Core.Models.Entities
|
||||
_key = Guid.Empty;
|
||||
_hasIdentity = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the entity when it is being saved for the first time.
|
||||
/// </summary>
|
||||
internal virtual void AddingEntity()
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
// set the create and update dates, if not already set
|
||||
if (IsPropertyDirty("CreateDate") == false || _createDate == default)
|
||||
CreateDate = now;
|
||||
if (IsPropertyDirty("UpdateDate") == false || _updateDate == default)
|
||||
UpdateDate = now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the entity when it is being saved.
|
||||
/// </summary>
|
||||
internal virtual void UpdatingEntity()
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
// just in case
|
||||
if (_createDate == default)
|
||||
CreateDate = now;
|
||||
|
||||
// set the update date if not already set
|
||||
if (IsPropertyDirty("UpdateDate") == false || _updateDate == default)
|
||||
UpdateDate = now;
|
||||
}
|
||||
|
||||
|
||||
public virtual bool Equals(EntityBase other)
|
||||
{
|
||||
return other != null && (ReferenceEquals(this, other) || SameIdentityAs(other));
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models.Entities
|
||||
{
|
||||
internal static class EntityExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the entity when it is being saved.
|
||||
/// </summary>
|
||||
internal static void UpdatingEntity(this IEntity entity)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
|
||||
// just in case
|
||||
if (entity.CreateDate == default)
|
||||
{
|
||||
entity.CreateDate = now;
|
||||
}
|
||||
|
||||
// set the update date if not already set
|
||||
if (entity.UpdateDate == default || (entity is ICanBeDirty canBeDirty && canBeDirty.IsPropertyDirty("UpdateDate") == false))
|
||||
{
|
||||
entity.UpdateDate = now;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the entity when it is being saved for the first time.
|
||||
/// </summary>
|
||||
internal static void AddingEntity(this IEntity entity)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
var canBeDirty = entity as ICanBeDirty;
|
||||
|
||||
// set the create and update dates, if not already set
|
||||
if (entity.CreateDate == default || canBeDirty?.IsPropertyDirty("CreateDate") == false)
|
||||
{
|
||||
entity.CreateDate = now;
|
||||
}
|
||||
if (entity.UpdateDate == default || canBeDirty?.IsPropertyDirty("UpdateDate") == false)
|
||||
{
|
||||
entity.UpdateDate = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,19 +478,6 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _providerUserKey, nameof(ProviderUserKey));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being saved
|
||||
/// </summary>
|
||||
/// <remarks>Created date is set and a Unique key is assigned</remarks>
|
||||
internal override void AddingEntity()
|
||||
{
|
||||
base.AddingEntity();
|
||||
|
||||
if (ProviderUserKey == null)
|
||||
ProviderUserKey = Key;
|
||||
}
|
||||
|
||||
/* Internal experiment - only used for mapping queries.
|
||||
* Adding these to have first level properties instead of the Properties collection.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Umbraco.Core.Models
|
||||
private string _alias;
|
||||
private string _description;
|
||||
private int _dataTypeId;
|
||||
private Guid _dataTypeKey;
|
||||
private Lazy<int> _propertyGroupId;
|
||||
private string _propertyEditorAlias;
|
||||
private ValueStorageType _valueStorageType;
|
||||
@@ -139,6 +140,13 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _dataTypeId, nameof(DataTypeId));
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public Guid DataTypeKey
|
||||
{
|
||||
get => _dataTypeKey;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _dataTypeKey, nameof(DataTypeKey));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alias of the property editor for this property type.
|
||||
/// </summary>
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
/// <summary>
|
||||
/// Refreshes the factory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This will typically re-compiled models/classes into a new DLL that are used to populate the cache.</para>
|
||||
/// <para>This is called prior to refreshing the cache.</para>
|
||||
/// </remarks>
|
||||
void Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,19 +193,6 @@ namespace Umbraco.Core.Models
|
||||
return ContentPermissionsHelper.HasPathAccess(entity.Path, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
|
||||
}
|
||||
|
||||
internal static bool IsInBranchOfStartNode(this IUser user, IUmbracoEntity entity, IEntityService entityService, int recycleBinId, out bool hasPathAccess)
|
||||
{
|
||||
switch (recycleBinId)
|
||||
{
|
||||
case Constants.System.RecycleBinMedia:
|
||||
return ContentPermissionsHelper.IsInBranchOfStartNode(entity.Path, user.CalculateMediaStartNodeIds(entityService), user.GetMediaStartNodePaths(entityService), out hasPathAccess);
|
||||
case Constants.System.RecycleBinContent:
|
||||
return ContentPermissionsHelper.IsInBranchOfStartNode(entity.Path, user.CalculateContentStartNodeIds(entityService), user.GetContentStartNodePaths(entityService), out hasPathAccess);
|
||||
default:
|
||||
throw new NotSupportedException("Path access is only determined on content or media");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this user has access to view sensitive data
|
||||
/// </summary>
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
propertyType.Alias = typeDto.Alias;
|
||||
propertyType.DataTypeId = typeDto.DataTypeId;
|
||||
propertyType.DataTypeKey = typeDto.DataTypeDto.NodeDto.UniqueId;
|
||||
propertyType.Description = typeDto.Description;
|
||||
propertyType.Id = typeDto.Id;
|
||||
propertyType.Key = typeDto.UniqueId;
|
||||
|
||||
@@ -18,7 +18,8 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
DefineMap<AuditItem, LogDto>(nameof(AuditItem.Id), nameof(LogDto.NodeId));
|
||||
DefineMap<AuditItem, LogDto>(nameof(AuditItem.CreateDate), nameof(LogDto.Datestamp));
|
||||
DefineMap<AuditItem, LogDto>(nameof(AuditItem.UserId), nameof(LogDto.UserId));
|
||||
DefineMap<AuditItem, LogDto>(nameof(AuditItem.AuditType), nameof(LogDto.Header));
|
||||
// we cannot map that one - because AuditType is an enum but Header is a string
|
||||
//DefineMap<AuditItem, LogDto>(nameof(AuditItem.AuditType), nameof(LogDto.Header));
|
||||
DefineMap<AuditItem, LogDto>(nameof(AuditItem.Comment), nameof(LogDto.Comment));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,17 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
// I'm just unsure right now due to time constraints how to make it correct. It won't matter right now and has been working already with this bug but I've
|
||||
// only just discovered what it is actually doing.
|
||||
|
||||
// TODO
|
||||
// in most cases we want to convert the value to a plain object,
|
||||
// but for in some rare cases, we may want to do it differently,
|
||||
// for instance a Models.AuditType (an enum) may in some cases
|
||||
// need to be converted to its string value.
|
||||
// but - we cannot have specific code here, really - and how would
|
||||
// we configure this? is it even possible?
|
||||
/*
|
||||
var toString = typeof(object).GetMethod("ToString");
|
||||
var member = Expression.Call(m, toString);
|
||||
*/
|
||||
var member = Expression.Convert(m, typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
|
||||
@@ -33,5 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Direction orderDirection,
|
||||
AuditType[] auditTypeFilter,
|
||||
IQuery<IAuditItem> customFilter);
|
||||
|
||||
IEnumerable<IAuditItem> Get(AuditType type, IQuery<IAuditItem> query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// <inheritdoc />
|
||||
protected override void PersistNewItem(IAuditEntry entity)
|
||||
{
|
||||
((EntityBase) entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var dto = AuditEntryFactory.BuildDto(entity);
|
||||
Database.Insert(dto);
|
||||
|
||||
@@ -74,6 +74,18 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return dtos.Select(x => new AuditItem(x.NodeId, Enum<AuditType>.Parse(x.Header), x.UserId ?? Constants.Security.UnknownUserId, x.EntityType, x.Comment, x.Parameters)).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<IAuditItem> Get(AuditType type, IQuery<IAuditItem> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false)
|
||||
.Where<LogDto>(x => x.Header == type.ToString());
|
||||
var translator = new SqlTranslator<IAuditItem>(sqlClause, query);
|
||||
var sql = translator.Translate();
|
||||
|
||||
var dtos = Database.Fetch<LogDto>(sql);
|
||||
|
||||
return dtos.Select(x => new AuditItem(x.NodeId, Enum<AuditType>.Parse(x.Header), x.UserId ?? Constants.Security.UnknownUserId, x.EntityType, x.Comment, x.Parameters)).ToList();
|
||||
}
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = SqlContext.Sql();
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// <inheritdoc />
|
||||
protected override void PersistNewItem(IConsent entity)
|
||||
{
|
||||
((EntityBase) entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var dto = ConsentFactory.BuildDto(entity);
|
||||
Database.Insert(dto);
|
||||
@@ -80,7 +80,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// <inheritdoc />
|
||||
protected override void PersistUpdatedItem(IConsent entity)
|
||||
{
|
||||
((EntityBase) entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var dto = ConsentFactory.BuildDto(entity);
|
||||
Database.Update(dto);
|
||||
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Scoping;
|
||||
using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
@@ -188,10 +189,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var groupDtos = Database.Fetch<PropertyTypeGroupDto>(sql1);
|
||||
|
||||
var sql2 = Sql()
|
||||
.Select<PropertyTypeDto>(r => r.Select(x => x.DataTypeDto))
|
||||
.Select<PropertyTypeDto>(r => r.Select(x => x.DataTypeDto, r1 => r1.Select(x => x.NodeDto)))
|
||||
.AndSelect<MemberPropertyTypeDto>()
|
||||
.From<PropertyTypeDto>()
|
||||
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((pt, dt) => pt.DataTypeId == dt.NodeId)
|
||||
.InnerJoin<NodeDto>().On<DataTypeDto, NodeDto>((dt, n) => dt.NodeId == n.NodeId)
|
||||
.InnerJoin<ContentTypeDto>().On<PropertyTypeDto, ContentTypeDto>((pt, ct) => pt.ContentTypeId == ct.NodeId)
|
||||
.LeftJoin<PropertyTypeGroupDto>().On<PropertyTypeDto, PropertyTypeGroupDto>((pt, ptg) => pt.PropertyTypeGroupId == ptg.Id)
|
||||
.LeftJoin<MemberPropertyTypeDto>().On<PropertyTypeDto, MemberPropertyTypeDto>((pt, mpt) => pt.Id == mpt.PropertyTypeId)
|
||||
@@ -290,6 +292,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
Description = dto.Description,
|
||||
DataTypeId = dto.DataTypeId,
|
||||
DataTypeKey = dto.DataTypeDto.NodeDto.UniqueId,
|
||||
Id = dto.Id,
|
||||
Key = dto.UniqueId,
|
||||
Mandatory = dto.Mandatory,
|
||||
|
||||
@@ -5,6 +5,7 @@ using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
@@ -230,7 +231,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
throw ex;
|
||||
}
|
||||
|
||||
((ContentType)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
PersistNewBaseContentType(entity);
|
||||
PersistTemplates(entity, false);
|
||||
@@ -270,7 +271,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
ValidateAlias(entity);
|
||||
|
||||
//Updates Modified date
|
||||
((ContentType)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
//Look up parent to get and set the correct Path if ParentId has changed
|
||||
if (entity.IsPropertyDirty("ParentId"))
|
||||
|
||||
@@ -1013,8 +1013,9 @@ AND umbracoNode.id <> @id",
|
||||
if (propertyType.PropertyEditorAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
var sql = Sql()
|
||||
.SelectAll()
|
||||
.Select<DataTypeDto>(dt => dt.Select(x => x.NodeDto))
|
||||
.From<DataTypeDto>()
|
||||
.InnerJoin<NodeDto>().On<DataTypeDto, NodeDto>((dt, n) => dt.NodeId == n.NodeId)
|
||||
.Where("propertyEditorAlias = @propertyEditorAlias", new { propertyEditorAlias = propertyType.PropertyEditorAlias })
|
||||
.OrderBy<DataTypeDto>(typeDto => typeDto.NodeId);
|
||||
var datatype = Database.FirstOrDefault<DataTypeDto>(sql);
|
||||
@@ -1022,6 +1023,7 @@ AND umbracoNode.id <> @id",
|
||||
if (datatype != null)
|
||||
{
|
||||
propertyType.DataTypeId = datatype.NodeId;
|
||||
propertyType.DataTypeKey = datatype.NodeDto.UniqueId;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -106,7 +107,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IDataType entity)
|
||||
{
|
||||
((DataType)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
//ensure a datatype has a unique name before creating it
|
||||
entity.Name = EnsureUniqueNodeName(entity.Name);
|
||||
@@ -174,7 +175,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
}
|
||||
|
||||
//Updates Modified date
|
||||
((DataType)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
//Look up parent to get and set the correct Path if ParentId has changed
|
||||
if (entity.IsPropertyDirty("ParentId"))
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IDictionaryItem entity)
|
||||
{
|
||||
((EntityBase)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
foreach (var translation in entity.Translations)
|
||||
translation.Value = translation.Value.ToValidXmlString();
|
||||
|
||||
@@ -6,6 +6,7 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
@@ -205,7 +206,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersionCultureVariation + " WHERE versionId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Content + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.AccessRule + " WHERE accessId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE nodeId = @id OR loginNodeId = @id OR noAccessNodeId = @id)",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE loginNodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE noAccessNodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Node + " WHERE id = @id"
|
||||
};
|
||||
return list;
|
||||
@@ -260,21 +264,16 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IContent entity)
|
||||
{
|
||||
// TODO: https://github.com/umbraco/Umbraco-CMS/issues/4234 - sort out IContent vs Content
|
||||
// however, it's not just so we have access to AddingEntity
|
||||
// there are tons of things at the end of the methods, that can only work with a true Content
|
||||
// and basically, the repository requires a Content, not an IContent
|
||||
var content = (Content)entity;
|
||||
entity.AddingEntity();
|
||||
|
||||
content.AddingEntity();
|
||||
var publishing = content.PublishedState == PublishedState.Publishing;
|
||||
var publishing = entity.PublishedState == PublishedState.Publishing;
|
||||
|
||||
// ensure that the default template is assigned
|
||||
if (entity.TemplateId.HasValue == false)
|
||||
entity.TemplateId = entity.ContentType.DefaultTemplate?.Id;
|
||||
|
||||
// sanitize names
|
||||
SanitizeNames(content, publishing);
|
||||
SanitizeNames(entity, publishing);
|
||||
|
||||
// ensure that strings don't contain characters that are invalid in xml
|
||||
// TODO: do we really want to keep doing this here?
|
||||
@@ -324,11 +323,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
contentVersionDto.NodeId = nodeDto.NodeId;
|
||||
contentVersionDto.Current = !publishing;
|
||||
Database.Insert(contentVersionDto);
|
||||
content.VersionId = contentVersionDto.Id;
|
||||
entity.VersionId = contentVersionDto.Id;
|
||||
|
||||
// persist the document version dto
|
||||
var documentVersionDto = dto.DocumentVersionDto;
|
||||
documentVersionDto.Id = content.VersionId;
|
||||
documentVersionDto.Id = entity.VersionId;
|
||||
if (publishing)
|
||||
documentVersionDto.Published = true;
|
||||
Database.Insert(documentVersionDto);
|
||||
@@ -336,62 +335,62 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// and again in case we're publishing immediately
|
||||
if (publishing)
|
||||
{
|
||||
content.PublishedVersionId = content.VersionId;
|
||||
entity.PublishedVersionId = entity.VersionId;
|
||||
contentVersionDto.Id = 0;
|
||||
contentVersionDto.Current = true;
|
||||
contentVersionDto.Text = content.Name;
|
||||
contentVersionDto.Text = entity.Name;
|
||||
Database.Insert(contentVersionDto);
|
||||
content.VersionId = contentVersionDto.Id;
|
||||
entity.VersionId = contentVersionDto.Id;
|
||||
|
||||
documentVersionDto.Id = content.VersionId;
|
||||
documentVersionDto.Id = entity.VersionId;
|
||||
documentVersionDto.Published = false;
|
||||
Database.Insert(documentVersionDto);
|
||||
}
|
||||
|
||||
// persist the property data
|
||||
var propertyDataDtos = PropertyFactory.BuildDtos(content.ContentType.Variations, content.VersionId, content.PublishedVersionId, entity.Properties, LanguageRepository, out var edited, out var editedCultures);
|
||||
var propertyDataDtos = PropertyFactory.BuildDtos(entity.ContentType.Variations, entity.VersionId, entity.PublishedVersionId, entity.Properties, LanguageRepository, out var edited, out var editedCultures);
|
||||
foreach (var propertyDataDto in propertyDataDtos)
|
||||
Database.Insert(propertyDataDto);
|
||||
|
||||
// if !publishing, we may have a new name != current publish name,
|
||||
// also impacts 'edited'
|
||||
if (!publishing && content.PublishName != content.Name)
|
||||
if (!publishing && entity.PublishName != entity.Name)
|
||||
edited = true;
|
||||
|
||||
// persist the document dto
|
||||
// at that point, when publishing, the entity still has its old Published value
|
||||
// so we need to explicitly update the dto to persist the correct value
|
||||
if (content.PublishedState == PublishedState.Publishing)
|
||||
if (entity.PublishedState == PublishedState.Publishing)
|
||||
dto.Published = true;
|
||||
dto.NodeId = nodeDto.NodeId;
|
||||
content.Edited = dto.Edited = !dto.Published || edited; // if not published, always edited
|
||||
entity.Edited = dto.Edited = !dto.Published || edited; // if not published, always edited
|
||||
Database.Insert(dto);
|
||||
|
||||
//insert the schedule
|
||||
PersistContentSchedule(content, false);
|
||||
PersistContentSchedule(entity, false);
|
||||
|
||||
// persist the variations
|
||||
if (content.ContentType.VariesByCulture())
|
||||
if (entity.ContentType.VariesByCulture())
|
||||
{
|
||||
// bump dates to align cultures to version
|
||||
if (publishing)
|
||||
content.AdjustDates(contentVersionDto.VersionDate);
|
||||
entity.AdjustDates(contentVersionDto.VersionDate);
|
||||
|
||||
// names also impact 'edited'
|
||||
// ReSharper disable once UseDeconstruction
|
||||
foreach (var cultureInfo in content.CultureInfos)
|
||||
if (cultureInfo.Name != content.GetPublishName(cultureInfo.Culture))
|
||||
foreach (var cultureInfo in entity.CultureInfos)
|
||||
if (cultureInfo.Name != entity.GetPublishName(cultureInfo.Culture))
|
||||
(editedCultures ?? (editedCultures = new HashSet<string>(StringComparer.OrdinalIgnoreCase))).Add(cultureInfo.Culture);
|
||||
|
||||
// insert content variations
|
||||
Database.BulkInsertRecords(GetContentVariationDtos(content, publishing));
|
||||
Database.BulkInsertRecords(GetContentVariationDtos(entity, publishing));
|
||||
|
||||
// insert document variations
|
||||
Database.BulkInsertRecords(GetDocumentVariationDtos(content, publishing, editedCultures));
|
||||
Database.BulkInsertRecords(GetDocumentVariationDtos(entity, publishing, editedCultures));
|
||||
}
|
||||
|
||||
// refresh content
|
||||
content.SetCultureEdited(editedCultures);
|
||||
entity.SetCultureEdited(editedCultures);
|
||||
|
||||
// trigger here, before we reset Published etc
|
||||
OnUowRefreshedEntity(new ScopedEntityEventArgs(AmbientScope, entity));
|
||||
@@ -399,23 +398,23 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// flip the entity's published property
|
||||
// this also flips its published state
|
||||
// note: what depends on variations (eg PublishNames) is managed directly by the content
|
||||
if (content.PublishedState == PublishedState.Publishing)
|
||||
if (entity.PublishedState == PublishedState.Publishing)
|
||||
{
|
||||
content.Published = true;
|
||||
content.PublishTemplateId = content.TemplateId;
|
||||
content.PublisherId = content.WriterId;
|
||||
content.PublishName = content.Name;
|
||||
content.PublishDate = content.UpdateDate;
|
||||
entity.Published = true;
|
||||
entity.PublishTemplateId = entity.TemplateId;
|
||||
entity.PublisherId = entity.WriterId;
|
||||
entity.PublishName = entity.Name;
|
||||
entity.PublishDate = entity.UpdateDate;
|
||||
|
||||
SetEntityTags(entity, _tagRepository);
|
||||
}
|
||||
else if (content.PublishedState == PublishedState.Unpublishing)
|
||||
else if (entity.PublishedState == PublishedState.Unpublishing)
|
||||
{
|
||||
content.Published = false;
|
||||
content.PublishTemplateId = null;
|
||||
content.PublisherId = null;
|
||||
content.PublishName = null;
|
||||
content.PublishDate = null;
|
||||
entity.Published = false;
|
||||
entity.PublishTemplateId = null;
|
||||
entity.PublisherId = null;
|
||||
entity.PublishName = null;
|
||||
entity.PublishDate = null;
|
||||
|
||||
ClearEntityTags(entity, _tagRepository);
|
||||
}
|
||||
@@ -437,34 +436,33 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IContent entity)
|
||||
{
|
||||
// however, it's not just so we have access to AddingEntity
|
||||
// there are tons of things at the end of the methods, that can only work with a true Content
|
||||
// and basically, the repository requires a Content, not an IContent
|
||||
var content = (Content)entity;
|
||||
var entityBase = entity as EntityBase;
|
||||
var isEntityDirty = entityBase != null && entityBase.IsDirty();
|
||||
|
||||
// check if we need to make any database changes at all
|
||||
if ((content.PublishedState == PublishedState.Published || content.PublishedState == PublishedState.Unpublished)
|
||||
&& !content.IsEntityDirty() && !content.IsAnyUserPropertyDirty())
|
||||
if ((entity.PublishedState == PublishedState.Published || entity.PublishedState == PublishedState.Unpublished)
|
||||
&& !isEntityDirty && !entity.IsAnyUserPropertyDirty())
|
||||
return; // no change to save, do nothing, don't even update dates
|
||||
|
||||
// whatever we do, we must check that we are saving the current version
|
||||
var version = Database.Fetch<ContentVersionDto>(SqlContext.Sql().Select<ContentVersionDto>().From<ContentVersionDto>().Where<ContentVersionDto>(x => x.Id == content.VersionId)).FirstOrDefault();
|
||||
var version = Database.Fetch<ContentVersionDto>(SqlContext.Sql().Select<ContentVersionDto>().From<ContentVersionDto>().Where<ContentVersionDto>(x => x.Id == entity.VersionId)).FirstOrDefault();
|
||||
if (version == null || !version.Current)
|
||||
throw new InvalidOperationException("Cannot save a non-current version.");
|
||||
|
||||
// update
|
||||
content.UpdatingEntity();
|
||||
var publishing = content.PublishedState == PublishedState.Publishing;
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var publishing = entity.PublishedState == PublishedState.Publishing;
|
||||
|
||||
// check if we need to create a new version
|
||||
if (publishing && content.PublishedVersionId > 0)
|
||||
if (publishing && entity.PublishedVersionId > 0)
|
||||
{
|
||||
// published version is not published anymore
|
||||
Database.Execute(Sql().Update<DocumentVersionDto>(u => u.Set(x => x.Published, false)).Where<DocumentVersionDto>(x => x.Id == content.PublishedVersionId));
|
||||
Database.Execute(Sql().Update<DocumentVersionDto>(u => u.Set(x => x.Published, false)).Where<DocumentVersionDto>(x => x.Id == entity.PublishedVersionId));
|
||||
}
|
||||
|
||||
// sanitize names
|
||||
SanitizeNames(content, publishing);
|
||||
SanitizeNames(entity, publishing);
|
||||
|
||||
// ensure that strings don't contain characters that are invalid in xml
|
||||
// TODO: do we really want to keep doing this here?
|
||||
@@ -504,13 +502,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// and, if publishing, insert new content & document version dtos
|
||||
if (publishing)
|
||||
{
|
||||
content.PublishedVersionId = content.VersionId;
|
||||
entity.PublishedVersionId = entity.VersionId;
|
||||
|
||||
contentVersionDto.Id = 0; // want a new id
|
||||
contentVersionDto.Current = true; // current version
|
||||
contentVersionDto.Text = content.Name;
|
||||
contentVersionDto.Text = entity.Name;
|
||||
Database.Insert(contentVersionDto);
|
||||
content.VersionId = documentVersionDto.Id = contentVersionDto.Id; // get the new id
|
||||
entity.VersionId = documentVersionDto.Id = contentVersionDto.Id; // get the new id
|
||||
|
||||
documentVersionDto.Published = false; // non-published version
|
||||
Database.Insert(documentVersionDto);
|
||||
@@ -518,31 +516,31 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
// replace the property data (rather than updating)
|
||||
// only need to delete for the version that existed, the new version (if any) has no property data yet
|
||||
var versionToDelete = publishing ? content.PublishedVersionId : content.VersionId;
|
||||
var versionToDelete = publishing ? entity.PublishedVersionId : entity.VersionId;
|
||||
var deletePropertyDataSql = Sql().Delete<PropertyDataDto>().Where<PropertyDataDto>(x => x.VersionId == versionToDelete);
|
||||
Database.Execute(deletePropertyDataSql);
|
||||
|
||||
// insert property data
|
||||
var propertyDataDtos = PropertyFactory.BuildDtos(content.ContentType.Variations, content.VersionId, publishing ? content.PublishedVersionId : 0,
|
||||
var propertyDataDtos = PropertyFactory.BuildDtos(entity.ContentType.Variations, entity.VersionId, publishing ? entity.PublishedVersionId : 0,
|
||||
entity.Properties, LanguageRepository, out var edited, out var editedCultures);
|
||||
foreach (var propertyDataDto in propertyDataDtos)
|
||||
Database.Insert(propertyDataDto);
|
||||
|
||||
// if !publishing, we may have a new name != current publish name,
|
||||
// also impacts 'edited'
|
||||
if (!publishing && content.PublishName != content.Name)
|
||||
if (!publishing && entity.PublishName != entity.Name)
|
||||
edited = true;
|
||||
|
||||
if (content.ContentType.VariesByCulture())
|
||||
if (entity.ContentType.VariesByCulture())
|
||||
{
|
||||
// bump dates to align cultures to version
|
||||
if (publishing)
|
||||
content.AdjustDates(contentVersionDto.VersionDate);
|
||||
entity.AdjustDates(contentVersionDto.VersionDate);
|
||||
|
||||
// names also impact 'edited'
|
||||
// ReSharper disable once UseDeconstruction
|
||||
foreach (var cultureInfo in content.CultureInfos)
|
||||
if (cultureInfo.Name != content.GetPublishName(cultureInfo.Culture))
|
||||
foreach (var cultureInfo in entity.CultureInfos)
|
||||
if (cultureInfo.Name != entity.GetPublishName(cultureInfo.Culture))
|
||||
{
|
||||
edited = true;
|
||||
(editedCultures ?? (editedCultures = new HashSet<string>(StringComparer.OrdinalIgnoreCase))).Add(cultureInfo.Culture);
|
||||
@@ -560,7 +558,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
Database.Execute(deleteContentVariations);
|
||||
|
||||
// replace the document version variations (rather than updating)
|
||||
var deleteDocumentVariations = Sql().Delete<DocumentCultureVariationDto>().Where<DocumentCultureVariationDto>(x => x.NodeId == content.Id);
|
||||
var deleteDocumentVariations = Sql().Delete<DocumentCultureVariationDto>().Where<DocumentCultureVariationDto>(x => x.NodeId == entity.Id);
|
||||
Database.Execute(deleteDocumentVariations);
|
||||
|
||||
// TODO: NPoco InsertBulk issue?
|
||||
@@ -570,32 +568,32 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// (same in PersistNewItem above)
|
||||
|
||||
// insert content variations
|
||||
Database.BulkInsertRecords(GetContentVariationDtos(content, publishing));
|
||||
Database.BulkInsertRecords(GetContentVariationDtos(entity, publishing));
|
||||
|
||||
// insert document variations
|
||||
Database.BulkInsertRecords(GetDocumentVariationDtos(content, publishing, editedCultures));
|
||||
Database.BulkInsertRecords(GetDocumentVariationDtos(entity, publishing, editedCultures));
|
||||
}
|
||||
|
||||
// refresh content
|
||||
content.SetCultureEdited(editedCultures);
|
||||
entity.SetCultureEdited(editedCultures);
|
||||
|
||||
// update the document dto
|
||||
// at that point, when un/publishing, the entity still has its old Published value
|
||||
// so we need to explicitly update the dto to persist the correct value
|
||||
if (content.PublishedState == PublishedState.Publishing)
|
||||
if (entity.PublishedState == PublishedState.Publishing)
|
||||
dto.Published = true;
|
||||
else if (content.PublishedState == PublishedState.Unpublishing)
|
||||
else if (entity.PublishedState == PublishedState.Unpublishing)
|
||||
dto.Published = false;
|
||||
content.Edited = dto.Edited = !dto.Published || edited; // if not published, always edited
|
||||
entity.Edited = dto.Edited = !dto.Published || edited; // if not published, always edited
|
||||
Database.Update(dto);
|
||||
|
||||
//update the schedule
|
||||
if (content.IsPropertyDirty("ContentSchedule"))
|
||||
PersistContentSchedule(content, true);
|
||||
if (entity.IsPropertyDirty("ContentSchedule"))
|
||||
PersistContentSchedule(entity, true);
|
||||
|
||||
// if entity is publishing, update tags, else leave tags there
|
||||
// means that implicitly unpublished, or trashed, entities *still* have tags in db
|
||||
if (content.PublishedState == PublishedState.Publishing)
|
||||
if (entity.PublishedState == PublishedState.Publishing)
|
||||
SetEntityTags(entity, _tagRepository);
|
||||
|
||||
// trigger here, before we reset Published etc
|
||||
@@ -603,23 +601,23 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
// flip the entity's published property
|
||||
// this also flips its published state
|
||||
if (content.PublishedState == PublishedState.Publishing)
|
||||
if (entity.PublishedState == PublishedState.Publishing)
|
||||
{
|
||||
content.Published = true;
|
||||
content.PublishTemplateId = content.TemplateId;
|
||||
content.PublisherId = content.WriterId;
|
||||
content.PublishName = content.Name;
|
||||
content.PublishDate = content.UpdateDate;
|
||||
entity.Published = true;
|
||||
entity.PublishTemplateId = entity.TemplateId;
|
||||
entity.PublisherId = entity.WriterId;
|
||||
entity.PublishName = entity.Name;
|
||||
entity.PublishDate = entity.UpdateDate;
|
||||
|
||||
SetEntityTags(entity, _tagRepository);
|
||||
}
|
||||
else if (content.PublishedState == PublishedState.Unpublishing)
|
||||
else if (entity.PublishedState == PublishedState.Unpublishing)
|
||||
{
|
||||
content.Published = false;
|
||||
content.PublishTemplateId = null;
|
||||
content.PublisherId = null;
|
||||
content.PublishName = null;
|
||||
content.PublishDate = null;
|
||||
entity.Published = false;
|
||||
entity.PublishTemplateId = null;
|
||||
entity.PublisherId = null;
|
||||
entity.PublishName = null;
|
||||
entity.PublishDate = null;
|
||||
|
||||
ClearEntityTags(entity, _tagRepository);
|
||||
}
|
||||
@@ -1335,7 +1333,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
#region Utilities
|
||||
|
||||
private void SanitizeNames(Content content, bool publishing)
|
||||
private void SanitizeNames(IContent content, bool publishing)
|
||||
{
|
||||
// a content item *must* have an invariant name, and invariant published name
|
||||
// else we just cannot write the invariant rows (node, content version...) to the database
|
||||
@@ -1400,7 +1398,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
x.NodeId != SqlTemplate.Arg<int>("id"))
|
||||
.OrderBy<ContentVersionCultureVariationDto>(x => x.LanguageId));
|
||||
|
||||
private void EnsureVariantNamesAreUnique(Content content, bool publishing)
|
||||
private void EnsureVariantNamesAreUnique(IContent content, bool publishing)
|
||||
{
|
||||
if (!EnsureUniqueNaming || !content.ContentType.VariesByCulture() || content.CultureInfos.Count == 0) return;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
@@ -101,7 +102,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (languageExists == 0) throw new NullReferenceException("No language exists with id " + entity.LanguageId.Value);
|
||||
}
|
||||
|
||||
((UmbracoDomain)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var factory = new DomainModelFactory();
|
||||
var dto = factory.BuildDto(entity);
|
||||
@@ -120,7 +121,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IDomain entity)
|
||||
{
|
||||
((UmbracoDomain)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var exists = Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoDomain WHERE domainName = @domainName AND umbracoDomain.id <> @id",
|
||||
new { domainName = entity.DomainName, id = entity.Id });
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IIdentityUserLogin entity)
|
||||
{
|
||||
((EntityBase)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var dto = ExternalLoginFactory.BuildDto(entity);
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IIdentityUserLogin entity)
|
||||
{
|
||||
((EntityBase)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var dto = ExternalLoginFactory.BuildDto(entity);
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (entity.IsoCode.IsNullOrWhiteSpace() || entity.CultureName.IsNullOrWhiteSpace())
|
||||
throw new InvalidOperationException("Cannot save a language without an ISO code and a culture name.");
|
||||
|
||||
((EntityBase) entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
// deal with entity becoming the new default entity
|
||||
if (entity.IsDefault)
|
||||
@@ -156,7 +156,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (entity.IsoCode.IsNullOrWhiteSpace() || entity.CultureName.IsNullOrWhiteSpace())
|
||||
throw new InvalidOperationException("Cannot save a language without an ISO code and a culture name.");
|
||||
|
||||
((EntityBase) entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
if (entity.IsDefault)
|
||||
{
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IMacro entity)
|
||||
{
|
||||
((EntityBase)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var dto = MacroFactory.BuildDto(entity);
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IMacro entity)
|
||||
{
|
||||
((EntityBase)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
;
|
||||
var dto = MacroFactory.BuildDto(entity);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -217,7 +218,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
protected override void PersistNewItem(IMedia entity)
|
||||
{
|
||||
var media = (Models.Media) entity;
|
||||
media.AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
// ensure unique name on the same level
|
||||
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name);
|
||||
|
||||
@@ -5,6 +5,7 @@ using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
@@ -102,7 +103,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IMediaType entity)
|
||||
{
|
||||
((MediaType)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
PersistNewBaseContentType(entity);
|
||||
|
||||
@@ -114,7 +115,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
ValidateAlias(entity);
|
||||
|
||||
//Updates Modified date
|
||||
((MediaType)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
//Look up parent to get and set the correct Path if ParentId has changed
|
||||
if (entity.IsPropertyDirty("ParentId"))
|
||||
|
||||
@@ -6,6 +6,7 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -91,8 +92,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
protected override void PersistNewItem(IMemberGroup entity)
|
||||
{
|
||||
//Save to db
|
||||
entity.AddingEntity();
|
||||
var group = (MemberGroup)entity;
|
||||
group.AddingEntity();
|
||||
var dto = MemberGroupFactory.BuildDto(group);
|
||||
var o = Database.IsNew(dto) ? Convert.ToInt32(Database.Insert(dto)) : Database.Update(dto);
|
||||
group.Id = dto.NodeId; //Set Id on entity to ensure an Id is set
|
||||
|
||||
@@ -6,6 +6,7 @@ using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -232,8 +233,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IMember entity)
|
||||
{
|
||||
if (entity.ProviderUserKey == null)
|
||||
{
|
||||
entity.ProviderUserKey = entity.Key;
|
||||
}
|
||||
entity.AddingEntity();
|
||||
|
||||
var member = (Member) entity;
|
||||
member.AddingEntity();
|
||||
|
||||
// ensure that strings don't contain characters that are invalid in xml
|
||||
// TODO: do we really want to keep doing this here?
|
||||
|
||||
@@ -5,6 +5,7 @@ using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -131,12 +132,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
ValidateAlias(entity);
|
||||
|
||||
((MemberType)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
//set a default icon if one is not specified
|
||||
if (entity.Icon.IsNullOrWhiteSpace())
|
||||
{
|
||||
entity.Icon = "icon-user";
|
||||
entity.Icon = Constants.Icons.Member;
|
||||
}
|
||||
|
||||
//By Convention we add 9 standard PropertyTypes to an Umbraco MemberType
|
||||
@@ -165,7 +166,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
ValidateAlias(entity);
|
||||
|
||||
//Updates Modified date
|
||||
((MemberType)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
//Look up parent to get and set the correct Path if ParentId has changed
|
||||
if (entity.IsPropertyDirty("ParentId"))
|
||||
@@ -224,6 +225,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
//this reset's its current data type reference which will be re-assigned based on the property editor assigned on the next line
|
||||
propertyType.DataTypeId = 0;
|
||||
propertyType.DataTypeKey = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IRelation entity)
|
||||
{
|
||||
((EntityBase)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var factory = new RelationFactory(entity.RelationType);
|
||||
var dto = factory.BuildDto(entity);
|
||||
@@ -147,7 +147,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IRelation entity)
|
||||
{
|
||||
((EntityBase)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var factory = new RelationFactory(entity.RelationType);
|
||||
var dto = factory.BuildDto(entity);
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IRelationType entity)
|
||||
{
|
||||
((EntityBase)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var dto = RelationTypeFactory.BuildDto(entity);
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IRelationType entity)
|
||||
{
|
||||
((EntityBase)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var dto = RelationTypeFactory.BuildDto(entity);
|
||||
Database.Update(dto);
|
||||
|
||||
@@ -5,6 +5,7 @@ using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -96,7 +97,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IServerRegistration entity)
|
||||
{
|
||||
((ServerRegistration)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var dto = ServerRegistrationFactory.BuildDto(entity);
|
||||
|
||||
@@ -108,7 +109,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IServerRegistration entity)
|
||||
{
|
||||
((ServerRegistration)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var dto = ServerRegistrationFactory.BuildDto(entity);
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// <inheritdoc />
|
||||
protected override void PersistNewItem(ITag entity)
|
||||
{
|
||||
((EntityBase)entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var dto = TagFactory.BuildDto(entity);
|
||||
var id = Convert.ToInt32(Database.Insert(dto));
|
||||
@@ -97,7 +97,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// <inheritdoc />
|
||||
protected override void PersistUpdatedItem(ITag entity)
|
||||
{
|
||||
((EntityBase)entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var dto = TagFactory.BuildDto(entity);
|
||||
Database.Update(dto);
|
||||
|
||||
@@ -290,7 +290,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistNewItem(IUserGroup entity)
|
||||
{
|
||||
((UserGroup) entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
var userGroupDto = UserGroupFactory.BuildDto(entity);
|
||||
|
||||
@@ -304,7 +304,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override void PersistUpdatedItem(IUserGroup entity)
|
||||
{
|
||||
((UserGroup) entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
var userGroupDto = UserGroupFactory.BuildDto(entity);
|
||||
|
||||
|
||||
@@ -445,7 +445,7 @@ ORDER BY colName";
|
||||
return;
|
||||
}
|
||||
|
||||
((User) entity).AddingEntity();
|
||||
entity.AddingEntity();
|
||||
|
||||
// ensure security stamp if missing
|
||||
if (entity.SecurityStamp.IsNullOrWhiteSpace())
|
||||
@@ -495,7 +495,7 @@ ORDER BY colName";
|
||||
protected override void PersistUpdatedItem(IUser entity)
|
||||
{
|
||||
// updates Modified date
|
||||
((User) entity).UpdatingEntity();
|
||||
entity.UpdatingEntity();
|
||||
|
||||
// ensure security stamp if missing
|
||||
if (entity.SecurityStamp.IsNullOrWhiteSpace())
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interface for any editor configuration that supports Ignoring user start nodes
|
||||
/// </summary>
|
||||
internal interface IIgnoreUserStartNodesConfig
|
||||
{
|
||||
bool IgnoreUserStartNodes { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,14 @@ namespace Umbraco.Core
|
||||
public static class PublishedModelFactoryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes an action with a safe live factory/
|
||||
/// Returns true if the current <see cref="IPublishedModelFactory"/> is an implementation of <see cref="ILivePublishedModelFactory"/>
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsLiveFactory(this IPublishedModelFactory factory) => factory is ILivePublishedModelFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Executes an action with a safe live factory
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>If the factory is a live factory, ensures it is refreshed and locked while executing the action.</para>
|
||||
@@ -20,6 +27,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
lock (liveFactory.SyncRoot)
|
||||
{
|
||||
//Call refresh on the live factory to re-compile the models
|
||||
liveFactory.Refresh();
|
||||
action();
|
||||
}
|
||||
|
||||
@@ -6,9 +6,25 @@ namespace Umbraco.Core.Services.Changes
|
||||
public enum ContentTypeChangeTypes : byte
|
||||
{
|
||||
None = 0,
|
||||
Create = 1, // item type has been created, no impact
|
||||
RefreshMain = 2, // changed, impacts content (adding property or composition does NOT)
|
||||
RefreshOther = 4, // changed, other changes
|
||||
Remove = 8 // item type has been removed
|
||||
|
||||
/// <summary>
|
||||
/// Item type has been created, no impact
|
||||
/// </summary>
|
||||
Create = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Content type changes impact only the Content type being saved
|
||||
/// </summary>
|
||||
RefreshMain = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Content type changes impacts the content type being saved and others used that are composed of it
|
||||
/// </summary>
|
||||
RefreshOther = 4, // changed, other change
|
||||
|
||||
/// <summary>
|
||||
/// Content type was removed
|
||||
/// </summary>
|
||||
Remove = 8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
|
||||
@@ -11,6 +12,42 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public static class ContentServiceExtensions
|
||||
{
|
||||
#region RTE Anchor values
|
||||
|
||||
private static readonly Regex AnchorRegex = new Regex("<a id=\"(.*?)\">", RegexOptions.Compiled);
|
||||
|
||||
internal static IEnumerable<string> GetAnchorValuesFromRTEs(this IContentService contentService, int id, string culture = "*")
|
||||
{
|
||||
var result = new List<string>();
|
||||
var content = contentService.GetById(id);
|
||||
|
||||
foreach (var contentProperty in content.Properties)
|
||||
{
|
||||
if (contentProperty.PropertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.TinyMce))
|
||||
{
|
||||
var value = contentProperty.GetValue(culture)?.ToString();
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
result.AddRange(contentService.GetAnchorValuesFromRTEContent(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
internal static IEnumerable<string> GetAnchorValuesFromRTEContent(this IContentService contentService, string rteContent)
|
||||
{
|
||||
var result = new List<string>();
|
||||
var matches = AnchorRegex.Matches(rteContent);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
result.Add(match.Value.Split('\"')[1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static IEnumerable<IContent> GetByIds(this IContentService contentService, IEnumerable<Udi> ids)
|
||||
{
|
||||
var guids = new List<GuidUdi>();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
internal static class DateTypeServiceExtensions
|
||||
{
|
||||
public static bool IsDataTypeIgnoringUserStartNodes(this IDataTypeService dataTypeService, Guid key)
|
||||
{
|
||||
if (DataTypeExtensions.IsBuildInDataType(key)) return false; //built in ones can never be ignoring start nodes
|
||||
|
||||
var dataType = dataTypeService.GetDataType(key);
|
||||
|
||||
if (dataType != null && dataType.Configuration is IIgnoreUserStartNodesConfig ignoreStartNodesConfig)
|
||||
return ignoreStartNodesConfig.IgnoreUserStartNodes;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -526,5 +526,6 @@ namespace Umbraco.Core.Services
|
||||
OperationResult Rollback(int id, int versionId, string culture = "*", int userId = Constants.Security.SuperUserId);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Defines the DataType Service, which is an easy access to operations involving <see cref="IDataType"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -51,8 +51,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var result = sinceDate.HasValue == false
|
||||
? _auditRepository.Get(Query<IAuditItem>().Where(x => x.UserId == userId && x.AuditType == type))
|
||||
: _auditRepository.Get(Query<IAuditItem>().Where(x => x.UserId == userId && x.AuditType == type && x.CreateDate >= sinceDate.Value));
|
||||
? _auditRepository.Get(type, Query<IAuditItem>().Where(x => x.UserId == userId))
|
||||
: _auditRepository.Get(type, Query<IAuditItem>().Where(x => x.UserId == userId && x.CreateDate >= sinceDate.Value));
|
||||
scope.Complete();
|
||||
return result;
|
||||
}
|
||||
@@ -63,8 +63,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var result = sinceDate.HasValue == false
|
||||
? _auditRepository.Get(Query<IAuditItem>().Where(x => x.AuditType == type))
|
||||
: _auditRepository.Get(Query<IAuditItem>().Where(x => x.AuditType == type && x.CreateDate >= sinceDate.Value));
|
||||
? _auditRepository.Get(type, Query<IAuditItem>())
|
||||
: _auditRepository.Get(type, Query<IAuditItem>().Where(x => x.CreateDate >= sinceDate.Value));
|
||||
scope.Complete();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -31,6 +32,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
private IQuery<IContent> _queryNotTrashed;
|
||||
//TODO: The non-lazy object should be injected
|
||||
private readonly Lazy<PropertyValidationService> _propertyValidationService = new Lazy<PropertyValidationService>(() => new PropertyValidationService());
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
@@ -3024,5 +3026,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
@@ -23,7 +23,7 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
@@ -55,6 +55,11 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- note: NuGet deals with transitive references now -->
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub">
|
||||
<Version>1.0.0-beta2-19324-01</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Async">
|
||||
<Version>1.3.0</Version>
|
||||
</PackageReference>
|
||||
@@ -237,6 +242,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RenamingPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RichTextPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
|
||||
<Compile Include="Models\Entities\EntityExtensions.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueMigratorBase.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueDto.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\PropertyEditorsMigrationBase.cs" />
|
||||
@@ -258,6 +264,7 @@
|
||||
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedContentType.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedPropertyType.cs" />
|
||||
<Compile Include="PropertyEditors\IIgnoreUserStartNodesConfig.cs" />
|
||||
<Compile Include="PublishedContentExtensions.cs" />
|
||||
<Compile Include="Models\PublishedContent\UrlMode.cs" />
|
||||
<Compile Include="Persistence\Dtos\PropertyTypeCommonDto.cs" />
|
||||
@@ -267,6 +274,7 @@
|
||||
<Compile Include="PropertyEditors\DateTimeConfiguration.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameLabelAndRichTextPropertyEditorAliases.cs" />
|
||||
<Compile Include="PublishedModelFactoryExtensions.cs" />
|
||||
<Compile Include="Services\DateTypeServiceExtensions.cs" />
|
||||
<Compile Include="Services\PropertyValidationService.cs" />
|
||||
<Compile Include="Composing\TypeCollectionBuilderBase.cs" />
|
||||
<Compile Include="TypeLoaderExtensions.cs" />
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
@@ -23,7 +23,7 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
@@ -49,6 +49,11 @@
|
||||
<ItemGroup>
|
||||
<!-- note: NuGet deals with transitive references now -->
|
||||
<PackageReference Include="Examine" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub">
|
||||
<Version>1.0.0-beta2-19324-01</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="NPoco" Version="3.9.4" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
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", "%");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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,6 +1,5 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Semver;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Api
|
||||
{
|
||||
@@ -9,28 +8,81 @@ 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>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
internal ApiVersion(SemVersion executingVersion)
|
||||
/// <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)
|
||||
{
|
||||
Version = executingVersion ?? throw new ArgumentNullException(nameof(executingVersion));
|
||||
}
|
||||
if (executingVersion == null) throw new ArgumentNullException(nameof(executingVersion));
|
||||
if (minClientVersionSupportedByServer == null) throw new ArgumentNullException(nameof(minClientVersionSupportedByServer));
|
||||
|
||||
private static SemVersion CurrentAssemblyVersion
|
||||
=> SemVersion.Parse(Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion);
|
||||
Version = executingVersion;
|
||||
MinClientVersionSupportedByServer = minClientVersionSupportedByServer;
|
||||
MinServerVersionSupportingClient = minServerVersionSupportingClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently executing API version.
|
||||
/// </summary>
|
||||
public static ApiVersion Current { get; }
|
||||
= new ApiVersion(CurrentAssemblyVersion);
|
||||
= new ApiVersion(Assembly.GetExecutingAssembly().GetName().Version,
|
||||
MinClientVersionSupportedByServerConst, MinServerVersionSupportingClientConst);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the executing version of the API.
|
||||
/// </summary>
|
||||
public SemVersion Version { get; }
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
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,7 +5,6 @@ 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;
|
||||
|
||||
@@ -26,8 +25,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
private readonly IList<TypeModel> _typeModels;
|
||||
|
||||
protected Dictionary<string, string> ModelsMap { get; } = new Dictionary<string, string>();
|
||||
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
protected ParseResult ParseResult { get; }
|
||||
|
||||
// the list of assemblies that will be 'using' by default
|
||||
protected readonly IList<string> TypesUsing = new List<string>
|
||||
@@ -60,7 +58,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// <returns>The models to generate, ie those that are not ignored.</returns>
|
||||
public IEnumerable<TypeModel> GetModelsToGenerate()
|
||||
{
|
||||
return _typeModels;
|
||||
return _typeModels.Where(x => !x.IsContentIgnored);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,25 +72,27 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// and the result of code parsing.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
protected Builder(IList<TypeModel> typeModels)
|
||||
: this(typeModels, null)
|
||||
{ }
|
||||
/// <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();
|
||||
}
|
||||
|
||||
/// <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, string modelsNamespace)
|
||||
protected Builder(IList<TypeModel> typeModels, ParseResult parseResult, string modelsNamespace)
|
||||
: this(typeModels, parseResult)
|
||||
{
|
||||
_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,9 +108,49 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// </remarks>
|
||||
private void Prepare()
|
||||
{
|
||||
TypeModel.MapModelTypes(_typeModels, ModelsNamespace);
|
||||
var pureLive = UmbracoConfig.For.ModelsBuilder().ModelsMode == ModelsMode.PureLive;
|
||||
|
||||
var pureLive = Config.ModelsMode == ModelsMode.PureLive;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// for the first two of these two tests,
|
||||
// always throw, even in purelive: cannot happen unless ppl start fidling with attributes to rename
|
||||
@@ -118,22 +158,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.GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
|
||||
foreach (var xx in _typeModels.Where(x => !x.IsContentIgnored).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)
|
||||
foreach (var xx in typeModel.Properties.GroupBy(x => x.ClrName).Where(x => x.Count() > 1))
|
||||
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))
|
||||
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)
|
||||
foreach (var typeModel in _typeModels.Where(x => !x.IsContentIgnored))
|
||||
{
|
||||
foreach (var xx in typeModel.Properties.Where(x => x.ClrName == typeModel.ClrName))
|
||||
foreach (var xx in typeModel.Properties.Where(x => !x.IsIgnored && x.ClrName == typeModel.ClrName))
|
||||
{
|
||||
if (!pureLive)
|
||||
throw new InvalidOperationException($"The model class for content type with alias \"{typeModel.Alias}\" is named \"{xx.ClrName}\"."
|
||||
@@ -164,7 +204,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)
|
||||
if (typeModel.BaseType != null && !typeModel.BaseType.IsContentIgnored)
|
||||
TypeModel.CollectImplems(parentImplems, typeModel.BaseType);
|
||||
|
||||
// interfaces we must declare we implement (initially empty)
|
||||
@@ -172,6 +212,7 @@ 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);
|
||||
|
||||
@@ -186,16 +227,43 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
typeModel.ImplementingInterfaces.AddRange(mixinImplems.Except(parentImplems));
|
||||
}
|
||||
|
||||
// ensure elements don't inherit from non-elements
|
||||
foreach (var typeModel in _typeModels.Where(x => x.IsElement))
|
||||
// register using types
|
||||
foreach (var usingNamespace in ParseResult.UsingNamespaces)
|
||||
{
|
||||
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.");
|
||||
if (!TypesUsing.Contains(usingNamespace))
|
||||
TypesUsing.Add(usingNamespace);
|
||||
}
|
||||
|
||||
// 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'
|
||||
@@ -205,10 +273,20 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
// - 1 symbol is found BUT not matching (implicitely ambiguous)
|
||||
protected bool IsAmbiguousSymbol(string symbol, string match)
|
||||
{
|
||||
// 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;
|
||||
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
|
||||
}
|
||||
|
||||
internal string ModelsNamespaceForTests;
|
||||
@@ -218,17 +296,25 @@ 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 Config.ModelsNamespace;
|
||||
return UmbracoConfig.For.ModelsBuilder().ModelsNamespace;
|
||||
}
|
||||
|
||||
protected string GetModelsBaseClassName(TypeModel type)
|
||||
{
|
||||
// code attribute overrides everything
|
||||
if (ParseResult.HasModelsBaseClassName)
|
||||
return ParseResult.ModelsBaseClassName;
|
||||
|
||||
// default
|
||||
return type.IsElement ? "PublishedElementModel" : "PublishedContentModel";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
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,6 +41,11 @@ 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,9 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.ModelsBuilder.Api;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
@@ -20,8 +19,9 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// and the result of code parsing.
|
||||
/// </summary>
|
||||
/// <param name="typeModels">The list of models to generate.</param>
|
||||
public TextBuilder(IList<TypeModel> typeModels)
|
||||
: base(typeModels)
|
||||
/// <param name="parseResult">The result of code parsing.</param>
|
||||
public TextBuilder(IList<TypeModel> typeModels, ParseResult parseResult)
|
||||
: base(typeModels, parseResult)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
@@ -29,22 +29,21 @@ 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, string modelsNamespace)
|
||||
: base(typeModels, modelsNamespace)
|
||||
public TextBuilder(IList<TypeModel> typeModels, ParseResult parseResult, string modelsNamespace)
|
||||
: base(typeModels, parseResult, 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);
|
||||
@@ -98,20 +97,6 @@ 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;
|
||||
@@ -119,11 +104,11 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
if (type.IsMixin)
|
||||
{
|
||||
// write the interface declaration
|
||||
sb.AppendFormat("\t// Mixin Content Type with alias \"{0}\"\n", type.Alias);
|
||||
sb.AppendFormat("\t// Mixin 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));
|
||||
sb.AppendFormat("\tpublic partial interface I{0}", type.ClrName);
|
||||
var implements = type.BaseType == null
|
||||
var implements = type.BaseType == null || type.BaseType.IsContentIgnored
|
||||
? (type.HasBase ? null : (type.IsElement ? "PublishedElement" : "PublishedContent"))
|
||||
: type.BaseType.ClrName;
|
||||
if (implements != null)
|
||||
@@ -141,7 +126,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.OrderBy(x => x.ClrName))
|
||||
foreach (var prop in type.Properties.Where(x => !x.IsIgnored).OrderBy(x => x.ClrName))
|
||||
{
|
||||
if (more) sb.Append("\n");
|
||||
more = true;
|
||||
@@ -152,6 +137,8 @@ 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
|
||||
@@ -161,7 +148,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 == null || type.BaseType.IsContentIgnored
|
||||
? GetModelsBaseClassName(type)
|
||||
: type.BaseType.ClrName);
|
||||
if (inherits != null)
|
||||
@@ -191,25 +178,22 @@ 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
|
||||
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");
|
||||
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");
|
||||
|
||||
// write the properties
|
||||
sb.Append("\t\t// properties\n");
|
||||
@@ -221,10 +205,10 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
private void WriteContentTypeProperties(StringBuilder sb, TypeModel type)
|
||||
{
|
||||
var staticMixinGetters = true;
|
||||
var staticMixinGetters = UmbracoConfig.For.ModelsBuilder().StaticMixinGetters;
|
||||
|
||||
// write the properties
|
||||
foreach (var prop in type.Properties.OrderBy(x => x.ClrName))
|
||||
foreach (var prop in type.Properties.Where(x => !x.IsIgnored).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
|
||||
@@ -233,7 +217,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.OrderBy(x => x.ClrName))
|
||||
foreach (var prop in mixinType.Properties.Where(x => !x.IsIgnored).OrderBy(x => x.ClrName))
|
||||
if (staticMixinGetters)
|
||||
WriteMixinProperty(sb, prop, mixinType.ClrName);
|
||||
else
|
||||
@@ -258,7 +242,6 @@ 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 ");
|
||||
@@ -273,7 +256,7 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
|
||||
private static string MixinStaticGetterName(string clrName)
|
||||
{
|
||||
return string.Format("Get{0}", clrName);
|
||||
return string.Format(UmbracoConfig.For.ModelsBuilder().StaticMixinGetterPattern, clrName);
|
||||
}
|
||||
|
||||
private void WriteProperty(StringBuilder sb, TypeModel type, PropertyModel property, string mixinClrName = null)
|
||||
@@ -317,7 +300,6 @@ 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)
|
||||
@@ -361,7 +343,6 @@ 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",
|
||||
@@ -416,7 +397,6 @@ 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",
|
||||
@@ -481,7 +461,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, out string typeName))
|
||||
if (TypesMap.TryGetValue(s.ToLowerInvariant(), out string typeName))
|
||||
{
|
||||
sb.Append(typeName);
|
||||
return;
|
||||
@@ -501,11 +481,6 @@ 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
|
||||
@@ -556,24 +531,24 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
return s.Replace('<', '{').Replace('>', '}').Replace('\r', ' ').Replace('\n', ' ');
|
||||
}
|
||||
|
||||
private static readonly IDictionary<string, string> TypesMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
private static readonly IDictionary<string, string> TypesMap = new Dictionary<string, string>
|
||||
{
|
||||
{ "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,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Building
|
||||
{
|
||||
@@ -89,6 +88,16 @@ 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>
|
||||
@@ -99,6 +108,16 @@ 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>
|
||||
@@ -162,11 +181,11 @@ namespace Umbraco.ModelsBuilder.Building
|
||||
/// <remarks>Includes the specified type.</remarks>
|
||||
internal static void CollectImplems(ICollection<TypeModel> types, TypeModel type)
|
||||
{
|
||||
if (types.Contains(type) == false)
|
||||
if (!type.IsContentIgnored && types.Contains(type) == false)
|
||||
types.Add(type);
|
||||
if (type.BaseType != null)
|
||||
if (type.BaseType != null && !type.BaseType.IsContentIgnored)
|
||||
CollectImplems(types, type.BaseType);
|
||||
foreach (var mixin in type.MixinTypes)
|
||||
foreach (var mixin in type.MixinTypes.Where(x => !x.IsContentIgnored))
|
||||
CollectImplems(types, mixin);
|
||||
}
|
||||
|
||||
@@ -185,21 +204,5 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
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,8 +1,10 @@
|
||||
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
|
||||
@@ -12,13 +14,40 @@ 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>
|
||||
public Config()
|
||||
private Config()
|
||||
{
|
||||
const string prefix = "Umbraco.ModelsBuilder.";
|
||||
|
||||
@@ -27,7 +56,10 @@ 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("~/");
|
||||
@@ -48,6 +80,12 @@ 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;
|
||||
@@ -56,15 +94,17 @@ namespace Umbraco.ModelsBuilder.Configuration
|
||||
break;
|
||||
default:
|
||||
throw new ConfigurationErrorsException($"ModelsMode \"{modelsMode}\" is not a valid mode."
|
||||
+ " Note that modes are case-sensitive. Possible values are: " + string.Join(", ", Enum.GetNames(typeof(ModelsMode))));
|
||||
+ " Note that modes are case-sensitive.");
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -72,6 +112,45 @@ 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))
|
||||
@@ -107,9 +186,14 @@ 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)
|
||||
@@ -117,9 +201,14 @@ 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;
|
||||
@@ -170,6 +259,27 @@ 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>
|
||||
@@ -194,6 +304,24 @@ 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>
|
||||
@@ -202,6 +330,11 @@ 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,6 +31,22 @@
|
||||
/// </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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
{
|
||||
return
|
||||
modelsMode == ModelsMode.PureLive
|
||||
|| modelsMode == ModelsMode.LiveDll
|
||||
|| modelsMode == ModelsMode.LiveAppData;
|
||||
}
|
||||
|
||||
@@ -21,7 +22,18 @@
|
||||
public static bool IsLiveNotPure(this ModelsMode modelsMode)
|
||||
{
|
||||
return
|
||||
modelsMode == ModelsMode.LiveAppData;
|
||||
modelsMode == ModelsMode.LiveDll
|
||||
|| modelsMode == ModelsMode.LiveAppData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the mode is [Live]Dll.
|
||||
/// </summary>
|
||||
public static bool IsAnyDll(this ModelsMode modelsMode)
|
||||
{
|
||||
return
|
||||
modelsMode == ModelsMode.Dll
|
||||
|| modelsMode == ModelsMode.LiveDll;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -30,8 +42,10 @@
|
||||
public static bool SupportsExplicitGeneration(this ModelsMode modelsMode)
|
||||
{
|
||||
return
|
||||
modelsMode == ModelsMode.AppData
|
||||
modelsMode == ModelsMode.Dll
|
||||
|| modelsMode == ModelsMode.LiveDll
|
||||
|| modelsMode == ModelsMode.AppData
|
||||
|| modelsMode == ModelsMode.LiveAppData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.ModelsBuilder.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="UmbracoConfig"/> class.
|
||||
/// </summary>
|
||||
public static class UmbracoConfigExtensions
|
||||
{
|
||||
private static Config _config;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the models builder configuration.
|
||||
/// </summary>
|
||||
/// <param name="umbracoConfig">The umbraco configuration.</param>
|
||||
/// <returns>The models builder configuration.</returns>
|
||||
/// <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 UmbracoConfig umbracoConfig)
|
||||
{
|
||||
// capture the current Config2.Default value, cannot change anymore
|
||||
LazyInitializer.EnsureInitialized(ref _config, () => Config.Value);
|
||||
return _config;
|
||||
}
|
||||
|
||||
// internal for tests
|
||||
internal static void ResetConfig()
|
||||
{
|
||||
_config = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Text;
|
||||
using Umbraco.Core.Composing;
|
||||
using System;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
|
||||
@@ -7,11 +8,14 @@ namespace Umbraco.ModelsBuilder.Dashboard
|
||||
{
|
||||
internal static class BuilderDashboardHelper
|
||||
{
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
public static bool CanGenerate()
|
||||
{
|
||||
return Config.ModelsMode.SupportsExplicitGeneration();
|
||||
return UmbracoConfig.For.ModelsBuilder().ModelsMode.SupportsExplicitGeneration();
|
||||
}
|
||||
|
||||
public static bool GenerateCausesRestart()
|
||||
{
|
||||
return UmbracoConfig.For.ModelsBuilder().ModelsMode.IsAnyDll();
|
||||
}
|
||||
|
||||
public static bool AreModelsOutOfDate()
|
||||
@@ -26,17 +30,12 @@ namespace Umbraco.ModelsBuilder.Dashboard
|
||||
|
||||
public static string Text()
|
||||
{
|
||||
var config = Config;
|
||||
|
||||
var config = UmbracoConfig.For.ModelsBuilder();
|
||||
if (!config.Enable)
|
||||
return "Version: " + Api.ApiVersion.Current.Version + "<br /> <br />ModelsBuilder is disabled<br />(the .Enable key is missing, or its value is not 'true').";
|
||||
return "ModelsBuilder is disabled<br />(the .Enable key is missing, or its value is not 'true').";
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append("Version: ");
|
||||
sb.Append(Api.ApiVersion.Current.Version);
|
||||
sb.Append("<br /> <br />");
|
||||
|
||||
sb.Append("ModelsBuilder is enabled, with the following configuration:");
|
||||
|
||||
sb.Append("<ul>");
|
||||
@@ -47,12 +46,39 @@ namespace Umbraco.ModelsBuilder.Dashboard
|
||||
: "not enabled. Umbraco will <em>not</em> use models");
|
||||
sb.Append(".</li>");
|
||||
|
||||
sb.Append("<li>The <strong>API</strong> is ");
|
||||
if (config.ApiInstalled && config.EnableApi)
|
||||
{
|
||||
sb.Append("installed and enabled");
|
||||
if (!config.IsDebug) sb.Append(".<br />However, the API runs only with <em>debug</em> compilation mode");
|
||||
}
|
||||
else if (config.ApiInstalled || config.EnableApi)
|
||||
sb.Append(config.ApiInstalled ? "installed but not enabled" : "enabled but not installed");
|
||||
else sb.Append("neither installed nor enabled");
|
||||
sb.Append(".<br />");
|
||||
if (!config.ApiServer)
|
||||
sb.Append("External tools such as Visual Studio <em>cannot</em> use the API");
|
||||
else
|
||||
sb.Append("<span style=\"color:orange;font-weight:bold;\">The API endpoint is open on this server</span>");
|
||||
sb.Append(".</li>");
|
||||
|
||||
sb.Append(config.ModelsMode != ModelsMode.Nothing
|
||||
? $"<li><strong>{config.ModelsMode} models</strong> are enabled.</li>"
|
||||
: "<li>No models mode is specified: models will <em>not</em> be generated.</li>");
|
||||
|
||||
sb.Append($"<li>Models namespace is {config.ModelsNamespace}.</li>");
|
||||
|
||||
sb.Append("<li>Static mixin getters are ");
|
||||
sb.Append(config.StaticMixinGetters ? "enabled" : "disabled");
|
||||
if (config.StaticMixinGetters)
|
||||
{
|
||||
sb.Append(". The pattern for getters is ");
|
||||
sb.Append(string.IsNullOrWhiteSpace(config.StaticMixinGetterPattern)
|
||||
? "not configured (will use default)"
|
||||
: $"\"{config.StaticMixinGetterPattern}\"");
|
||||
}
|
||||
sb.Append(".</li>");
|
||||
|
||||
sb.Append("<li>Tracking of <strong>out-of-date models</strong> is ");
|
||||
sb.Append(config.FlagOutOfDateModels ? "enabled" : "not enabled");
|
||||
sb.Append(".</li>");
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Policy;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.ModelsBuilder;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
// for the time being it's all-or-nothing
|
||||
// when the content type is ignored then
|
||||
// - no class is generated for that content type
|
||||
// - no class is generated for any child of that class
|
||||
// - no interface is generated for that content type as a mixin
|
||||
// - and it is ignored as a mixin ie its properties are not generated
|
||||
// in the future we may way to do
|
||||
// [assembly:IgnoreContentType("foo", ContentTypeIgnorable.ContentType|ContentTypeIgnorable.Mixin|ContentTypeIgnorable.MixinProperties)]
|
||||
// so that we can
|
||||
// - generate a class for that content type, or not
|
||||
// - if not generated, generate children or not
|
||||
// - if generate children, include properties or not
|
||||
// - generate an interface for that content type as a mixin
|
||||
// - if not generated, still generate properties in content types implementing the mixin or not
|
||||
// but... I'm not even sure it makes sense
|
||||
// if we don't want it... we don't want it.
|
||||
|
||||
// about ignoring
|
||||
// - content (don't generate the content, use as mixin)
|
||||
// - mixin (don't generate the interface, use the properties)
|
||||
// - mixin properties (generate the interface, not the properties)
|
||||
// - mixin: local only or children too...
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that no model should be generated for a specified content type alias.
|
||||
/// </summary>
|
||||
/// <remarks>When a content type is ignored, its descendants are also ignored.</remarks>
|
||||
/// <remarks>Supports trailing wildcard eg "foo*".</remarks>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class IgnoreContentTypeAttribute : Attribute
|
||||
{
|
||||
public IgnoreContentTypeAttribute(string alias /*, bool ignoreContent = true, bool ignoreMixin = true, bool ignoreMixinProperties = true*/)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that no model should be generated for a specified property type alias.
|
||||
/// </summary>
|
||||
/// <remarks>Supports trailing wildcard eg "foo*".</remarks>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class IgnorePropertyTypeAttribute : Attribute
|
||||
{
|
||||
public IgnorePropertyTypeAttribute(string alias)
|
||||
{}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
// NOTE
|
||||
// that attribute should inherit from PublishedModelAttribute
|
||||
// so we do not have different syntaxes
|
||||
// but... is sealed at the moment.
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a (partial) class defines the model type for a specific alias.
|
||||
/// </summary>
|
||||
/// <remarks>Though a model will be generated - so that is the way to register a rename.</remarks>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class ImplementContentTypeAttribute : Attribute
|
||||
{
|
||||
public ImplementContentTypeAttribute(string alias)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the default base class for models.
|
||||
/// </summary>
|
||||
/// <remarks>Otherwise it is PublishedContentModel. Would make sense to inherit from PublishedContentModel.</remarks>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class ModelsBaseClassAttribute : Attribute
|
||||
{
|
||||
public ModelsBaseClassAttribute(Type type)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the models namespace.
|
||||
/// </summary>
|
||||
/// <remarks>Will override anything else that might come from settings.</remarks>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class ModelsNamespaceAttribute : Attribute
|
||||
{
|
||||
public ModelsNamespaceAttribute(string modelsNamespace)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Policy;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.ModelsBuilder;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates namespaces that should be used in generated models (in using clauses).
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class ModelsUsingAttribute : Attribute
|
||||
{
|
||||
public ModelsUsingAttribute(string usingNamespace)
|
||||
{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,4 +7,8 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyProduct("Umbraco CMS")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("52ac0ba8-a60e-4e36-897b-e8b97a54ed1c")]
|
||||
[assembly: Guid("7020a059-c0d1-43a0-8efd-23591a0c9af6")]
|
||||
|
||||
// code analysis
|
||||
// IDE1006 is broken, wants _value syntax for consts, etc - and it's even confusing ppl at MS, kill it
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "~_~")]
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.ModelsBuilder;
|
||||
using Umbraco.Web;
|
||||
|
||||
// same namespace as original Umbraco.Web PublishedElementExtensions
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Umbraco.Web
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods to models.
|
||||
@@ -16,14 +14,13 @@ namespace Umbraco.Web
|
||||
/// <summary>
|
||||
/// Gets the value of a property.
|
||||
/// </summary>
|
||||
public static TValue Value<TModel, TValue>(this TModel model, Expression<Func<TModel, TValue>> property, string culture = null, string segment = null, Fallback fallback = default, TValue defaultValue = default)
|
||||
public static TValue Value<TModel, TValue>(this TModel model, Expression<Func<TModel, TValue>> property, string culture = ".", string segment = ".")
|
||||
where TModel : IPublishedElement
|
||||
{
|
||||
var alias = GetAlias(model, property);
|
||||
return model.Value<TValue>(alias, culture, segment, fallback, defaultValue);
|
||||
return model.Value<TValue>(alias, culture, segment);
|
||||
}
|
||||
|
||||
// fixme that one should be public so ppl can use it
|
||||
private static string GetAlias<TModel, TValue>(TModel model, Expression<Func<TModel, TValue>> property)
|
||||
{
|
||||
if (property.NodeType != ExpressionType.Lambda)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
public static class PublishedPropertyTypeExtensions
|
||||
{
|
||||
// fixme - need to rewrite that one - we don't have prevalues anymore
|
||||
//public static KeyValuePair<int, string>[] PreValues(this PublishedPropertyType propertyType)
|
||||
//{
|
||||
// return ApplicationContext.Current.Services.DataTypeService
|
||||
// .GetPreValuesCollectionByDataTypeId(propertyType.DataType.Id)
|
||||
// .PreValuesAsArray
|
||||
// .Select(x => new KeyValuePair<int, string>(x.Id, x.Value))
|
||||
// .ToArray();
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Hosting;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
@@ -11,12 +12,17 @@ namespace Umbraco.ModelsBuilder
|
||||
internal static class ReferencedAssemblies
|
||||
{
|
||||
private static readonly Lazy<IEnumerable<string>> LazyLocations;
|
||||
private static readonly Lazy<IEnumerable<PortableExecutableReference>> LazyReferences;
|
||||
|
||||
static ReferencedAssemblies()
|
||||
{
|
||||
LazyLocations = new Lazy<IEnumerable<string>>(() => HostingEnvironment.IsHosted
|
||||
? GetAllReferencedAssembliesLocationFromBuildManager()
|
||||
: GetAllReferencedAssembliesFromDomain());
|
||||
|
||||
LazyReferences = new Lazy<IEnumerable<PortableExecutableReference>>(() => Locations
|
||||
.Select(x => MetadataReference.CreateFromFile(x))
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -25,68 +31,19 @@ namespace Umbraco.ModelsBuilder
|
||||
/// </summary>
|
||||
public static IEnumerable<string> Locations => LazyLocations.Value;
|
||||
|
||||
public static Assembly GetNetStandardAssembly(List<Assembly> assemblies)
|
||||
{
|
||||
if (assemblies == null)
|
||||
assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList();
|
||||
/// <summary>
|
||||
/// Gets the metadata reference of all the referenced assemblies.
|
||||
/// </summary>
|
||||
public static IEnumerable<PortableExecutableReference> References => LazyReferences.Value;
|
||||
|
||||
// for some reason, netstandard is also missing from BuildManager.ReferencedAssemblies and yet, is part of
|
||||
// the references that CSharpCompiler (above) receives - where is it coming from? cannot figure it out
|
||||
try
|
||||
{
|
||||
// so, resorting to an ugly trick
|
||||
// we should have System.Reflection.Metadata around, and it should reference netstandard
|
||||
var someAssembly = assemblies.First(x => x.FullName.StartsWith("System.Reflection.Metadata,"));
|
||||
var netStandardAssemblyName = someAssembly.GetReferencedAssemblies().First(x => x.FullName.StartsWith("netstandard,"));
|
||||
var netStandard = Assembly.Load(netStandardAssemblyName.FullName);
|
||||
return netStandard;
|
||||
}
|
||||
catch { /* never mind */ }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Assembly GetNetStandardAssembly()
|
||||
{
|
||||
// in PreApplicationStartMethod we cannot get BuildManager.Referenced assemblies, do it differently
|
||||
try
|
||||
{
|
||||
var someAssembly = Assembly.Load("System.Reflection.Metadata");
|
||||
var netStandardAssemblyName = someAssembly.GetReferencedAssemblies().First(x => x.FullName.StartsWith("netstandard,"));
|
||||
var netStandard = Assembly.Load(netStandardAssemblyName.FullName);
|
||||
return netStandard;
|
||||
}
|
||||
catch { /* never mind */ }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// hosted, get referenced assemblies from the BuildManager and filter
|
||||
// hosted, get referenced assemblies from the BuildManader and filter
|
||||
private static IEnumerable<string> GetAllReferencedAssembliesLocationFromBuildManager()
|
||||
{
|
||||
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList();
|
||||
|
||||
assemblies.Add(typeof(ReferencedAssemblies).Assembly); // always include ourselves
|
||||
|
||||
// see https://github.com/aspnet/RoslynCodeDomProvider/blob/master/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs:
|
||||
// mentions "Bug 913691: Explicitly add System.Runtime as a reference."
|
||||
// and explicitly adds System.Runtime to references before invoking csc.exe
|
||||
// so, doing the same here
|
||||
try
|
||||
{
|
||||
var systemRuntime = Assembly.Load("System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
|
||||
assemblies.Add(systemRuntime);
|
||||
}
|
||||
catch { /* never mind */ }
|
||||
|
||||
// for some reason, netstandard is also missing from BuildManager.ReferencedAssemblies and yet, is part of
|
||||
// the references that CSharpCompiler (above) receives - where is it coming from? cannot figure it out
|
||||
var netStandard = GetNetStandardAssembly(assemblies);
|
||||
if (netStandard != null) assemblies.Add(netStandard);
|
||||
|
||||
return assemblies
|
||||
return BuildManager.GetReferencedAssemblies()
|
||||
.Cast<Assembly>()
|
||||
.Where(x => !x.IsDynamic && !x.Location.IsNullOrWhiteSpace())
|
||||
.Select(x => x.Location)
|
||||
.And(typeof(ReferencedAssemblies).Assembly.Location) // always include ourselves
|
||||
.Distinct()
|
||||
.ToList();
|
||||
}
|
||||
@@ -175,5 +132,6 @@ namespace Umbraco.ModelsBuilder
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates a model name for a specified content alias.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class RenameContentTypeAttribute : Attribute
|
||||
{
|
||||
public RenameContentTypeAttribute(string alias, string name)
|
||||
{}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.ModelsBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates a model name for a specified property alias.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class RenamePropertyTypeAttribute : Attribute
|
||||
{
|
||||
public RenamePropertyTypeAttribute(string alias, string name)
|
||||
{}
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,17 @@
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}</ProjectGuid>
|
||||
<ProjectGuid>{7020A059-C0D1-43A0-8EFD-23591A0C9AF6}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Umbraco.ModelsBuilder</RootNamespace>
|
||||
<AssemblyName>Umbraco.ModelsBuilder</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
@@ -23,7 +22,7 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
@@ -33,10 +32,9 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -48,43 +46,72 @@
|
||||
<Compile Include="..\SolutionInfo.cs">
|
||||
<Link>Properties\SolutionInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Api\ApiBasicAuthFilter.cs" />
|
||||
<Compile Include="Api\ApiClient.cs" />
|
||||
<Compile Include="Api\ApiHelper.cs" />
|
||||
<Compile Include="Api\ApiVersion.cs" />
|
||||
<Compile Include="Api\GetModelsData.cs" />
|
||||
<Compile Include="Api\ModelsBuilderApiController.cs" />
|
||||
<Compile Include="Api\TokenData.cs" />
|
||||
<Compile Include="Api\ValidateClientVersionData.cs" />
|
||||
<Compile Include="Building\Builder.cs" />
|
||||
<Compile Include="Building\CodeDomBuilder.cs" />
|
||||
<Compile Include="Building\CodeParser.cs" />
|
||||
<Compile Include="Building\Compiler.cs" />
|
||||
<Compile Include="Building\CompilerException.cs" />
|
||||
<Compile Include="Building\ParseResult.cs" />
|
||||
<Compile Include="Building\PropertyModel.cs" />
|
||||
<Compile Include="Building\TextBuilder.cs" />
|
||||
<Compile Include="Building\TextHeaderWriter.cs" />
|
||||
<Compile Include="Building\TypeModel.cs" />
|
||||
<Compile Include="ConfigsExtensions.cs" />
|
||||
<Compile Include="Configuration\ClrNameSource.cs" />
|
||||
<Compile Include="Configuration\Config.cs" />
|
||||
<Compile Include="Configuration\ModelsMode.cs" />
|
||||
<Compile Include="Configuration\ModelsModeExtensions.cs" />
|
||||
<Compile Include="Configuration\UmbracoConfigExtensions.cs" />
|
||||
<Compile Include="Dashboard\BuilderDashboardHelper.cs" />
|
||||
<Compile Include="EnumerableExtensions.cs" />
|
||||
<Compile Include="IgnoreContentTypeAttribute.cs" />
|
||||
<Compile Include="IgnorePropertyTypeAttribute.cs" />
|
||||
<Compile Include="ImplementContentTypeAttribute.cs" />
|
||||
<Compile Include="ImplementPropertyTypeAttribute.cs" />
|
||||
<Compile Include="ModelsBaseClassAttribute.cs" />
|
||||
<Compile Include="ModelsBuilderAssemblyAttribute.cs" />
|
||||
<Compile Include="ModelsNamespaceAttribute.cs" />
|
||||
<Compile Include="ModelsUsingAttribute.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="PublishedElementExtensions.cs" />
|
||||
<Compile Include="PublishedPropertyTypeExtensions.cs" />
|
||||
<Compile Include="PureLiveAssemblyAttribute.cs" />
|
||||
<Compile Include="ReferencedAssemblies.cs" />
|
||||
<Compile Include="RenameContentTypeAttribute.cs" />
|
||||
<Compile Include="RenamePropertyTypeAttribute.cs" />
|
||||
<Compile Include="TypeExtensions.cs" />
|
||||
<Compile Include="Umbraco\UmbracoServices.cs" />
|
||||
<Compile Include="Umbraco\HashCombiner.cs" />
|
||||
<Compile Include="Umbraco\HashHelper.cs" />
|
||||
<Compile Include="Umbraco\LiveModelsProvider.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderBackOfficeController.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderComponent.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderComposer.cs" />
|
||||
<Compile Include="Umbraco\ModelsBuilderInitializer.cs" />
|
||||
<Compile Include="Umbraco\ModelsGenerationError.cs" />
|
||||
<Compile Include="Umbraco\OutOfDateModelsStatus.cs" />
|
||||
<Compile Include="Umbraco\PublishedModelUtility.cs" />
|
||||
<Compile Include="Umbraco\PureLiveModelFactory.cs" />
|
||||
<Compile Include="Umbraco\UmbracoServices.cs" />
|
||||
<Compile Include="Validation\ContentTypeModelValidator.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp">
|
||||
<Version>2.8.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub">
|
||||
<Version>1.0.0-beta2-19324-01</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
|
||||
<Project>{31785BC3-256C-4613-B2F5-A1B0BDDED8C1}</Project>
|
||||
<Project>{31785bc3-256c-4613-b2f5-a1b0bdded8c1}</Project>
|
||||
<Name>Umbraco.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Umbraco.Web\Umbraco.Web.csproj">
|
||||
@@ -92,10 +119,5 @@
|
||||
<Name>Umbraco.Web</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNet.Mvc">
|
||||
<Version>5.2.7</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -6,10 +6,13 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
{
|
||||
class HashHelper
|
||||
{
|
||||
public static string Hash(IEnumerable<TypeModel> typeModels)
|
||||
public static string Hash(IDictionary<string, string> ourFiles, IEnumerable<TypeModel> typeModels)
|
||||
{
|
||||
var hash = new HashCombiner();
|
||||
|
||||
foreach (var kvp in ourFiles)
|
||||
hash.Add(kvp.Key + "::" + kvp.Value);
|
||||
|
||||
// see Umbraco.ModelsBuilder.Umbraco.Application for what's important to hash
|
||||
// ie what comes from Umbraco (not computed by ModelsBuilder) and makes a difference
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.ModelsBuilder.Configuration;
|
||||
using Umbraco.ModelsBuilder.Umbraco;
|
||||
@@ -20,10 +21,15 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
private static Mutex _mutex;
|
||||
private static int _req;
|
||||
|
||||
private static Config Config => Current.Configs.ModelsBuilder();
|
||||
|
||||
// we do not manage pure live here
|
||||
internal static bool IsEnabled => Config.ModelsMode.IsLiveNotPure();
|
||||
internal static bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
var config = UmbracoConfig.For.ModelsBuilder();
|
||||
return config.ModelsMode.IsLiveNotPure();
|
||||
// we do not manage pure live here
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Install(UmbracoServices umbracoServices)
|
||||
{
|
||||
@@ -98,15 +104,16 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
|
||||
private static void GenerateModels()
|
||||
{
|
||||
var modelsDirectory = Config.ModelsDirectory;
|
||||
var modelsNamespace = Config.ModelsNamespace;
|
||||
var modelsDirectory = UmbracoConfig.For.ModelsBuilder().ModelsDirectory;
|
||||
|
||||
var bin = HostingEnvironment.MapPath("~/bin");
|
||||
if (bin == null)
|
||||
throw new Exception("Panic: bin is null.");
|
||||
|
||||
var config = UmbracoConfig.For.ModelsBuilder();
|
||||
|
||||
// EnableDllModels will recycle the app domain - but this request will end properly
|
||||
ModelsBuilderBackOfficeController.GenerateModels(_umbracoServices, modelsDirectory, modelsNamespace);
|
||||
ModelsBuilderBackOfficeController.GenerateModels(_umbracoServices, modelsDirectory, config.ModelsMode.IsAnyDll() ? bin : null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +133,9 @@ namespace Umbraco.ModelsBuilder.Umbraco
|
||||
|
||||
public static void Install()
|
||||
{
|
||||
// always - don't read config in PreApplicationStartMethod
|
||||
if (!LiveModelsProvider.IsEnabled)
|
||||
return;
|
||||
|
||||
HttpApplication.RegisterModule(typeof(LiveModelsProviderModule));
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user