Compare commits
450 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8db18bf82e | |||
| 31b293aa4d | |||
| f1d1c95709 | |||
| eace918258 | |||
| 8961e8b4be | |||
| b526b8f246 | |||
| ed6d54e64a | |||
| 57290c4180 | |||
| 84b60f8b9f | |||
| cfc04a9df0 | |||
| 3e4ff05d37 | |||
| 28034d664e | |||
| edf3fd5d31 | |||
| f7705ef134 | |||
| f0caa6be4b | |||
| 5aa38c1f43 | |||
| b809f9f03a | |||
| eabc05d6f8 | |||
| d3fb614d25 | |||
| 0eb7d404a1 | |||
| 093b57505a | |||
| 2a7cd4d94a | |||
| 4503967778 | |||
| f227f2ed61 | |||
| 553bf6d304 | |||
| 45dfef78bd | |||
| b172a5f847 | |||
| 41f80b942a | |||
| 055f983cbf | |||
| 3e9556fead | |||
| b403272389 | |||
| b5bda772af | |||
| 02ccd45bf6 | |||
| b86e7dc0e8 | |||
| 578eb8b32c | |||
| f2d7ed69ca | |||
| 746573d28b | |||
| 09dc908332 | |||
| 35bf75bc82 | |||
| cb0268dfdd | |||
| 9186b392c9 | |||
| 4f30dd32f1 | |||
| bac2b1cb71 | |||
| 57af355d85 | |||
| 9bcce48df3 | |||
| c83630b376 | |||
| e1856bf851 | |||
| fe3525bc54 | |||
| 452dcbd016 | |||
| 4b489b52ef | |||
| aa86dfa956 | |||
| 04e916b41c | |||
| e167388e74 | |||
| b8db430615 | |||
| f9d51ba415 | |||
| e07a17db29 | |||
| ad62983327 | |||
| fc8ae1b228 | |||
| 48f27afbc9 | |||
| e1532f9215 | |||
| a2279d03f6 | |||
| e52ff0ea03 | |||
| aaa8e881f8 | |||
| 14ec6b8792 | |||
| 90feb463aa | |||
| 73c4e734b3 | |||
| c85b90d65d | |||
| e923b940f9 | |||
| d29d629eae | |||
| 50b076ce38 | |||
| badb55476b | |||
| 9ecd63eaed | |||
| 5edd61107f | |||
| c21039f1af | |||
| 51f6c639bf | |||
| d9a3fa443d | |||
| 13a1c02507 | |||
| 7a9bc19ffd | |||
| 3dfe653ef4 | |||
| db4dc9006a | |||
| 212244b9f2 | |||
| 12f7492d80 | |||
| d9d68cf6bf | |||
| d94e383ed7 | |||
| 716fc582a0 | |||
| 50c9625cc6 | |||
| 5cbc428590 | |||
| db4d88b2dc | |||
| d9d54f7982 | |||
| a61a2b4d97 | |||
| 735d759208 | |||
| 65f99a9bfd | |||
| 6c23066fb7 | |||
| 717efb6b09 | |||
| 91c52cffc8 | |||
| 03e7779afb | |||
| 15562ec12f | |||
| 6e8862954a | |||
| 9c7ab96c92 | |||
| 8f17d6fcd2 | |||
| 49ca4bbc91 | |||
| 5121142760 | |||
| 4c53604bd0 | |||
| bf329aa431 | |||
| d456ee9a31 | |||
| f06d720dbd | |||
| 87839f4f6a | |||
| 02f8c4a106 | |||
| 71ad7df787 | |||
| 4b7520b6f8 | |||
| c06c996ccf | |||
| 9fe4d9c44e | |||
| 560174a21f | |||
| e34a0ec73b | |||
| 152b318d78 | |||
| 414c6b8788 | |||
| 1300389ce6 | |||
| ea8d8ba771 | |||
| 1eb6ae10c9 | |||
| 5d3e1fb95f | |||
| 19fb1a55e3 | |||
| b02a9c3e7a | |||
| e6f8309d54 | |||
| 3ecf4144e7 | |||
| 817dd21155 | |||
| 34216fd635 | |||
| c81ff85b41 | |||
| ca1ec0e4a3 | |||
| f2ae41ada2 | |||
| 90cbd69373 | |||
| 16629c78d2 | |||
| 04487557d7 | |||
| 5955ede1dc | |||
| 62463ecc21 | |||
| 5a11b1bcac | |||
| e1c22ef02c | |||
| e1d990e6e8 | |||
| ce8b29bfcc | |||
| 1c554a8770 | |||
| 4cc68912ce | |||
| e2baf50364 | |||
| dbb82cb3f8 | |||
| 11506e5548 | |||
| 7185089f1d | |||
| 050616f446 | |||
| 08d4747824 | |||
| ecfc8d819f | |||
| 30b5dd4d04 | |||
| 6b8fc66858 | |||
| d7ce71f6a7 | |||
| c2bf3d0d53 | |||
| ed6167fb0a | |||
| aef83b86d4 | |||
| 8ea6e2b855 | |||
| 8c9d115986 | |||
| 79c67e9c1b | |||
| aa90e61a97 | |||
| 59f51767b5 | |||
| f079f3d66b | |||
| 2958b42b31 | |||
| 876336d9fd | |||
| d8a9bfc22c | |||
| 7641e7a521 | |||
| 834a30b5c7 | |||
| 6a5f8c0ab8 | |||
| 4ab6ab1a1f | |||
| 94a44a2609 | |||
| 8e29dbd494 | |||
| a0896f168c | |||
| 0555f0868b | |||
| 5dc3cf45ec | |||
| 8631136444 | |||
| 7f764a4557 | |||
| e29b47069c | |||
| 73e0e3547c | |||
| 6f0ba2236f | |||
| a46d40e9ef | |||
| 2adec8ee74 | |||
| 68662e271d | |||
| cdae0adf52 | |||
| f0dd69d95c | |||
| 90c1fa4a10 | |||
| eab1e46a4b | |||
| a29f7b764f | |||
| 47ee3bf3e4 | |||
| 64154da4e4 | |||
| 4879e7164e | |||
| ed0769f74b | |||
| 0aae5c1df1 | |||
| 3223f23ce4 | |||
| 9292254aa8 | |||
| 52548316aa | |||
| 45f7e71787 | |||
| a87ca8fa1e | |||
| 6f7e1cac3e | |||
| 997b96e9d4 | |||
| afbfc0034d | |||
| 02e3a8f19c | |||
| 6a49f1f99d | |||
| 4fb0414db3 | |||
| 9a5d6afaef | |||
| 90e3b4273a | |||
| 4662b2e5d4 | |||
| 3704bfcfe8 | |||
| 013fa2e454 | |||
| 8fe8a0dfa3 | |||
| 4249f3d1ec | |||
| 759940b48f | |||
| 5cf0a3adb0 | |||
| 19f884e196 | |||
| c1de832c4b | |||
| 5a482a49bf | |||
| 46b5c18cc5 | |||
| 3a469cdc77 | |||
| f4a0546dba | |||
| 04525b014e | |||
| 8079b64684 | |||
| 53e6528e6d | |||
| 8a676947bc | |||
| 177a84273f | |||
| 02281a0ee2 | |||
| 9cf4b7b063 | |||
| f130fcc390 | |||
| 9205d2f514 | |||
| d76d9b8bcf | |||
| 20e12644e5 | |||
| 2f377dbefa | |||
| fef604d551 | |||
| 822d6cb4c0 | |||
| 0d507612cc | |||
| 0d36151e53 | |||
| 280a6d79b4 | |||
| 2f68853802 | |||
| a8f4cf73d8 | |||
| a7afb2784c | |||
| 0a486de6a2 | |||
| 1fe1762724 | |||
| 6943be9726 | |||
| d4a76f1bea | |||
| 8cf73e4ecd | |||
| 65670ab539 | |||
| c4ab4688c7 | |||
| 92dd1b0f8f | |||
| 19ac18d13a | |||
| 609786e0c3 | |||
| 382a3aba81 | |||
| de189e506f | |||
| 29ca926c50 | |||
| 684bacb937 | |||
| 6665695986 | |||
| a643f6d1f0 | |||
| aef9cb807d | |||
| fa9dae93b9 | |||
| 7b03bc20cc | |||
| 1770a0abec | |||
| 494bdfef1e | |||
| 0ac196bec6 | |||
| d933724e39 | |||
| 186e8fc58b | |||
| 30386cc96e | |||
| 1bed04f384 | |||
| e5142e4915 | |||
| 866fdadbe2 | |||
| 7edd338dd0 | |||
| abceda7750 | |||
| 969c2aa184 | |||
| a37512ffb4 | |||
| 7045eb196c | |||
| 825d8421ed | |||
| 466642af26 | |||
| 71f128d796 | |||
| 2927ff0af7 | |||
| e098b9c184 | |||
| 7660e9fb25 | |||
| fe9b964ffe | |||
| 01b82ee4e8 | |||
| 026094c1b9 | |||
| 2c34979ee8 | |||
| 65ce753925 | |||
| 94cb6cb668 | |||
| d1624fab2d | |||
| 64df1d040f | |||
| 7e9d8e5de8 | |||
| c50daf87a5 | |||
| 5e38cadacc | |||
| f814a80ab7 | |||
| 6644fc790a | |||
| fd5a2f355b | |||
| f385e1d01d | |||
| 9a264a120b | |||
| 286730c65e | |||
| 6d372fa609 | |||
| 672f57de5e | |||
| e0fa99ee56 | |||
| c62ce2ab4b | |||
| 30434eacea | |||
| b3a0cd4dd6 | |||
| 3e0f3bc782 | |||
| 9003314d56 | |||
| 2001487c1e | |||
| d7c8112a7a | |||
| df41813ce2 | |||
| 2b0cfdb143 | |||
| 95f154cc59 | |||
| 375fc62414 | |||
| 0a7a42383d | |||
| fa1c360000 | |||
| 3ffeb751b9 | |||
| 412c9ffa6e | |||
| b5da6c876b | |||
| c318bc55dc | |||
| 7aebfce579 | |||
| a9c2ec76f7 | |||
| 0c475aa174 | |||
| d16bcdc841 | |||
| f2472c321d | |||
| 3415332504 | |||
| 0a4502af60 | |||
| 0176e2f2e0 | |||
| ac44823ebb | |||
| 4443465e74 | |||
| b5a90bf26a | |||
| 3e9113f1ef | |||
| ff8f9083ec | |||
| 5d5e411219 | |||
| d0c4e44e9e | |||
| 1b6fd92087 | |||
| 3c9770c6b6 | |||
| 169e93ed81 | |||
| 4a17702849 | |||
| c6da0f3b96 | |||
| cc50a7a3ba | |||
| e19cd5f49f | |||
| 730a2f7768 | |||
| 3c2b2e2963 | |||
| 7b36e89bd3 | |||
| 7aac3dc1bf | |||
| 775ea0de3c | |||
| 1f7092e2a8 | |||
| ee4c751423 | |||
| f016d04c1f | |||
| 44929e5512 | |||
| d7d37e3d63 | |||
| 00082a87fa | |||
| 47aec9768c | |||
| 1def9014cd | |||
| 385a86b3b3 | |||
| 7d589eb607 | |||
| 7b5ff7b2eb | |||
| 22918b40bf | |||
| 06a8569570 | |||
| e6b77cf307 | |||
| 88e11396b4 | |||
| 2ca5c1d94a | |||
| 0cfe1b8348 | |||
| ca39531f45 | |||
| cdef97efba | |||
| 786c9ff3cc | |||
| 3820457536 | |||
| 7cd600e58a | |||
| f7c37fecdc | |||
| 1677442fad | |||
| ddc88af809 | |||
| 4a1c36c8d0 | |||
| 20dc1b5c10 | |||
| 810d8fa87a | |||
| 11f4e2429a | |||
| 7b84c755b3 | |||
| bb27a3f42e | |||
| 6593b704d5 | |||
| f4db356511 | |||
| f5d31a4c5a | |||
| fd01f4e7c6 | |||
| 724eca7575 | |||
| 3f314fe5be | |||
| 7f7afef976 | |||
| c4eb76faad | |||
| ed2743d570 | |||
| 88a2878cf2 | |||
| 118e31d647 | |||
| 54aa1924c0 | |||
| c00f805ea2 | |||
| 1a1222905b | |||
| 77d70c7e7f | |||
| 3d729eb2c3 | |||
| 978f59ffe8 | |||
| f71fe3f78d | |||
| 21d1b7c599 | |||
| b5bd138bf7 | |||
| 59f437ebf8 | |||
| d8574248fc | |||
| 0d963d3c4d | |||
| 5fb4e40c3b | |||
| 60ca85fe25 | |||
| 944c8d59d7 | |||
| e4a492dc57 | |||
| 154b59c84b | |||
| a77b0fc51f | |||
| 64f41541fe | |||
| a6fc9f4ede | |||
| 5342e65f7c | |||
| 0bdd1131bb | |||
| 18c8911164 | |||
| e08a7c3ea8 | |||
| a892ae1567 | |||
| 14f878b690 | |||
| 153b665d0a | |||
| e62de9561b | |||
| e35436225f | |||
| dd54b0324c | |||
| 6fdada69eb | |||
| 99887cb362 | |||
| c75ac83c98 | |||
| 0c860e999b | |||
| 3587a774f3 | |||
| 462a6168b3 | |||
| cb33442e7c | |||
| 0dd5ba61ab | |||
| 89a701c865 | |||
| 4f53cfc855 | |||
| b177607d47 | |||
| f549522573 | |||
| 521fc227ba | |||
| 612a63b6bb | |||
| 1860a175d1 | |||
| b5c803b5ed | |||
| 393b8f08c8 | |||
| 8f39cd605a | |||
| 354c45e0e2 | |||
| 065cc69f51 | |||
| 14db9da57c | |||
| e5a27a2108 | |||
| 2ab3889b23 | |||
| 5c8fad330e | |||
| 0b19eab5a9 | |||
| 42803ff006 | |||
| fb070928f7 | |||
| 68f34d5643 | |||
| 8d305b2c6a | |||
| c813aafb38 | |||
| 64d2940c3b | |||
| 2f0d8b75df | |||
| b9d554908d | |||
| bd4b4620d4 | |||
| 5566afbabb | |||
| c045d4774a | |||
| 19aae9ffdc | |||
| 218995f9e0 | |||
| 0d167c4f2d | |||
| d44e0d8664 |
@@ -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! 🎉👍
|
||||
|
||||
+5
-3
@@ -1,7 +1,9 @@
|
||||
_You are browsing the Umbraco v8 branch. Umbraco 8 is currently under development._
|
||||
[](https://pullreminders.com?ref=badge)
|
||||
[](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [](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)._
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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-beta078,1.999999)" />
|
||||
<dependency id="Examine" version="[1.0.1,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)" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
+2
-2
@@ -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")]
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
{
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
namespace Umbraco.Core.Components
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Compose
|
||||
{
|
||||
public sealed class AuditEventsComposer : ComponentComposer<AuditEventsComponent>, ICoreComposer
|
||||
{ }
|
||||
+2
-1
@@ -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
|
||||
{
|
||||
+3
-1
@@ -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
|
||||
+1
-1
@@ -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
|
||||
+3
-1
@@ -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
|
||||
+1
-1
@@ -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
|
||||
{
|
||||
+3
-1
@@ -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
|
||||
+2
-3
@@ -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))
|
||||
+2
-3
@@ -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);
|
||||
}
|
||||
+3
-1
@@ -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
-1
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a composer requires another composer.
|
||||
+1
-1
@@ -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
-2
@@ -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.
|
||||
+3
-5
@@ -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)
|
||||
{
|
||||
+2
-3
@@ -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)
|
||||
{
|
||||
+6
-6
@@ -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>();
|
||||
+3
-4
@@ -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
-3
@@ -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
-1
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a composer should be disabled.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a composer should be disabled.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a composer should be enabled.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a composer should be enabled.
|
||||
+1
-1
@@ -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.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a core <see cref="IComposer"/>.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a runtime <see cref="IComposer"/>.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace Umbraco.Core.Components
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user <see cref="IComposer"/>.
|
||||
+1
-2
@@ -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.
|
||||
@@ -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);
|
||||
|
||||
+5
-53
@@ -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>());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-37
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
/// alias for the macro tree.
|
||||
/// </summary>
|
||||
public const string Macros = "macros";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// alias for the datatype tree.
|
||||
/// </summary>
|
||||
@@ -92,7 +92,7 @@
|
||||
/// alias for the dictionary tree.
|
||||
/// </summary>
|
||||
public const string Dictionary = "dictionary";
|
||||
|
||||
|
||||
public const string Stylesheets = "stylesheets";
|
||||
|
||||
/// <summary>
|
||||
@@ -121,7 +121,7 @@
|
||||
public const string Templates = "templates";
|
||||
|
||||
public const string RelationTypes = "relationTypes";
|
||||
|
||||
|
||||
public const string Languages = "languages";
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -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.
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Components;
|
||||
using Umbraco.Core.Compose;
|
||||
using Umbraco.Core.Composing;
|
||||
|
||||
namespace Umbraco.Core.Logging.Viewer
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
{ }
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
+2
-2
@@ -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; }
|
||||
@@ -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);
|
||||
|
||||
@@ -96,6 +96,12 @@ namespace Umbraco.Core.Migrations
|
||||
return tables.Any(x => x.InvariantEquals(tableName));
|
||||
}
|
||||
|
||||
protected bool IndexExists(string indexName)
|
||||
{
|
||||
var indexes = SqlSyntax.GetDefinedIndexes(Context.Database);
|
||||
return indexes.Any(x => x.Item2.InvariantEquals(indexName));
|
||||
}
|
||||
|
||||
protected bool ColumnExists(string tableName, string columnName)
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).Distinct().ToArray();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
}
|
||||
}
|
||||
|
||||
// define the plan
|
||||
// define the plan
|
||||
protected void DefinePlan()
|
||||
{
|
||||
// MODIFYING THE PLAN
|
||||
@@ -127,8 +127,16 @@ 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}");
|
||||
|
||||
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}");
|
||||
//FINAL
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
public class AddUserLoginDtoDateIndex : MigrationBase
|
||||
{
|
||||
public AddUserLoginDtoDateIndex(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
if (!IndexExists("IX_umbracoUserLogin_lastValidatedUtc"))
|
||||
Create.Index("IX_umbracoUserLogin_lastValidatedUtc")
|
||||
.OnTable(UserLoginDto.TableName)
|
||||
.OnColumn("lastValidatedUtc")
|
||||
.Ascending()
|
||||
.WithOptions().NonClustered()
|
||||
.Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
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;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
public class RadioAndCheckboxAndDropdownPropertyEditorsMigration : MigrationBase
|
||||
{
|
||||
public RadioAndCheckboxAndDropdownPropertyEditorsMigration(IMigrationContext context)
|
||||
: base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
var refreshCache = false;
|
||||
|
||||
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.RadioButtonList, (dto, configuration) => UpdateRadioOrCheckboxPropertyDataDto(dto, configuration, true));
|
||||
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.CheckBoxList, (dto, configuration) => UpdateRadioOrCheckboxPropertyDataDto(dto, configuration, false));
|
||||
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.DropDownListFlexible, UpdateDropDownPropertyDataDto);
|
||||
|
||||
if (refreshCache)
|
||||
{
|
||||
Context.AddPostMigration<RebuildPublishedSnapshot>();
|
||||
}
|
||||
}
|
||||
|
||||
private bool Migrate(string editorAlias, Func<PropertyDataDto, ValueListConfiguration, bool> updateRadioPropertyDataFunc)
|
||||
{
|
||||
var refreshCache = false;
|
||||
var dataTypes = GetDataTypes(editorAlias);
|
||||
|
||||
foreach (var dataType in dataTypes)
|
||||
{
|
||||
ValueListConfiguration config;
|
||||
|
||||
if (dataType.Configuration.IsNullOrWhiteSpace())
|
||||
continue;
|
||||
|
||||
// parse configuration, and update everything accordingly
|
||||
try
|
||||
{
|
||||
config = (ValueListConfiguration) new ValueListConfigurationEditor().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;
|
||||
}
|
||||
|
||||
// get property data dtos
|
||||
var propertyDataDtos = Database.Fetch<PropertyDataDto>(Sql()
|
||||
.Select<PropertyDataDto>()
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>()
|
||||
.On<PropertyTypeDto, PropertyDataDto>((pt, pd) => pt.Id == pd.PropertyTypeId)
|
||||
.InnerJoin<DataTypeDto>()
|
||||
.On<DataTypeDto, PropertyTypeDto>((dt, pt) => dt.NodeId == pt.DataTypeId)
|
||||
.Where<PropertyTypeDto>(x => x.DataTypeId == dataType.NodeId));
|
||||
|
||||
// update dtos
|
||||
var updatedDtos = propertyDataDtos.Where(x => updateRadioPropertyDataFunc(x, config));
|
||||
|
||||
// persist changes
|
||||
foreach (var propertyDataDto in updatedDtos) Database.Update(propertyDataDto);
|
||||
|
||||
UpdateDataType(dataType);
|
||||
refreshCache = true;
|
||||
}
|
||||
|
||||
return refreshCache;
|
||||
}
|
||||
|
||||
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 void UpdateDataType(DataTypeDto dataType)
|
||||
{
|
||||
dataType.DbType = ValueStorageType.Nvarchar.ToString();
|
||||
Database.Update(dataType);
|
||||
}
|
||||
|
||||
private bool UpdateRadioOrCheckboxPropertyDataDto(PropertyDataDto propData, ValueListConfiguration config, bool singleValue)
|
||||
{
|
||||
//Get the INT ids stored for this property/drop down
|
||||
int[] ids = null;
|
||||
if (!propData.VarcharValue.IsNullOrWhiteSpace())
|
||||
{
|
||||
ids = ConvertStringValues(propData.VarcharValue);
|
||||
}
|
||||
else if (!propData.TextValue.IsNullOrWhiteSpace())
|
||||
{
|
||||
ids = ConvertStringValues(propData.TextValue);
|
||||
}
|
||||
else if (propData.IntegerValue.HasValue)
|
||||
{
|
||||
ids = new[] {propData.IntegerValue.Value};
|
||||
}
|
||||
|
||||
//if there are INT ids, convert them to values based on the configuration
|
||||
if (ids == null || ids.Length <= 0) return false;
|
||||
|
||||
//map the ids to values
|
||||
var values = new List<string>();
|
||||
var canConvert = true;
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
var val = config.Items.FirstOrDefault(x => x.Id == id);
|
||||
if (val != null)
|
||||
values.Add(val.Value);
|
||||
else
|
||||
{
|
||||
Logger.Warn<DropDownPropertyEditorsMigration>(
|
||||
"Could not find associated data type configuration for stored Id {DataTypeId}", id);
|
||||
canConvert = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!canConvert) return false;
|
||||
|
||||
//The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first
|
||||
propData.VarcharValue = singleValue ? values[0] : JsonConvert.SerializeObject(values);
|
||||
propData.TextValue = null;
|
||||
propData.IntegerValue = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool UpdateDropDownPropertyDataDto(PropertyDataDto propData, ValueListConfiguration config)
|
||||
{
|
||||
//Get the INT ids stored for this property/drop down
|
||||
var values = propData.VarcharValue.Split(new []{","}, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
//if there are INT ids, convert them to values based on the configuration
|
||||
if (values == null || values.Length <= 0) return false;
|
||||
|
||||
//The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first
|
||||
propData.VarcharValue = JsonConvert.SerializeObject(values);
|
||||
propData.TextValue = null;
|
||||
propData.IntegerValue = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private int[] ConvertStringValues(string val)
|
||||
{
|
||||
var splitVals = val.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var intVals = splitVals
|
||||
.Select(x => int.TryParse(x, out var i) ? i : int.MinValue)
|
||||
.Where(x => x != int.MinValue)
|
||||
.ToArray();
|
||||
|
||||
//only return if the number of values are the same (i.e. All INTs)
|
||||
if (splitVals.Length == intVals.Length)
|
||||
return intVals;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ValueListConfigurationEditor : ConfigurationEditor<ValueListConfiguration>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>>(
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
// actually OK as IsPublishing is constant
|
||||
// ReSharper disable once VirtualMemberCallInConstructor
|
||||
_noGroupPropertyTypes = new PropertyTypeCollection(IsPublishing);
|
||||
_noGroupPropertyTypes = new PropertyTypeCollection(SupportsPublishing);
|
||||
_noGroupPropertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
|
||||
_variations = ContentVariation.Nothing;
|
||||
@@ -61,7 +61,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
// actually OK as IsPublishing is constant
|
||||
// ReSharper disable once VirtualMemberCallInConstructor
|
||||
_noGroupPropertyTypes = new PropertyTypeCollection(IsPublishing);
|
||||
_noGroupPropertyTypes = new PropertyTypeCollection(SupportsPublishing);
|
||||
_noGroupPropertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
|
||||
_variations = ContentVariation.Nothing;
|
||||
@@ -70,7 +70,7 @@ namespace Umbraco.Core.Models
|
||||
public abstract ISimpleContentType ToSimple();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content type is publishing.
|
||||
/// Gets a value indicating whether the content type supports publishing.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>A publishing content type supports draft and published values for properties.
|
||||
@@ -80,7 +80,7 @@ namespace Umbraco.Core.Models
|
||||
/// the draft or published value of a property returns the same thing, and publishing
|
||||
/// a value property has no effect.</para>
|
||||
/// </remarks>
|
||||
public abstract bool IsPublishing { get; }
|
||||
public abstract bool SupportsPublishing { get; }
|
||||
|
||||
//Custom comparer for enumerable
|
||||
private static readonly DelegateEqualityComparer<IEnumerable<ContentTypeSort>> ContentTypeSortComparer =
|
||||
@@ -257,7 +257,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (_noGroupPropertyTypes != null)
|
||||
_noGroupPropertyTypes.CollectionChanged -= PropertyTypesChanged;
|
||||
_noGroupPropertyTypes = new PropertyTypeCollection(IsPublishing, value);
|
||||
_noGroupPropertyTypes = new PropertyTypeCollection(SupportsPublishing, value);
|
||||
_noGroupPropertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
PropertyTypesChanged(_noGroupPropertyTypes, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ namespace Umbraco.Core.Models
|
||||
return null;
|
||||
|
||||
// create the new group
|
||||
var group = new PropertyGroup(IsPublishing) { Name = name, SortOrder = 0 };
|
||||
var group = new PropertyGroup(SupportsPublishing) { Name = name, SortOrder = 0 };
|
||||
|
||||
// check if it is inherited - there might be more than 1 but we want the 1st, to
|
||||
// reuse its sort order - if there are more than 1 and they have different sort
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public class MediaType : ContentTypeCompositionBase, IMediaType
|
||||
{
|
||||
public const bool IsPublishingConst = false;
|
||||
public const bool SupportsPublishingConst = false;
|
||||
|
||||
/// <summary>
|
||||
/// Constuctor for creating a MediaType with the parent's id.
|
||||
@@ -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;
|
||||
|
||||
/// <inheritdoc />
|
||||
IMediaType IMediaType.DeepCloneWithResetIdentities(string newAlias) => (IMediaType)DeepCloneWithResetIdentities(newAlias);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public class MemberType : ContentTypeCompositionBase, IMemberType
|
||||
{
|
||||
public const bool IsPublishingConst = false;
|
||||
public const bool SupportsPublishingConst = false;
|
||||
|
||||
//Dictionary is divided into string: PropertyTypeAlias, Tuple: MemberCanEdit, VisibleOnProfile, PropertyTypeId
|
||||
private string _alias;
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Core.Models
|
||||
public override ISimpleContentType ToSimple() => new SimpleContentType(this);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsPublishing => IsPublishingConst;
|
||||
public override bool SupportsPublishing => SupportsPublishingConst;
|
||||
|
||||
public override ContentVariation Variations
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Umbraco.Core.Models.Packaging
|
||||
public RequirementsType UmbracoVersionRequirementsType { get; set; }
|
||||
public string Author { get; set; }
|
||||
public string AuthorUrl { get; set; }
|
||||
public IList<string> Contributors { get; set; }
|
||||
public string Readme { get; set; }
|
||||
public string PackageView { get; set; }
|
||||
public string IconUrl { get; set; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Packaging
|
||||
{
|
||||
@@ -12,6 +13,7 @@ namespace Umbraco.Core.Models.Packaging
|
||||
Version UmbracoVersion { get; }
|
||||
string Author { get; }
|
||||
string AuthorUrl { get; }
|
||||
IList<string> Contributors { get; }
|
||||
string Readme { get; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Umbraco.Core.Models.Packaging
|
||||
Actions = compiled.Actions,
|
||||
Author = compiled.Author,
|
||||
AuthorUrl = compiled.AuthorUrl,
|
||||
Contributors = compiled.Contributors,
|
||||
PackageView = compiled.PackageView,
|
||||
IconUrl = compiled.IconUrl,
|
||||
License = compiled.License,
|
||||
@@ -79,6 +80,9 @@ namespace Umbraco.Core.Models.Packaging
|
||||
[Url]
|
||||
public string AuthorUrl { get; set; } = string.Empty;
|
||||
|
||||
[DataMember(Name = "contributors")]
|
||||
public IList<string> Contributors { get; set; } = new List<string>();
|
||||
|
||||
[DataMember(Name = "license")]
|
||||
public string License { get; set; } = "MIT License";
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (pvalue == null) return null;
|
||||
|
||||
return PropertyType.IsPublishing
|
||||
return PropertyType.SupportsPublishing
|
||||
? (published ? pvalue.PublishedValue : pvalue.EditedValue)
|
||||
: pvalue.EditedValue;
|
||||
}
|
||||
@@ -244,7 +244,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (pvalue == null) return;
|
||||
|
||||
if (!PropertyType.IsPublishing)
|
||||
if (!PropertyType.SupportsPublishing)
|
||||
throw new NotSupportedException("Property type does not support publishing.");
|
||||
var origValue = pvalue.PublishedValue;
|
||||
pvalue.PublishedValue = PropertyType.ConvertAssignedValue(pvalue.EditedValue);
|
||||
@@ -255,7 +255,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (pvalue == null) return;
|
||||
|
||||
if (!PropertyType.IsPublishing)
|
||||
if (!PropertyType.SupportsPublishing)
|
||||
throw new NotSupportedException("Property type does not support publishing.");
|
||||
var origValue = pvalue.PublishedValue;
|
||||
pvalue.PublishedValue = PropertyType.ConvertAssignedValue(null);
|
||||
@@ -288,7 +288,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
var (pvalue, _) = GetPValue(culture, segment, true);
|
||||
|
||||
if (published && PropertyType.IsPublishing)
|
||||
if (published && PropertyType.SupportsPublishing)
|
||||
pvalue.PublishedValue = value;
|
||||
else
|
||||
pvalue.EditedValue = value;
|
||||
@@ -332,56 +332,6 @@ namespace Umbraco.Core.Models
|
||||
return (pvalue, change);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the property has valid values.
|
||||
/// </summary>
|
||||
internal bool IsValid(string culture = "*", string segment = "*")
|
||||
{
|
||||
// TODO: validating values shouldn't be done here, this calls in to IsValidValue
|
||||
|
||||
culture = culture.NullOrWhiteSpaceAsNull();
|
||||
segment = segment.NullOrWhiteSpaceAsNull();
|
||||
|
||||
// if validating invariant/neutral, and it is supported, validate
|
||||
// (including ensuring that the value exists, if mandatory)
|
||||
if ((culture == null || culture == "*") && (segment == null || segment == "*") && PropertyType.SupportsVariation(null, null))
|
||||
if (!IsValidValue(_pvalue?.EditedValue))
|
||||
return false;
|
||||
|
||||
// if validating only invariant/neutral, we are good
|
||||
if (culture == null && segment == null)
|
||||
return true;
|
||||
|
||||
// if nothing else to validate, we are good
|
||||
if ((culture == null || culture == "*") && (segment == null || segment == "*") && !PropertyType.VariesByCulture())
|
||||
return true;
|
||||
|
||||
// for anything else, validate the existing values (including mandatory),
|
||||
// but we cannot validate mandatory globally (we don't know the possible cultures and segments)
|
||||
|
||||
if (_vvalues == null) return culture == "*" || IsValidValue(null);
|
||||
|
||||
var pvalues = _vvalues.Where(x =>
|
||||
PropertyType.SupportsVariation(x.Value.Culture, x.Value.Segment, true) && // the value variation is ok
|
||||
(culture == "*" || x.Value.Culture.InvariantEquals(culture)) && // the culture matches
|
||||
(segment == "*" || x.Value.Segment.InvariantEquals(segment))) // the segment matches
|
||||
.Select(x => x.Value)
|
||||
.ToList();
|
||||
|
||||
return pvalues.Count == 0 || pvalues.All(x => IsValidValue(x.EditedValue));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the passed in value is valid
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns>True is property value is valid, otherwise false</returns>
|
||||
private bool IsValidValue(object value)
|
||||
{
|
||||
// TODO: this shouldn't exist here, the model itself shouldn't be responsible for it's own validation and this requires singleton access
|
||||
return PropertyType.IsPropertyValueValid(value);
|
||||
}
|
||||
|
||||
protected override void PerformDeepClone(object clone)
|
||||
{
|
||||
base.PerformDeepClone(clone);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user