Merge remote-tracking branch 'origin/dev-v8' into temp8-ui-update-login-screen

This commit is contained in:
Niels Lyngsø
2019-03-07 10:00:56 +01:00
759 changed files with 7987 additions and 10376 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/temp8/.github/V8_GETTING_STARTED.md) to go to the v8 branch_
_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/dev-v8/.github/V8_GETTING_STARTED.md) to go to the v8 branch_
# Contributing to Umbraco CMS
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
+2 -4
View File
@@ -103,11 +103,9 @@ There's two big areas that you should know about:
1. The Umbraco backoffice is a extensible AngularJS app and requires you to run a `gulp dev` command while you're working with it, so changes are copied over to the appropriate directories and you can refresh your browser to view the results of your changes.
You may need to run the following commands to set up gulp properly:
```
npm cache clean
npm install -g gulp
npm install -g gulp-cli
npm cache clean --force
npm install
gulp build
npm run build
```
2. "The rest" is a C# based codebase, with some traces of our WebForms past but mostly ASP.NET MVC based these days. You can make changes, build them in Visual Studio, and hit `F5` to see the result.
+1 -1
View File
@@ -2,7 +2,7 @@
- [ ] I have added steps to test this contribution in the description below
If there's an existing issue for this PR then this fixes: <!-- link to the issue here! -->
If there's an existing issue for this PR then this fixes <!-- link to the issue here! -->
### Description
<!-- A description of the changes proposed in the pull-request and how to test these changes -->
+5 -3
View File
@@ -1,7 +1,9 @@
_You are browsing the Umbraco v8 branch. Umbraco 8 is currently under development._
[![pullreminders](https://pullreminders.com/badge.svg)](https://pullreminders.com?ref=badge)
[![Build status](https://umbraco.visualstudio.com/Umbraco%20Cms/_apis/build/status/Cms%208%20Continuous?branchName=dev-v8)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [![pullreminders](https://pullreminders.com/badge.svg)](https://pullreminders.com?ref=badge)
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS) to go to the v7 branch._
_You are browsing the Umbraco v8 branch. Umbraco 8 is currently under development._
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS/tree/dev-v7) to go to the v7 branch._
_Ready to try out Version 8? [See the quick start guide](V8_GETTING_STARTED.md)._
+1 -1
View File
@@ -5,7 +5,7 @@
* [Visual Studio 2017 Community (Free)](https://www.visualstudio.com/vs/community/), or Professional, Enterprise, etc... _(**Minimum of Version 15.7** or higher, this is important, you WILL get issues with lesser versions)_
* .NET Framework 4.7.2 installed, get it here: https://www.microsoft.com/net/download/thank-you/net472?survey=false
* .NET Framework 4.7.2 developer pack, get it here: https://www.microsoft.com/net/download/thank-you/net472-developer-pack _(be sure this is the ENU file which will be named `NDP472-DevPack-ENU.exe`)_
* Clone the Umbraco repository using the `temp8` branch. If your git client doesn't support specifying the branch as you clone then use the command `git clone --single-branch -b temp8 <your fork url>`. _(If you clone the repo using the default v7 branch and then checkout the `temp8` branch you **might** get problems)_
* Clone the Umbraco repository using the `dev-v8` branch. If your git client doesn't support specifying the branch as you clone then use the command `git clone --single-branch -b dev-v8 <your fork url>`. _(If you clone the repo using the default v7 branch and then checkout the `dev-v8` branch you **might** get problems)_
### Start the solution
+161 -158
View File
@@ -1,160 +1,163 @@
#
# Umbraco Cms Git Ignore
#
# common files
*.obj
*.pdb
*.user
*.aps
*.pch
*.vspscc
*.orig
*.suo
*.vs10x
*.ndproj
#
# Umbraco Cms Git Ignore
#
# common files
*.obj
*.pdb
*.user
*.aps
*.pch
*.vspscc
*.orig
*.suo
*.vs10x
*.ndproj
*.ignorer.*
# common directories
.DS_Store
._.DS_Store
.vs/
/local/
# build directories
[Bb]in/
[Db]ebug*/
[Rr]elease*/
obj/
# tools
_ReSharper*/
_NCrunch_*/
*.ncrunchsolution
*.ncrunchsolution.user
*.ncrunchproject
*.crunchsolution.cache
tools/NDepend/
[Tt]est[Rr]esult*
[Bb]uild[Ll]og.*
*.[Pp]ublish.xml
[sS]ource
[sS]andbox
umbraco.config
App_Data/TEMP/*
[Uu]mbraco/[Pp]resentation/[Uu]mbraco/[Pp]lugins/*
[Uu]mbraco/[Pp]resentation/[Uu]ser[Cc]ontrols/*
[Uu]mbraco/[Pp]resentation/[Ss]cripts/*
[Uu]mbraco/[Pp]resentation/[Ff]onts/*
[Uu]mbraco/[Pp]resentation/[Cc]ss/*
src/Umbraco.Web.UI/[Cc]ss/*
src/Umbraco.Web.UI/App_Code/*
src/Umbraco.Web.UI/App_Data/*
src/Umbraco.Tests/App_Data/*
src/Umbraco.Web.UI/[Mm]edia/*
src/Umbraco.Web.UI/[Mm]aster[Pp]ages/*
src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/*
!src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/[Ww]eb.[Cc]onfig
src/Umbraco.Web.UI/[Xx]slt/*
src/Umbraco.Web.UI/[Ii]mages/*
src/Umbraco.Web.UI/[Ss]cripts/*
src/Umbraco.Web.UI/Web.*.config.transformed
umbraco/presentation/umbraco/plugins/uComponents/uComponentsInstaller.ascx
umbraco/presentation/packages/uComponents/MultiNodePicker/CustomTreeService.asmx
src/Umbraco.Tests/config/applications.config
src/Umbraco.Tests/config/trees.config
src/Umbraco.Web.UI/web.config
src/Umbraco.Web.UI/[Cc]onfig/ClientDependency.config
src/Umbraco.Tests/config/404handlers.config
src/Umbraco.Web.UI/[Vv]iews/*.cshtml
src/Umbraco.Web.UI/[Vv]iews/*.vbhtml
src/Umbraco.Tests/[Cc]onfig/umbracoSettings.config
src/Umbraco.Web.UI/[Vv]iews/*
src/packages/
src/packages/repositories.config
src/Umbraco.Web.UI/[Ww]eb.config
*.transformed
node_modules
lib-bower
src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ib/*
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/umbraco.*
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/*.loader.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/init.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/routes.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.dev.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.dev.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/canvasdesigner.*.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.html
src/Umbraco.Web.UI/[Uu]mbraco/[Aa]ssets/*
src/Umbraco.Web.UI.Client/[Bb]uild/*
src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/
src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/
src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css
src/Umbraco.Web.UI.Client/vwd.webinfo
src/Umbraco.Web.UI/App_Plugins/*
src/*.psess
src/*.vspx
NDependOut/*
QueryResult.htm
src/Umbraco.Web.UI/[Cc]onfig/appSettings.config
src/Umbraco.Web.UI/[Cc]onfig/connectionStrings.config
src/Umbraco.Web.UI/[Uu]mbraco/plugins/*
build/ApiDocs/*
build/ApiDocs/Output/*
src/Umbraco.Web.UI.Client/bower_components/*
/src/Umbraco.Web.UI/[Uu]mbraco/preview
/src/Umbraco.Web.UI/[Uu]mbraco/preview.old
# ignore rule for clearing out Belle (avoid rebuilding all the time)
preserve.belle
#Ignore Rule for output of generated documentation files from Grunt docserve
src/Umbraco.Web.UI.Client/docs/api
src/*.boltdata/
src/umbraco.sln.ide/*
src/.vs/
src/Umbraco.Web.UI/[Jj]s/*
src/Umbraco.Tests/[Mm]edia
tools/docfx/*
apidocs/_site/*
src/*/project.lock.json
src/.idea/*
apidocs/api/*
build/docs.zip
build/ui-docs.zip
build/csharp-docs.zip
src/packages/
src/PrecompiledWeb/*
# build
build.out/
build.tmp/
build/hooks/
build/temp/
# common directories
.DS_Store
._.DS_Store
.vs/
/local/
# build directories
[Bb]in/
[Db]ebug*/
[Rr]elease*/
obj/
# tools
_ReSharper*/
_NCrunch_*/
*.ncrunchsolution
*.ncrunchsolution.user
*.ncrunchproject
*.crunchsolution.cache
tools/NDepend/
[Tt]est[Rr]esult*
[Bb]uild[Ll]og.*
*.[Pp]ublish.xml
[sS]ource
[sS]andbox
umbraco.config
App_Data/TEMP/*
[Uu]mbraco/[Pp]resentation/[Uu]mbraco/[Pp]lugins/*
[Uu]mbraco/[Pp]resentation/[Uu]ser[Cc]ontrols/*
[Uu]mbraco/[Pp]resentation/[Ss]cripts/*
[Uu]mbraco/[Pp]resentation/[Ff]onts/*
[Uu]mbraco/[Pp]resentation/[Cc]ss/*
src/Umbraco.Web.UI/[Cc]ss/*
src/Umbraco.Web.UI/App_Code/*
src/Umbraco.Web.UI/App_Data/*
src/Umbraco.Tests/App_Data/*
src/Umbraco.Web.UI/[Mm]edia/*
src/Umbraco.Web.UI/[Mm]aster[Pp]ages/*
src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/*
!src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/[Ww]eb.[Cc]onfig
src/Umbraco.Web.UI/[Xx]slt/*
src/Umbraco.Web.UI/[Ii]mages/*
src/Umbraco.Web.UI/[Ss]cripts/*
src/Umbraco.Web.UI/Web.*.config.transformed
umbraco/presentation/umbraco/plugins/uComponents/uComponentsInstaller.ascx
umbraco/presentation/packages/uComponents/MultiNodePicker/CustomTreeService.asmx
src/Umbraco.Tests/config/applications.config
src/Umbraco.Tests/config/trees.config
src/Umbraco.Web.UI/web.config
src/Umbraco.Web.UI/[Cc]onfig/ClientDependency.config
src/Umbraco.Web.UI/[Cc]onfig/serilog.config
src/Umbraco.Web.UI/[Cc]onfig/serilog.user.config
src/Umbraco.Tests/config/404handlers.config
src/Umbraco.Web.UI/[Vv]iews/*.cshtml
src/Umbraco.Web.UI/[Vv]iews/*.vbhtml
src/Umbraco.Tests/[Cc]onfig/umbracoSettings.config
src/Umbraco.Web.UI/[Vv]iews/*
src/packages/
src/packages/repositories.config
src/Umbraco.Web.UI/[Ww]eb.config
*.transformed
node_modules
lib-bower
src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ib/*
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/umbraco.*
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/*.loader.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/init.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/routes.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.dev.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.dev.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/canvasdesigner.*.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.html
src/Umbraco.Web.UI/[Uu]mbraco/[Aa]ssets/*
src/Umbraco.Web.UI.Client/[Bb]uild/*
src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/
src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/
src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css
src/Umbraco.Web.UI.Client/vwd.webinfo
src/Umbraco.Web.UI/App_Plugins/*
src/*.psess
src/*.vspx
NDependOut/*
QueryResult.htm
src/Umbraco.Web.UI/[Cc]onfig/appSettings.config
src/Umbraco.Web.UI/[Cc]onfig/connectionStrings.config
src/Umbraco.Web.UI/[Uu]mbraco/plugins/*
build/ApiDocs/*
build/ApiDocs/Output/*
src/Umbraco.Web.UI.Client/bower_components/*
/src/Umbraco.Web.UI/[Uu]mbraco/preview
/src/Umbraco.Web.UI/[Uu]mbraco/preview.old
# ignore rule for clearing out Belle (avoid rebuilding all the time)
preserve.belle
#Ignore Rule for output of generated documentation files from Grunt docserve
src/Umbraco.Web.UI.Client/docs/api
src/*.boltdata/
src/umbraco.sln.ide/*
src/.vs/
src/Umbraco.Web.UI/[Jj]s/*
src/Umbraco.Tests/[Mm]edia
tools/docfx/*
apidocs/_site/*
src/*/project.lock.json
src/.idea/*
apidocs/api/*
build/docs.zip
build/ui-docs.zip
build/csharp-docs.zip
src/packages/
src/PrecompiledWeb/*
# build
build.out/
build.tmp/
build/hooks/
build/temp/
# eof
/src/Umbraco.Web.UI.Client/TESTS-*.xml
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<metadata minClientVersion="4.6.0">
<id>UmbracoCms.Core</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
+3 -3
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<metadata minClientVersion="4.6.0">
<id>UmbracoCms.Web</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
@@ -27,9 +27,9 @@
<dependency id="ClientDependency" version="[1.9.7,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.0.0-beta079,1.999999)" />
<dependency id="Examine" version="[1.0.0,1.999999)" />
<dependency id="HtmlAgilityPack" version="[1.8.14,1.999999)" />
<dependency id="ImageProcessor" version="[2.6.2.25,2.999999)" />
<dependency id="ImageProcessor" version="[2.7.0.100,2.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
<dependency id="Markdown" version="[2.2.1,2.999999)" />
+5 -5
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<metadata minClientVersion="4.6.0">
<id>UmbracoCms</id>
<version>8.0.0</version>
<title>Umbraco Cms</title>
@@ -25,15 +25,15 @@
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.4.0, 2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.0-alpha.37]" />
<dependency id="ImageProcessor.Web" version="[4.9.3.25,4.999999)" />
<dependency id="ImageProcessor.Web.Config" version="[2.4.1.19,2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.1]" />
<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)" />
<dependency id="Microsoft.Net.Compilers" version="[2.10.0,2.999999)" />
</group>
</dependencies>
</metadata>
<files>
+46 -36
View File
@@ -126,45 +126,55 @@
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.CodeAnalysis.CSharp')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='log4net')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Data.SqlServerCe')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.ValueTuple')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
</assemblyBinding>
</runtime>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.6.0" newVersion="5.2.6.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.6.0" newVersion="5.2.6.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.web.webPages.razor xdt:Transform="Remove" />
-93
View File
@@ -1,93 +0,0 @@
param($installPath, $toolsPath, $package, $project)
Write-Host "installPath:" "${installPath}"
Write-Host "toolsPath:" "${toolsPath}"
Write-Host " "
if ($project) {
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
# Create paths and list them
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
Write-Host "projectPath:" "${projectPath}"
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
Write-Host "backupPath:" "${backupPath}"
$copyLogsPath = Join-Path $backupPath "CopyLogs"
Write-Host "copyLogsPath:" "${copyLogsPath}"
$umbracoBinFolder = Join-Path $projectPath "bin"
Write-Host "umbracoBinFolder:" "${umbracoBinFolder}"
# Create backup folder and logs folder if it doesn't exist yet
New-Item -ItemType Directory -Force -Path $backupPath
New-Item -ItemType Directory -Force -Path $copyLogsPath
# After backing up, remove all umbraco dlls from bin folder in case dll files are included in the VS project
# See: http://issues.umbraco.org/issue/U4-4930
if(Test-Path $umbracoBinFolder) {
$umbracoBinBackupPath = Join-Path $backupPath "bin"
New-Item -ItemType Directory -Force -Path $umbracoBinBackupPath
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
# Delete files Umbraco ships with
if(Test-Path $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll) { Remove-Item $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Web.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Core.dll) { Remove-Item $umbracoBinFolder\Umbraco.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Examine.dll) { Remove-Item $umbracoBinFolder\Umbraco.Examine.dll -Force -Confirm:$false }
# Delete files Umbraco depends upon
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
if(Test-Path $amd64Folder) { Remove-Item $amd64Folder -Force -Recurse -Confirm:$false }
$x86Folder = Join-Path $umbracoBinFolder "x86"
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
if(Test-Path $umbracoBinFolder\AutoMapper.dll) { Remove-Item $umbracoBinFolder\AutoMapper.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\AutoMapper.Net4.dll) { Remove-Item $umbracoBinFolder\AutoMapper.Net4.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ClientDependency.Core.dll) { Remove-Item $umbracoBinFolder\ClientDependency.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ClientDependency.Core.Mvc.dll) { Remove-Item $umbracoBinFolder\ClientDependency.Core.Mvc.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\CookComputing.XmlRpcV2.dll) { Remove-Item $umbracoBinFolder\CookComputing.XmlRpcV2.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Examine.dll) { Remove-Item $umbracoBinFolder\Examine.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\HtmlAgilityPack.dll) { Remove-Item $umbracoBinFolder\HtmlAgilityPack.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ICSharpCode.SharpZipLib.dll) { Remove-Item $umbracoBinFolder\ICSharpCode.SharpZipLib.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ImageProcessor.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ImageProcessor.Web.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.Web.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.IO.RecyclableMemoryStream.dll) { Remove-Item $umbracoBinFolder\Microsoft.IO.RecyclableMemoryStream.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.Cookies.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.Cookies.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.OAuth.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.OAuth.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Infrastructure.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Infrastructure.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Helpers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\MiniProfiler.dll) { Remove-Item $umbracoBinFolder\MiniProfiler.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Owin.dll) { Remove-Item $umbracoBinFolder\Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Semver.dll) { Remove-Item $umbracoBinFolder\Semver.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Collections.Immutable.dll) { Remove-Item $umbracoBinFolder\System.Collections.Immutable.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Reflection.Metadata.dll) { Remove-Item $umbracoBinFolder\System.Reflection.Metadata.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Extensions.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Extensions.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Primitives.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Primitives.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\System.Web.Helpers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Http.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Http.WebHost.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.WebHost.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Mvc.dll) { Remove-Item $umbracoBinFolder\System.Web.Mvc.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.Razor.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.WebPages.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Deployment.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Deployment.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
}
}
-27
View File
@@ -11,37 +11,15 @@ if ($project) {
# Create paths and list them
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
Write-Host "projectPath:" "${projectPath}"
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
Write-Host "backupPath:" "${backupPath}"
$copyLogsPath = Join-Path $backupPath "CopyLogs"
Write-Host "copyLogsPath:" "${copyLogsPath}"
$webConfigSource = Join-Path $projectPath "Web.config"
Write-Host "webConfigSource:" "${webConfigSource}"
$configFolder = Join-Path $projectPath "Config"
Write-Host "configFolder:" "${configFolder}"
# Create backup folder and logs folder if it doesn't exist yet
New-Item -ItemType Directory -Force -Path $backupPath
New-Item -ItemType Directory -Force -Path $copyLogsPath
# Create a backup of original web.config
Copy-Item $webConfigSource $backupPath -Force
# Backup config files folder
if(Test-Path $configFolder) {
$umbracoBackupPath = Join-Path $backupPath "Config"
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
robocopy $configFolder $umbracoBackupPath /e /LOG:$copyLogsPath\ConfigBackup.log
}
# Copy umbraco and umbraco_files from package to project folder
$umbracoFolder = Join-Path $projectPath "Umbraco"
New-Item -ItemType Directory -Force -Path $umbracoFolder
$umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
$umbracoBackupPath = Join-Path $backupPath "Umbraco"
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
$copyWebconfig = $true
@@ -100,11 +78,6 @@ if ($project) {
}
}
$installFolder = Join-Path $projectPath "Install"
if(Test-Path $installFolder) {
Remove-Item $installFolder -Force -Recurse -Confirm:$false
}
# Open appropriate readme
if($copyWebconfig -eq $true)
{
+11 -2
View File
@@ -15,7 +15,12 @@
[Parameter(Mandatory=$false)]
[Alias("c")]
[Alias("cont")]
[switch] $continue = $false
[switch] $continue = $false,
# execute a command
[Parameter(Mandatory=$false, ValueFromRemainingArguments=$true)]
[String[]]
$command
)
# ################################################################
@@ -475,7 +480,11 @@
# run
if (-not $get)
{
$ubuild.Build()
if ($command.Length -eq 0)
{
$command = @( "Build" )
}
$ubuild.RunMethod($command);
if ($ubuild.OnError()) { return }
}
if ($get) { return $ubuild }
+2 -2
View File
@@ -18,5 +18,5 @@ using System.Resources;
[assembly: AssemblyVersion("8.0.0")]
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.0.0")]
[assembly: AssemblyInformationalVersion("8.0.0-alpha.58")]
[assembly: AssemblyFileVersion("8.1.0")]
[assembly: AssemblyInformationalVersion("8.1.0")]
+13 -7
View File
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
namespace Umbraco.Core.Cache
@@ -110,7 +111,7 @@ namespace Umbraco.Core.Cache
#region Lock
private bool _entered;
private const string ContextItemsLockKey = "Umbraco.Core.Cache.HttpRequestCache::LockEntered";
protected override void EnterReadLock() => EnterWriteLock();
@@ -118,7 +119,13 @@ namespace Umbraco.Core.Cache
{
if (HasContextItems)
{
System.Threading.Monitor.Enter(ContextItems.SyncRoot, ref _entered);
// note: cannot keep 'entered' as a class variable here,
// since there is one per request - so storing it within
// ContextItems - which is locked, so this should be safe
var entered = false;
Monitor.Enter(ContextItems.SyncRoot, ref entered);
ContextItems[ContextItemsLockKey] = entered;
}
}
@@ -126,11 +133,10 @@ namespace Umbraco.Core.Cache
protected override void ExitWriteLock()
{
if (_entered)
{
_entered = false;
System.Threading.Monitor.Exit(ContextItems.SyncRoot);
}
var entered = (bool?) ContextItems[ContextItemsLockKey] ?? false;
if (entered)
Monitor.Exit(ContextItems.SyncRoot);
ContextItems.Remove(ContextItemsLockKey);
}
#endregion
@@ -1,13 +0,0 @@
namespace Umbraco.Core.Components
{
/// <summary>
/// Represents a core <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All core composers are required by (compose before) all user composers,
/// and require (compose after) all runtime composers.</para>
/// </remarks>
[ComposeAfter(typeof(IRuntimeComposer))]
public interface ICoreComposer : IComposer
{ }
}
@@ -1,11 +0,0 @@
namespace Umbraco.Core.Components
{
/// <summary>
/// Represents a runtime <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All runtime composers are required by (compose before) all core composers</para>
/// </remarks>
public interface IRuntimeComposer : IComposer
{ }
}
@@ -3,6 +3,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Web;
using Umbraco.Core.Composing;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -10,7 +11,7 @@ using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Compose
{
public sealed class AuditEventsComponent : IComponent
{
@@ -1,4 +1,6 @@
namespace Umbraco.Core.Components
using Umbraco.Core.Composing;
namespace Umbraco.Core.Compose
{
public sealed class AuditEventsComposer : ComponentComposer<AuditEventsComponent>, ICoreComposer
{ }
@@ -1,9 +1,10 @@
using System.IO;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Compose
{
public sealed class ManifestWatcherComponent : IComponent
{
@@ -1,4 +1,6 @@
namespace Umbraco.Core.Components
using Umbraco.Core.Composing;
namespace Umbraco.Core.Compose
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class ManifestWatcherComposer : ComponentComposer<ManifestWatcherComponent>, ICoreComposer
@@ -3,7 +3,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Compose
{
// TODO: This should just exist in the content service/repo!
public sealed class RelateOnCopyComponent : IComponent
@@ -1,4 +1,6 @@
namespace Umbraco.Core.Components
using Umbraco.Core.Composing;
namespace Umbraco.Core.Compose
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public sealed class RelateOnCopyComposer : ComponentComposer<RelateOnCopyComponent>, ICoreComposer
@@ -5,7 +5,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Compose
{
public sealed class RelateOnTrashComponent : IComponent
{
@@ -1,4 +1,6 @@
namespace Umbraco.Core.Components
using Umbraco.Core.Composing;
namespace Umbraco.Core.Compose
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public sealed class RelateOnTrashComposer : ComponentComposer<RelateOnTrashComponent>, ICoreComposer
@@ -1,9 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents the collection of <see cref="IComponent"/> implementations.
@@ -24,7 +23,7 @@ namespace Umbraco.Core.Components
{
using (_logger.DebugDuration<ComponentCollection>($"Initializing. (log components when >{LogThresholdMilliseconds}ms)", "Initialized."))
{
foreach (var component in this.Reverse()) // terminate components in reverse order
foreach (var component in this)
{
var componentType = component.GetType();
using (_logger.DebugDuration<ComponentCollection>($"Initializing {componentType.FullName}.", $"Initialized {componentType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
@@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Builds a <see cref="ComponentCollection"/>.
@@ -31,7 +30,7 @@ namespace Umbraco.Core.Components
protected override IComponent CreateItem(IFactory factory, Type itemType)
{
using (_logger.DebugDuration<Composers>($"Creating {itemType.FullName}.", $"Created {itemType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
using (_logger.DebugDuration<ComponentCollectionBuilder>($"Creating {itemType.FullName}.", $"Created {itemType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
{
return base.CreateItem(factory, itemType);
}
@@ -1,4 +1,6 @@
namespace Umbraco.Core.Components
using Umbraco.Core.Compose;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Provides a base class for composers which compose a component.
@@ -1,6 +1,6 @@
using System;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Indicates that a composer requires another composer.
@@ -1,6 +1,6 @@
using System;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Indicates that a component is required by another composer.
@@ -6,7 +6,7 @@ using System.Text;
using Umbraco.Core.Collections;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
// note: this class is NOT thread-safe in any ways
@@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents a composition.
@@ -1,13 +1,11 @@
using Umbraco.Core.Components;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Core.Composing.Composers
namespace Umbraco.Core.Composing.CompositionExtensions
{
/// <summary>
/// Compose configurations.
/// </summary>
public static class ConfigurationComposer
public static class Configuration
{
public static Composition ComposeConfiguration(this Composition composition)
{
@@ -1,11 +1,10 @@
using AutoMapper;
using Umbraco.Core.Components;
using Umbraco.Core.Models.Identity;
namespace Umbraco.Core.Composing.Composers
namespace Umbraco.Core.Composing.CompositionExtensions
{
public static class CoreMappingProfilesComposer
public static class CoreMappingProfiles
{
public static Composition ComposeCoreMappingProfiles(this Composition composition)
{
@@ -1,10 +1,10 @@
using Umbraco.Core.Components;
using Umbraco.Core.Compose;
using Umbraco.Core.IO;
using Umbraco.Core.IO.MediaPathSchemes;
namespace Umbraco.Core.Composing.Composers
namespace Umbraco.Core.Composing.CompositionExtensions
{
public static class FileSystemsComposer
public static class FileSystems
{
/*
* HOW TO REPLACE THE MEDIA UNDERLYING FILESYSTEM
@@ -73,13 +73,13 @@ namespace Umbraco.Core.Composing.Composers
// it needs to be registered (not only the interface) because it provides additional
// functionality eg for scoping, and is injected in the scope provider - whereas the
// interface is really for end-users to get access to filesystems.
composition.RegisterUnique(factory => factory.CreateInstance<FileSystems>(factory));
composition.RegisterUnique(factory => factory.CreateInstance<IO.FileSystems>(factory));
// register IFileSystems, which gives access too all filesystems
composition.RegisterUnique<IFileSystems>(factory => factory.GetInstance<FileSystems>());
composition.RegisterUnique<IFileSystems>(factory => factory.GetInstance<IO.FileSystems>());
// register the scheme for media paths
composition.RegisterUnique<IMediaPathScheme, TwoGuidsMediaPathScheme>();
composition.RegisterUnique<IMediaPathScheme, UniqueMediaPathScheme>();
// register the IMediaFileSystem implementation
composition.RegisterFileSystem<IMediaFileSystem, MediaFileSystem>();
@@ -1,13 +1,12 @@
using Umbraco.Core.Components;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.Repositories.Implement;
namespace Umbraco.Core.Composing.Composers
namespace Umbraco.Core.Composing.CompositionExtensions
{
/// <summary>
/// Composes repositories.
/// </summary>
public static class RepositoriesComposer
public static class Repositories
{
public static Composition ComposeRepositories(this Composition composition)
{
@@ -2,7 +2,6 @@
using System.IO;
using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Components;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
@@ -10,9 +9,9 @@ using Umbraco.Core.Packaging;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Core.Composing.Composers
namespace Umbraco.Core.Composing.CompositionExtensions
{
public static class ServicesComposer
public static class Services
{
public static Composition ComposeServices(this Composition composition)
{
@@ -1,6 +1,6 @@
using System;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Indicates that a composer should be disabled.
@@ -1,6 +1,6 @@
using System;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Indicates that a composer should be disabled.
@@ -1,6 +1,6 @@
using System;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Indicates that a composer should be enabled.
@@ -1,6 +1,6 @@
using System;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Indicates that a composer should be enabled.
@@ -1,4 +1,4 @@
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents a component.
@@ -1,6 +1,4 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents a composer.
@@ -10,7 +8,6 @@ namespace Umbraco.Core.Components
/// <summary>
/// Compose.
/// </summary>
/// <param name="composition"></param>
void Compose(Composition composition);
}
}
}
@@ -0,0 +1,11 @@
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents a core <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>Core composers compose after the initial composer, and before user composers.</para>
/// </remarks>
public interface ICoreComposer : IComposer
{ }
}
@@ -1,12 +1,12 @@
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents a user <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All user composers require (compose after) all core composers.</para>
/// <para>User composers compose after core composers, and before the final composer.</para>
/// </remarks>
[ComposeAfter(typeof(ICoreComposer))]
public interface IUserComposer : IComposer
{ }
}
}
@@ -1,7 +1,6 @@
using System;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Components
namespace Umbraco.Core.Composing
{
/// <summary>
/// Marks a composer to indicate a minimum and/or maximum runtime level for which the composer would compose.
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Provides a base class for collections of types.
/// </summary>
public abstract class TypeCollectionBuilderBase<TCollection, TConstraint> : ICollectionBuilder<TCollection, Type>
where TCollection : class, IBuilderCollection<Type>
{
private readonly HashSet<Type> _types = new HashSet<Type>();
private Type Validate(Type type, string action)
{
if (!typeof(TConstraint).IsAssignableFrom(type))
throw new InvalidOperationException($"Cannot {action} type {type.FullName} as it does not inherit from/implement {typeof(TConstraint).FullName}.");
return type;
}
public void Add(Type type) => _types.Add(Validate(type, "add"));
public void Add<T>() => Add(typeof(T));
public void Add(IEnumerable<Type> types)
{
foreach (var type in types) Add(type);
}
public void Remove(Type type) => _types.Remove(Validate(type, "remove"));
public void Remove<T>() => Remove(typeof(T));
public TCollection CreateCollection(IFactory factory)
{
return factory.CreateInstance<TCollection>(_types);
}
public void RegisterWith(IRegister register)
{
register.Register(CreateCollection, Lifetime.Singleton);
}
}
}
+8 -26
View File
@@ -42,30 +42,30 @@ namespace Umbraco.Core.Composing
private string _currentAssembliesHash;
private IEnumerable<Assembly> _assemblies;
private bool _reportedChange;
private static LocalTempStorage _localTempStorage;
private static string _localTempPath;
private static string _fileBasePath;
/// <summary>
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
/// </summary>
/// <param name="runtimeCache">The application runtime cache.</param>
/// <param name="localTempStorage">Files storage mode.</param>
/// <param name="localTempPath">Files storage location.</param>
/// <param name="logger">A profiling logger.</param>
public TypeLoader(IAppPolicyCache runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger)
: this(runtimeCache, localTempStorage, logger, true)
public TypeLoader(IAppPolicyCache runtimeCache, string localTempPath, IProfilingLogger logger)
: this(runtimeCache, localTempPath, logger, true)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="TypeLoader"/> class.
/// </summary>
/// <param name="runtimeCache">The application runtime cache.</param>
/// <param name="localTempStorage">Files storage mode.</param>
/// <param name="localTempPath">Files storage location.</param>
/// <param name="logger">A profiling logger.</param>
/// <param name="detectChanges">Whether to detect changes using hashes.</param>
internal TypeLoader(IAppPolicyCache runtimeCache, LocalTempStorage localTempStorage, IProfilingLogger logger, bool detectChanges)
internal TypeLoader(IAppPolicyCache runtimeCache, string localTempPath, IProfilingLogger logger, bool detectChanges)
{
_runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache));
_localTempStorage = localTempStorage == LocalTempStorage.Unknown ? LocalTempStorage.Default : localTempStorage;
_localTempPath = localTempPath;
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
if (detectChanges)
@@ -388,25 +388,7 @@ namespace Umbraco.Core.Composing
if (_fileBasePath != null)
return _fileBasePath;
switch (_localTempStorage)
{
case LocalTempStorage.AspNetTemp:
_fileBasePath = Path.Combine(HttpRuntime.CodegenDir, "UmbracoData", "umbraco-types");
break;
case LocalTempStorage.EnvironmentTemp:
// include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash);
_fileBasePath = Path.Combine(cachePath, "umbraco-types");
break;
case LocalTempStorage.Default:
default:
var tempFolder = IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "TypesCache");
_fileBasePath = Path.Combine(tempFolder, "umbraco-types." + NetworkHelper.FileSafeMachineName);
break;
}
_fileBasePath = Path.Combine(_localTempPath, "TypesCache", "umbraco-types." + NetworkHelper.FileSafeMachineName);
// ensure that the folder exists
var directory = Path.GetDirectoryName(_fileBasePath);
@@ -1,64 +1,23 @@
using System;
using Umbraco.Core.Cache;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Composing;
using Umbraco.Core.Dictionary;
using Umbraco.Core.IO;
using Umbraco.Core.Migrations;
using Umbraco.Core.Logging.Viewer;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PackageActions;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Core.Logging.Viewer;
using Umbraco.Core.PackageActions;
namespace Umbraco.Core.Components
namespace Umbraco.Core
{
/// <summary>
/// Provides extension methods to the <see cref="Composition"/> class.
/// </summary>
public static class CompositionExtensions
public static partial class CompositionExtensions
{
#region FileSystems
/// <summary>
/// Registers a filesystem.
/// </summary>
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
/// <typeparam name="TImplementing">The implementing type.</typeparam>
/// <param name="composition">The composition.</param>
/// <returns>The register.</returns>
public static void RegisterFileSystem<TFileSystem, TImplementing>(this Composition composition)
where TImplementing : FileSystemWrapper, TFileSystem
where TFileSystem : class
{
composition.RegisterUnique<TFileSystem>(factory =>
{
var fileSystems = factory.GetInstance<FileSystems>();
var supporting = factory.GetInstance<SupportingFileSystems>();
return fileSystems.GetFileSystem<TImplementing>(supporting.For<TFileSystem>());
});
}
/// <summary>
/// Registers a filesystem.
/// </summary>
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
/// <param name="composition">The composition.</param>
/// <returns>The register.</returns>
public static void RegisterFileSystem<TFileSystem>(this Composition composition)
where TFileSystem : FileSystemWrapper
{
composition.RegisterUnique(factory =>
{
var fileSystems = factory.GetInstance<FileSystems>();
var supporting = factory.GetInstance<SupportingFileSystems>();
return fileSystems.GetFileSystem<TFileSystem>(supporting.For<TFileSystem>());
});
}
#endregion
#region Collection Builders
/// <summary>
@@ -110,13 +69,6 @@ namespace Umbraco.Core.Components
internal static ManifestValueValidatorCollectionBuilder Validators(this Composition composition)
=> composition.WithCollectionBuilder<ManifestValueValidatorCollectionBuilder>();
/// <summary>
/// Gets the post-migrations collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
internal static PostMigrationCollectionBuilder PostMigrations(this Composition composition)
=> composition.WithCollectionBuilder<PostMigrationCollectionBuilder>();
/// <summary>
/// Gets the components collection builder.
/// </summary>
@@ -0,0 +1,35 @@
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
namespace Umbraco.Core
{
/// <summary>
/// Provides extension methods to the <see cref="Composition"/> class.
/// </summary>
public static partial class CompositionExtensions
{
/// <summary>
/// Registers essential services.
/// </summary>
public static void RegisterEssentials(this Composition composition,
ILogger logger, IProfiler profiler, IProfilingLogger profilingLogger,
IMainDom mainDom,
AppCaches appCaches,
IUmbracoDatabaseFactory databaseFactory,
TypeLoader typeLoader,
IRuntimeState state)
{
composition.RegisterUnique(logger);
composition.RegisterUnique(profiler);
composition.RegisterUnique(profilingLogger);
composition.RegisterUnique(mainDom);
composition.RegisterUnique(appCaches);
composition.RegisterUnique(databaseFactory);
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoDatabaseFactory>().SqlContext);
composition.RegisterUnique(typeLoader);
composition.RegisterUnique(state);
}
}
}
@@ -0,0 +1,47 @@
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
namespace Umbraco.Core
{
/// <summary>
/// Provides extension methods to the <see cref="Composition"/> class.
/// </summary>
public static partial class CompositionExtensions
{
/// <summary>
/// Registers a filesystem.
/// </summary>
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
/// <typeparam name="TImplementing">The implementing type.</typeparam>
/// <param name="composition">The composition.</param>
/// <returns>The register.</returns>
public static void RegisterFileSystem<TFileSystem, TImplementing>(this Composition composition)
where TImplementing : FileSystemWrapper, TFileSystem
where TFileSystem : class
{
composition.RegisterUnique<TFileSystem>(factory =>
{
var fileSystems = factory.GetInstance<FileSystems>();
var supporting = factory.GetInstance<SupportingFileSystems>();
return fileSystems.GetFileSystem<TImplementing>(supporting.For<TFileSystem>());
});
}
/// <summary>
/// Registers a filesystem.
/// </summary>
/// <typeparam name="TFileSystem">The type of the filesystem.</typeparam>
/// <param name="composition">The composition.</param>
/// <returns>The register.</returns>
public static void RegisterFileSystem<TFileSystem>(this Composition composition)
where TFileSystem : FileSystemWrapper
{
composition.RegisterUnique(factory =>
{
var fileSystems = factory.GetInstance<FileSystems>();
var supporting = factory.GetInstance<SupportingFileSystems>();
return fileSystems.GetFileSystem<TFileSystem>(supporting.For<TFileSystem>());
});
}
}
}
@@ -1,43 +1,12 @@
using Umbraco.Core.Cache;
using Umbraco.Core.Components;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Composing
namespace Umbraco.Core
{
/// <summary>
/// Provides extension methods to the <see cref="Composition"/> class.
/// </summary>
public static class CompositionExtensions
public static partial class CompositionExtensions
{
#region Essentials
/// <summary>
/// Registers essential services.
/// </summary>
public static void RegisterEssentials(this Composition composition,
ILogger logger, IProfiler profiler, IProfilingLogger profilingLogger,
IMainDom mainDom,
AppCaches appCaches,
IUmbracoDatabaseFactory databaseFactory,
TypeLoader typeLoader,
IRuntimeState state)
{
composition.RegisterUnique(logger);
composition.RegisterUnique(profiler);
composition.RegisterUnique(profilingLogger);
composition.RegisterUnique(mainDom);
composition.RegisterUnique(appCaches);
composition.RegisterUnique(databaseFactory);
composition.RegisterUnique(factory => factory.GetInstance<IUmbracoDatabaseFactory>().SqlContext);
composition.RegisterUnique(typeLoader);
composition.RegisterUnique(state);
}
#endregion
#region Unique
/// <summary>
/// Registers a unique service as its own implementation.
/// </summary>
@@ -62,7 +31,5 @@ namespace Umbraco.Core.Composing
/// </summary>
public static void RegisterUnique<TService>(this Composition composition, TService instance)
=> composition.RegisterUnique(typeof(TService), instance);
#endregion
}
}
}
@@ -4,15 +4,8 @@ using System.Linq;
using System.Net.Configuration;
using System.Web;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.Security;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Security;
namespace Umbraco.Core.Configuration
{
@@ -277,12 +270,7 @@ namespace Umbraco.Core.Configuration
}
}
/// <summary>
/// This is the location type to store temporary files such as cache files or other localized files for a given machine
/// </summary>
/// <remarks>
/// Currently used for the xml cache file and the plugin cache files
/// </remarks>
/// <inheritdoc />
public LocalTempStorage LocalTempStorageLocation
{
get
@@ -295,6 +283,30 @@ namespace Umbraco.Core.Configuration
}
}
/// <inheritdoc />
public string LocalTempPath
{
get
{
switch (LocalTempStorageLocation)
{
case LocalTempStorage.AspNetTemp:
return System.IO.Path.Combine(HttpRuntime.CodegenDir, "UmbracoData");
case LocalTempStorage.EnvironmentTemp:
// include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId
var appDomainHash = HttpRuntime.AppDomainAppId.GenerateHash();
return System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash);
//case LocalTempStorage.Default:
//case LocalTempStorage.Unknown:
default:
return IOHelper.MapPath("~/App_Data/TEMP");
}
}
}
/// <summary>
/// Gets the default UI language.
/// </summary>
@@ -348,10 +360,5 @@ namespace Umbraco.Core.Configuration
}
}
}
}
}
@@ -128,6 +128,7 @@ namespace Umbraco.Core.Configuration
if (routes == null) throw new ArgumentNullException(nameof(routes));
//check if the current request matches a route, if so then it is reserved.
//TODO: This value should be cached! Else this is doing double routing in MVC every request!
var route = routes.GetRouteData(httpContext);
if (route != null)
return true;
@@ -1,6 +1,4 @@
using System;
namespace Umbraco.Core.Configuration
namespace Umbraco.Core.Configuration
{
/// <summary>
/// Contains general settings information for the entire Umbraco instance based on information from web.config appsettings
@@ -61,11 +59,13 @@ namespace Umbraco.Core.Configuration
int VersionCheckPeriod { get; }
/// <summary>
/// This is the location type to store temporary files such as cache files or other localized files for a given machine
/// Gets the configuration for the location of temporary files.
/// </summary>
/// <remarks>
/// Used for some cache files and for specific environments such as Azure
/// </remarks>
LocalTempStorage LocalTempStorageLocation { get; }
/// <summary>
/// Gets the location of temporary files.
/// </summary>
string LocalTempPath { get; }
}
}
+6 -6
View File
@@ -219,7 +219,7 @@ namespace Umbraco.Core
},
{
FailedPasswordAttempts,
new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.Integer, true, FailedPasswordAttempts)
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
{
Name = FailedPasswordAttemptsLabel
}
@@ -240,35 +240,35 @@ namespace Umbraco.Core
},
{
LastLockoutDate,
new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.Date, true, LastLockoutDate)
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
{
Name = LastLockoutDateLabel
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.Date, true, LastLoginDate)
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
{
Name = LastLoginDateLabel
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.Date, true, LastPasswordChangeDate)
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
{
Name = LastPasswordChangeDateLabel
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.Nvarchar, true, PasswordAnswer)
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.Aliases.NoEdit, ValueStorageType.Nvarchar, true, PasswordQuestion)
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
}
+7 -11
View File
@@ -34,11 +34,7 @@ namespace Umbraco.Core
/// </summary>
public const string ContentPicker = "Umbraco.ContentPicker";
/// <summary>
/// Date.
/// </summary>
public const string Date = "Umbraco.Date";
/// <summary>
/// DateTime.
/// </summary>
@@ -48,7 +44,7 @@ namespace Umbraco.Core
/// DropDown List.
/// </summary>
public const string DropDownListFlexible = "Umbraco.DropDown.Flexible";
/// <summary>
/// Grid.
/// </summary>
@@ -105,9 +101,9 @@ namespace Umbraco.Core
public const string MultipleTextstring = "Umbraco.MultipleTextstring";
/// <summary>
/// NoEdit.
/// Label.
/// </summary>
public const string NoEdit = "Umbraco.NoEdit";
public const string Label = "Umbraco.Label";
/// <summary>
/// Picker Relations.
@@ -118,7 +114,7 @@ namespace Umbraco.Core
/// RadioButton list.
/// </summary>
public const string RadioButtonList = "Umbraco.RadioButtonList";
/// <summary>
/// Slider.
/// </summary>
@@ -142,7 +138,7 @@ namespace Umbraco.Core
/// <summary>
/// TinyMCE
/// </summary>
public const string TinyMce = "Umbraco.TinyMCEv3";
public const string TinyMce = "Umbraco.TinyMCE";
/// <summary>
/// Boolean.
@@ -163,7 +159,7 @@ namespace Umbraco.Core
/// Upload Field.
/// </summary>
public const string UploadField = "Umbraco.UploadField";
/// <summary>
/// Email Address.
/// </summary>
-64
View File
@@ -1,64 +0,0 @@
using System;
namespace Umbraco.Core
{
/// <summary>
/// Abstract implementation of IDisposable.
/// </summary>
/// <remarks>
/// This is for objects that DO have unmanaged resources. Use <see cref="DisposableObjectSlim"/>
/// for objects that do NOT have unmanaged resources, and avoid creating a finalizer.
///
/// Can also be used as a pattern for when inheriting is not possible.
///
/// See also: https://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.110%29.aspx
/// See also: https://lostechies.com/chrispatterson/2012/11/29/idisposable-done-right/
///
/// Note: if an object's ctor throws, it will never be disposed, and so if that ctor
/// has allocated disposable objects, it should take care of disposing them.
/// </remarks>
public abstract class DisposableObject : IDisposable
{
private readonly object _locko = new object();
// gets a value indicating whether this instance is disposed.
// for internal tests only (not thread safe)
public bool Disposed { get; private set; }
// implements IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// finalizer
~DisposableObject()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
// can happen if the object construction failed
if (_locko == null)
return;
lock (_locko)
{
if (Disposed) return;
Disposed = true;
}
DisposeUnmanagedResources();
if (disposing)
DisposeResources();
}
protected abstract void DisposeResources();
protected virtual void DisposeUnmanagedResources()
{ }
}
}
@@ -1,8 +1,9 @@
using System;
using System.Linq;
using System.Reflection;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Composing
namespace Umbraco.Core
{
/// <summary>
/// Provides extension methods to the <see cref="IFactory"/> class.
+67
View File
@@ -40,5 +40,72 @@ namespace Umbraco.Core
public DecomposedGuid(Guid value) : this() => this.Value = value;
}
private static readonly char[] Base32Table =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5'
};
/// <summary>
/// Converts a Guid into a base-32 string.
/// </summary>
/// <param name="guid">A Guid.</param>
/// <param name="length">The string length.</param>
/// <returns>A base-32 encoded string.</returns>
/// <remarks>
/// <para>A base-32 string representation of a Guid is the shortest, efficient, representation
/// that is case insensitive (base-64 is case sensitive).</para>
/// <para>Length must be 1-26, anything else becomes 26.</para>
/// </remarks>
public static string ToBase32String(Guid guid, int length = 26)
{
if (length <= 0 || length > 26)
length = 26;
var bytes = guid.ToByteArray(); // a Guid is 128 bits ie 16 bytes
// this could be optimized by making it unsafe,
// and fixing the table + bytes + chars (see Convert.ToBase64CharArray)
// each block of 5 bytes = 5*8 = 40 bits
// becomes 40 bits = 8*5 = 8 byte-32 chars
// a Guid is 3 blocks + 8 bits
// so it turns into a 3*8+2 = 26 chars string
var chars = new char[length];
var i = 0;
var j = 0;
while (i < 15)
{
if (j == length) break;
chars[j++] = Base32Table[(bytes[i] & 0b1111_1000) >> 3];
if (j == length) break;
chars[j++] = Base32Table[((bytes[i] & 0b0000_0111) << 2) | ((bytes[i + 1] & 0b1100_0000) >> 6)];
if (j == length) break;
chars[j++] = Base32Table[(bytes[i + 1] & 0b0011_1110) >> 1];
if (j == length) break;
chars[j++] = Base32Table[(bytes[i + 1] & 0b0000_0001) | ((bytes[i + 2] & 0b1111_0000) >> 4)];
if (j == length) break;
chars[j++] = Base32Table[((bytes[i + 2] & 0b0000_1111) << 1) | ((bytes[i + 3] & 0b1000_0000) >> 7)];
if (j == length) break;
chars[j++] = Base32Table[(bytes[i + 3] & 0b0111_1100) >> 2];
if (j == length) break;
chars[j++] = Base32Table[((bytes[i + 3] & 0b0000_0011) << 3) | ((bytes[i + 4] & 0b1110_0000) >> 5)];
if (j == length) break;
chars[j++] = Base32Table[bytes[i + 4] & 0b0001_1111];
i += 5;
}
if (j < length)
chars[j++] = Base32Table[(bytes[i] & 0b1111_1000) >> 3];
if (j < length)
chars[j] = Base32Table[(bytes[i] & 0b0000_0111) << 2];
return new string(chars);
}
}
}
+48 -18
View File
@@ -29,7 +29,7 @@ namespace Umbraco.Core.IO
// shadow support
private readonly List<ShadowWrapper> _shadowWrappers = new List<ShadowWrapper>();
private readonly object _shadowLocker = new object();
private static Guid _shadowCurrentId = Guid.Empty; // static - unique!!
private static string _shadowCurrentId; // static - unique!!
#region Constructor
// DI wants a public ctor
@@ -45,13 +45,13 @@ namespace Umbraco.Core.IO
_shadowWrappers.Clear();
_filesystems.Clear();
Volatile.Write(ref _wkfsInitialized, false);
_shadowCurrentId = Guid.Empty;
_shadowCurrentId = null;
}
// for tests only, totally unsafe
internal static void ResetShadowId()
{
_shadowCurrentId = Guid.Empty;
_shadowCurrentId = null;
}
// set by the scope provider when taking control of filesystems
@@ -126,11 +126,11 @@ namespace Umbraco.Core.IO
var scriptsFileSystem = new PhysicalFileSystem(SystemDirectories.Scripts);
var mvcViewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews);
_macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "Views/MacroPartials", IsScoped);
_partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "Views/Partials", IsScoped);
_macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "macro-partials", IsScoped);
_partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "partials", IsScoped);
_stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, "css", IsScoped);
_scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, "scripts", IsScoped);
_mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, "Views", IsScoped);
_mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, "views", IsScoped);
// TODO: do we need a lock here?
_shadowWrappers.Add(_macroPartialFileSystem);
@@ -146,6 +146,11 @@ namespace Umbraco.Core.IO
#region Providers
private readonly Dictionary<Type, string> _paths = new Dictionary<Type, string>();
// internal for tests
internal IReadOnlyDictionary<Type, string> Paths => _paths;
/// <summary>
/// Gets a strongly-typed filesystem.
/// </summary>
@@ -162,10 +167,33 @@ namespace Umbraco.Core.IO
return (TFileSystem) _filesystems.GetOrAdd(typeof(TFileSystem), _ => new Lazy<IFileSystem>(() =>
{
var name = typeof(TFileSystem).FullName;
if (name == null) throw new Exception("panic!");
var typeofTFileSystem = typeof(TFileSystem);
var shadowWrapper = CreateShadowWrapper(supporting, "typed/" + name);
// path must be unique and not collide with paths used in CreateWellKnownFileSystems
// for our well-known 'media' filesystem we can use the short 'media' path
// for others, put them under 'x/' and use ... something
string path;
if (typeofTFileSystem == typeof(MediaFileSystem))
{
path = "media";
}
else
{
lock (_paths)
{
if (!_paths.TryGetValue(typeofTFileSystem, out path))
{
path = Guid.NewGuid().ToString("N").Substring(0, 6);
while (_paths.ContainsValue(path)) // this can't loop forever, right?
path = Guid.NewGuid().ToString("N").Substring(0, 6);
_paths[typeofTFileSystem] = path;
}
}
path = "x/" + path;
}
var shadowWrapper = CreateShadowWrapper(supporting, path);
return _container.CreateInstance<TFileSystem>(shadowWrapper);
})).Value;
}
@@ -179,35 +207,37 @@ namespace Umbraco.Core.IO
// global shadow for the entire application, so great care should be taken to ensure that the
// application is *not* doing anything else when using a shadow.
internal ICompletable Shadow(Guid id)
internal ICompletable Shadow()
{
if (Volatile.Read(ref _wkfsInitialized) == false) EnsureWellKnownFileSystems();
var id = ShadowWrapper.CreateShadowId();
return new ShadowFileSystems(this, id); // will invoke BeginShadow and EndShadow
}
internal void BeginShadow(Guid id)
internal void BeginShadow(string id)
{
lock (_shadowLocker)
{
// if we throw here, it means that something very wrong happened.
if (_shadowCurrentId != Guid.Empty)
if (_shadowCurrentId != null)
throw new InvalidOperationException("Already shadowing.");
_shadowCurrentId = id;
_logger.Debug<ShadowFileSystems>("Shadow '{ShadowId}'", id);
_logger.Debug<ShadowFileSystems>("Shadow '{ShadowId}'", _shadowCurrentId);
foreach (var wrapper in _shadowWrappers)
wrapper.Shadow(id);
wrapper.Shadow(_shadowCurrentId);
}
}
internal void EndShadow(Guid id, bool completed)
internal void EndShadow(string id, bool completed)
{
lock (_shadowLocker)
{
// if we throw here, it means that something very wrong happened.
if (_shadowCurrentId == Guid.Empty)
if (_shadowCurrentId == null)
throw new InvalidOperationException("Not shadowing.");
if (id != _shadowCurrentId)
throw new InvalidOperationException("Not the current shadow.");
@@ -228,7 +258,7 @@ namespace Umbraco.Core.IO
}
}
_shadowCurrentId = Guid.Empty;
_shadowCurrentId = null;
if (exceptions.Count > 0)
throw new AggregateException(completed ? "Failed to apply all changes (see exceptions)." : "Failed to abort (see exceptions).", exceptions);
@@ -240,7 +270,7 @@ namespace Umbraco.Core.IO
lock (_shadowLocker)
{
var wrapper = new ShadowWrapper(filesystem, shadowPath, IsScoped);
if (_shadowCurrentId != Guid.Empty)
if (_shadowCurrentId != null)
wrapper.Shadow(_shadowCurrentId);
_shadowWrappers.Add(wrapper);
return wrapper;
@@ -7,7 +7,7 @@ namespace Umbraco.Core.IO.MediaPathSchemes
/// Implements a combined-guids media path scheme.
/// </summary>
/// <remarks>
/// <para>Path is "{combinedGuid}/{filename>}" where combinedGuid is a combination of itemGuid and propertyGuid.</para>
/// <para>Path is "{combinedGuid}/{filename}" where combinedGuid is a combination of itemGuid and propertyGuid.</para>
/// </remarks>
public class CombinedGuidsMediaPathScheme : IMediaPathScheme
{
@@ -16,7 +16,9 @@ namespace Umbraco.Core.IO.MediaPathSchemes
{
// assumes that cuid and puid keys can be trusted - and that a single property type
// for a single content cannot store two different files with the same name
var directory = HexEncoder.Encode(GuidUtils.Combine(itemGuid, propertyGuid).ToByteArray()/*'/', 2, 4*/); // could use ext to fragment path eg 12/e4/f2/...
var combinedGuid = GuidUtils.Combine(itemGuid, propertyGuid);
var directory = HexEncoder.Encode(combinedGuid.ToByteArray()/*'/', 2, 4*/); // could use ext to fragment path eg 12/e4/f2/...
return Path.Combine(directory, filename).Replace('\\', '/');
}
@@ -0,0 +1,37 @@
using System;
using System.IO;
namespace Umbraco.Core.IO.MediaPathSchemes
{
/// <summary>
/// Implements a unique directory media path scheme.
/// </summary>
/// <remarks>
/// <para>This scheme provides deterministic short paths, with potential collisions.</para>
/// </remarks>
public class UniqueMediaPathScheme : IMediaPathScheme
{
private const int DirectoryLength = 8;
/// <inheritdoc />
public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null)
{
var combinedGuid = GuidUtils.Combine(itemGuid, propertyGuid);
var directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength);
return Path.Combine(directory, filename).Replace('\\', '/');
}
/// <inheritdoc />
/// <remarks>
/// <para>Returning null so that <see cref="MediaFileSystem.DeleteMediaFiles"/> does *not*
/// delete any directory. This is because the above shortening of the Guid to 8 chars
/// means we're increasing the risk of collision, and we don't want to delete files
/// belonging to other media items.</para>
/// <para>And, at the moment, we cannot delete directory "only if it is empty" because of
/// race conditions. We'd need to implement locks in <see cref="MediaFileSystem"/> for
/// this.</para>
/// </remarks>
public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) => null;
}
}
@@ -304,7 +304,13 @@ namespace Umbraco.Core.IO
// permissions to reach that path, but it may nevertheless be outside of
// our root path, due to relative segments, so better check
if (IOHelper.PathStartsWith(path, _rootPath, Path.DirectorySeparatorChar))
{
// this says that 4.7.2 supports long paths - but Windows does not
// https://docs.microsoft.com/en-us/dotnet/api/system.io.pathtoolongexception?view=netframework-4.7.2
if (path.Length > 260)
throw new PathTooLongException($"Path {path} is too long.");
return path;
}
// nothing prevents us to reach the file, security-wise, yet it is outside
// this filesystem's root - throw
+2 -2
View File
@@ -10,7 +10,7 @@ namespace Umbraco.Core.IO
private bool _completed;
// invoked by the filesystems when shadowing
public ShadowFileSystems(FileSystems fileSystems, Guid id)
public ShadowFileSystems(FileSystems fileSystems, string id)
{
_fileSystems = fileSystems;
Id = id;
@@ -19,7 +19,7 @@ namespace Umbraco.Core.IO
}
// for tests
public Guid Id { get; }
public string Id { get; }
// invoked by the scope when exiting, if completed
public void Complete()
+27 -1
View File
@@ -22,7 +22,33 @@ namespace Umbraco.Core.IO
_isScoped = isScoped;
}
internal void Shadow(Guid id)
public static string CreateShadowId()
{
const int retries = 50; // avoid infinite loop
const int idLength = 8; // 6 chars
// shorten a Guid to idLength chars, and see whether it collides
// with an existing directory or not - if it does, try again, and
// we should end up with a unique identifier eventually - but just
// detect infinite loops (just in case)
for (var i = 0; i < retries; i++)
{
var id = GuidUtils.ToBase32String(Guid.NewGuid(), idLength);
var virt = ShadowFsPath + "/" + id;
var shadowDir = IOHelper.MapPath(virt);
if (Directory.Exists(shadowDir))
continue;
Directory.CreateDirectory(shadowDir);
return id;
}
throw new Exception($"Could not get a shadow identifier (tried {retries} times)");
}
internal void Shadow(string id)
{
// note: no thread-safety here, because ShadowFs is thread-safe due to the check
// on ShadowFileSystemsScope.None - and if None is false then we should be running
+2 -20
View File
@@ -1,6 +1,4 @@
using System;
using System.IO;
using System.Web;
using System.IO;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.IO
@@ -12,23 +10,7 @@ namespace Umbraco.Core.IO
// TODO: Kill this off we don't have umbraco.config XML cache we now have NuCache
public static string GetContentCacheXml(IGlobalSettings globalSettings)
{
switch (globalSettings.LocalTempStorageLocation)
{
case LocalTempStorage.AspNetTemp:
return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config");
case LocalTempStorage.EnvironmentTemp:
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData",
//include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path
appDomainHash);
return Path.Combine(cachePath, "umbraco.config");
case LocalTempStorage.Default:
return IOHelper.ReturnPath(Constants.AppSettings.ContentXML, "~/App_Data/umbraco.config");
default:
throw new ArgumentOutOfRangeException();
}
return Path.Combine(globalSettings.LocalTempPath, "umbraco.config");
}
}
}
+1 -1
View File
@@ -41,7 +41,7 @@ namespace Umbraco.Core.Logging
}
// a lightweight disposable timer
private class LightDisposableTimer : DisposableObject
private class LightDisposableTimer : DisposableObjectSlim
{
private readonly Action<long> _callback;
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
@@ -22,6 +22,7 @@ namespace Umbraco.Core.Logging.Serilog
//Set this environment variable - so that it can be used in external config file
//add key="serilog:write-to:RollingFile.pathFormat" value="%BASEDIR%\logs\log.txt" />
Environment.SetEnvironmentVariable("BASEDIR", AppDomain.CurrentDomain.BaseDirectory, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("MACHINENAME", Environment.MachineName, EnvironmentVariableTarget.Process);
logConfig.MinimumLevel.Verbose() //Set to highest level of logging (as any sinks may want to restrict it to Errors only)
.Enrich.WithProcessId()
@@ -41,8 +41,6 @@ namespace Umbraco.Core.Logging.Serilog
var loggerConfig = new LoggerConfiguration();
loggerConfig
.MinimalConfiguration()
.OutputDefaultTextFile(LogEventLevel.Debug)
.OutputDefaultJsonFile()
.ReadFromConfigFile()
.ReadFromUserConfigFile();
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Serilog.Events;
using Serilog.Formatting.Compact.Reader;
@@ -10,13 +11,15 @@ namespace Umbraco.Core.Logging.Viewer
internal class JsonLogViewer : LogViewerSourceBase
{
private readonly string _logsPath;
private readonly ILogger _logger;
public JsonLogViewer(string logsPath = "", string searchPath = "") : base(searchPath)
public JsonLogViewer(ILogger logger, string logsPath = "", string searchPath = "") : base(searchPath)
{
if (string.IsNullOrEmpty(logsPath))
logsPath = $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\";
_logsPath = logsPath;
_logger = logger;
}
private const int FileSizeCap = 100;
@@ -77,8 +80,14 @@ namespace Umbraco.Core.Logging.Viewer
using (var stream = new StreamReader(fs))
{
var reader = new LogEventReader(stream);
while (reader.TryRead(out var evt))
while (TryRead(reader, out var evt))
{
//We may get a null if log line is malformed
if (evt == null)
{
continue;
}
if (count > skip + take)
{
break;
@@ -105,5 +114,21 @@ namespace Umbraco.Core.Logging.Viewer
return logs;
}
private bool TryRead(LogEventReader reader, out LogEvent evt)
{
try
{
return reader.TryRead(out evt);
}
catch (JsonReaderException ex)
{
// As we are reading/streaming one line at a time in the JSON file
// Thus we can not report the line number, as it will always be 1
_logger.Error<JsonLogViewer>(ex, "Unable to parse a line in the JSON log file");
evt = null;
return true;
}
}
}
}
@@ -1,4 +1,5 @@
using Umbraco.Core.Components;
using Umbraco.Core.Compose;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Logging.Viewer
{
@@ -8,7 +9,7 @@ namespace Umbraco.Core.Logging.Viewer
{
public void Compose(Composition composition)
{
composition.SetLogViewer(_ => new JsonLogViewer());
composition.SetLogViewer(_ => new JsonLogViewer(composition.Logger));
}
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Logging
public void Stop(bool discardResults = false)
{ }
private class VoidDisposable : DisposableObject
private class VoidDisposable : DisposableObjectSlim
{
protected override void DisposeResources()
{ }
+1 -1
View File
@@ -101,7 +101,7 @@ namespace Umbraco.Core.Manifest
var gridEditors = new List<GridEditor>();
var contentApps = new List<ManifestContentAppDefinition>();
var dashboards = new List<ManifestDashboard>();
var sections = new List<ManifestBackOfficeSection>();
var sections = new List<ManifestSection>();
foreach (var manifest in manifests)
{
@@ -1,10 +1,10 @@
using System.Runtime.Serialization;
using Umbraco.Core.Models.Trees;
using Umbraco.Core.Models.Sections;
namespace Umbraco.Core.Manifest
{
[DataContract(Name = "section", Namespace = "")]
public class ManifestBackOfficeSection : IBackOfficeSection
public class ManifestSection : ISection
{
[DataMember(Name = "alias")]
public string Alias { get; set; }
+1 -1
View File
@@ -55,6 +55,6 @@ namespace Umbraco.Core.Manifest
/// Gets or sets the sections listed in the manifest.
/// </summary>
[JsonProperty("sections")]
public ManifestBackOfficeSection[] Sections { get; set; } = Array.Empty<ManifestBackOfficeSection>();
public ManifestSection[] Sections { get; set; } = Array.Empty<ManifestSection>();
}
}
@@ -1,4 +1,6 @@
using Umbraco.Core.Logging;
using System;
using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
namespace Umbraco.Core.Migrations
@@ -32,5 +34,11 @@ namespace Umbraco.Core.Migrations
/// Gets or sets a value indicating whether an expression is being built.
/// </summary>
bool BuildingExpression { get; set; }
/// <summary>
/// Adds a post-migrations.
/// </summary>
void AddPostMigration<TMigration>()
where TMigration : IMigration;
}
}
@@ -1,12 +0,0 @@
using Semver;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Scoping;
namespace Umbraco.Core.Migrations
{
public interface IPostMigration : IDiscoverable
{
void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger);
}
}
@@ -27,7 +27,6 @@ namespace Umbraco.Core.Migrations.Install
private readonly IRuntimeState _runtime;
private readonly IMigrationBuilder _migrationBuilder;
private readonly IKeyValueService _keyValueService;
private readonly PostMigrationCollection _postMigrations;
private readonly ILogger _logger;
private DatabaseSchemaResult _databaseSchemaValidationResult;
@@ -35,7 +34,7 @@ namespace Umbraco.Core.Migrations.Install
/// <summary>
/// Initializes a new instance of the <see cref="DatabaseBuilder"/> class.
/// </summary>
public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations)
public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService)
{
_scopeProvider = scopeProvider;
_globalSettings = globalSettings;
@@ -44,7 +43,6 @@ namespace Umbraco.Core.Migrations.Install
_logger = logger;
_migrationBuilder = migrationBuilder;
_keyValueService = keyValueService;
_postMigrations = postMigrations;
}
#region Status
@@ -483,7 +481,7 @@ namespace Umbraco.Core.Migrations.Install
/// configured and it is possible to connect to the database.</para>
/// <para>Runs whichever migrations need to run.</para>
/// </remarks>
public Result UpgradeSchemaAndData()
public Result UpgradeSchemaAndData(MigrationPlan plan)
{
try
{
@@ -496,8 +494,8 @@ namespace Umbraco.Core.Migrations.Install
_logger.Info<DatabaseBuilder>("Database upgrade started");
// upgrade
var upgrader = new UmbracoUpgrader();
upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger, _postMigrations);
var upgrader = new Upgrader(plan);
upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger);
var message = "<p>Upgrade completed!</p>";
@@ -271,17 +271,17 @@ namespace Umbraco.Core.Migrations.Install
_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" });
InsertDataTypeDto(Constants.DataTypes.LabelString, Constants.PropertyEditors.Aliases.NoEdit, "Nvarchar", "{\"umbracoDataValueType\":\"STRING\"}");
InsertDataTypeDto(Constants.DataTypes.LabelInt, Constants.PropertyEditors.Aliases.NoEdit, "Integer", "{\"umbracoDataValueType\":\"INT\"}");
InsertDataTypeDto(Constants.DataTypes.LabelBigint, Constants.PropertyEditors.Aliases.NoEdit, "Nvarchar", "{\"umbracoDataValueType\":\"BIGINT\"}");
InsertDataTypeDto(Constants.DataTypes.LabelDateTime, Constants.PropertyEditors.Aliases.NoEdit, "Date", "{\"umbracoDataValueType\":\"DATETIME\"}");
InsertDataTypeDto(Constants.DataTypes.LabelDecimal, Constants.PropertyEditors.Aliases.NoEdit, "Decimal", "{\"umbracoDataValueType\":\"DECIMAL\"}");
InsertDataTypeDto(Constants.DataTypes.LabelTime, Constants.PropertyEditors.Aliases.NoEdit, "Date", "{\"umbracoDataValueType\":\"TIME\"}");
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 = -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 = Constants.PropertyEditors.Aliases.Date, DbType = "Date" });
_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",
@@ -321,7 +321,7 @@ namespace Umbraco.Core.Migrations.Install
{
// on install, initialize the umbraco migration plan with the final state
var upgrader = new UmbracoUpgrader();
var upgrader = new Upgrader(new UmbracoPlan());
var stateValueKey = upgrader.StateValueKey;
var finalState = upgrader.Plan.FinalState;
@@ -50,8 +50,6 @@ namespace Umbraco.Core.Migrations.Install
typeof (MemberTypeDto),
typeof (MemberDto),
typeof (Member2MemberGroupDto),
typeof (ContentXmlDto),
typeof (PreviewXmlDto),
typeof (PropertyTypeGroupDto),
typeof (PropertyTypeDto),
typeof (PropertyDataDto),
@@ -139,13 +137,18 @@ namespace Umbraco.Core.Migrations.Install
/// Validates the schema of the current database.
/// </summary>
internal DatabaseSchemaResult ValidateSchema()
{
return ValidateSchema(OrderedTables);
}
internal DatabaseSchemaResult ValidateSchema(IEnumerable<Type> orderedTables)
{
var result = new DatabaseSchemaResult(SqlSyntax);
result.IndexDefinitions.AddRange(SqlSyntax.GetDefinedIndexes(_database)
.Select(x => new DbIndexDefinition(x)));
result.TableDefinitions.AddRange(OrderedTables
result.TableDefinitions.AddRange(orderedTables
.Select(x => DefinitionFactory.GetTableDefinition(x, SqlSyntax)));
ValidateDbTables(result);
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
namespace Umbraco.Core.Migrations
{
/// <summary>
/// Represents a migration context.
/// Implements <see cref="IMigrationContext"/>.
/// </summary>
internal class MigrationContext : IMigrationContext
{
@@ -32,5 +33,15 @@ namespace Umbraco.Core.Migrations
/// <inheritdoc />
public bool BuildingExpression { get; set; }
// this is only internally exposed
public List<Type> PostMigrations { get; } = new List<Type>();
/// <inheritdoc />
public void AddPostMigration<TMigration>()
where TMigration : IMigration
{
PostMigrations.Add(typeof(TMigration));
}
}
}
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Migrations
public class MigrationPlan
{
private readonly Dictionary<string, Transition> _transitions = new Dictionary<string, Transition>();
private readonly List<Type> _postMigrationTypes = new List<Type>();
private string _prevState;
private string _finalState;
@@ -166,6 +167,25 @@ namespace Umbraco.Core.Migrations
return this;
}
/// <summary>
/// Prepares post-migrations.
/// </summary>
/// <remarks>
/// <para>This can be overriden to filter, complement, and/or re-order post-migrations.</para>
/// </remarks>
protected virtual IEnumerable<Type> PreparePostMigrations(IEnumerable<Type> types)
=> types;
/// <summary>
/// Adds a post-migration to the plan.
/// </summary>
public virtual MigrationPlan AddPostMigration<TMigration>()
where TMigration : IMigration
{
_postMigrationTypes.Add(typeof(TMigration));
return this;
}
/// <summary>
/// Creates a random, unique state.
/// </summary>
@@ -270,6 +290,7 @@ namespace Umbraco.Core.Migrations
throw new Exception($"Unknown state \"{origState}\".");
var context = new MigrationContext(scope.Database, logger);
context.PostMigrations.AddRange(_postMigrationTypes);
while (transition != null)
{
@@ -285,6 +306,20 @@ namespace Umbraco.Core.Migrations
throw new Exception($"Unknown state \"{origState}\".");
}
// prepare and de-duplicate post-migrations, only keeping the 1st occurence
var temp = new HashSet<Type>();
var postMigrationTypes = PreparePostMigrations(context.PostMigrations)
.Where(x => !temp.Contains(x))
.Select(x => { temp.Add(x); return x; });
// run post-migrations
foreach (var postMigrationType in postMigrationTypes)
{
logger.Info<MigrationPlan>($"PostMigration: {postMigrationType.FullName}.");
var postMigration = migrationBuilder.Build(postMigrationType, context);
postMigration.Migrate();
}
logger.Info<MigrationPlan>("Done (pending scope completion).");
// safety check
@@ -1,12 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Migrations
{
public class PostMigrationCollection : BuilderCollectionBase<IPostMigration>
{
public PostMigrationCollection(IEnumerable<IPostMigration> items)
: base(items)
{ }
}
}
@@ -1,11 +0,0 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.Migrations
{
public class PostMigrationCollectionBuilder : LazyCollectionBuilderBase<PostMigrationCollectionBuilder, PostMigrationCollection, IPostMigration>
{
protected override PostMigrationCollectionBuilder This => this;
protected override Lifetime CollectionLifetime => Lifetime.Transient;
}
}
@@ -0,0 +1,18 @@
namespace Umbraco.Core.Migrations.PostMigrations
{
/// <summary>
/// Rebuilds the published snapshot.
/// </summary>
/// <remarks>
/// <para>This interface exists because the entire published snapshot lives in Umbraco.Web
/// but we may want to trigger rebuilds from Umbraco.Core. These two assemblies should
/// be refactored, really.</para>
/// </remarks>
public interface IPublishedSnapshotRebuilder
{
/// <summary>
/// Rebuilds.
/// </summary>
void Rebuild();
}
}
@@ -0,0 +1,12 @@
namespace Umbraco.Core.Migrations.PostMigrations
{
/// <summary>
/// Implements <see cref="IPublishedSnapshotRebuilder"/> in Umbraco.Core (doing nothing).
/// </summary>
public class PublishedSnapshotRebuilder : IPublishedSnapshotRebuilder
{
/// <inheritdoc />
public void Rebuild()
{ }
}
}
@@ -0,0 +1,24 @@
namespace Umbraco.Core.Migrations.PostMigrations
{
/// <summary>
/// Rebuilds the published snapshot.
/// </summary>
public class RebuildPublishedSnapshot : IMigration
{
private readonly IPublishedSnapshotRebuilder _rebuilder;
/// <summary>
/// Initializes a new instance of the <see cref="RebuildPublishedSnapshot"/> class.
/// </summary>
public RebuildPublishedSnapshot(IPublishedSnapshotRebuilder rebuilder)
{
_rebuilder = rebuilder;
}
/// <inheritdoc />
public void Migrate()
{
_rebuilder.Rebuild();
}
}
}
@@ -5,6 +5,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
namespace Umbraco.Core.Migrations.Upgrade
{
@@ -56,7 +57,7 @@ namespace Umbraco.Core.Migrations.Upgrade
}
}
// define the plan
// define the plan
protected void DefinePlan()
{
// MODIFYING THE PLAN
@@ -127,8 +128,17 @@ namespace Umbraco.Core.Migrations.Upgrade
To<ConvertRelatedLinksToMultiUrlPicker>("{ED28B66A-E248-4D94-8CDB-9BDF574023F0}");
To<UpdatePickerIntegerValuesToUdi>("{38C809D5-6C34-426B-9BEA-EFD39162595C}");
To<RenameUmbracoDomainsTable>("{6017F044-8E70-4E10-B2A3-336949692ADD}");
To<AddUserLoginDtoDateIndex>("98339BEF-E4B2-48A8-B9D1-D173DC842BBE");
To<RadioAndCheckboxAndDropdownPropertyEditorsMigration>("{940FD19A-00A8-4D5C-B8FF-939143585726}");
To<AddUserLoginDtoDateIndex>("{98339BEF-E4B2-48A8-B9D1-D173DC842BBE}");
Merge()
.To<DropXmlTables>("{CDBEDEE4-9496-4903-9CF2-4104E00FF960}")
.With()
.To<RadioAndCheckboxAndDropdownPropertyEditorsMigration>("{940FD19A-00A8-4D5C-B8FF-939143585726}")
.As("{0576E786-5C30-4000-B969-302B61E90CA3}");
To<RenameLabelAndRichTextPropertyEditorAliases>("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
To<MergeDateAndDateTimePropertyEditor>("{78BAF571-90D0-4D28-8175-EF96316DA789}");
To<ChangeNuCacheJsonFormat>("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
//FINAL
@@ -160,7 +170,7 @@ namespace Umbraco.Core.Migrations.Upgrade
From("{init-7.12.4}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.13.0}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.13.1}").To("{init-7.10.0}"); // same as 7.12.0
// 7.14.0 has migrations, handle it...
// clone going from 7.10 to 1350617A (the last one before we started to merge 7.12 migrations), then
// clone going from CF51B39B (after 7.12 migrations) to 0009109C (the last one before we started to merge 7.12 migrations),
@@ -1,48 +0,0 @@
using System;
using System.Configuration;
using Semver;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
namespace Umbraco.Core.Migrations.Upgrade
{
/// <summary>
/// Represents the Umbraco upgrader.
/// </summary>
public class UmbracoUpgrader : Upgrader
{
private PostMigrationCollection _postMigrations;
/// <summary>
/// Initializes a new instance of the <see ref="UmbracoUpgrader" /> class.
/// </summary>
public UmbracoUpgrader()
: base(new UmbracoPlan())
{ }
/// <summary>
/// Executes.
/// </summary>
public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations)
{
_postMigrations = postMigrations;
Execute(scopeProvider, migrationBuilder, keyValueService, logger);
}
/// <inheritdoc />
public override void AfterMigrations(IScope scope, ILogger logger)
{
// assume we have something in web.config that makes some sense = the origin version
if (!SemVersion.TryParse(ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus], out var originVersion))
throw new InvalidOperationException($"Could not get current version from web.config {Constants.AppSettings.ConfigurationStatus} appSetting.");
// target version is the code version
var targetVersion = UmbracoVersion.SemanticVersion;
foreach (var postMigration in _postMigrations)
postMigration.Execute(Name, scope, originVersion, targetVersion, logger);
}
}
}
@@ -53,7 +53,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
var dataTypeDto = new DataTypeDto
{
NodeId = id,
EditorAlias = Constants.PropertyEditors.Aliases.NoEdit,
EditorAlias = Constants.PropertyEditors.Aliases.Label,
DbType = dbType
};
@@ -1,6 +1,5 @@
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class DropTaskTables : MigrationBase
{
public DropTaskTables(IMigrationContext context)
@@ -0,0 +1,17 @@
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class DropXmlTables : MigrationBase
{
public DropXmlTables(IMigrationContext context)
: base(context)
{ }
public override void Migrate()
{
if (TableExists("cmsContentXml"))
Delete.Table("cmsContentXml").Do();
if (TableExists("cmsPreviewXml"))
Delete.Table("cmsPreviewXml").Do();
}
}
}
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class MergeDateAndDateTimePropertyEditor : MigrationBase
{
public MergeDateAndDateTimePropertyEditor(IMigrationContext context)
: base(context)
{
}
public override void Migrate()
{
var dataTypes = GetDataTypes("Umbraco.Date");
foreach (var dataType in dataTypes)
{
DateTimeConfiguration config;
try
{
config = (DateTimeConfiguration) new CustomDateTimeConfigurationEditor().FromDatabase(
dataType.Configuration);
}
catch (Exception ex)
{
Logger.Error<DropDownPropertyEditorsMigration>(
ex,
"Invalid property editor configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared",
dataType.Configuration);
continue;
}
config.OffsetTime = false;
dataType.EditorAlias = Constants.PropertyEditors.Aliases.DateTime;
dataType.Configuration = ConfigurationEditor.ToDatabase(config);
Database.Update(dataType);
}
}
private List<DataTypeDto> GetDataTypes(string editorAlias)
{
//need to convert the old drop down data types to use the new one
var dataTypes = Database.Fetch<DataTypeDto>(Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias == editorAlias));
return dataTypes;
}
private class CustomDateTimeConfigurationEditor : ConfigurationEditor<DateTimeConfiguration>
{
}
}
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core.Logging;
using Umbraco.Core.Migrations.PostMigrations;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
@@ -27,7 +28,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
if (refreshCache)
{
//FIXME: trigger cache rebuild. Currently the data in the database tables is wrong.
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
}
@@ -53,7 +54,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
Logger.Error<DropDownPropertyEditorsMigration>(
ex,
"Invalid radio button configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared",
"Invalid property editor configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared",
dataType.Configuration);
continue;
@@ -0,0 +1,41 @@
using System.Collections.Generic;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class RenameLabelAndRichTextPropertyEditorAliases : MigrationBase
{
public RenameLabelAndRichTextPropertyEditorAliases(IMigrationContext context)
: base(context)
{
}
public override void Migrate()
{
MigratePropertyEditorAlias("Umbraco.TinyMCEv3", Constants.PropertyEditors.Aliases.TinyMce);
MigratePropertyEditorAlias("Umbraco.NoEdit", Constants.PropertyEditors.Aliases.Label);
}
private void MigratePropertyEditorAlias(string oldAlias, string newAlias)
{
var dataTypes = GetDataTypes(oldAlias);
foreach (var dataType in dataTypes)
{
dataType.EditorAlias = newAlias;
Database.Update(dataType);
}
}
private List<DataTypeDto> GetDataTypes(string editorAlias)
{
var dataTypes = Database.Fetch<DataTypeDto>(Sql()
.Select<DataTypeDto>()
.From<DataTypeDto>()
.Where<DataTypeDto>(x => x.EditorAlias == editorAlias));
return dataTypes;
}
}
}
@@ -0,0 +1,16 @@
using Umbraco.Core.Migrations.PostMigrations;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_1
{
public class ChangeNuCacheJsonFormat : MigrationBase
{
public ChangeNuCacheJsonFormat(IMigrationContext context) : base(context)
{ }
public override void Migrate()
{
// nothing - just adding the post-migration
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
}
}
@@ -0,0 +1,16 @@
using Umbraco.Core.Migrations.PostMigrations;
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
{
public class ChangeNuCacheJsonFormat : MigrationBase
{
public ChangeNuCacheJsonFormat(IMigrationContext context) : base(context)
{ }
public override void Migrate()
{
// nothing - just adding the post-migration
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
}
}
@@ -1,7 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Collections;
using Umbraco.Core.Composing;
using Umbraco.Core.Exceptions;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
@@ -101,35 +105,6 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Validates the content item's properties pass variant rules
/// </summary>
/// <para>If the content type is variant, then culture can be either '*' or an actual culture, but neither 'null' nor
/// 'empty'. If the content type is invariant, then culture can be either '*' or null or empty.</para>
public static Property[] ValidateProperties(this IContentBase content, string culture = "*")
{
// select invalid properties
return content.Properties.Where(x =>
{
// if culture is null, we validate invariant properties only
// if culture is '*' we validate both variant and invariant properties, automatically
// if culture is specific eg 'en-US' we both too, but explicitly
var varies = x.PropertyType.VariesByCulture();
if (culture == null)
return !(varies || x.IsValid(null)); // validate invariant property, invariant culture
if (culture == "*")
return !x.IsValid(culture); // validate property, all cultures
return varies
? !x.IsValid(culture) // validate variant property, explicit culture
: !x.IsValid(null); // validate invariant property, explicit culture
})
.ToArray();
}
public static void SetPublishInfo(this IContent content, string culture, string name, DateTime date)
{
if (string.IsNullOrWhiteSpace(name))
@@ -191,6 +166,13 @@ namespace Umbraco.Core.Models
content.CultureInfos.AddOrUpdate(culture, name, date);
}
/// <summary>
/// Sets the publishing values for names and properties.
/// </summary>
/// <param name="content"></param>
/// <param name="culture"></param>
/// <returns>A value indicating whether it was possible to publish the names and values for the specified
/// culture(s). The method may fail if required names are not set, but it does NOT validate property data</returns>
public static bool PublishCulture(this IContent content, string culture = "*")
{
culture = culture.NullOrWhiteSpaceAsNull();
@@ -201,10 +183,6 @@ namespace Umbraco.Core.Models
if (!content.ContentType.SupportsPropertyVariation(culture, "*", true))
throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\".");
// the values we want to publish should be valid
if (content.ValidateProperties(culture).Any())
return false;
var alsoInvariant = false;
if (culture == "*") // all cultures
{
+2 -2
View File
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class ContentType : ContentTypeCompositionBase, IContentType
{
public const bool IsPublishingConst = true;
public const bool SupportsPublishingConst = true;
private int _defaultTemplate;
private IEnumerable<ITemplate> _allowedTemplates;
@@ -45,7 +45,7 @@ namespace Umbraco.Core.Models
public override ISimpleContentType ToSimple() => new SimpleContentType(this);
/// <inheritdoc />
public override bool IsPublishing => IsPublishingConst;
public override bool SupportsPublishing => SupportsPublishingConst;
//Custom comparer for enumerable
private static readonly DelegateEqualityComparer<IEnumerable<ITemplate>> TemplateComparer = new DelegateEqualityComparer<IEnumerable<ITemplate>>(

Some files were not shown because too many files have changed in this diff Show More