Compare commits
498 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 21426610ad | |||
| 40b0a62cc3 | |||
| 3949b78c61 | |||
| 55179d7400 | |||
| 517147346e | |||
| e1e63d079f | |||
| 86744046e3 | |||
| a5f1c3e564 | |||
| 2b2734cd66 | |||
| c2d33f3301 | |||
| 8fc999f771 | |||
| be0fb51193 | |||
| 097f5355e2 | |||
| 843fad9963 | |||
| 7b5670f275 | |||
| f4410891e4 | |||
| 9da95ce28f | |||
| 33e05625ed | |||
| b8575d04ad | |||
| b64b67ce81 | |||
| 1b6a2c7d5c | |||
| a1a90d5bff | |||
| 08733d7351 | |||
| 5d0d65c624 | |||
| 6c7c333d8f | |||
| b039fbfb13 | |||
| 428bc7fbad | |||
| fe9686f215 | |||
| e4a472f902 | |||
| 900f8970f0 | |||
| dd6c24d3b8 | |||
| 8175e68ecd | |||
| c839285f90 | |||
| 21378a07c8 | |||
| 74e6633f2a | |||
| 8693b13e68 | |||
| a0a861370b | |||
| 7282626c0f | |||
| cf604255fc | |||
| b275850aca | |||
| 8aa36a82c4 | |||
| 06132fcdaf | |||
| f1e5b3fcfa | |||
| fba4b91bec | |||
| 0ef987207b | |||
| 2d7b5b959e | |||
| 2837861d9a | |||
| 212222c98e | |||
| 15237a6d91 | |||
| 95b2ef0f3c | |||
| c452d31f25 | |||
| 7361d1f16f | |||
| 7ffb22a40f | |||
| f78e496e69 | |||
| 48ed511ba5 | |||
| 3cff6fdd6c | |||
| 81da2e49f7 | |||
| 2cd6427958 | |||
| 061f1ae0b1 | |||
| f503cd41de | |||
| 4428877158 | |||
| 876f61ac27 | |||
| 2cc541e084 | |||
| ddd3c78fa6 | |||
| 62dffedc02 | |||
| 13e5409ab2 | |||
| 927e9cf14a | |||
| 7611829f2e | |||
| 1ff5d171e3 | |||
| b8aaebf51a | |||
| 2c9bc5135c | |||
| 248177f518 | |||
| d34901fd13 | |||
| 94b12dfb02 | |||
| 0cc88a1706 | |||
| 78524398b7 | |||
| f97123015a | |||
| b1e6559f4d | |||
| 9d9c36b253 | |||
| 6d9a747b34 | |||
| a28cd8a54f | |||
| 44ad842542 | |||
| 917e05a16c | |||
| e60d5c8f2c | |||
| 03f16dfb78 | |||
| c9106065fd | |||
| 2c9e96406b | |||
| 21c7d6a667 | |||
| e0f95f18d3 | |||
| b9ffbe9a57 | |||
| dc9b2b3ca8 | |||
| baafa604fe | |||
| e79bfebb76 | |||
| 131fdab675 | |||
| efc2a8e2ea | |||
| d725f1362f | |||
| e79427619b | |||
| 4887302b51 | |||
| aea735f20e | |||
| 7a34b490c7 | |||
| 8091d9a098 | |||
| e2e6440109 | |||
| caffb36ec2 | |||
| 0d054de6ac | |||
| 5397f2c53a | |||
| 61b11025bd | |||
| 8c8a0160a1 | |||
| cbd980357b | |||
| 8b37f1dc6c | |||
| 6ec7028fe8 | |||
| 14c0055899 | |||
| e0981f1c44 | |||
| 2ca7304215 | |||
| 88f8052573 | |||
| 5afeb315ba | |||
| c2eeff6e47 | |||
| 893c2a99be | |||
| 9da18d0697 | |||
| 3bb991edd3 | |||
| dd0373b855 | |||
| 48786fcae1 | |||
| 28b4945d36 | |||
| 4a5314d8b9 | |||
| c67adcc43f | |||
| 0a43fea1c0 | |||
| a20b7f9303 | |||
| 5b9b6be383 | |||
| fce0a4b0eb | |||
| 381de750e7 | |||
| 40f6de950c | |||
| 916c350352 | |||
| 4186791d9a | |||
| 02cef43815 | |||
| 8d291efedd | |||
| a5c8052439 | |||
| 704169abab | |||
| 8ee8b52832 | |||
| 81819aa3b7 | |||
| 90ffae5526 | |||
| a3c99531bf | |||
| 1b6bf2f331 | |||
| f5d18157bf | |||
| 7c7dd0736e | |||
| 0a5cd9f113 | |||
| 9b498b8471 | |||
| fee217e8d7 | |||
| c05a28a901 | |||
| fa45cd1a88 | |||
| 6cb5331918 | |||
| fca865a743 | |||
| 1f313b9487 | |||
| 85d243508c | |||
| 365da75d1b | |||
| a74feab9eb | |||
| ae591d4883 | |||
| 3489bf22bb | |||
| 9e82b8d693 | |||
| 71482f0fc9 | |||
| 8216fa1d88 | |||
| 4133574db0 | |||
| af5455a500 | |||
| be57692a62 | |||
| 460d884109 | |||
| 1a1a3c43ca | |||
| 6df6b87c4c | |||
| 172895f17f | |||
| 8d3add8834 | |||
| ae257550da | |||
| 4653746117 | |||
| 84bd22190b | |||
| 5e58e0d0a5 | |||
| 8b2fa22b90 | |||
| f76fd360f1 | |||
| bc9a6abccf | |||
| 39ebb9545d | |||
| 6572eea915 | |||
| 99ad5d6826 | |||
| 2a1697b0a3 | |||
| 583a09260e | |||
| 344dab65d4 | |||
| 9f5a9f179f | |||
| f658613fad | |||
| 1216f4a49e | |||
| 460e72fc1f | |||
| 908c8837e9 | |||
| 11c720cc2a | |||
| c93b4fa1fe | |||
| d409d17189 | |||
| 38c876bb53 | |||
| 95fb7f97d0 | |||
| 9dfa9e2fb6 | |||
| 6ee8382ff3 | |||
| 69fb5e9932 | |||
| ca9f3bbd5a | |||
| fe7efa4fba | |||
| 1ec2cc430b | |||
| c1a8ea9df3 | |||
| cd2c79e7d5 | |||
| d5d0a958d3 | |||
| 9e9e51cf29 | |||
| 808793edd8 | |||
| 3895a93b61 | |||
| eadb9ba276 | |||
| fc582b0516 | |||
| 432fac7dc9 | |||
| fad69046df | |||
| 6bcadfea44 | |||
| a3c457e50b | |||
| b2a56fa58f | |||
| f97c20253a | |||
| 51f57eb5ce | |||
| 54e82f9ed1 | |||
| 2ff3ce933b | |||
| 1c15daca52 | |||
| de2d4bef13 | |||
| 8c6f56d3f5 | |||
| 2f0b26db47 | |||
| 1fd020a0f2 | |||
| e12c294150 | |||
| 8d1d394ded | |||
| 3274965c34 | |||
| 54fb1c6231 | |||
| d3ff1cbba9 | |||
| f4072bc975 | |||
| 31e0913488 | |||
| f55e673632 | |||
| f1087fce3c | |||
| 5620074790 | |||
| 600d7be2ac | |||
| 596888a8f6 | |||
| 0f0a0a186c | |||
| 200f0bb67e | |||
| af1be7f32f | |||
| d355d2609a | |||
| 06da9f4f7d | |||
| 5bd5bf87ad | |||
| db78e26647 | |||
| a2adfe4798 | |||
| a7b19e1acf | |||
| a92aa6ad9a | |||
| 154e4a19a5 | |||
| 0142bc61bc | |||
| d99a691bdc | |||
| 10422079b6 | |||
| c1da28dd47 | |||
| 2018dab869 | |||
| 5b88f35471 | |||
| 2ee71ecb96 | |||
| 213a25e3fe | |||
| 14b527a9fa | |||
| 2d25c4dad5 | |||
| 8bdf0924de | |||
| 1b85163a7f | |||
| 634dfaaf75 | |||
| 2279e6cc53 | |||
| 82c5b91deb | |||
| 9d2efdfb37 | |||
| 952cfc6d5f | |||
| ff2311d19c | |||
| ef64098f4e | |||
| 611acf8cea | |||
| 910e6b7a64 | |||
| bffd9c340d | |||
| df116555ad | |||
| ca7e9c90b9 | |||
| 65fc23dadc | |||
| 3ac7512a98 | |||
| a553fabce4 | |||
| 2a2453a969 | |||
| f4711a4473 | |||
| 2069c585fb | |||
| 045374993f | |||
| 57923866ed | |||
| bf61956b7f | |||
| 9ad84a7eab | |||
| 4301af108f | |||
| c331ba134a | |||
| 7d4e547b8d | |||
| cbd20cb9b3 | |||
| 3170d6829a | |||
| 55752abdcf | |||
| 69c952ddda | |||
| 4ff728b62a | |||
| 1b9a3e8ebc | |||
| fee4a84c66 | |||
| ad2a644bdf | |||
| f4b0700528 | |||
| 126c358546 | |||
| f316393955 | |||
| 80d579891b | |||
| bfc2e6f666 | |||
| c3035f26a7 | |||
| b2e03dcc1b | |||
| 97a765d6af | |||
| 67430392e3 | |||
| 6560f752d6 | |||
| e02575830f | |||
| a838d20c3e | |||
| 081284bc62 | |||
| 9e9c1ad030 | |||
| 32d48b12d1 | |||
| b4b91f0fef | |||
| cbf67a4399 | |||
| f58e0dc08e | |||
| e449c237be | |||
| 1dae6724cc | |||
| a28c52aa16 | |||
| 26708ae82b | |||
| 809970bc2e | |||
| 27d041c055 | |||
| 7bf3d04a25 | |||
| 87934e52dc | |||
| 4022c3cec9 | |||
| 816107a348 | |||
| aedba40b54 | |||
| 31b17e3048 | |||
| 42666403a6 | |||
| aa66fd6e33 | |||
| 19325ac522 | |||
| b8b30bdc6e | |||
| 69b6044bc6 | |||
| 18a1aa2f6f | |||
| 92f7782ab9 | |||
| 3e932ecf3f | |||
| dd62a917fd | |||
| 958e20356c | |||
| 1f8dc9a424 | |||
| 539637720f | |||
| 6a3f146da1 | |||
| 7fe7f88c98 | |||
| 774f00d4f5 | |||
| aab2c65aaa | |||
| 3dcba7a6b0 | |||
| 3ece30bd8b | |||
| 36a191464d | |||
| 9131b73cbb | |||
| 68b3ea349e | |||
| 2f0ba3ac07 | |||
| 6c271d92f9 | |||
| e1daa79bab | |||
| a136235c72 | |||
| e8e440516f | |||
| b2e7c7a8d4 | |||
| 2c15db5950 | |||
| 7ed240d510 | |||
| a91b8e0acf | |||
| 0be81aa4e5 | |||
| 221edc76cf | |||
| 0280d832b5 | |||
| 875070fed8 | |||
| 9d62b2f5f9 | |||
| 548c7845cb | |||
| 9c7052f0fd | |||
| 177b61bbf5 | |||
| 8038016b55 | |||
| ae0ad2becf | |||
| ba11de51e3 | |||
| ccaa198e25 | |||
| 66c0d9dc12 | |||
| 59c3d6a206 | |||
| 0ab145e4ac | |||
| 423588d018 | |||
| 16afab86f3 | |||
| 43737e78fb | |||
| f6943ceab4 | |||
| 6495077568 | |||
| c61a9ee433 | |||
| b7264b58f9 | |||
| ba5be0e22a | |||
| d8f68f5f9b | |||
| b365a9944f | |||
| 5b2bcdbfac | |||
| abb994cf30 | |||
| 6e480058b9 | |||
| 912a460bd8 | |||
| 52d366bb6f | |||
| 2ddbca8861 | |||
| e66eefbbd7 | |||
| f1d9775a0f | |||
| 1aa2845b4a | |||
| 1c88117498 | |||
| 6237d4a3e5 | |||
| 77cbdcf38f | |||
| 85a3abf643 | |||
| c53a04d658 | |||
| b4d5140d07 | |||
| 11cafa2c4c | |||
| a5f3b50699 | |||
| 00bc454080 | |||
| 67cd4aeb59 | |||
| b4ea03cdf3 | |||
| c8d7a62a47 | |||
| b9fcda8f39 | |||
| e020779a14 | |||
| d611ae85e1 | |||
| 2df8f55032 | |||
| 6788e8954e | |||
| 080da771ff | |||
| 08b3b635b4 | |||
| 8e411069f4 | |||
| 7d0c92937a | |||
| 1ca6674095 | |||
| 3ebb3dc544 | |||
| 1f6caa0164 | |||
| 6adccb66dd | |||
| 6837dd2ce8 | |||
| b686fa74c9 | |||
| 22d12f3abc | |||
| bb4671faf1 | |||
| 57d2901c2e | |||
| 9914ab6c59 | |||
| ccd03cb1f2 | |||
| 89fd31085c | |||
| e53b81b627 | |||
| 385c53936e | |||
| be8a52e7b6 | |||
| 3cdf80a82b | |||
| b631db14c3 | |||
| 5f7859a8c1 | |||
| 1a2f7b8788 | |||
| 39aca137a4 | |||
| 88c6b0450e | |||
| 9ae339f17b | |||
| b1f13cdbb2 | |||
| 1636c16954 | |||
| f7f736fe63 | |||
| ba6736dbb3 | |||
| 29be571afd | |||
| c5b9e6a194 | |||
| 2cad3838f4 | |||
| c955cce28d | |||
| bb376367d6 | |||
| a83b524130 | |||
| dcdd47dff4 | |||
| c6a2d41888 | |||
| d37b65adcf | |||
| 379a0d68f7 | |||
| c206965f88 | |||
| 8fd1743bce | |||
| 4acfd1dcca | |||
| 67234ef115 | |||
| de89f555d4 | |||
| 9f36d2b7c6 | |||
| 2aa27dcf8c | |||
| 43da97332c | |||
| 379661e302 | |||
| 5f3f698ffd | |||
| 4ab200d538 | |||
| 55fad36bad | |||
| 99a7aa53a1 | |||
| d783554476 | |||
| 5444b65eaf | |||
| c4400a20d6 | |||
| 32d59bb2bc | |||
| 6c6c56645d | |||
| be16e84dbb | |||
| a4fec9dd0f | |||
| 3f2ebbda59 | |||
| ed392cd252 | |||
| 0fe24a45ff | |||
| b290e6af8a | |||
| 6e440f0f69 | |||
| 2eaa2b3166 | |||
| a0caab410e | |||
| 05ebc9dfa7 | |||
| f4a2990819 | |||
| dc476dcb02 | |||
| 0603cb3ab1 | |||
| d81a95dbdc | |||
| 576539c774 | |||
| 4786a8037c | |||
| e7f0eda504 | |||
| b9b3de0b01 | |||
| 826b9e9cc3 | |||
| 4b08442652 | |||
| fdd1a89fb3 | |||
| 29e45534c5 | |||
| 889ef47fd2 | |||
| 8d55a55a80 | |||
| 944898d6e5 | |||
| f247e1b66f | |||
| 2e9e8f23e9 | |||
| a099c40d93 | |||
| 952ff74899 | |||
| 3f5729767d | |||
| def690b8c3 | |||
| b168923d5f | |||
| 1fc17e6f46 | |||
| 695c69af7f | |||
| 0607782028 | |||
| 45ff11b884 | |||
| e39f818389 | |||
| e2aee08959 | |||
| 5fab1ca207 | |||
| 02ffaa9ee8 | |||
| 89cd2f50d7 | |||
| c10534a064 | |||
| f5ceab82f1 |
@@ -3,11 +3,13 @@ Umbraco CMS
|
||||
Umbraco is a free open source Content Management System built on the ASP.NET platform.
|
||||
|
||||
## Building Umbraco from source ##
|
||||
The easiest way to get started is to run `build/build.bat` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `grunt dev` in `src\Umbraco.Web.UI.Client`.
|
||||
The easiest way to get started is to run `build/build.bat` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `grunt vs` in `src\Umbraco.Web.UI.Client`.
|
||||
|
||||
If you're interested in making changes to Belle make sure to read the [Belle ReadMe file](src/Umbraco.Web.UI.Client/README.md). Note that you can always [download a nightly build](http://nightly.umbraco.org/umbraco%207.0.0/) so you don't have to build the code yourself.
|
||||
If you're interested in making changes to Belle without running Visual Studio make sure to read the [Belle ReadMe file](src/Umbraco.Web.UI.Client/README.md).
|
||||
|
||||
## Watch a introduction video ##
|
||||
Note that you can always [download a nightly build](http://nightly.umbraco.org/?container=umbraco-750) so you don't have to build the code yourself.
|
||||
|
||||
## Watch an introduction video ##
|
||||
|
||||
[](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/)
|
||||
|
||||
|
||||
@@ -35,7 +35,18 @@ test:
|
||||
assemblies: src\Umbraco.Tests\bin\Debug\Umbraco.Tests.dll
|
||||
artifacts:
|
||||
- path: build\UmbracoCms.*
|
||||
name: UmbracoFiles
|
||||
- path: build\msbuild.log
|
||||
name: BuildLog
|
||||
deploy:
|
||||
- provider: AzureBlob
|
||||
storage_account_name: umbraconightlies
|
||||
storage_access_key:
|
||||
secure: bmEMml2SF7QLHULiePa/a01XOeIa2SxJeXuaZ+1R27b+Vb2nNUQVYiPlUyF2cZAFSHI/zO/LekRsVU1rTescGhJjF7SSjKybymI3p+F/OWpwqiu2WfFee1ofXBFx8QHw
|
||||
container: umbraco-750
|
||||
artifact: UmbracoFiles
|
||||
on:
|
||||
branch: dev-v7
|
||||
notifications:
|
||||
- provider: Slack
|
||||
auth_token:
|
||||
|
||||
+42
-11
@@ -1,23 +1,33 @@
|
||||
@ECHO OFF
|
||||
SETLOCAL
|
||||
REM SETLOCAL is on, so changes to the path not persist to the actual user's path
|
||||
:: SETLOCAL is on, so changes to the path not persist to the actual user's path
|
||||
|
||||
git.exe --version
|
||||
if %ERRORLEVEL%==9009 GOTO :trydefaultpath
|
||||
IF %ERRORLEVEL%==9009 GOTO :trydefaultpath
|
||||
GOTO :EOF
|
||||
:: Git is installed, no need to to anything else
|
||||
|
||||
:trydefaultpath
|
||||
path=C:\Program Files (x86)\Git\cmd;C:\Program Files\Git\cmd;%PATH%
|
||||
PATH=C:\Program Files (x86)\Git\cmd;C:\Program Files\Git\cmd;%PATH%
|
||||
git.exe --version
|
||||
if %ERRORLEVEL%==9009 GOTO :showerror
|
||||
IF %ERRORLEVEL%==9009 GOTO :showerror
|
||||
GOTO :EOF
|
||||
:: Git is installed, no need to to anything else
|
||||
|
||||
:showerror
|
||||
ECHO Git is not in your path and could not be found in C:\Program Files (x86)\Git\cmd nor in C:\Program Files\Git\cmd
|
||||
set /p install=" Do you want to install Git through Chocolatey [y/n]? " %=%
|
||||
if %install%==y (
|
||||
SET /p install=" Do you want to install Git through Chocolatey [y/n]? " %=%
|
||||
IF %install%==y (
|
||||
:: Create a temporary batch file to execute either after elevating to admin or as-is when the user is already admin
|
||||
ECHO @ECHO OFF > "%temp%\ChocoInstallGit.cmd"
|
||||
ECHO SETLOCAL >> "%temp%\ChocoInstallGit.cmd"
|
||||
ECHO ECHO Installing Chocolatey first >> "%temp%\ChocoInstallGit.cmd"
|
||||
ECHO @powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" >> "%temp%\ChocoInstallGit.cmd"
|
||||
ECHO SET PATH=%%PATH%%;%%ALLUSERSPROFILE%%\chocolatey\bin >> "%temp%\ChocoInstallGit.cmd"
|
||||
ECHO choco install git -y >> "%temp%\ChocoInstallGit.cmd"
|
||||
|
||||
GOTO :installgit
|
||||
) else (
|
||||
) ELSE (
|
||||
GOTO :cantcontinue
|
||||
)
|
||||
|
||||
@@ -26,7 +36,28 @@ ECHO Can't complete the build without Git being in the path. Please add it to be
|
||||
GOTO :EOF
|
||||
|
||||
:installgit
|
||||
ECHO Installing Chocolatey first
|
||||
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
|
||||
ECHO Installing Git through Chocolatey
|
||||
choco install git
|
||||
pushd %~dp0
|
||||
:: Running prompt elevated
|
||||
|
||||
:: --> Check for permissions
|
||||
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
|
||||
|
||||
:: --> If error flag set, we do not have admin.
|
||||
IF '%errorlevel%' NEQ '0' (
|
||||
GOTO UACPrompt
|
||||
) ELSE ( GOTO gotAdmin )
|
||||
|
||||
:UACPrompt
|
||||
ECHO You're not currently running this with admin privileges, we'll now try to execute the install of Git through Chocolatey after elevating to admin privileges
|
||||
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
|
||||
ECHO UAC.ShellExecute "%temp%\ChocoInstallGit.cmd", "", "", "runas", 1 >> "%temp%\getadmin.vbs"
|
||||
|
||||
"%temp%\getadmin.vbs"
|
||||
EXIT /B
|
||||
|
||||
:gotAdmin
|
||||
IF EXIST "%temp%\getadmin.vbs" ( DEL "%temp%\getadmin.vbs" )
|
||||
pushd "%CD%"
|
||||
CD /D "%~dp0"
|
||||
|
||||
CALL "%temp%\ChocoInstallGit.cmd"
|
||||
@@ -27,14 +27,14 @@
|
||||
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.9.8, 7.0.0)" />
|
||||
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.9.0-beta4, 2.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.9.1, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
|
||||
<!-- AutoMapper can not be updated due to: https://github.com/AutoMapper/AutoMapper/issues/373#issuecomment-127644405 -->
|
||||
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 9.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.69-beta, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.4.3, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.6.3, 5.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.70, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.4.5, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.6.6, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 2.0.0)" />
|
||||
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
|
||||
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 9.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.3, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.4, 4.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
@@ -45,4 +45,4 @@
|
||||
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
|
||||
<file src="build\**" target="build" />
|
||||
</files>
|
||||
</package>
|
||||
</package>
|
||||
|
||||
@@ -21,6 +21,12 @@
|
||||
</section>
|
||||
|
||||
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
|
||||
<areas xdt:Transform="InsertIfMissing">
|
||||
<area xdt:Transform="InsertIfMissing">developer</area>
|
||||
</areas>
|
||||
</section>
|
||||
|
||||
<section alias="StartupDeveloperDashboardSection">
|
||||
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Replace">
|
||||
<control showOnce="true" addPanel="true" panelCaption="">
|
||||
views/dashboard/developer/developerdashboardvideos.html
|
||||
@@ -30,16 +36,21 @@
|
||||
</section>
|
||||
|
||||
<section alias="StartupDeveloperDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
|
||||
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
|
||||
<tab caption="Examine Management" xdt:Locator="Match(caption)" xdt:Transform="InsertIfMissing">
|
||||
<control>
|
||||
views/dashboard/developer/examinemanagement.html
|
||||
</control>
|
||||
</tab>
|
||||
<tab caption="Xml Data Integrity Report" xdt:Transform="InsertIfMissing">
|
||||
</tab>
|
||||
<tab caption="Health Check" xdt:Transform="InsertIfMissing" xdt:Locator="Match(caption)">
|
||||
<control>
|
||||
views/dashboard/developer/xmldataintegrityreport.html
|
||||
views/dashboard/developer/healthcheck.html
|
||||
</control>
|
||||
</tab>
|
||||
</tab>
|
||||
<tab caption="Redirect URL Management" xdt:Transform="InsertIfMissing" xdt:Locator="Match(caption)">
|
||||
<control>
|
||||
views/dashboard/developer/redirecturls.html
|
||||
</control>
|
||||
</tab>
|
||||
</section>
|
||||
|
||||
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
|
||||
@@ -52,19 +63,6 @@
|
||||
</tab>
|
||||
</section>
|
||||
|
||||
<section alias="StartupDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
|
||||
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
<tab caption="Get Started" xdt:Transform="Insert">
|
||||
<access>
|
||||
<grant>admin</grant>
|
||||
</access>
|
||||
<control showOnce="true" addPanel="true" panelCaption="">
|
||||
views/dashboard/default/startupdashboardintro.html
|
||||
</control>
|
||||
</tab>
|
||||
<tab caption="Last Edits" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
</section>
|
||||
|
||||
<section alias="StartupMemberDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
|
||||
<tab caption="Get Started" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
<tab caption="Get Started" xdt:Transform="Insert">
|
||||
@@ -80,5 +78,6 @@
|
||||
|
||||
<section alias="StartupDashboardSection">
|
||||
<tab caption="Change Password" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
<tab caption="Last Edits" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
</section>
|
||||
</dashBoard>
|
||||
@@ -292,6 +292,8 @@
|
||||
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
|
||||
<remove fileExtension=".woff" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
|
||||
<mimeMap fileExtension=".woff" mimeType="application/x-font-woff" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
|
||||
<remove fileExtension=".woff2" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
|
||||
<mimeMap fileExtension=".woff2" mimeType="application/x-font-woff2" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
|
||||
<remove fileExtension=".less" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
|
||||
<mimeMap fileExtension=".less" mimeType="text/css" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
|
||||
</staticContent>
|
||||
@@ -317,6 +319,7 @@
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='HtmlAgilityPack')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='AutoMapper')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Newtonsoft.Json')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Mvc')" xdt:Transform="Remove" />
|
||||
@@ -336,6 +339,10 @@
|
||||
<assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.9.0" newVersion="1.4.9.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="AutoMapper" publicKeyToken="be96cd2c38ef1005" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.3.1.0" newVersion="3.3.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
|
||||
|
||||
@@ -55,21 +55,29 @@
|
||||
xdt:Transform="SetAttributes()" />
|
||||
|
||||
<!--Developer-->
|
||||
<add alias="datatype" application="developer"
|
||||
<add alias="packager" application="developer"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="Remove" />
|
||||
<add initialize="true" sortOrder="0" alias="datatypes" application="developer" title="Data Types" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.DataTypeTreeController, umbraco"
|
||||
<add alias="packagerPackages" application="developer"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="InsertIfMissing" />
|
||||
xdt:Transform="Remove" />
|
||||
<add initialize="true" sortOrder="0" alias="packager" application="developer" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.PackagesTreeController, umbraco"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="InsertIfMissing" />
|
||||
|
||||
<!-- Before 7.4 this tree had the alias 'dataType', without the 's' on the end, this is here to rename it -->
|
||||
<add sortOrder="1" alias="dataTypes" application="developer" type="Umbraco.Web.Trees.DataTypeTreeController, umbraco"
|
||||
xdt:Locator="Match(application,type)"
|
||||
xdt:Transform="SetAttributes(alias,sortOrder)" />
|
||||
|
||||
<!-- Yes, set the sortOrder again, like above because.. sometimes apparently we already have a dataTypes node and we can't remove more than one.. if they're equal though (same alias,application and sortOrder) it doesn't throw an error -->
|
||||
<add sortOrder="1" alias="dataTypes" application="developer"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes(sortOrder)" />
|
||||
|
||||
<add application="developer" alias="macros" title="Macros" type="umbraco.loadMacros, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="2"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
<add application="developer" alias="packager" title="Packages" type="umbraco.loadPackager, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="3"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
<add application="developer" alias="packagerPackages" title="Packager Packages" type="umbraco.loadPackages, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" initialize="false" sortOrder="3"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
<add application="developer" alias="relationTypes" title="Relation Types" type="umbraco.loadRelationTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.5.0
|
||||
beta2
|
||||
7.5.4
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.5.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.5.0-beta2")]
|
||||
[assembly: AssemblyFileVersion("7.5.4")]
|
||||
[assembly: AssemblyInformationalVersion("7.5.4")]
|
||||
@@ -291,7 +291,19 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[ConfigurationProperty("EnableInheritedMediaTypes")]
|
||||
internal InnerTextConfigurationElement<bool> EnableInheritedMediaTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<bool>(
|
||||
(InnerTextConfigurationElement<bool>)this["EnableInheritedMediaTypes"],
|
||||
//set the default
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
string IContentSection.NotificationEmailAddress
|
||||
{
|
||||
get { return Notifications.NotificationEmailAddress; }
|
||||
@@ -431,5 +443,10 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
get { return EnableInheritedDocumentTypes; }
|
||||
}
|
||||
|
||||
bool IContentSection.EnableInheritedMediaTypes
|
||||
{
|
||||
get { return EnableInheritedMediaTypes; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,5 +61,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
string DefaultDocumentTypeProperty { get; }
|
||||
|
||||
bool EnableInheritedDocumentTypes { get; }
|
||||
|
||||
bool EnableInheritedMediaTypes { get; }
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
bool DisableAlternativeTemplates { get; }
|
||||
|
||||
bool DisableFindContentByIdPath { get; }
|
||||
|
||||
bool DisableRedirectUrlTracking { get; }
|
||||
|
||||
string UrlProviderMode { get; }
|
||||
|
||||
|
||||
@@ -27,6 +27,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return (bool) base["disableFindContentByIdPath"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("disableRedirectUrlTracking", DefaultValue = "false")]
|
||||
public bool DisableRedirectUrlTracking
|
||||
{
|
||||
get { return (bool) base["disableRedirectUrlTracking"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("urlProviderMode", DefaultValue = "AutoLegacy")]
|
||||
public string UrlProviderMode
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.5.0");
|
||||
private static readonly Version Version = new Version("7.5.4");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "beta2"; } }
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Core
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
public static class Examine
|
||||
{
|
||||
/// <summary>
|
||||
/// The alias of the internal member indexer
|
||||
/// </summary>
|
||||
public const string InternalMemberIndexer = "InternalMemberIndexer";
|
||||
|
||||
/// <summary>
|
||||
/// The alias of the internal content indexer
|
||||
/// </summary>
|
||||
public const string InternalIndexer = "InternalIndexer";
|
||||
|
||||
/// <summary>
|
||||
/// The alias of the external content indexer
|
||||
/// </summary>
|
||||
public const string ExternalIndexer = "ExternalIndexer";
|
||||
/// <summary>
|
||||
/// The alias of the internal member searcher
|
||||
/// </summary>
|
||||
@@ -19,6 +27,11 @@ namespace Umbraco.Core
|
||||
/// The alias of the internal content searcher
|
||||
/// </summary>
|
||||
public const string InternalSearcher = "InternalSearcher";
|
||||
|
||||
/// <summary>
|
||||
/// The alias of the external content searcher
|
||||
/// </summary>
|
||||
public const string ExternalSearcher = "ExternalSearcher";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document object.
|
||||
/// </summary>
|
||||
public static readonly Guid DocumentGuid = new Guid(Document);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document Type object.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,33 +1,40 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco system nodes.
|
||||
/// </summary>
|
||||
public static class System
|
||||
{
|
||||
/// <summary>
|
||||
/// The integer identifier for global system root node.
|
||||
/// </summary>
|
||||
public const int Root = -1;
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco system nodes.
|
||||
/// </summary>
|
||||
public static class System
|
||||
{
|
||||
/// <summary>
|
||||
/// The integer identifier for global system root node.
|
||||
/// </summary>
|
||||
public const int Root = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The integer identifier for content's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinContent = -20;
|
||||
/// <summary>
|
||||
/// The integer identifier for content's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinContent = -20;
|
||||
|
||||
/// <summary>
|
||||
/// The integer identifier for media's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinMedia = -21;
|
||||
/// <summary>
|
||||
/// The integer identifier for media's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinMedia = -21;
|
||||
|
||||
public const int DefaultContentListViewDataTypeId = -95;
|
||||
public const int DefaultContentListViewDataTypeId = -95;
|
||||
public const int DefaultMediaListViewDataTypeId = -96;
|
||||
public const int DefaultMembersListViewDataTypeId = -97;
|
||||
|
||||
// identifiers for lock objects
|
||||
public const int ServersLock = -331;
|
||||
}
|
||||
}
|
||||
public const int ServersLock = -331;
|
||||
}
|
||||
|
||||
public static class DatabaseProviders
|
||||
{
|
||||
public const string SqlCe = "System.Data.SqlServerCe.4.0";
|
||||
public const string SqlServer = "System.Data.SqlClient";
|
||||
public const string MySql = "MySql.Data.MySqlClient";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ namespace Umbraco.Core
|
||||
if (string.IsNullOrEmpty(_providerName) == false)
|
||||
return _providerName;
|
||||
|
||||
_providerName = "System.Data.SqlClient";
|
||||
_providerName = Constants.DatabaseProviders.SqlServer;
|
||||
if (ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName] != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName) == false)
|
||||
@@ -212,10 +212,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
var provider = DbConnectionExtensions.DetectProviderFromConnectionString(connectionString);
|
||||
var databaseProvider = provider.ToString();
|
||||
var providerName = "System.Data.SqlClient";
|
||||
var providerName = Constants.DatabaseProviders.SqlServer;
|
||||
if (databaseProvider.ToLower().Contains("mysql"))
|
||||
{
|
||||
providerName = "MySql.Data.MySqlClient";
|
||||
providerName = Constants.DatabaseProviders.MySql;
|
||||
}
|
||||
SaveConnectionString(connectionString, providerName);
|
||||
Initialize(string.Empty);
|
||||
@@ -240,10 +240,10 @@ namespace Umbraco.Core
|
||||
|
||||
public string GetDatabaseConnectionString(string server, string databaseName, string user, string password, string databaseProvider, out string providerName)
|
||||
{
|
||||
providerName = "System.Data.SqlClient";
|
||||
providerName = Constants.DatabaseProviders.SqlServer;
|
||||
if (databaseProvider.ToLower().Contains("mysql"))
|
||||
{
|
||||
providerName = "MySql.Data.MySqlClient";
|
||||
providerName = Constants.DatabaseProviders.MySql;
|
||||
return string.Format("Server={0}; Database={1};Uid={2};Pwd={3}", server, databaseName, user, password);
|
||||
}
|
||||
if (databaseProvider.ToLower().Contains("azure"))
|
||||
@@ -260,7 +260,7 @@ namespace Umbraco.Core
|
||||
/// <param name="databaseName">Name of the database</param>
|
||||
public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName)
|
||||
{
|
||||
const string providerName = "System.Data.SqlClient";
|
||||
const string providerName = Constants.DatabaseProviders.SqlServer;
|
||||
var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName);
|
||||
SaveConnectionString(connectionString, providerName);
|
||||
Initialize(providerName);
|
||||
@@ -373,7 +373,7 @@ namespace Umbraco.Core
|
||||
var databaseSettings = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName];
|
||||
if (databaseSettings != null && string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) == false && string.IsNullOrWhiteSpace(databaseSettings.ProviderName) == false)
|
||||
{
|
||||
var providerName = "System.Data.SqlClient";
|
||||
var providerName = Constants.DatabaseProviders.SqlServer;
|
||||
string connString = null;
|
||||
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName))
|
||||
{
|
||||
@@ -381,8 +381,7 @@ namespace Umbraco.Core
|
||||
connString = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ConnectionString;
|
||||
}
|
||||
Initialize(providerName, connString);
|
||||
|
||||
DetermineSqlServerVersion();
|
||||
|
||||
}
|
||||
else if (ConfigurationManager.AppSettings.ContainsKey(GlobalSettings.UmbracoConnectionName) && string.IsNullOrEmpty(ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName]) == false)
|
||||
{
|
||||
@@ -395,8 +394,8 @@ namespace Umbraco.Core
|
||||
else if (legacyConnString.ToLowerInvariant().Contains("tcp:"))
|
||||
{
|
||||
//Must be sql azure
|
||||
SaveConnectionString(legacyConnString, "System.Data.SqlClient");
|
||||
Initialize("System.Data.SqlClient");
|
||||
SaveConnectionString(legacyConnString, Constants.DatabaseProviders.SqlServer);
|
||||
Initialize(Constants.DatabaseProviders.SqlServer);
|
||||
}
|
||||
else if (legacyConnString.ToLowerInvariant().Contains("datalayer=mysql"))
|
||||
{
|
||||
@@ -407,20 +406,19 @@ namespace Umbraco.Core
|
||||
foreach (var variable in legacyConnString.Split(';').Where(x => x.ToLowerInvariant().StartsWith("datalayer") == false))
|
||||
connectionStringWithoutDatalayer = string.Format("{0}{1};", connectionStringWithoutDatalayer, variable);
|
||||
|
||||
SaveConnectionString(connectionStringWithoutDatalayer, "MySql.Data.MySqlClient");
|
||||
Initialize("MySql.Data.MySqlClient");
|
||||
SaveConnectionString(connectionStringWithoutDatalayer, Constants.DatabaseProviders.MySql);
|
||||
Initialize(Constants.DatabaseProviders.MySql);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Must be sql
|
||||
SaveConnectionString(legacyConnString, "System.Data.SqlClient");
|
||||
Initialize("System.Data.SqlClient");
|
||||
SaveConnectionString(legacyConnString, Constants.DatabaseProviders.SqlServer);
|
||||
Initialize(Constants.DatabaseProviders.SqlServer);
|
||||
}
|
||||
|
||||
//Remove the legacy connection string, so we don't end up in a loop if something goes wrong.
|
||||
GlobalSettings.RemoveSetting(GlobalSettings.UmbracoConnectionName);
|
||||
|
||||
DetermineSqlServerVersion();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -465,49 +463,6 @@ namespace Umbraco.Core
|
||||
Initialize(providerName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the lazy resolution of determining the SQL server version if that is the db type we're using
|
||||
/// </summary>
|
||||
private void DetermineSqlServerVersion()
|
||||
{
|
||||
|
||||
var sqlServerSyntax = SqlSyntax as SqlServerSyntaxProvider;
|
||||
if (sqlServerSyntax != null)
|
||||
{
|
||||
//this will not execute now, it is lazy so will only execute when we need to actually know
|
||||
// the sql server version.
|
||||
sqlServerSyntax.VersionName = new Lazy<SqlServerVersionName>(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var database = this._factory.CreateDatabase();
|
||||
|
||||
var version = database.ExecuteScalar<string>("SELECT SERVERPROPERTY('productversion')");
|
||||
var firstPart = version.Split('.')[0];
|
||||
switch (firstPart)
|
||||
{
|
||||
case "11":
|
||||
return SqlServerVersionName.V2012;
|
||||
case "10":
|
||||
return SqlServerVersionName.V2008;
|
||||
case "9":
|
||||
return SqlServerVersionName.V2005;
|
||||
case "8":
|
||||
return SqlServerVersionName.V2000;
|
||||
case "7":
|
||||
return SqlServerVersionName.V7;
|
||||
default:
|
||||
return SqlServerVersionName.Other;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return SqlServerVersionName.Invalid;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal DatabaseSchemaResult ValidateDatabaseSchema()
|
||||
{
|
||||
if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName)))
|
||||
@@ -517,7 +472,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
|
||||
if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted
|
||||
&& ProviderName == "MySql.Data.MySqlClient")
|
||||
&& ProviderName == Constants.DatabaseProviders.MySql)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration");
|
||||
}
|
||||
@@ -625,13 +580,8 @@ namespace Umbraco.Core
|
||||
|
||||
var installedSchemaVersion = new SemVersion(schemaResult.DetermineInstalledVersion());
|
||||
|
||||
var installedMigrationVersion = new SemVersion(0);
|
||||
//we cannot check the migrations table if it doesn't exist, this will occur when upgrading to 7.3
|
||||
if (schemaResult.ValidTables.Any(x => x.InvariantEquals("umbracoMigration")))
|
||||
{
|
||||
installedMigrationVersion = schemaResult.DetermineInstalledVersionByMigrations(migrationEntryService);
|
||||
}
|
||||
|
||||
var installedMigrationVersion = schemaResult.DetermineInstalledVersionByMigrations(migrationEntryService);
|
||||
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
|
||||
//In some cases - like upgrading from 7.2.6 -> 7.3, there will be no migration information in the database and therefore it will
|
||||
@@ -731,7 +681,7 @@ namespace Umbraco.Core
|
||||
private Attempt<Result> CheckReadyForInstall()
|
||||
{
|
||||
if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted
|
||||
&& ProviderName == "MySql.Data.MySqlClient")
|
||||
&& ProviderName == Constants.DatabaseProviders.MySql)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration");
|
||||
}
|
||||
@@ -780,7 +730,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
var dbIsSqlCe = false;
|
||||
if (databaseSettings != null && databaseSettings.ProviderName != null)
|
||||
dbIsSqlCe = databaseSettings.ProviderName == "System.Data.SqlServerCe.4.0";
|
||||
dbIsSqlCe = databaseSettings.ProviderName == Constants.DatabaseProviders.SqlCe;
|
||||
var sqlCeDatabaseExists = false;
|
||||
if (dbIsSqlCe)
|
||||
{
|
||||
|
||||
@@ -128,8 +128,14 @@ namespace Umbraco.Core.Events
|
||||
get { return TargetSemVersion.GetVersion(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the origin version of the migration, i.e. the one that is currently installed.
|
||||
/// </summary>
|
||||
public SemVersion ConfiguredSemVersion { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target version of the migration.
|
||||
/// </summary>
|
||||
public SemVersion TargetSemVersion { get; private set; }
|
||||
|
||||
public string ProductName { get; private set; }
|
||||
|
||||
@@ -41,11 +41,7 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
using (var file = fs.OpenFile(path))
|
||||
{
|
||||
using (var sr = new StreamReader(file))
|
||||
{
|
||||
var str = sr.ReadToEnd();
|
||||
return str.Length;
|
||||
}
|
||||
return file.Length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Umbraco.Core.IO
|
||||
private void Initialize()
|
||||
{
|
||||
Filename = _fs.GetFileName(Path);
|
||||
Extension = _fs.GetExtension(Path) != null
|
||||
Extension = string.IsNullOrEmpty(_fs.GetExtension(Path)) == false
|
||||
? _fs.GetExtension(Path).Substring(1).ToLowerInvariant()
|
||||
: "";
|
||||
Url = _fs.GetUrl(Path);
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
Culture = Configuration.GlobalSettings.DefaultUILanguage;
|
||||
}
|
||||
|
||||
public virtual async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager manager)
|
||||
public virtual async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager<BackOfficeIdentityUser> manager)
|
||||
{
|
||||
// NOTE the authenticationType must match the umbraco one
|
||||
// defined in CookieAuthenticationOptions.AuthenticationType
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
private static void ThrowTypeException(object value, Type expected, string alias)
|
||||
{
|
||||
throw new Exception(string.Format("Value \"{0}\" of type \"{1}\" could not be converted"
|
||||
throw new InvalidOperationException(string.Format("Value \"{0}\" of type \"{1}\" could not be converted"
|
||||
+ " to type \"{2}\" which is expected by property type \"{3}\".",
|
||||
value, value.GetType(), expected, alias));
|
||||
}
|
||||
|
||||
@@ -107,9 +107,9 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public void ClearRules()
|
||||
{
|
||||
foreach (var rule in _ruleCollection)
|
||||
for (var i = _ruleCollection.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RemoveRule(rule);
|
||||
RemoveRule(_ruleCollection[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoRedirectUrl")]
|
||||
[PrimaryKey("id")]
|
||||
[PrimaryKey("id", autoIncrement = false)]
|
||||
[ExplicitColumns]
|
||||
class RedirectUrlDto
|
||||
{
|
||||
@@ -22,8 +22,8 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
// inserts, and much faster on reads, so... we have an index on a hash.
|
||||
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 1, Name = "PK_umbracoRedirectUrl")]
|
||||
public int Id { get; set; }
|
||||
[PrimaryKeyColumn(Name = "PK_umbracoRedirectUrl", AutoIncrement = false)]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public int ContentId { get; set; }
|
||||
@@ -39,12 +39,12 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[Column("url")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
//[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRedirectUrl", ForColumns = "url, createDateUtc")]
|
||||
public string Url { get; set; }
|
||||
|
||||
[Column("urlHash")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRedirectUrl", ForColumns = "urlHash, contentKey, createDateUtc")]
|
||||
[Length(40)]
|
||||
public string UrlHash { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
@@ -83,5 +80,19 @@ namespace Umbraco.Core.Models
|
||||
if (media == null) throw new ArgumentNullException("media");
|
||||
return HasPathAccess(media.Path, user.StartMediaId, Constants.System.RecycleBinMedia);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this user is an admin.
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this user is admin; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsAdmin(this IUser user)
|
||||
{
|
||||
if (user == null) throw new ArgumentNullException("user");
|
||||
return user.UserType.Alias == "admin";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,10 +107,10 @@ namespace Umbraco.Core.Persistence
|
||||
var foreignSql = _syntaxProvider.Format(tableDefinition.ForeignKeys);
|
||||
var indexSql = _syntaxProvider.Format(tableDefinition.Indexes);
|
||||
|
||||
var tableExist = _db.TableExist(tableName);
|
||||
var tableExist = TableExist(tableName);
|
||||
if (overwrite && tableExist)
|
||||
{
|
||||
_db.DropTable(tableName);
|
||||
DropTable(tableName);
|
||||
tableExist = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,13 +42,13 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
case DatabaseProviders.SqlServer:
|
||||
case DatabaseProviders.SqlAzure:
|
||||
factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
|
||||
factory = DbProviderFactories.GetFactory(Constants.DatabaseProviders.SqlServer);
|
||||
break;
|
||||
case DatabaseProviders.SqlServerCE:
|
||||
factory = DbProviderFactories.GetFactory("System.Data.SqlServerCe.4.0");
|
||||
break;
|
||||
case DatabaseProviders.MySql:
|
||||
factory = DbProviderFactories.GetFactory("MySql.Data.MySqlClient");
|
||||
factory = DbProviderFactories.GetFactory(Constants.DatabaseProviders.MySql);
|
||||
break;
|
||||
case DatabaseProviders.PostgreSQL:
|
||||
case DatabaseProviders.Oracle:
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
else if (entity is IMemberType)
|
||||
nodeObjectType = Constants.ObjectTypes.MemberTypeGuid;
|
||||
else
|
||||
throw new Exception("oops: invalid entity.");
|
||||
throw new Exception("Invalid entity.");
|
||||
|
||||
var contentTypeDto = new ContentTypeDto
|
||||
{
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
// note: no idea why Id is nullable here, but better check
|
||||
if (groupDto.Id.HasValue == false)
|
||||
throw new Exception("oops: groupDto.Id has no value.");
|
||||
throw new Exception("GroupDto.Id has no value.");
|
||||
group.Id = groupDto.Id.Value;
|
||||
}
|
||||
|
||||
|
||||
@@ -266,9 +266,9 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
|
||||
//defaults for the member list
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -1, Alias = "pageSize", SortOrder = 1, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "10" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -2, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "Name" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -2, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "username" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -3, Alias = "orderDirection", SortOrder = 3, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "asc" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -4, Alias = "includeProperties", SortOrder = 4, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "[{\"alias\":\"email\",\"isSystem\":1},{\"alias\":\"username\",\"isSystem\":1},{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1}]" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -4, Alias = "includeProperties", SortOrder = 4, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "[{\"alias\":\"username\",\"isSystem\":1},{\"alias\":\"email\",\"isSystem\":1},{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1}]" });
|
||||
|
||||
//layouts for the list view
|
||||
var cardLayout = "{\"name\": \"Grid\",\"path\": \"views/propertyeditors/listview/layouts/grid/grid.html\", \"icon\": \"icon-thumbnails-small\", \"isSystem\": 1, \"selected\": true}";
|
||||
@@ -276,10 +276,10 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
|
||||
//defaults for the media list
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -5, Alias = "pageSize", SortOrder = 1, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "100" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -6, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "VersionDate" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -6, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "updateDate" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -7, Alias = "orderDirection", SortOrder = 3, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "desc" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -8, Alias = "layouts", SortOrder = 4, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[" + cardLayout + "," + listLayout + "]" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -9, Alias = "includeProperties", SortOrder = 5, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[{\"alias\":\"sortOrder\",\"isSystem\":1, \"header\": \"Sort order\"},{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1},{\"alias\":\"owner\",\"header\":\"Updated by\",\"isSystem\":1}]" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -9, Alias = "includeProperties", SortOrder = 5, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1},{\"alias\":\"owner\",\"header\":\"Updated by\",\"isSystem\":1}]" });
|
||||
}
|
||||
|
||||
private void CreateUmbracoRelationTypeData()
|
||||
|
||||
@@ -43,8 +43,13 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
/// <returns></returns>
|
||||
public SemVersion DetermineInstalledVersionByMigrations(IMigrationEntryService migrationEntryService)
|
||||
{
|
||||
var allMigrations = migrationEntryService.GetAll(GlobalSettings.UmbracoMigrationName);
|
||||
var mostrecent = allMigrations.OrderByDescending(x => x.Version).Select(x => x.Version).FirstOrDefault();
|
||||
SemVersion mostrecent = null;
|
||||
|
||||
if (ValidTables.Any(x => x.InvariantEquals("umbracoMigration")))
|
||||
{
|
||||
var allMigrations = migrationEntryService.GetAll(GlobalSettings.UmbracoMigrationName);
|
||||
mostrecent = allMigrations.OrderByDescending(x => x.Version).Select(x => x.Version).FirstOrDefault();
|
||||
}
|
||||
|
||||
return mostrecent ?? new SemVersion(new Version(0, 0, 0));
|
||||
}
|
||||
@@ -116,13 +121,19 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
//if the error is for umbracoAccess it must be the previous version to 7.3 since that is when it is added
|
||||
if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoAccess"))))
|
||||
{
|
||||
return new Version(7, 2, 5);
|
||||
return new Version(7, 2, 0);
|
||||
}
|
||||
|
||||
//if the error is for umbracoDeployChecksum it must be the previous version to 7.4 since that is when it is added
|
||||
if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoDeployChecksum"))))
|
||||
{
|
||||
return new Version(7, 3, 4);
|
||||
return new Version(7, 3, 0);
|
||||
}
|
||||
|
||||
//if the error is for umbracoRedirectUrl it must be the previous version to 7.5 since that is when it is added
|
||||
if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoRedirectUrl"))))
|
||||
{
|
||||
return new Version(7, 4, 0);
|
||||
}
|
||||
|
||||
return UmbracoVersion.Current;
|
||||
|
||||
+28
-13
@@ -1,7 +1,6 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero
|
||||
@@ -21,24 +20,40 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZer
|
||||
|
||||
private string MigrationCode(Database database)
|
||||
{
|
||||
// don't execute if the table is already there
|
||||
var tables = SqlSyntax.GetTablesInSchema(database).ToArray();
|
||||
if (tables.InvariantContains("umbracoRedirectUrl")) return null;
|
||||
var umbracoRedirectUrlTableName = "umbracoRedirectUrl";
|
||||
|
||||
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
|
||||
|
||||
localContext.Create.Table("umbracoRedirectUrl")
|
||||
.WithColumn("id").AsInt32().Identity().PrimaryKey("PK_umbracoRedirectUrl")
|
||||
.WithColumn("contentId").AsInt32().NotNullable()
|
||||
.WithColumn("createDateUtc").AsDateTime().NotNullable()
|
||||
.WithColumn("url").AsString(2048).NotNullable();
|
||||
var tables = SqlSyntax.GetTablesInSchema(database).ToArray();
|
||||
|
||||
if (tables.InvariantContains(umbracoRedirectUrlTableName))
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
|
||||
if (columns.Any(x => x.TableName.InvariantEquals(umbracoRedirectUrlTableName) && x.ColumnName.InvariantEquals("id") && x.DataType == "uniqueidentifier"))
|
||||
return null;
|
||||
localContext.Delete.Table(umbracoRedirectUrlTableName);
|
||||
}
|
||||
|
||||
localContext.Create.Index("IX_umbracoRedirectUrl")
|
||||
.OnTable("umbracoRedirectUrl")
|
||||
.OnColumn("url").Ascending()
|
||||
.OnColumn("createDateUtc").Ascending()
|
||||
localContext.Create.Table(umbracoRedirectUrlTableName)
|
||||
.WithColumn("id").AsGuid().NotNullable().PrimaryKey("PK_" + umbracoRedirectUrlTableName)
|
||||
.WithColumn("createDateUtc").AsDateTime().NotNullable()
|
||||
.WithColumn("url").AsString(2048).NotNullable()
|
||||
.WithColumn("contentKey").AsGuid().NotNullable()
|
||||
.WithColumn("urlHash").AsString(40).NotNullable();
|
||||
|
||||
localContext.Create.Index("IX_" + umbracoRedirectUrlTableName).OnTable(umbracoRedirectUrlTableName)
|
||||
.OnColumn("urlHash")
|
||||
.Ascending()
|
||||
.OnColumn("contentKey")
|
||||
.Ascending()
|
||||
.OnColumn("createDateUtc")
|
||||
.Descending()
|
||||
.WithOptions().NonClustered();
|
||||
|
||||
localContext.Create.ForeignKey("FK_" + umbracoRedirectUrlTableName)
|
||||
.FromTable(umbracoRedirectUrlTableName).ForeignColumn("contentKey")
|
||||
.ToTable("umbracoNode").PrimaryColumn("uniqueID");
|
||||
|
||||
return localContext.GetSql();
|
||||
}
|
||||
|
||||
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Alter;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Delete;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Execute;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero
|
||||
{
|
||||
[Migration("7.5.0", 101, GlobalSettings.UmbracoMigrationName)]
|
||||
public class AddRedirectUrlTable2 : MigrationBase
|
||||
{
|
||||
public AddRedirectUrlTable2(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
// defer, because we are making decisions based upon what's in the database
|
||||
Execute.Code(MigrationCode);
|
||||
}
|
||||
|
||||
private string MigrationCode(Database database)
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
|
||||
|
||||
if (columns.Any(x => x.TableName.InvariantEquals("umbracoRedirectUrl") && x.ColumnName.InvariantEquals("contentKey")))
|
||||
return null;
|
||||
|
||||
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
|
||||
|
||||
localContext.Execute.Sql("DELETE FROM umbracoRedirectUrl"); // else cannot add non-nullable field
|
||||
|
||||
localContext.Delete.Column("contentId").FromTable("umbracoRedirectUrl");
|
||||
|
||||
// SQL CE does not want to alter-add non-nullable columns ;-(
|
||||
// but it's OK to create as nullable then alter, go figure
|
||||
//localContext.Alter.Table("umbracoRedirectUrl")
|
||||
// .AddColumn("contentKey").AsGuid().NotNullable();
|
||||
localContext.Alter.Table("umbracoRedirectUrl")
|
||||
.AddColumn("contentKey").AsGuid().Nullable();
|
||||
localContext.Alter.Table("umbracoRedirectUrl")
|
||||
.AlterColumn("contentKey").AsGuid().NotNullable();
|
||||
|
||||
localContext.Create.ForeignKey("FK_umbracoRedirectUrl")
|
||||
.FromTable("umbracoRedirectUrl").ForeignColumn("contentKey")
|
||||
.ToTable("umbracoNode").PrimaryColumn("uniqueID");
|
||||
|
||||
return localContext.GetSql();
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
-57
@@ -1,57 +0,0 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero
|
||||
{
|
||||
[Migration("7.5.0", 102, GlobalSettings.UmbracoMigrationName)]
|
||||
public class AddRedirectUrlTable3 : MigrationBase
|
||||
{
|
||||
public AddRedirectUrlTable3(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
// defer, because we are making decisions based upon what's in the database
|
||||
Execute.Code(MigrationCode);
|
||||
}
|
||||
private string MigrationCode(Database database)
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
|
||||
|
||||
if (columns.Any(x => x.TableName.InvariantEquals("umbracoRedirectUrl") && x.ColumnName.InvariantEquals("hurl")))
|
||||
return null;
|
||||
|
||||
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
|
||||
|
||||
localContext.Execute.Sql("DELETE FROM umbracoRedirectUrl"); // else cannot add non-nullable field
|
||||
|
||||
localContext.Delete.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl");
|
||||
|
||||
// SQL CE does not want to alter-add non-nullable columns ;-(
|
||||
// but it's OK to create as nullable then alter, go figure
|
||||
//localContext.Alter.Table("umbracoRedirectUrl")
|
||||
// .AddColumn("urlHash").AsString(16).NotNullable();
|
||||
localContext.Alter.Table("umbracoRedirectUrl")
|
||||
.AddColumn("hurl").AsString(16).Nullable();
|
||||
localContext.Alter.Table("umbracoRedirectUrl")
|
||||
.AlterColumn("hurl").AsString(16).NotNullable();
|
||||
|
||||
localContext.Create.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl")
|
||||
.OnColumn("hurl")
|
||||
.Ascending()
|
||||
.OnColumn("contentKey")
|
||||
.Ascending()
|
||||
.OnColumn("createDateUtc")
|
||||
.Descending()
|
||||
.WithOptions().NonClustered();
|
||||
|
||||
return localContext.GetSql();
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero
|
||||
{
|
||||
[Migration("7.5.0", 103, GlobalSettings.UmbracoMigrationName)]
|
||||
public class AddRedirectUrlTable4 : MigrationBase
|
||||
{
|
||||
public AddRedirectUrlTable4(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
// defer, because we are making decisions based upon what's in the database
|
||||
Execute.Code(MigrationCode);
|
||||
}
|
||||
private string MigrationCode(Database database)
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
|
||||
|
||||
if (columns.Any(x => x.TableName.InvariantEquals("umbracoRedirectUrl") && x.ColumnName.InvariantEquals("urlHash")))
|
||||
return null;
|
||||
|
||||
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
|
||||
|
||||
localContext.Execute.Sql("DELETE FROM umbracoRedirectUrl"); // else cannot add non-nullable field
|
||||
|
||||
localContext.Delete.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl");
|
||||
|
||||
localContext.Delete.Column("hurl").FromTable("umbracoRedirectUrl");
|
||||
|
||||
// SQL CE does not want to alter-add non-nullable columns ;-(
|
||||
// but it's OK to create as nullable then alter, go figure
|
||||
//localContext.Alter.Table("umbracoRedirectUrl")
|
||||
// .AddColumn("urlHash").AsString(16).NotNullable();
|
||||
localContext.Alter.Table("umbracoRedirectUrl")
|
||||
.AddColumn("urlHash").AsString(16).Nullable();
|
||||
localContext.Alter.Table("umbracoRedirectUrl")
|
||||
.AlterColumn("urlHash").AsString(16).NotNullable();
|
||||
|
||||
localContext.Create.Index("IX_umbracoRedirectUrl").OnTable("umbracoRedirectUrl")
|
||||
.OnColumn("urlHash")
|
||||
.Ascending()
|
||||
.OnColumn("contentKey")
|
||||
.Ascending()
|
||||
.OnColumn("createDateUtc")
|
||||
.Descending()
|
||||
.WithOptions().NonClustered();
|
||||
|
||||
return localContext.GetSql();
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
+16
-6
@@ -19,22 +19,32 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZer
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
// defer, because we are making decisions based upon what's in the database
|
||||
Execute.Code(MigrationCode);
|
||||
}
|
||||
|
||||
private string MigrationCode(Database database)
|
||||
{
|
||||
var localContext = new LocalMigrationContext(Context.CurrentDatabaseProvider, database, SqlSyntax, Logger);
|
||||
|
||||
//Clear all stylesheet data if the tables exist
|
||||
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
|
||||
if (tables.InvariantContains("cmsStylesheetProperty"))
|
||||
{
|
||||
Delete.FromTable("cmsStylesheetProperty").AllRows();
|
||||
Delete.FromTable("umbracoNode").Row(new { nodeObjectType = new Guid(Constants.ObjectTypes.StylesheetProperty) });
|
||||
localContext.Delete.FromTable("cmsStylesheetProperty").AllRows();
|
||||
localContext.Delete.FromTable("umbracoNode").Row(new { nodeObjectType = new Guid(Constants.ObjectTypes.StylesheetProperty) });
|
||||
|
||||
Delete.Table("cmsStylesheetProperty");
|
||||
localContext.Delete.Table("cmsStylesheetProperty");
|
||||
}
|
||||
if (tables.InvariantContains("cmsStylesheet"))
|
||||
{
|
||||
Delete.FromTable("cmsStylesheet").AllRows();
|
||||
Delete.FromTable("umbracoNode").Row(new { nodeObjectType = new Guid(Constants.ObjectTypes.Stylesheet) });
|
||||
localContext.Delete.FromTable("cmsStylesheet").AllRows();
|
||||
localContext.Delete.FromTable("umbracoNode").Row(new { nodeObjectType = new Guid(Constants.ObjectTypes.Stylesheet) });
|
||||
|
||||
Delete.Table("cmsStylesheet");
|
||||
localContext.Delete.Table("cmsStylesheet");
|
||||
}
|
||||
|
||||
return localContext.GetSql();
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace Umbraco.Core.Persistence
|
||||
connectionStringName = ConfigurationManager.ConnectionStrings[0].Name;
|
||||
|
||||
// Work out connection string and provider name
|
||||
var providerName = "System.Data.SqlClient";
|
||||
var providerName = Constants.DatabaseProviders.SqlServer;
|
||||
if (ConfigurationManager.ConnectionStrings[connectionStringName] != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName))
|
||||
@@ -181,7 +181,7 @@ namespace Umbraco.Core.Persistence
|
||||
CommonConstruct();
|
||||
}
|
||||
|
||||
enum DBType
|
||||
internal enum DBType
|
||||
{
|
||||
SqlServer,
|
||||
SqlServerCE,
|
||||
@@ -726,6 +726,42 @@ namespace Umbraco.Core.Persistence
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NOTE: This is a custom mod of PetaPoco!! This builds the paging sql for different db providers
|
||||
/// </summary>
|
||||
/// <param name="sql"></param>
|
||||
/// <param name="sqlSelectRemoved"></param>
|
||||
/// <param name="sqlOrderBy"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <param name="sqlPage"></param>
|
||||
/// <param name="databaseType"></param>
|
||||
/// <param name="skip"></param>
|
||||
/// <param name="take"></param>
|
||||
internal virtual void BuildSqlDbSpecificPagingQuery(DBType databaseType, long skip, long take, string sql, string sqlSelectRemoved, string sqlOrderBy, ref object[] args, out string sqlPage)
|
||||
{
|
||||
if (databaseType == DBType.SqlServer || databaseType == DBType.Oracle)
|
||||
{
|
||||
sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, "");
|
||||
if (rxDistinct.IsMatch(sqlSelectRemoved))
|
||||
{
|
||||
sqlSelectRemoved = "peta_inner.* FROM (SELECT " + sqlSelectRemoved + ") peta_inner";
|
||||
}
|
||||
sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) peta_rn, {1}) peta_paged WHERE peta_rn>@{2} AND peta_rn<=@{3}",
|
||||
sqlOrderBy == null ? "ORDER BY (SELECT NULL)" : sqlOrderBy, sqlSelectRemoved, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { skip, skip + take }).ToArray();
|
||||
}
|
||||
else if (databaseType == DBType.SqlServerCE)
|
||||
{
|
||||
sqlPage = string.Format("{0}\nOFFSET @{1} ROWS FETCH NEXT @{2} ROWS ONLY", sql, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { skip, take }).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlPage = string.Format("{0}\nLIMIT @{1} OFFSET @{2}", sql, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { take, skip }).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildPageQueries<T>(long skip, long take, string sql, ref object[] args, out string sqlCount, out string sqlPage)
|
||||
{
|
||||
// Add auto select clause
|
||||
@@ -734,34 +770,12 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
// Split the SQL into the bits we need
|
||||
string sqlSelectRemoved, sqlOrderBy;
|
||||
if (!SplitSqlForPaging(sql, out sqlCount, out sqlSelectRemoved, out sqlOrderBy))
|
||||
if (SplitSqlForPaging(sql, out sqlCount, out sqlSelectRemoved, out sqlOrderBy) == false)
|
||||
throw new Exception("Unable to parse SQL statement for paged query");
|
||||
if (_dbType == DBType.Oracle && sqlSelectRemoved.StartsWith("*"))
|
||||
throw new Exception("Query must alias '*' when performing a paged query.\neg. select t.* from table t order by t.id");
|
||||
|
||||
// Build the SQL for the actual final result
|
||||
if (_dbType == DBType.SqlServer || _dbType == DBType.Oracle)
|
||||
{
|
||||
sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, "");
|
||||
if (rxDistinct.IsMatch(sqlSelectRemoved))
|
||||
{
|
||||
sqlSelectRemoved = "peta_inner.* FROM (SELECT " + sqlSelectRemoved + ") peta_inner";
|
||||
}
|
||||
sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) peta_rn, {1}) peta_paged WHERE peta_rn>@{2} AND peta_rn<=@{3}",
|
||||
sqlOrderBy==null ? "ORDER BY (SELECT NULL)" : sqlOrderBy, sqlSelectRemoved, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { skip, skip+take }).ToArray();
|
||||
}
|
||||
else if (_dbType == DBType.SqlServerCE)
|
||||
{
|
||||
sqlPage = string.Format("{0}\nOFFSET @{1} ROWS FETCH NEXT @{2} ROWS ONLY", sql, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { skip, take }).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlPage = string.Format("{0}\nLIMIT @{1} OFFSET @{2}", sql, args.Length, args.Length + 1);
|
||||
args = args.Concat(new object[] { take, skip }).ToArray();
|
||||
}
|
||||
|
||||
|
||||
BuildSqlDbSpecificPagingQuery(_dbType, skip, take, sql, sqlSelectRemoved, sqlOrderBy, ref args, out sqlPage);
|
||||
}
|
||||
|
||||
// Fetch a page
|
||||
@@ -2315,8 +2329,8 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
|
||||
// Member variables
|
||||
string _connectionString;
|
||||
string _providerName;
|
||||
readonly string _connectionString;
|
||||
readonly string _providerName;
|
||||
DbProviderFactory _factory;
|
||||
IDbConnection _sharedConnection;
|
||||
IDbTransaction _transaction;
|
||||
|
||||
@@ -203,7 +203,8 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
//if it is sql ce or it is a sql server version less than 2008, we need to do individual inserts.
|
||||
var sqlServerSyntax = SqlSyntaxContext.SqlSyntaxProvider as SqlServerSyntaxProvider;
|
||||
if ((sqlServerSyntax != null && (int)sqlServerSyntax.VersionName.Value < (int)SqlServerVersionName.V2008)
|
||||
|
||||
if ((sqlServerSyntax != null && (int)sqlServerSyntax.GetVersionName(db) < (int)SqlServerVersionName.V2008)
|
||||
|| SqlSyntaxContext.SqlSyntaxProvider is SqlCeSyntaxProvider)
|
||||
{
|
||||
//SqlCe doesn't support bulk insert statements!
|
||||
|
||||
@@ -34,11 +34,27 @@ namespace Umbraco.Core.Persistence
|
||||
return sql.Where(whereExpression, expresionist.GetSqlParameters());
|
||||
}
|
||||
|
||||
private static string GetFieldName<T>(Expression<Func<T, object>> fieldSelector, ISqlSyntaxProvider sqlSyntax)
|
||||
{
|
||||
var field = ExpressionHelper.FindProperty(fieldSelector) as PropertyInfo;
|
||||
var fieldName = field.GetColumnName();
|
||||
|
||||
var type = typeof(T);
|
||||
var tableName = type.GetTableName();
|
||||
|
||||
return sqlSyntax.GetQuotedTableName(tableName) + "." + sqlSyntax.GetQuotedColumnName(fieldName);
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload specifying ISqlSyntaxProvider instead")]
|
||||
public static Sql WhereIn<T>(this Sql sql, Expression<Func<T, object>> fieldSelector, IEnumerable values)
|
||||
{
|
||||
var expresionist = new PocoToSqlExpressionHelper<T>();
|
||||
var fieldExpression = expresionist.Visit(fieldSelector);
|
||||
return sql.Where(fieldExpression + " IN (@values)", new {@values = values});
|
||||
return sql.WhereIn(fieldSelector, values, SqlSyntaxContext.SqlSyntaxProvider);
|
||||
}
|
||||
|
||||
public static Sql WhereIn<T>(this Sql sql, Expression<Func<T, object>> fieldSelector, IEnumerable values, ISqlSyntaxProvider sqlSyntax)
|
||||
{
|
||||
var fieldName = GetFieldName(fieldSelector, sqlSyntax);
|
||||
return sql.Where(fieldName + " IN (@values)", new { values });
|
||||
}
|
||||
|
||||
[Obsolete("Use the overload specifying ISqlSyntaxProvider instead")]
|
||||
@@ -49,17 +65,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
public static Sql OrderBy<TColumn>(this Sql sql, Expression<Func<TColumn, object>> columnMember, ISqlSyntaxProvider sqlSyntax)
|
||||
{
|
||||
var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo;
|
||||
var columnName = column.GetColumnName();
|
||||
|
||||
var type = typeof(TColumn);
|
||||
var tableName = type.GetTableName();
|
||||
|
||||
//need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177
|
||||
var syntax = string.Format("({0}.{1})",
|
||||
sqlSyntax.GetQuotedTableName(tableName),
|
||||
sqlSyntax.GetQuotedColumnName(columnName));
|
||||
|
||||
var syntax = "(" + GetFieldName(columnMember, sqlSyntax) + ")";
|
||||
return sql.OrderBy(syntax);
|
||||
}
|
||||
|
||||
@@ -77,7 +83,8 @@ namespace Umbraco.Core.Persistence
|
||||
var type = typeof(TColumn);
|
||||
var tableName = type.GetTableName();
|
||||
|
||||
var syntax = string.Format("{0}.{1} DESC",
|
||||
//need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177
|
||||
var syntax = string.Format("({0}.{1}) DESC",
|
||||
sqlSyntax.GetQuotedTableName(tableName),
|
||||
sqlSyntax.GetQuotedColumnName(columnName));
|
||||
|
||||
|
||||
@@ -440,6 +440,55 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
}
|
||||
|
||||
return HandleStringComparison(visitedObjectForMethod, compareValue, m.Method.Name, colType);
|
||||
|
||||
case "Replace":
|
||||
string searchValue;
|
||||
|
||||
if (methodArgs[0].NodeType != ExpressionType.Constant)
|
||||
{
|
||||
//This occurs when we are getting a value from a non constant such as: x => x.Path.StartsWith(content.Path)
|
||||
// So we'll go get the value:
|
||||
var member = Expression.Convert(methodArgs[0], typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
searchValue = getter().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
searchValue = methodArgs[0].ToString();
|
||||
}
|
||||
|
||||
if (methodArgs[0].Type != typeof(string) && TypeHelper.IsTypeAssignableFrom<IEnumerable>(methodArgs[0].Type))
|
||||
{
|
||||
throw new NotSupportedException("An array Contains method is not supported");
|
||||
}
|
||||
|
||||
string replaceValue;
|
||||
|
||||
if (methodArgs[1].NodeType != ExpressionType.Constant)
|
||||
{
|
||||
//This occurs when we are getting a value from a non constant such as: x => x.Path.StartsWith(content.Path)
|
||||
// So we'll go get the value:
|
||||
var member = Expression.Convert(methodArgs[1], typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
replaceValue = getter().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
replaceValue = methodArgs[1].ToString();
|
||||
}
|
||||
|
||||
if (methodArgs[1].Type != typeof(string) && TypeHelper.IsTypeAssignableFrom<IEnumerable>(methodArgs[1].Type))
|
||||
{
|
||||
throw new NotSupportedException("An array Contains method is not supported");
|
||||
}
|
||||
|
||||
SqlParameters.Add(RemoveQuote(searchValue));
|
||||
|
||||
SqlParameters.Add(RemoveQuote(replaceValue));
|
||||
|
||||
return string.Format("replace({0}, @{1}, @{2})", visitedObjectForMethod, SqlParameters.Count - 2, SqlParameters.Count - 1);
|
||||
//case "Substring":
|
||||
// var startIndex = Int32.Parse(args[0].ToString()) + 1;
|
||||
// if (args.Count == 2)
|
||||
@@ -501,7 +550,7 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
//case "As":
|
||||
// return string.Format("{0} As {1}", r,
|
||||
// GetQuotedColumnName(RemoveQuoteFromAlias(RemoveQuote(args[0].ToString()))));
|
||||
|
||||
|
||||
default:
|
||||
|
||||
throw new ArgumentOutOfRangeException("No logic supported for " + m.Method.Name);
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dynamics;
|
||||
@@ -63,9 +64,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.Where<DocumentDto>(x => x.Newest)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sql).FirstOrDefault();
|
||||
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
|
||||
if (dto == null)
|
||||
return null;
|
||||
@@ -688,6 +689,77 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This builds the Xml document used for the XML cache
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public XmlDocument BuildXmlCache()
|
||||
{
|
||||
//TODO: This is what we should do , but converting to use XDocument would be breaking unless we convert
|
||||
// to XmlDocument at the end of this, but again, this would be bad for memory... though still not nearly as
|
||||
// bad as what is happening before!
|
||||
// We'll keep using XmlDocument for now though, but XDocument xml generation is much faster:
|
||||
// https://blogs.msdn.microsoft.com/codejunkie/2008/10/08/xmldocument-vs-xelement-performance/
|
||||
// I think we already have code in here to convert XDocument to XmlDocument but in case we don't here
|
||||
// it is: https://blogs.msdn.microsoft.com/marcelolr/2009/03/13/fast-way-to-convert-xmldocument-into-xdocument/
|
||||
|
||||
//// Prepare an XmlDocument with an appropriate inline DTD to match
|
||||
//// the expected content
|
||||
//var parent = new XElement("root", new XAttribute("id", "-1"));
|
||||
//var xmlDoc = new XDocument(
|
||||
// new XDocumentType("root", null, null, DocumentType.GenerateDtd()),
|
||||
// parent);
|
||||
|
||||
var xmlDoc = new XmlDocument();
|
||||
var doctype = xmlDoc.CreateDocumentType("root", null, null,
|
||||
ApplicationContext.Current.Services.ContentTypeService.GetContentTypesDtd());
|
||||
xmlDoc.AppendChild(doctype);
|
||||
var parent = xmlDoc.CreateElement("root");
|
||||
var pIdAtt = xmlDoc.CreateAttribute("id");
|
||||
pIdAtt.Value = "-1";
|
||||
parent.Attributes.Append(pIdAtt);
|
||||
xmlDoc.AppendChild(parent);
|
||||
|
||||
const string sql = @"select umbracoNode.id, umbracoNode.parentID, umbracoNode.sortOrder, cmsContentXml.xml, umbracoNode.level from umbracoNode
|
||||
inner join cmsContentXml on cmsContentXml.nodeId = umbracoNode.id and umbracoNode.nodeObjectType = @type
|
||||
where umbracoNode.id in (select cmsDocument.nodeId from cmsDocument where cmsDocument.published = 1)
|
||||
order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
|
||||
|
||||
XmlElement last = null;
|
||||
|
||||
//NOTE: Query creates a reader - does not load all into memory
|
||||
foreach (var row in Database.Query<dynamic>(sql, new { type = new Guid(Constants.ObjectTypes.Document) }))
|
||||
{
|
||||
string parentId = ((int)row.parentID).ToInvariantString();
|
||||
string xml = row.xml;
|
||||
int sortOrder = row.sortOrder;
|
||||
|
||||
//if the parentid is changing
|
||||
if (last != null && last.GetAttribute("parentID") != parentId)
|
||||
{
|
||||
parent = xmlDoc.GetElementById(parentId);
|
||||
if (parent == null)
|
||||
{
|
||||
//Need to short circuit here, if the parent is not there it means that the parent is unpublished
|
||||
// and therefore the child is not published either so cannot be included in the xml cache
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var xmlDocFragment = xmlDoc.CreateDocumentFragment();
|
||||
xmlDocFragment.InnerXml = xml;
|
||||
|
||||
last = (XmlElement)parent.AppendChild(xmlDocFragment);
|
||||
|
||||
// fix sortOrder - see notes in UpdateSortOrder
|
||||
last.Attributes["sortOrder"].Value = sortOrder.ToInvariantString();
|
||||
}
|
||||
|
||||
return xmlDoc;
|
||||
|
||||
}
|
||||
|
||||
public int CountPublished()
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
|
||||
@@ -251,8 +251,8 @@ AND umbracoNode.id <> @id",
|
||||
var nodeDto = dto.NodeDto;
|
||||
Database.Update(nodeDto);
|
||||
|
||||
// look up ContentType entry to get PrimaryKey for updating the DTO
|
||||
// fixme - why? we are UPDATING so we should ALREADY have a PK!
|
||||
//Look up ContentType entry to get PrimaryKey for updating the DTO
|
||||
var dtoPk = Database.First<ContentTypeDto>("WHERE nodeId = @Id", new { Id = entity.Id });
|
||||
dto.PrimaryKey = dtoPk.PrimaryKey;
|
||||
Database.Update(dto);
|
||||
@@ -262,31 +262,30 @@ AND umbracoNode.id <> @id",
|
||||
foreach (var composition in entity.ContentTypeComposition)
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id });
|
||||
|
||||
//Removing a ContentType from a composition (U4-1690)
|
||||
//1. Find content based on the current ContentType: entity.Id
|
||||
//2. Find all PropertyTypes on the ContentType that was removed - tracked id (key)
|
||||
//3. Remove properties based on property types from the removed content type where the content ids correspond to those found in step one
|
||||
// removing a ContentType from a composition (U4-1690)
|
||||
// 1. Find content based on the current ContentType: entity.Id
|
||||
// 2. Find all PropertyTypes on the ContentType that was removed - tracked id (key)
|
||||
// 3. Remove properties based on property types from the removed content type where the content ids correspond to those found in step one
|
||||
var compositionBase = entity as ContentTypeCompositionBase;
|
||||
if (compositionBase != null && compositionBase.RemovedContentTypeKeyTracker != null &&
|
||||
compositionBase.RemovedContentTypeKeyTracker.Any())
|
||||
{
|
||||
//Find Content based on the current ContentType
|
||||
// find Content based on the current ContentType
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
.From<ContentDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.From<ContentDto>(SqlSyntax)
|
||||
.InnerJoin<NodeDto>(SqlSyntax).On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == new Guid(Constants.ObjectTypes.Document))
|
||||
.Where<ContentDto>(x => x.ContentTypeId == entity.Id);
|
||||
|
||||
var contentDtos = Database.Fetch<ContentDto, NodeDto>(sql);
|
||||
//Loop through all tracked keys, which corresponds to the ContentTypes that has been removed from the composition
|
||||
|
||||
// loop through all tracked keys, which corresponds to the ContentTypes that has been removed from the composition
|
||||
foreach (var key in compositionBase.RemovedContentTypeKeyTracker)
|
||||
{
|
||||
//Find PropertyTypes for the removed ContentType
|
||||
// find PropertyTypes for the removed ContentType
|
||||
var propertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = key });
|
||||
//Loop through the Content that is based on the current ContentType in order to remove the Properties that are
|
||||
//based on the PropertyTypes that belong to the removed ContentType.
|
||||
// loop through the Content that is based on the current ContentType in order to remove the Properties that are
|
||||
// based on the PropertyTypes that belong to the removed ContentType.
|
||||
foreach (var contentDto in contentDtos)
|
||||
{
|
||||
foreach (var propertyType in propertyTypes)
|
||||
@@ -294,51 +293,47 @@ AND umbracoNode.id <> @id",
|
||||
var nodeId = contentDto.NodeId;
|
||||
var propertyTypeId = propertyType.Id;
|
||||
var propertySql = new Sql().Select("cmsPropertyData.id")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>()
|
||||
.On<PropertyDataDto, PropertyTypeDto>(
|
||||
left => left.PropertyTypeId, right => right.Id)
|
||||
.Where<PropertyDataDto>(x => x.NodeId == nodeId)
|
||||
.Where<PropertyTypeDto>(x => x.Id == propertyTypeId);
|
||||
.From<PropertyDataDto>(SqlSyntax)
|
||||
.InnerJoin<PropertyTypeDto>(SqlSyntax).On<PropertyDataDto, PropertyTypeDto>(SqlSyntax, left => left.PropertyTypeId, right => right.Id)
|
||||
.Where<PropertyDataDto>(x => x.NodeId == nodeId)
|
||||
.Where<PropertyTypeDto>(x => x.Id == propertyTypeId);
|
||||
|
||||
//Finally delete the properties that match our criteria for removing a ContentType from the composition
|
||||
// finally delete the properties that match our criteria for removing a ContentType from the composition
|
||||
Database.Delete<PropertyDataDto>(new Sql("WHERE id IN (" + propertySql.SQL + ")", propertySql.Arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Delete the allowed content type entries before adding the updated collection
|
||||
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new { Id = entity.Id });
|
||||
//Insert collection of allowed content types
|
||||
// delete the allowed content type entries before re-inserting the collectino of allowed content types
|
||||
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new { entity.Id });
|
||||
foreach (var allowedContentType in entity.AllowedContentTypes)
|
||||
{
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto
|
||||
{
|
||||
Id = entity.Id,
|
||||
AllowedId = allowedContentType.Id.Value,
|
||||
SortOrder = allowedContentType.SortOrder
|
||||
});
|
||||
{
|
||||
Id = entity.Id,
|
||||
AllowedId = allowedContentType.Id.Value,
|
||||
SortOrder = allowedContentType.SortOrder
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME below, manage the property types
|
||||
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyTypes") || entity.PropertyTypes.Any(x => x.IsDirty()))
|
||||
// delete ??? fixme wtf is this?!
|
||||
// by excepting entries from db with entries from collections
|
||||
if (entity.IsPropertyDirty("PropertyTypes") || entity.PropertyTypes.Any(x => x.IsDirty()))
|
||||
{
|
||||
//Delete PropertyTypes by excepting entries from db with entries from collections
|
||||
var dbPropertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = entity.Id });
|
||||
var dbPropertyTypeAlias = dbPropertyTypes.Select(x => x.Id);
|
||||
var entityPropertyTypes = entity.PropertyTypes.Where(x => x.HasIdentity).Select(x => x.Id);
|
||||
var items = dbPropertyTypeAlias.Except(entityPropertyTypes);
|
||||
foreach (var item in items)
|
||||
{
|
||||
//Before a PropertyType can be deleted, all Properties based on that PropertyType should be deleted.
|
||||
Database.Delete<TagRelationshipDto>("WHERE propertyTypeId = @Id", new { Id = item });
|
||||
Database.Delete<PropertyDataDto>("WHERE propertytypeid = @Id", new { Id = item });
|
||||
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND id = @PropertyTypeId",
|
||||
new { Id = entity.Id, PropertyTypeId = item });
|
||||
}
|
||||
DeletePropertyType(entity.Id, item);
|
||||
}
|
||||
|
||||
// delete tabs
|
||||
// by excepting entries from db with entries from collections
|
||||
List<int> orphanPropertyTypeIds = null;
|
||||
if (entity.IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
{
|
||||
// todo
|
||||
@@ -357,68 +352,97 @@ AND umbracoNode.id <> @id",
|
||||
// (all gone)
|
||||
|
||||
// delete tabs that do not exist anymore
|
||||
// get the tabs that are currently existing (in the db)
|
||||
// get the tabs that we want, now
|
||||
// and derive the tabs that we want to delete
|
||||
// get the tabs that are currently existing (in the db), get the tabs that we want,
|
||||
// now, and derive the tabs that we want to delete
|
||||
var existingPropertyGroups = Database.Fetch<PropertyTypeGroupDto>("WHERE contentTypeNodeId = @id", new { id = entity.Id })
|
||||
.Select(x => x.Id)
|
||||
.ToList();
|
||||
var newPropertyGroups = entity.PropertyGroups.Select(x => x.Id).ToList();
|
||||
var tabsToDelete = existingPropertyGroups
|
||||
var groupsToDelete = existingPropertyGroups
|
||||
.Except(newPropertyGroups)
|
||||
.ToArray();
|
||||
|
||||
// move properties to generic properties, and delete the tabs
|
||||
if (tabsToDelete.Length > 0)
|
||||
// delete the tabs
|
||||
if (groupsToDelete.Length > 0)
|
||||
{
|
||||
Database.Update<PropertyTypeDto>("SET propertyTypeGroupId=NULL WHERE propertyTypeGroupId IN (@ids)", new { ids = tabsToDelete });
|
||||
Database.Delete<PropertyTypeGroupDto>("WHERE id IN (@ids)", new { ids = tabsToDelete });
|
||||
// if the tab contains properties, take care of them
|
||||
// - move them to 'generic properties' so they remain consistent
|
||||
// - keep track of them, later on we'll figure out what to do with them
|
||||
// see http://issues.umbraco.org/issue/U4-8663
|
||||
orphanPropertyTypeIds = Database.Fetch<PropertyTypeDto>("WHERE propertyTypeGroupId IN (@ids)", new { ids = groupsToDelete })
|
||||
.Select(x => x.Id).ToList();
|
||||
Database.Update<PropertyTypeDto>("SET propertyTypeGroupId=NULL WHERE propertyTypeGroupId IN (@ids)", new { ids = groupsToDelete });
|
||||
|
||||
// now we can delete the tabs
|
||||
Database.Delete<PropertyTypeGroupDto>("WHERE id IN (@ids)", new { ids = groupsToDelete });
|
||||
}
|
||||
}
|
||||
|
||||
var propertyGroupFactory = new PropertyGroupFactory(entity.Id);
|
||||
|
||||
//Run through all groups to insert or update entries
|
||||
// insert or update groups, assign properties
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
var tabDto = propertyGroupFactory.BuildGroupDto(propertyGroup);
|
||||
int groupPrimaryKey = propertyGroup.HasIdentity
|
||||
? Database.Update(tabDto)
|
||||
: Convert.ToInt32(Database.Insert(tabDto));
|
||||
// insert or update group
|
||||
var groupDto = propertyGroupFactory.BuildGroupDto(propertyGroup);
|
||||
var groupId = propertyGroup.HasIdentity
|
||||
? Database.Update(groupDto)
|
||||
: Convert.ToInt32(Database.Insert(groupDto));
|
||||
if (propertyGroup.HasIdentity == false)
|
||||
propertyGroup.Id = groupPrimaryKey; //Set Id on new PropertyGroup
|
||||
propertyGroup.Id = groupId;
|
||||
else
|
||||
groupId = propertyGroup.Id;
|
||||
|
||||
//Ensure that the PropertyGroup's Id is set on the PropertyTypes within a group
|
||||
//unless the PropertyGroupId has already been changed.
|
||||
// assign properties to the group
|
||||
// (all of them, even those that have .IsPropertyDirty("PropertyGroupId") == true,
|
||||
// because it should have been set to this group anyways and better be safe)
|
||||
foreach (var propertyType in propertyGroup.PropertyTypes)
|
||||
{
|
||||
if (propertyType.IsPropertyDirty("PropertyGroupId") == false)
|
||||
{
|
||||
var tempGroup = propertyGroup;
|
||||
propertyType.PropertyGroupId = new Lazy<int>(() => tempGroup.Id);
|
||||
}
|
||||
}
|
||||
propertyType.PropertyGroupId = new Lazy<int>(() => groupId);
|
||||
}
|
||||
|
||||
//Run through all PropertyTypes to insert or update entries
|
||||
// insert or update properties
|
||||
// all of them, no-group and in groups
|
||||
foreach (var propertyType in entity.PropertyTypes)
|
||||
{
|
||||
var tabId = propertyType.PropertyGroupId != null ? propertyType.PropertyGroupId.Value : default(int);
|
||||
//If the Id of the DataType is not set, we resolve it from the db by its PropertyEditorAlias
|
||||
if (propertyType.DataTypeDefinitionId == 0 || propertyType.DataTypeDefinitionId == default(int))
|
||||
{
|
||||
AssignDataTypeFromPropertyEditor(propertyType);
|
||||
}
|
||||
var groupId = propertyType.PropertyGroupId != null ? propertyType.PropertyGroupId.Value : default(int);
|
||||
|
||||
//validate the alias!
|
||||
// if the Id of the DataType is not set, we resolve it from the db by its PropertyEditorAlias
|
||||
if (propertyType.DataTypeDefinitionId == 0 || propertyType.DataTypeDefinitionId == default(int))
|
||||
AssignDataTypeFromPropertyEditor(propertyType);
|
||||
|
||||
// validate the alias
|
||||
ValidateAlias(propertyType);
|
||||
|
||||
var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(tabId, propertyType);
|
||||
int typePrimaryKey = propertyType.HasIdentity
|
||||
? Database.Update(propertyTypeDto)
|
||||
: Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
// insert or update property
|
||||
var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(groupId, propertyType);
|
||||
var typeId = propertyType.HasIdentity
|
||||
? Database.Update(propertyTypeDto)
|
||||
: Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
if (propertyType.HasIdentity == false)
|
||||
propertyType.Id = typePrimaryKey; //Set Id on new PropertyType
|
||||
propertyType.Id = typeId;
|
||||
else
|
||||
typeId = propertyType.Id;
|
||||
|
||||
// not an orphan anymore
|
||||
if (orphanPropertyTypeIds != null)
|
||||
orphanPropertyTypeIds.Remove(typeId);
|
||||
}
|
||||
|
||||
// deal with orphan properties: those that were in a deleted tab,
|
||||
// and have not been re-mapped to another tab or to 'generic properties'
|
||||
if (orphanPropertyTypeIds != null)
|
||||
foreach (var id in orphanPropertyTypeIds)
|
||||
DeletePropertyType(entity.Id, id);
|
||||
}
|
||||
|
||||
private void DeletePropertyType(int contentTypeId, int propertyTypeId)
|
||||
{
|
||||
// first clear dependencies
|
||||
Database.Delete<TagRelationshipDto>("WHERE propertyTypeId = @Id", new { Id = propertyTypeId });
|
||||
Database.Delete<PropertyDataDto>("WHERE propertytypeid = @Id", new { Id = propertyTypeId });
|
||||
|
||||
// then delete the property type
|
||||
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND id = @PropertyTypeId", new { Id = contentTypeId, PropertyTypeId = propertyTypeId });
|
||||
}
|
||||
|
||||
protected IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
|
||||
@@ -649,7 +673,7 @@ AND umbracoNode.id <> @id",
|
||||
var allParentContentTypes = contentTypes.Where(x => allParentIdsAsArray.Contains(x.Id)).ToArray();
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
{
|
||||
var entityId = contentType.Id;
|
||||
|
||||
var parentContentTypes = allParentContentTypes.Where(x =>
|
||||
@@ -714,10 +738,10 @@ AND umbracoNode.id <> @id",
|
||||
out IDictionary<int, List<int>> parentMediaTypeIds)
|
||||
{
|
||||
Mandate.ParameterNotNull(db, "db");
|
||||
|
||||
|
||||
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
@@ -741,7 +765,7 @@ AND umbracoNode.id <> @id",
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
|
||||
ORDER BY ctId";
|
||||
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType) });
|
||||
|
||||
if (result.Any() == false)
|
||||
@@ -848,16 +872,16 @@ AND umbracoNode.id <> @id",
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
internal static IEnumerable<IContentType> MapContentTypes(Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
internal static IEnumerable<IContentType> MapContentTypes(Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<int, List<AssociatedTemplate>> associatedTemplates,
|
||||
out IDictionary<int, List<int>> parentContentTypeIds)
|
||||
{
|
||||
Mandate.ParameterNotNull(db, "db");
|
||||
|
||||
|
||||
var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId,
|
||||
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
@@ -890,7 +914,7 @@ AND umbracoNode.id <> @id",
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
|
||||
ORDER BY ctId";
|
||||
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType)});
|
||||
|
||||
if (result.Any() == false)
|
||||
@@ -911,7 +935,7 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
var ct = queue.Dequeue();
|
||||
|
||||
//check for default templates
|
||||
//check for default templates
|
||||
bool? isDefaultTemplate = Convert.ToBoolean(ct.dtIsDefault);
|
||||
int? templateId = ct.dtTemplateId;
|
||||
if (currDefaultTemplate == -1 && isDefaultTemplate.HasValue && isDefaultTemplate.Value && templateId.HasValue)
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false).Where(GetBaseWhereClause(), new { id = id, NodeObjectType = NodeObjectTypeId });
|
||||
|
||||
var nodeDto = Database.Fetch<NodeDto>(sql).FirstOrDefault();
|
||||
var nodeDto = Database.Fetch<NodeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
return nodeDto == null ? null : CreateEntity(nodeDto);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,12 +58,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var macroDto = Database.Fetch<ExternalLoginDto>(sql).FirstOrDefault();
|
||||
if (macroDto == null)
|
||||
var dto = Database.Fetch<ExternalLoginDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var factory = new ExternalLoginFactory();
|
||||
var entity = factory.BuildEntity(macroDto);
|
||||
var entity = factory.BuildEntity(dto);
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
@@ -11,6 +12,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentRepository : IRepositoryVersionable<int, IContent>, IRecycleBinRepository<IContent>, IDeleteMediaFilesRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// This builds the Xml document used for the XML cache
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
XmlDocument BuildXmlCache();
|
||||
|
||||
/// <summary>
|
||||
/// Get the count of published items
|
||||
/// </summary>
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Defines the <see cref="IRedirectUrl"/> repository.
|
||||
/// </summary>
|
||||
public interface IRedirectUrlRepository : IRepositoryQueryable<int, IRedirectUrl>
|
||||
public interface IRedirectUrlRepository : IRepositoryQueryable<Guid, IRedirectUrl>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a redirect url.
|
||||
@@ -21,7 +21,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// Deletes a redirect url.
|
||||
/// </summary>
|
||||
/// <param name="id">The redirect url identifier.</param>
|
||||
void Delete(int id);
|
||||
void Delete(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all redirect urls.
|
||||
@@ -66,5 +66,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="total">The total count of redirect urls.</param>
|
||||
/// <returns>The redirect urls.</returns>
|
||||
IEnumerable<IRedirectUrl> GetAllUrls(int rootContentId, long pageIndex, int pageSize, out long total);
|
||||
|
||||
/// <summary>
|
||||
/// Searches for all redirect urls that contain a given search term in their URL property.
|
||||
/// </summary>
|
||||
/// <param name="searchTerm">The term to search for.</param>
|
||||
/// <param name="pageIndex">The page index.</param>
|
||||
/// <param name="pageSize">The page size.</param>
|
||||
/// <param name="total">The total count of redirect urls.</param>
|
||||
/// <returns>The redirect urls.</returns>
|
||||
IEnumerable<IRedirectUrl> SearchUrls(string searchTerm, long pageIndex, int pageSize, out long total);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,19 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
int CountDescendants(int parentId, string contentTypeAlias = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all versions for an <see cref="TEntity"/>.
|
||||
/// Gets a list of all versions for an <see cref="TEntity"/> ordered so latest is first
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="TEntity"/> to retrieve versions from</param>
|
||||
/// <returns>An enumerable list of the same <see cref="TEntity"/> object with different versions</returns>
|
||||
IEnumerable<TEntity> GetAllVersions(int id);
|
||||
IEnumerable<TEntity> GetAllVersions(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all version Ids for the given content item
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="maxRows">The maximum number of rows to return</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Guid> GetVersionIds(int id, int maxRows);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specific version of an <see cref="TEntity"/>.
|
||||
|
||||
@@ -52,9 +52,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
var dto = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
|
||||
var dto = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
|
||||
if (dto == null)
|
||||
return null;
|
||||
@@ -413,6 +413,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
foreach (var property in entity.Properties)
|
||||
{
|
||||
if (keyDictionary.ContainsKey(property.PropertyTypeId) == false) continue;
|
||||
|
||||
property.Id = keyDictionary[property.PropertyTypeId];
|
||||
}
|
||||
}
|
||||
@@ -453,8 +455,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Func<Tuple<string, object[]>> filterCallback = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
sbWhere.Append("AND (umbracoNode." + SqlSyntax.GetQuotedColumnName("text") + " LIKE @" + args.Count + ")");
|
||||
sbWhere
|
||||
.Append("AND (")
|
||||
.Append(SqlSyntax.GetQuotedTableName("umbracoNode"))
|
||||
.Append(".")
|
||||
.Append(SqlSyntax.GetQuotedColumnName("text"))
|
||||
.Append(" LIKE @")
|
||||
.Append(args.Count)
|
||||
.Append(")");
|
||||
args.Add("%" + filter + "%");
|
||||
|
||||
filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString().Trim(), args.ToArray());
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var dto = Database.Fetch<NodeDto>(sql).FirstOrDefault();
|
||||
var dto = Database.Fetch<NodeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
|
||||
return dto == null ? null : _modelFactory.BuildEntity(dto);
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
|
||||
var dto = Database.Fetch<MemberDto, ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
|
||||
var dto = Database.Fetch<MemberDto, ContentVersionDto, ContentDto, NodeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
|
||||
if (dto == null)
|
||||
return null;
|
||||
@@ -365,6 +365,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
foreach (var property in ((Member)entity).Properties)
|
||||
{
|
||||
if (keyDictionary.ContainsKey(property.PropertyTypeId) == false) continue;
|
||||
|
||||
property.Id = keyDictionary[property.PropertyTypeId];
|
||||
}
|
||||
}
|
||||
@@ -622,9 +624,32 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Func<Tuple<string, object[]>> filterCallback = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
sbWhere.Append("AND ((umbracoNode. " + SqlSyntax.GetQuotedColumnName("text") + " LIKE @" + args.Count + ") " +
|
||||
"OR (cmsMember.LoginName LIKE @0" + args.Count + "))");
|
||||
args.Add("%" + filter + "%");
|
||||
//This will build up the where clause - even though the same 'filter' is being
|
||||
//applied to both columns, the parameters values passed to PetaPoco need to be
|
||||
//duplicated, otherwise it gets confused :/
|
||||
var columnFilters = new List<Tuple<string, string>>
|
||||
{
|
||||
new Tuple<string, string>("umbracoNode", "text"),
|
||||
new Tuple<string, string>("cmsMember", "LoginName")
|
||||
};
|
||||
sbWhere.Append("AND (");
|
||||
for (int i = 0; i < columnFilters.Count; i++)
|
||||
{
|
||||
sbWhere
|
||||
.Append("(")
|
||||
.Append(SqlSyntax.GetQuotedTableName(columnFilters[i].Item1))
|
||||
.Append(".")
|
||||
.Append(SqlSyntax.GetQuotedColumnName(columnFilters[i].Item2))
|
||||
.Append(" LIKE @")
|
||||
.Append(args.Count)
|
||||
.Append(") ");
|
||||
args.Add(string.Format("%{0}%", filter));
|
||||
if (i < (columnFilters.Count - 1))
|
||||
{
|
||||
sbWhere.Append("OR ");
|
||||
}
|
||||
}
|
||||
sbWhere.Append(")");
|
||||
filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString().Trim(), args.ToArray());
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var dto = Database.First<MigrationDto>(sql);
|
||||
var dto = Database.Fetch<MigrationDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -18,6 +18,27 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
_unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public IEnumerable<Notification> GetUsersNotifications(IEnumerable<int> userIds, string action, IEnumerable<int> nodeIds, Guid objectType)
|
||||
{
|
||||
var nodeIdsA = nodeIds.ToArray();
|
||||
var syntax = ApplicationContext.Current.DatabaseContext.SqlSyntax; // bah
|
||||
var sql = new Sql()
|
||||
.Select("DISTINCT umbracoNode.id nodeId, umbracoUser.id userId, umbracoNode.nodeObjectType, umbracoUser2NodeNotify.action")
|
||||
.From<User2NodeNotifyDto>(syntax)
|
||||
.InnerJoin<NodeDto>(syntax).On<User2NodeNotifyDto, NodeDto>(syntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<UserDto>(syntax).On<User2NodeNotifyDto, UserDto>(syntax, left => left.UserId, right => right.Id)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == objectType)
|
||||
.Where<UserDto>(x => x.Disabled == false) // only approved users
|
||||
.Where<User2NodeNotifyDto>(x => x.Action == action); // on the specified action
|
||||
if (nodeIdsA.Length > 0)
|
||||
sql
|
||||
.WhereIn<NodeDto>(x => x.NodeId, nodeIdsA); // for the specified nodes
|
||||
sql
|
||||
.OrderBy<UserDto>(x => x.Id, syntax)
|
||||
.OrderBy<NodeDto>(dto => dto.NodeId, syntax);
|
||||
return _unitOfWork.Database.Fetch<dynamic>(sql).Select(x => new Notification(x.nodeId, x.userId, x.action, objectType));
|
||||
}
|
||||
|
||||
public IEnumerable<Notification> GetUserNotifications(IUser user)
|
||||
{
|
||||
var sql = new Sql()
|
||||
|
||||
@@ -17,8 +17,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public PublicAccessRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
private FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid> _cachePolicyFactory;
|
||||
protected override IRepositoryCachePolicyFactory<PublicAccessEntry, Guid> CachePolicyFactory
|
||||
@@ -46,6 +45,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
sql.Where("umbracoAccess.id IN (@ids)", new { ids = ids });
|
||||
}
|
||||
|
||||
sql.OrderBy<AccessDto>(x => x.NodeId, SqlSyntax);
|
||||
|
||||
var factory = new PublicAccessEntryFactory();
|
||||
var dtos = Database.Fetch<AccessDto, AccessRuleDto, AccessDto>(new AccessRulesRelator().Map, sql);
|
||||
return dtos.Select(factory.BuildEntity);
|
||||
@@ -69,7 +70,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.From<AccessDto>(SqlSyntax)
|
||||
.LeftJoin<AccessRuleDto>(SqlSyntax)
|
||||
.On<AccessDto, AccessRuleDto>(SqlSyntax, left => left.Id, right => right.AccessId);
|
||||
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -162,7 +163,5 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
return entity.Key;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
INNER JOIN umbracoNode as TB2 ON TB1.nodeId = TB2.id
|
||||
WHERE TB2.trashed = '1' AND TB2.nodeObjectType = @NodeObjectType)",
|
||||
FormatDeleteStatement("umbracoAccess", "nodeId"),
|
||||
@"DELETE FROM umbracoRedirectUrl WHERE umbracoRedirectUrl.id IN(
|
||||
SELECT TB1.id FROM umbracoRedirectUrl as TB1
|
||||
INNER JOIN umbracoNode as TB2 ON TB1.contentKey = TB2.uniqueId
|
||||
WHERE TB2.trashed = '1' AND TB2.nodeObjectType = @NodeObjectType)",
|
||||
FormatDeleteStatement("umbracoRelation", "parentId"),
|
||||
FormatDeleteStatement("umbracoRelation", "childId"),
|
||||
FormatDeleteStatement("cmsTagRelationship", "nodeId"),
|
||||
|
||||
@@ -12,9 +12,9 @@ using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class RedirectUrlRepository : PetaPocoRepositoryBase<int, IRedirectUrl>, IRedirectUrlRepository
|
||||
internal class RedirectUrlRepository : PetaPocoRepositoryBase<Guid, IRedirectUrl>, IRedirectUrlRepository
|
||||
{
|
||||
public RedirectUrlRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
public RedirectUrlRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{ }
|
||||
|
||||
@@ -23,19 +23,19 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
throw new NotSupportedException("This repository does not support this method.");
|
||||
}
|
||||
|
||||
protected override bool PerformExists(int id)
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return PerformGet(id) != null;
|
||||
}
|
||||
|
||||
protected override IRedirectUrl PerformGet(int id)
|
||||
protected override IRedirectUrl PerformGet(Guid id)
|
||||
{
|
||||
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Id == id);
|
||||
var dto = Database.Fetch<RedirectUrlDto>(sql).FirstOrDefault();
|
||||
var dto = Database.Fetch<RedirectUrlDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
return dto == null ? null : Map(dto);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IRedirectUrl> PerformGetAll(params int[] ids)
|
||||
protected override IEnumerable<IRedirectUrl> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
if (ids.Length > 2000)
|
||||
throw new NotSupportedException("This repository does not support more than 2000 ids.");
|
||||
@@ -86,7 +86,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
{
|
||||
var dto = Map(entity);
|
||||
Database.Insert(dto);
|
||||
entity.Id = dto.Id;
|
||||
entity.Id = entity.Key.GetHashCode();
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(IRedirectUrl entity)
|
||||
@@ -101,11 +101,11 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
|
||||
return new RedirectUrlDto
|
||||
{
|
||||
Id = redirectUrl.Id,
|
||||
Id = redirectUrl.Key,
|
||||
ContentKey = redirectUrl.ContentKey,
|
||||
CreateDateUtc = redirectUrl.CreateDateUtc,
|
||||
Url = redirectUrl.Url,
|
||||
UrlHash = HashUrl(redirectUrl.Url)
|
||||
UrlHash = redirectUrl.Url.ToSHA1()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -117,7 +117,8 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
try
|
||||
{
|
||||
url.DisableChangeTracking();
|
||||
url.Id = dto.Id;
|
||||
url.Key = dto.Id;
|
||||
url.Id = dto.Id.GetHashCode();
|
||||
url.ContentId = dto.ContentId;
|
||||
url.ContentKey = dto.ContentKey;
|
||||
url.CreateDateUtc = dto.CreateDateUtc;
|
||||
@@ -132,7 +133,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
|
||||
public IRedirectUrl Get(string url, Guid contentKey)
|
||||
{
|
||||
var urlHash = HashUrl(url);
|
||||
var urlHash = url.ToSHA1();
|
||||
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash && x.ContentKey == contentKey);
|
||||
var dto = Database.Fetch<RedirectUrlDto>(sql).FirstOrDefault();
|
||||
return dto == null ? null : Map(dto);
|
||||
@@ -148,14 +149,14 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
Database.Execute("DELETE FROM umbracoRedirectUrl WHERE contentKey=@contentKey", new { contentKey });
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
public void Delete(Guid id)
|
||||
{
|
||||
Database.Delete<RedirectUrlDto>(id);
|
||||
}
|
||||
|
||||
public IRedirectUrl GetMostRecentUrl(string url)
|
||||
{
|
||||
var urlHash = HashUrl(url);
|
||||
var urlHash = url.ToSHA1();
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash)
|
||||
.OrderByDescending<RedirectUrlDto>(x => x.CreateDateUtc, SqlSyntax);
|
||||
@@ -185,7 +186,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
public IEnumerable<IRedirectUrl> GetAllUrls(int rootContentId, long pageIndex, int pageSize, out long total)
|
||||
{
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where("umbracoNode.path LIKE @path", new { path = "%," + rootContentId + ",%" })
|
||||
.Where(string.Format("{0}.{1} LIKE @path", SqlSyntax.GetQuotedTableName("umbracoNode"), SqlSyntax.GetQuotedColumnName("path")), new { path = "%," + rootContentId + ",%" })
|
||||
.OrderByDescending<RedirectUrlDto>(x => x.CreateDateUtc, SqlSyntax);
|
||||
var result = Database.Page<RedirectUrlDto>(pageIndex + 1, pageSize, sql);
|
||||
total = Convert.ToInt32(result.TotalItems);
|
||||
@@ -194,12 +195,16 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
return rules;
|
||||
}
|
||||
|
||||
private static string HashUrl(string url)
|
||||
public IEnumerable<IRedirectUrl> SearchUrls(string searchTerm, long pageIndex, int pageSize, out long total)
|
||||
{
|
||||
var crypto = new MD5CryptoServiceProvider();
|
||||
var inputBytes = Encoding.UTF8.GetBytes(url);
|
||||
var hashedBytes = crypto.ComputeHash(inputBytes);
|
||||
return Encoding.UTF8.GetString(hashedBytes);
|
||||
}
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(string.Format("{0}.{1} LIKE @url", SqlSyntax.GetQuotedTableName("umbracoRedirectUrl"), SqlSyntax.GetQuotedColumnName("Url")), new { url = "%" + searchTerm.Trim().ToLowerInvariant() + "%" })
|
||||
.OrderByDescending<RedirectUrlDto>(x => x.CreateDateUtc, SqlSyntax);
|
||||
var result = Database.Page<RedirectUrlDto>(pageIndex + 1, pageSize, sql);
|
||||
total = Convert.ToInt32(result.TotalItems);
|
||||
|
||||
var rules = result.Items.Select(Map);
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var dto = Database.FirstOrDefault<RelationDto>(sql);
|
||||
var dto = Database.Fetch<RelationDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var dto = Database.FirstOrDefault<RelationTypeDto>(sql);
|
||||
var dto = Database.Fetch<RelationTypeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -26,7 +25,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var tagDto = Database.Fetch<TagDto>(sql).FirstOrDefault();
|
||||
var tagDto = Database.Fetch<TagDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
if (tagDto == null)
|
||||
return null;
|
||||
|
||||
@@ -566,7 +565,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var array = tagsToInsert
|
||||
.Select(tag =>
|
||||
string.Format("select '{0}' as Tag, '{1}' as " + SqlSyntax.GetQuotedColumnName("group") + @"",
|
||||
string.Format("select N'{0}' as Tag, '{1}' as " + SqlSyntax.GetQuotedColumnName("group") + @"",
|
||||
PetaPocoExtensions.EscapeAtSymbols(tag.Text.Replace("'", "''")), tag.Group))
|
||||
.ToArray();
|
||||
return "(" + string.Join(" union ", array).Replace(" ", " ") + ") as TagSet";
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var taskDto = Database.Fetch<TaskDto, TaskTypeDto>(sql).FirstOrDefault();
|
||||
var taskDto = Database.Fetch<TaskDto, TaskTypeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
if (taskDto == null)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var taskDto = Database.Fetch<TaskTypeDto>(sql).FirstOrDefault();
|
||||
var taskDto = Database.Fetch<TaskTypeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
if (taskDto == null)
|
||||
return null;
|
||||
|
||||
|
||||
@@ -320,51 +320,51 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </remarks>
|
||||
public IEnumerable<IUser> GetPagedResultsByQuery(IQuery<IUser> query, int pageIndex, int pageSize, out int totalRecords, Expression<Func<IUser, string>> orderBy)
|
||||
{
|
||||
if (orderBy == null) throw new ArgumentNullException("orderBy");
|
||||
if (orderBy == null)
|
||||
throw new ArgumentNullException("orderBy");
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*").From<UserDto>();
|
||||
|
||||
Sql resultQuery;
|
||||
if (query != null)
|
||||
{
|
||||
var translator = new SqlTranslator<IUser>(sql, query);
|
||||
resultQuery = translator.Translate();
|
||||
}
|
||||
else
|
||||
{
|
||||
resultQuery = sql;
|
||||
}
|
||||
|
||||
//get the referenced column name
|
||||
// get the referenced column name and find the corresp mapped column name
|
||||
var expressionMember = ExpressionHelper.GetMemberInfo(orderBy);
|
||||
//now find the mapped column name
|
||||
var mapper = MappingResolver.Current.ResolveMapperByType(typeof(IUser));
|
||||
var mappedField = mapper.Map(expressionMember.Name);
|
||||
|
||||
if (mappedField.IsNullOrWhiteSpace())
|
||||
{
|
||||
throw new ArgumentException("Could not find a mapping for the column specified in the orderBy clause");
|
||||
}
|
||||
//need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177
|
||||
resultQuery.OrderBy(string.Format("({0})", mappedField));
|
||||
|
||||
var pagedResult = Database.Page<UserDto>(pageIndex + 1, pageSize, resultQuery);
|
||||
var sql = new Sql()
|
||||
.Select("umbracoUser.Id")
|
||||
.From<UserDto>(SqlSyntax);
|
||||
|
||||
totalRecords = Convert.ToInt32(pagedResult.TotalItems);
|
||||
var idsQuery = query == null ? sql : new SqlTranslator<IUser>(sql, query).Translate();
|
||||
|
||||
// need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177
|
||||
idsQuery.OrderBy("(" + mappedField + ")");
|
||||
var page = Database.Page<int>(pageIndex + 1, pageSize, idsQuery);
|
||||
totalRecords = Convert.ToInt32(page.TotalItems);
|
||||
|
||||
//now that we have the user dto's we need to construct true members from the list.
|
||||
if (totalRecords == 0)
|
||||
{
|
||||
return Enumerable.Empty<IUser>();
|
||||
}
|
||||
|
||||
var ids = pagedResult.Items.Select(x => x.Id).ToArray();
|
||||
var result = ids.Length == 0 ? Enumerable.Empty<IUser>() : GetAll(ids);
|
||||
|
||||
//now we need to ensure this result is also ordered by the same order by clause
|
||||
return result.OrderBy(orderBy.Compile());
|
||||
// now get the actual users and ensure they are ordered properly (same clause)
|
||||
var ids = page.Items.ToArray();
|
||||
return ids.Length == 0 ? Enumerable.Empty<IUser>() : GetAll(ids).OrderBy(orderBy.Compile());
|
||||
}
|
||||
|
||||
|
||||
internal IEnumerable<IUser> GetNextUsers(int id, int count)
|
||||
{
|
||||
var idsQuery = new Sql()
|
||||
.Select("umbracoUser.Id")
|
||||
.From<UserDto>(SqlSyntax)
|
||||
.Where<UserDto>(x => x.Id >= id)
|
||||
.OrderBy<UserDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
// first page is index 1, not zero
|
||||
var ids = Database.Page<int>(1, count, idsQuery).Items.ToArray();
|
||||
|
||||
// now get the actual users and ensure they are ordered properly (same clause)
|
||||
return ids.Length == 0 ? Enumerable.Empty<IUser>() : GetAll(ids).OrderBy(x => x.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns permissions for a given user for any number of nodes
|
||||
/// </summary>
|
||||
|
||||
@@ -40,6 +40,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region IRepositoryVersionable Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all versions for an <see cref="TEntity"/> ordered so latest is first
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the <see cref="TEntity"/> to retrieve versions from</param>
|
||||
/// <returns>An enumerable list of the same <see cref="TEntity"/> object with different versions</returns>
|
||||
public virtual IEnumerable<TEntity> GetAllVersions(int id)
|
||||
{
|
||||
var sql = new Sql();
|
||||
@@ -60,6 +65,28 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all version Ids for the given content item ordered so latest is first
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="maxRows">The maximum number of rows to return</param>
|
||||
/// <returns></returns>
|
||||
public virtual IEnumerable<Guid> GetVersionIds(int id, int maxRows)
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select("cmsDocument.versionId")
|
||||
.From<DocumentDto>(SqlSyntax)
|
||||
.InnerJoin<ContentDto>(SqlSyntax)
|
||||
.On<DocumentDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
|
||||
.Where<NodeDto>(x => x.NodeId == id)
|
||||
.OrderByDescending<DocumentDto>(x => x.UpdateDate, SqlSyntax);
|
||||
|
||||
return Database.Fetch<Guid>(SqlSyntax.SelectTop(sql, maxRows));
|
||||
}
|
||||
|
||||
public virtual void DeleteVersion(Guid versionId)
|
||||
{
|
||||
var dto = Database.FirstOrDefault<ContentVersionDto>("WHERE versionId = @VersionId", new { VersionId = versionId });
|
||||
@@ -236,7 +263,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private Sql GetFilteredSqlForPagedResults(Sql sql, Func<Tuple<string, object[]>> defaultFilter = null)
|
||||
{
|
||||
Sql filteredSql;
|
||||
|
||||
|
||||
// Apply filter
|
||||
if (defaultFilter != null)
|
||||
{
|
||||
@@ -262,7 +289,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return filteredSql;
|
||||
}
|
||||
|
||||
private Sql GetSortedSqlForPagedResults(Sql sql, Direction orderDirection, string orderBy, bool orderBySystemField)
|
||||
private Sql GetSortedSqlForPagedResults(Sql sql, Direction orderDirection, string orderBy, bool orderBySystemField, Tuple<string, string> nodeIdSelect)
|
||||
{
|
||||
|
||||
//copy to var so that the original isn't changed
|
||||
@@ -286,44 +313,71 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sorting by a custom field, so set-up sub-query for ORDER BY clause to pull through valie
|
||||
// Sorting by a custom field, so set-up sub-query for ORDER BY clause to pull through value
|
||||
// from most recent content version for the given order by field
|
||||
var sortedInt = string.Format(SqlSyntax.ConvertIntegerToOrderableString, "dataInt");
|
||||
var sortedDate = string.Format(SqlSyntax.ConvertDateToOrderableString, "dataDate");
|
||||
var sortedString = string.Format("COALESCE({0},'')", "dataNvarchar");
|
||||
var sortedDecimal = string.Format(SqlSyntax.ConvertDecimalToOrderableString, "dataDecimal");
|
||||
|
||||
var innerJoinTempTable = string.Format(@"INNER JOIN (
|
||||
SELECT CASE
|
||||
WHEN dataInt Is Not Null THEN {0}
|
||||
WHEN dataDecimal Is Not Null THEN {1}
|
||||
WHEN dataDate Is Not Null THEN {2}
|
||||
ELSE {3}
|
||||
END AS CustomPropVal,
|
||||
cd.nodeId AS CustomPropValContentId
|
||||
FROM cmsDocument cd
|
||||
INNER JOIN cmsPropertyData cpd ON cpd.contentNodeId = cd.nodeId AND cpd.versionId = cd.versionId
|
||||
INNER JOIN cmsPropertyType cpt ON cpt.Id = cpd.propertytypeId
|
||||
WHERE cpt.Alias = @{4} AND cd.newest = 1) AS CustomPropData
|
||||
ON CustomPropData.CustomPropValContentId = umbracoNode.id
|
||||
", sortedInt, sortedDecimal, sortedDate, sortedString, sortedSql.Arguments.Length);
|
||||
//these are defaults that will be used in the query - they can be overridden for non-versioned entities or document entities
|
||||
var versionQuery = " AND cpd.versionId = cd.versionId";
|
||||
var newestQuery = string.Empty;
|
||||
|
||||
//cmsDocument needs to filter by the 'newest' parameter in the query
|
||||
if (nodeIdSelect.Item1 == "cmsDocument")
|
||||
newestQuery = " AND cd.newest = 1";
|
||||
|
||||
//members do not use versions so clear the versionQuery string
|
||||
if (nodeIdSelect.Item1 == "cmsMember")
|
||||
versionQuery = string.Empty;
|
||||
|
||||
//needs to be an outer join since there's no guarantee that any of the nodes have values for this property
|
||||
var outerJoinTempTable = string.Format(@"LEFT OUTER JOIN (
|
||||
SELECT CASE
|
||||
WHEN dataInt Is Not Null THEN {0}
|
||||
WHEN dataDecimal Is Not Null THEN {1}
|
||||
WHEN dataDate Is Not Null THEN {2}
|
||||
ELSE {3}
|
||||
END AS CustomPropVal,
|
||||
cd.{4} AS CustomPropValContentId
|
||||
FROM {5} cd
|
||||
INNER JOIN cmsPropertyData cpd ON cpd.contentNodeId = cd.{4}{6}
|
||||
INNER JOIN cmsPropertyType cpt ON cpt.Id = cpd.propertytypeId
|
||||
WHERE cpt.Alias = @{7}{8}) AS CustomPropData
|
||||
ON CustomPropData.CustomPropValContentId = umbracoNode.id
|
||||
", sortedInt, sortedDecimal, sortedDate, sortedString, nodeIdSelect.Item2, nodeIdSelect.Item1, versionQuery, sortedSql.Arguments.Length, newestQuery);
|
||||
|
||||
//insert this just above the first LEFT OUTER JOIN (for cmsDocument) or the last WHERE (everything else)
|
||||
string newSql;
|
||||
if (nodeIdSelect.Item1 == "cmsDocument")
|
||||
newSql = sortedSql.SQL.Insert(sortedSql.SQL.IndexOf("LEFT OUTER JOIN"), outerJoinTempTable);
|
||||
else
|
||||
newSql = sortedSql.SQL.Insert(sortedSql.SQL.LastIndexOf("WHERE"), outerJoinTempTable);
|
||||
|
||||
//insert this just above the LEFT OUTER JOIN
|
||||
var newSql = sortedSql.SQL.Insert(sortedSql.SQL.IndexOf("LEFT OUTER JOIN"), innerJoinTempTable);
|
||||
var newArgs = sortedSql.Arguments.ToList();
|
||||
newArgs.Add(orderBy);
|
||||
|
||||
sortedSql = new Sql(newSql, newArgs.ToArray());
|
||||
|
||||
sortedSql.OrderBy("CustomPropData.CustomPropVal");
|
||||
if (orderDirection == Direction.Descending)
|
||||
{
|
||||
sortedSql.Append(" DESC");
|
||||
}
|
||||
sortedSql.OrderByDescending("CustomPropData.CustomPropVal");
|
||||
}
|
||||
else
|
||||
{
|
||||
sortedSql.OrderBy("CustomPropData.CustomPropVal");
|
||||
}
|
||||
}
|
||||
|
||||
//no matter what we always MUST order the result also by umbracoNode.id to ensure that all records being ordered by are unique.
|
||||
// if we do not do this then we end up with issues where we are ordering by a field that has duplicate values (i.e. the 'text' column
|
||||
// is empty for many nodes)
|
||||
// see: http://issues.umbraco.org/issue/U4-8831
|
||||
sortedSql.OrderBy("umbracoNode.id");
|
||||
|
||||
return sortedSql;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -371,7 +425,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//get sorted and filtered sql
|
||||
var sqlNodeIdsWithSort = GetSortedSqlForPagedResults(
|
||||
GetFilteredSqlForPagedResults(sqlNodeIds, defaultFilter),
|
||||
orderDirection, orderBy, orderBySystemField);
|
||||
orderDirection, orderBy, orderBySystemField, nodeIdSelect);
|
||||
|
||||
// Get page of results and total count
|
||||
IEnumerable<TEntity> result;
|
||||
@@ -409,7 +463,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//get sorted and filtered sql
|
||||
var fullQuery = GetSortedSqlForPagedResults(
|
||||
GetFilteredSqlForPagedResults(withInnerJoinSql, defaultFilter),
|
||||
orderDirection, orderBy, orderBySystemField);
|
||||
orderDirection, orderBy, orderBySystemField, nodeIdSelect);
|
||||
return processQuery(fullQuery);
|
||||
}
|
||||
else
|
||||
@@ -483,17 +537,6 @@ WHERE EXISTS(
|
||||
var propertyFactory = new PropertyFactory(compositionProperties, def.Version, def.Id, def.CreateDate, def.VersionDate);
|
||||
var properties = propertyFactory.BuildEntity(propertyDataDtos.ToArray()).ToArray();
|
||||
|
||||
var newProperties = properties.Where(x => x.HasIdentity == false && x.PropertyType.HasIdentity);
|
||||
|
||||
foreach (var property in newProperties)
|
||||
{
|
||||
var propertyDataDto = new PropertyDataDto { NodeId = def.Id, PropertyTypeId = property.PropertyTypeId, VersionId = def.Version };
|
||||
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
|
||||
|
||||
property.Version = def.Version;
|
||||
property.Id = primaryKey;
|
||||
}
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
//NOTE: The benchmarks run with and without the following code show very little change so this is not a perf bottleneck
|
||||
@@ -567,6 +610,8 @@ WHERE EXISTS(
|
||||
return "cmsContentVersion.VersionDate";
|
||||
case "NAME":
|
||||
return "umbracoNode.text";
|
||||
case "PUBLISHED":
|
||||
return "cmsDocument.published";
|
||||
case "OWNER":
|
||||
//TODO: This isn't going to work very nicely because it's going to order by ID, not by letter
|
||||
return "umbracoNode.nodeUser";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -66,6 +67,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
string Format(ForeignKeyDefinition foreignKey);
|
||||
string FormatColumnRename(string tableName, string oldName, string newName);
|
||||
string FormatTableRename(string oldName, string newName);
|
||||
Sql SelectTop(Sql sql, int top);
|
||||
bool SupportsClustered();
|
||||
bool SupportsIdentityInsert();
|
||||
bool? SupportsCaseInsensitiveQueries(Database db);
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for MySql
|
||||
/// </summary>
|
||||
[SqlSyntaxProviderAttribute("MySql.Data.MySqlClient")]
|
||||
[SqlSyntaxProvider(Constants.DatabaseProviders.MySql)]
|
||||
public class MySqlSyntaxProvider : SqlSyntaxProviderBase<MySqlSyntaxProvider>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
@@ -178,6 +178,11 @@ ORDER BY TABLE_NAME, INDEX_NAME",
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
public override Sql SelectTop(Sql sql, int top)
|
||||
{
|
||||
return new Sql(string.Concat(sql.SQL, " LIMIT ", top), sql.Arguments);
|
||||
}
|
||||
|
||||
public override bool SupportsClustered()
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Ce
|
||||
/// </summary>
|
||||
[SqlSyntaxProviderAttribute("System.Data.SqlServerCe.4.0")]
|
||||
[SqlSyntaxProviderAttribute(Constants.DatabaseProviders.SqlCe)]
|
||||
public class SqlCeSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlCeSyntaxProvider>
|
||||
{
|
||||
public SqlCeSyntaxProvider()
|
||||
@@ -18,6 +18,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
|
||||
}
|
||||
|
||||
public override Sql SelectTop(Sql sql, int top)
|
||||
{
|
||||
return new Sql(sql.SQL.Insert(sql.SQL.IndexOf(' '), " TOP " + top), sql.Arguments);
|
||||
}
|
||||
|
||||
public override bool SupportsClustered()
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -8,18 +8,63 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Server
|
||||
/// </summary>
|
||||
[SqlSyntaxProviderAttribute("System.Data.SqlClient")]
|
||||
[SqlSyntaxProviderAttribute(Constants.DatabaseProviders.SqlServer)]
|
||||
public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase<SqlServerSyntaxProvider>
|
||||
{
|
||||
public SqlServerSyntaxProvider()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the version of the current SQL server instance
|
||||
/// </summary>
|
||||
internal Lazy<SqlServerVersionName> VersionName { get; set; }
|
||||
internal SqlServerVersionName GetVersionName(Database database)
|
||||
{
|
||||
if (_versionName.HasValue)
|
||||
return _versionName.Value;
|
||||
|
||||
try
|
||||
{
|
||||
var version = database.ExecuteScalar<string>("SELECT SERVERPROPERTY('productversion')");
|
||||
var firstPart = version.Split('.')[0];
|
||||
switch (firstPart)
|
||||
{
|
||||
case "13":
|
||||
_versionName = SqlServerVersionName.V2014;
|
||||
break;
|
||||
case "12":
|
||||
_versionName = SqlServerVersionName.V2014;
|
||||
break;
|
||||
case "11":
|
||||
_versionName = SqlServerVersionName.V2012;
|
||||
break;
|
||||
case "10":
|
||||
_versionName = SqlServerVersionName.V2008;
|
||||
break;
|
||||
case "9":
|
||||
_versionName = SqlServerVersionName.V2005;
|
||||
break;
|
||||
case "8":
|
||||
_versionName = SqlServerVersionName.V2000;
|
||||
break;
|
||||
case "7":
|
||||
_versionName = SqlServerVersionName.V7;
|
||||
break;
|
||||
default:
|
||||
_versionName = SqlServerVersionName.Other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_versionName = SqlServerVersionName.Invalid;
|
||||
}
|
||||
|
||||
return _versionName.Value;
|
||||
}
|
||||
|
||||
private SqlServerVersionName? _versionName;
|
||||
|
||||
/// <summary>
|
||||
/// SQL Server stores default values assigned to columns as constraints, it also stores them with named values, this is the only
|
||||
@@ -104,6 +149,11 @@ order by T.name, I.name");
|
||||
return column.IsIdentity ? GetIdentityString(column) : string.Empty;
|
||||
}
|
||||
|
||||
public override Sql SelectTop(Sql sql, int top)
|
||||
{
|
||||
return new Sql(sql.SQL.Insert(sql.SQL.IndexOf(' '), " TOP " + top), sql.Arguments);
|
||||
}
|
||||
|
||||
private static string GetIdentityString(ColumnDefinition column)
|
||||
{
|
||||
return "IDENTITY(1,1)";
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
/// <summary>
|
||||
/// Represents the version name of SQL server (i.e. the year 2008, 2005, etc...)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// see: https://support.microsoft.com/en-us/kb/321185
|
||||
/// </remarks>
|
||||
internal enum SqlServerVersionName
|
||||
{
|
||||
Invalid = -1,
|
||||
@@ -11,6 +14,8 @@
|
||||
V2005 = 2,
|
||||
V2008 = 3,
|
||||
V2012 = 4,
|
||||
Other = 5
|
||||
V2014 = 5,
|
||||
V2016 = 6,
|
||||
Other = 100
|
||||
}
|
||||
}
|
||||
@@ -503,6 +503,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
|
||||
protected abstract string FormatIdentity(ColumnDefinition column);
|
||||
|
||||
public abstract Sql SelectTop(Sql sql, int top);
|
||||
|
||||
public virtual string DeleteDefaultConstraint
|
||||
{
|
||||
get
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using StackExchange.Profiling;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
@@ -154,5 +155,41 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
base.OnExecutedCommand(cmd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We are overriding this in the case that we are using SQL Server 2012+ so we can make paging more efficient than the default PetaPoco paging
|
||||
/// see: http://issues.umbraco.org/issue/U4-8837
|
||||
/// </summary>
|
||||
/// <param name="sql"></param>
|
||||
/// <param name="sqlSelectRemoved"></param>
|
||||
/// <param name="sqlOrderBy"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <param name="sqlPage"></param>
|
||||
/// <param name="databaseType"></param>
|
||||
/// <param name="skip"></param>
|
||||
/// <param name="take"></param>
|
||||
internal override void BuildSqlDbSpecificPagingQuery(DBType databaseType, long skip, long take, string sql, string sqlSelectRemoved, string sqlOrderBy, ref object[] args, out string sqlPage)
|
||||
{
|
||||
if (databaseType == DBType.SqlServer)
|
||||
{
|
||||
//we need to check it's version to see what kind of paging format we can use
|
||||
//TODO: This is a hack, but we don't have access to the SqlSyntaxProvider here, we can in v8 but not now otherwise
|
||||
// this would be a breaking change.
|
||||
var sqlServerSyntax = SqlSyntaxContext.SqlSyntaxProvider as SqlServerSyntaxProvider;
|
||||
if (sqlServerSyntax != null)
|
||||
{
|
||||
if ((int) sqlServerSyntax.GetVersionName(this) >= (int) SqlServerVersionName.V2012)
|
||||
{
|
||||
//we can use the good paging! to do that we are going to change the databaseType to SQLCE since
|
||||
//it also uses the good paging syntax.
|
||||
base.BuildSqlDbSpecificPagingQuery(DBType.SqlServerCE, skip, take, sql, sqlSelectRemoved, sqlOrderBy, ref args, out sqlPage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//use the defaults
|
||||
base.BuildSqlDbSpecificPagingQuery(databaseType, skip, take, sql, sqlSelectRemoved, sqlOrderBy, ref args, out sqlPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -28,7 +28,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
// </values>
|
||||
// </keyFeatureList>
|
||||
|
||||
var sourceString = source.ToString();
|
||||
var sourceString = source != null ? source.ToString() : null;
|
||||
if (string.IsNullOrWhiteSpace(sourceString)) return Enumerable.Empty<string>();
|
||||
|
||||
//SD: I have no idea why this logic is here, I'm pretty sure we've never saved the multiple txt string
|
||||
|
||||
@@ -17,8 +17,15 @@ namespace Umbraco.Core.Publishing
|
||||
_contentService = contentService;
|
||||
}
|
||||
|
||||
public void CheckPendingAndProcess()
|
||||
/// <summary>
|
||||
/// Processes scheduled operations
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns the number of items successfully completed
|
||||
/// </returns>
|
||||
public int CheckPendingAndProcess()
|
||||
{
|
||||
var counter = 0;
|
||||
foreach (var d in _contentService.GetContentForRelease())
|
||||
{
|
||||
try
|
||||
@@ -32,10 +39,14 @@ namespace Umbraco.Core.Publishing
|
||||
LogHelper.Error<ScheduledPublisher>("Could not published the document (" + d.Id + ") based on it's scheduled release, status result: " + result.Result.StatusType, result.Exception);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
LogHelper.Warn<ScheduledPublisher>("Could not published the document (" + d.Id + ") based on it's scheduled release. Status result: " + result.Result.StatusType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
@@ -48,7 +59,11 @@ namespace Umbraco.Core.Publishing
|
||||
try
|
||||
{
|
||||
d.ExpireDate = null;
|
||||
_contentService.UnPublish(d, (int)d.GetWriterProfile().Id);
|
||||
var result = _contentService.UnPublish(d, (int)d.GetWriterProfile().Id);
|
||||
if (result)
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
@@ -56,6 +71,8 @@ namespace Umbraco.Core.Publishing
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Configuration;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
public class ActiveDirectoryBackOfficeUserPasswordChecker : IBackOfficeUserPasswordChecker
|
||||
{
|
||||
public virtual string ActiveDirectoryDomain {
|
||||
get {
|
||||
return ConfigurationManager.AppSettings["ActiveDirectoryDomain"];
|
||||
}
|
||||
}
|
||||
|
||||
public Task<BackOfficeUserPasswordCheckerResult> CheckPasswordAsync(BackOfficeIdentityUser user, string password)
|
||||
{
|
||||
bool isValid;
|
||||
using (var pc = new PrincipalContext(ContextType.Domain, ActiveDirectoryDomain))
|
||||
{
|
||||
isValid = pc.ValidateCredentials(user.UserName, password);
|
||||
}
|
||||
|
||||
var result = isValid
|
||||
? BackOfficeUserPasswordCheckerResult.ValidCredentials
|
||||
: BackOfficeUserPasswordCheckerResult.InvalidCredentials;
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,8 +113,8 @@ namespace Umbraco.Core.Security
|
||||
|
||||
//Otherwise convert to a UmbracoBackOfficeIdentity if it's auth'd and has the back office session
|
||||
var claimsIdentity = http.User.Identity as ClaimsIdentity;
|
||||
if (claimsIdentity != null && claimsIdentity.IsAuthenticated)
|
||||
{
|
||||
if (claimsIdentity != null && claimsIdentity.IsAuthenticated && claimsIdentity.HasClaim(x => x.Type == Constants.Security.SessionIdClaimType))
|
||||
{
|
||||
try
|
||||
{
|
||||
return UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity);
|
||||
|
||||
@@ -7,7 +7,8 @@ using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
public class BackOfficeClaimsIdentityFactory : ClaimsIdentityFactory<BackOfficeIdentityUser, int>
|
||||
public class BackOfficeClaimsIdentityFactory<T> : ClaimsIdentityFactory<T, int>
|
||||
where T: BackOfficeIdentityUser
|
||||
{
|
||||
public BackOfficeClaimsIdentityFactory()
|
||||
{
|
||||
@@ -20,7 +21,7 @@ namespace Umbraco.Core.Security
|
||||
/// </summary>
|
||||
/// <param name="manager"/><param name="user"/><param name="authenticationType"/>
|
||||
/// <returns/>
|
||||
public override async Task<ClaimsIdentity> CreateAsync(UserManager<BackOfficeIdentityUser, int> manager, BackOfficeIdentityUser user, string authenticationType)
|
||||
public override async Task<ClaimsIdentity> CreateAsync(UserManager<T, int> manager, T user, string authenticationType)
|
||||
{
|
||||
var baseIdentity = await base.CreateAsync(manager, user, authenticationType);
|
||||
|
||||
@@ -42,4 +43,9 @@ namespace Umbraco.Core.Security
|
||||
return umbracoIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
public class BackOfficeClaimsIdentityFactory : BackOfficeClaimsIdentityFactory<BackOfficeIdentityUser>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Security
|
||||
private readonly ILogger _logger;
|
||||
private readonly IOwinRequest _request;
|
||||
|
||||
public BackOfficeSignInManager(BackOfficeUserManager userManager, IAuthenticationManager authenticationManager, ILogger logger, IOwinRequest request)
|
||||
public BackOfficeSignInManager(UserManager<BackOfficeIdentityUser, int> userManager, IAuthenticationManager authenticationManager, ILogger logger, IOwinRequest request)
|
||||
: base(userManager, authenticationManager)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
@@ -29,13 +29,13 @@ namespace Umbraco.Core.Security
|
||||
|
||||
public override Task<ClaimsIdentity> CreateUserIdentityAsync(BackOfficeIdentityUser user)
|
||||
{
|
||||
return user.GenerateUserIdentityAsync((BackOfficeUserManager)UserManager);
|
||||
return user.GenerateUserIdentityAsync((BackOfficeUserManager<BackOfficeIdentityUser>)UserManager);
|
||||
}
|
||||
|
||||
public static BackOfficeSignInManager Create(IdentityFactoryOptions<BackOfficeSignInManager> options, IOwinContext context, ILogger logger)
|
||||
{
|
||||
return new BackOfficeSignInManager(
|
||||
context.GetUserManager<BackOfficeUserManager>(),
|
||||
context.GetBackOfficeUserManager(),
|
||||
context.Authentication,
|
||||
logger,
|
||||
context.Request);
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using System.Web.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin.Security.DataProtection;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
@@ -15,6 +16,8 @@ namespace Umbraco.Core.Security
|
||||
/// </summary>
|
||||
public class BackOfficeUserManager : BackOfficeUserManager<BackOfficeIdentityUser>
|
||||
{
|
||||
public const string OwinMarkerKey = "Umbraco.Web.Security.Identity.BackOfficeUserManagerMarker";
|
||||
|
||||
public BackOfficeUserManager(IUserStore<BackOfficeIdentityUser, int> store)
|
||||
: base(store)
|
||||
{
|
||||
@@ -26,9 +29,8 @@ namespace Umbraco.Core.Security
|
||||
MembershipProviderBase membershipProvider)
|
||||
: base(store)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException("options");
|
||||
var manager = new BackOfficeUserManager(store);
|
||||
InitUserManager(manager, membershipProvider, options);
|
||||
if (options == null) throw new ArgumentNullException("options");;
|
||||
InitUserManager(this, membershipProvider, options);
|
||||
}
|
||||
|
||||
#region Static Create methods
|
||||
@@ -69,7 +71,7 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
var manager = new BackOfficeUserManager(customUserStore, options, membershipProvider);
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -79,65 +81,15 @@ namespace Umbraco.Core.Security
|
||||
/// <param name="membershipProvider"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
protected void InitUserManager(BackOfficeUserManager manager, MembershipProviderBase membershipProvider, IdentityFactoryOptions<BackOfficeUserManager> options)
|
||||
protected void InitUserManager(
|
||||
BackOfficeUserManager manager,
|
||||
MembershipProviderBase membershipProvider,
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options)
|
||||
{
|
||||
// Configure validation logic for usernames
|
||||
manager.UserValidator = new UserValidator<BackOfficeIdentityUser, int>(manager)
|
||||
{
|
||||
AllowOnlyAlphanumericUserNames = false,
|
||||
RequireUniqueEmail = true
|
||||
};
|
||||
|
||||
// Configure validation logic for passwords
|
||||
manager.PasswordValidator = new PasswordValidator
|
||||
{
|
||||
RequiredLength = membershipProvider.MinRequiredPasswordLength,
|
||||
RequireNonLetterOrDigit = membershipProvider.MinRequiredNonAlphanumericCharacters > 0,
|
||||
RequireDigit = false,
|
||||
RequireLowercase = false,
|
||||
RequireUppercase = false
|
||||
//TODO: Do we support the old regex match thing that membership providers used?
|
||||
};
|
||||
|
||||
//use a custom hasher based on our membership provider
|
||||
manager.PasswordHasher = new MembershipPasswordHasher(membershipProvider);
|
||||
|
||||
var dataProtectionProvider = options.DataProtectionProvider;
|
||||
if (dataProtectionProvider != null)
|
||||
{
|
||||
manager.UserTokenProvider = new DataProtectorTokenProvider<BackOfficeIdentityUser, int>(dataProtectionProvider.Create("ASP.NET Identity"));
|
||||
}
|
||||
|
||||
manager.UserLockoutEnabledByDefault = true;
|
||||
manager.MaxFailedAccessAttemptsBeforeLockout = membershipProvider.MaxInvalidPasswordAttempts;
|
||||
//NOTE: This just needs to be in the future, we currently don't support a lockout timespan, it's either they are locked
|
||||
// or they are not locked, but this determines what is set on the account lockout date which corresponds to whether they are
|
||||
// locked out or not.
|
||||
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromDays(30);
|
||||
|
||||
//custom identity factory for creating the identity object for which we auth against in the back office
|
||||
manager.ClaimsIdentityFactory = new BackOfficeClaimsIdentityFactory();
|
||||
|
||||
manager.EmailService = new EmailService();
|
||||
|
||||
//NOTE: Not implementing these, if people need custom 2 factor auth, they'll need to implement their own UserStore to suport it
|
||||
|
||||
//// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
|
||||
//// You can write your own provider and plug in here.
|
||||
//manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>
|
||||
//{
|
||||
// MessageFormat = "Your security code is: {0}"
|
||||
//});
|
||||
//manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
|
||||
//{
|
||||
// Subject = "Security Code",
|
||||
// BodyFormat = "Your security code is: {0}"
|
||||
//});
|
||||
|
||||
//manager.SmsService = new SmsService();
|
||||
//NOTE: This method is mostly here for backwards compat
|
||||
base.InitUserManager(manager, membershipProvider, options.DataProtectionProvider);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -180,6 +132,73 @@ namespace Umbraco.Core.Security
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the user manager with the correct options
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="membershipProvider"></param>
|
||||
/// <param name="dataProtectionProvider"></param>
|
||||
/// <returns></returns>
|
||||
protected void InitUserManager(
|
||||
BackOfficeUserManager<T> manager,
|
||||
MembershipProviderBase membershipProvider,
|
||||
IDataProtectionProvider dataProtectionProvider)
|
||||
{
|
||||
// Configure validation logic for usernames
|
||||
manager.UserValidator = new UserValidator<T, int>(manager)
|
||||
{
|
||||
AllowOnlyAlphanumericUserNames = false,
|
||||
RequireUniqueEmail = true
|
||||
};
|
||||
|
||||
// Configure validation logic for passwords
|
||||
manager.PasswordValidator = new PasswordValidator
|
||||
{
|
||||
RequiredLength = membershipProvider.MinRequiredPasswordLength,
|
||||
RequireNonLetterOrDigit = membershipProvider.MinRequiredNonAlphanumericCharacters > 0,
|
||||
RequireDigit = false,
|
||||
RequireLowercase = false,
|
||||
RequireUppercase = false
|
||||
//TODO: Do we support the old regex match thing that membership providers used?
|
||||
};
|
||||
|
||||
//use a custom hasher based on our membership provider
|
||||
manager.PasswordHasher = new MembershipPasswordHasher(membershipProvider);
|
||||
|
||||
if (dataProtectionProvider != null)
|
||||
{
|
||||
manager.UserTokenProvider = new DataProtectorTokenProvider<T, int>(dataProtectionProvider.Create("ASP.NET Identity"));
|
||||
}
|
||||
|
||||
manager.UserLockoutEnabledByDefault = true;
|
||||
manager.MaxFailedAccessAttemptsBeforeLockout = membershipProvider.MaxInvalidPasswordAttempts;
|
||||
//NOTE: This just needs to be in the future, we currently don't support a lockout timespan, it's either they are locked
|
||||
// or they are not locked, but this determines what is set on the account lockout date which corresponds to whether they are
|
||||
// locked out or not.
|
||||
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromDays(30);
|
||||
|
||||
//custom identity factory for creating the identity object for which we auth against in the back office
|
||||
manager.ClaimsIdentityFactory = new BackOfficeClaimsIdentityFactory<T>();
|
||||
|
||||
manager.EmailService = new EmailService();
|
||||
|
||||
//NOTE: Not implementing these, if people need custom 2 factor auth, they'll need to implement their own UserStore to suport it
|
||||
|
||||
//// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
|
||||
//// You can write your own provider and plug in here.
|
||||
//manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>
|
||||
//{
|
||||
// MessageFormat = "Your security code is: {0}"
|
||||
//});
|
||||
//manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
|
||||
//{
|
||||
// Subject = "Security Code",
|
||||
// BodyFormat = "Your security code is: {0}"
|
||||
//});
|
||||
|
||||
//manager.SmsService = new SmsService();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logic used to validate a username and password
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is only here due to the fact that IOwinContext Get / Set only work in generics, if they worked
|
||||
/// with regular 'object' then we wouldn't have to use this work around but because of that we have to use this
|
||||
/// class to resolve the 'real' type of the registered user manager
|
||||
/// </summary>
|
||||
/// <typeparam name="TManager"></typeparam>
|
||||
/// <typeparam name="TUser"></typeparam>
|
||||
internal class BackOfficeUserManagerMarker<TManager, TUser> : IBackOfficeUserManagerMarker
|
||||
where TManager : BackOfficeUserManager<TUser>
|
||||
where TUser : BackOfficeIdentityUser
|
||||
{
|
||||
public BackOfficeUserManager<BackOfficeIdentityUser> GetManager(IOwinContext owin)
|
||||
{
|
||||
var mgr = owin.Get<TManager>() as BackOfficeUserManager<BackOfficeIdentityUser>;
|
||||
if (mgr == null) throw new InvalidOperationException("Could not cast the registered back office user of type " + typeof(TManager) + " to " + typeof(BackOfficeUserManager<BackOfficeIdentityUser>));
|
||||
return mgr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.Owin;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface is only here due to the fact that IOwinContext Get / Set only work in generics, if they worked
|
||||
/// with regular 'object' then we wouldn't have to use this work around but because of that we have to use this
|
||||
/// class to resolve the 'real' type of the registered user manager
|
||||
/// </summary>
|
||||
internal interface IBackOfficeUserManagerMarker
|
||||
{
|
||||
BackOfficeUserManager<BackOfficeIdentityUser> GetManager(IOwinContext owin);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
public static class OwinExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the back office sign in manager out of OWIN
|
||||
/// </summary>
|
||||
/// <param name="owinContext"></param>
|
||||
/// <returns></returns>
|
||||
public static BackOfficeSignInManager GetBackOfficeSignInManager(this IOwinContext owinContext)
|
||||
{
|
||||
var mgr = owinContext.Get<BackOfficeSignInManager>();
|
||||
if (mgr == null)
|
||||
{
|
||||
throw new NullReferenceException("Could not resolve an instance of " + typeof(BackOfficeSignInManager) + " from the " + typeof(IOwinContext));
|
||||
}
|
||||
return mgr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the back office user manager out of OWIN
|
||||
/// </summary>
|
||||
/// <param name="owinContext"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is required because to extract the user manager we need to user a custom service since owin only deals in generics and
|
||||
/// developers could register their own user manager types
|
||||
/// </remarks>
|
||||
public static BackOfficeUserManager<BackOfficeIdentityUser> GetBackOfficeUserManager(this IOwinContext owinContext)
|
||||
{
|
||||
var marker = owinContext.Get<IBackOfficeUserManagerMarker>(BackOfficeUserManager.OwinMarkerKey);
|
||||
if (marker == null) throw new NullReferenceException("No " + typeof(IBackOfficeUserManagerMarker) + " has been registered with Owin which means that no Umbraco back office user manager has been registered");
|
||||
|
||||
var mgr = marker.GetManager(owinContext);
|
||||
if (mgr == null)
|
||||
{
|
||||
throw new NullReferenceException("Could not resolve an instance of " + typeof(BackOfficeUserManager<BackOfficeIdentityUser>));
|
||||
}
|
||||
return mgr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Auditing;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -341,11 +342,23 @@ namespace Umbraco.Core.Services
|
||||
/// <returns><see cref="IContent"/></returns>
|
||||
public IEnumerable<IContent> GetByIds(IEnumerable<int> ids)
|
||||
{
|
||||
if (ids.Any() == false) return Enumerable.Empty<IContent>();
|
||||
var idsArray = ids.ToArray();
|
||||
if (idsArray.Length == 0) return Enumerable.Empty<IContent>();
|
||||
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetAll(ids.ToArray());
|
||||
//ensure that the result has the order based on the ids passed in
|
||||
var result = repository.GetAll(idsArray);
|
||||
|
||||
var content = result.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
var sortedResult = idsArray.Select(x =>
|
||||
{
|
||||
IContent c;
|
||||
return content.TryGetValue(x, out c) ? c : null;
|
||||
}).WhereNotNull();
|
||||
|
||||
return sortedResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,6 +448,21 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all version Ids for the given content item ordered so latest is first
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="maxRows">The maximum number of rows to return</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Guid> GetVersionIds(int id, int maxRows)
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var versions = repository.GetVersionIds(id, maxRows);
|
||||
return versions;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of <see cref="IContent"/> objects, which are ancestors of the current content.
|
||||
/// </summary>
|
||||
@@ -636,7 +664,7 @@ namespace Umbraco.Core.Services
|
||||
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
|
||||
}
|
||||
var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
|
||||
|
||||
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -1714,6 +1742,20 @@ namespace Umbraco.Core.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This builds the Xml document used for the XML cache
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public XmlDocument BuildXmlCache()
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
var result = repository.BuildXmlCache();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds all xml content in the cmsContentXml table for all documents
|
||||
/// </summary>
|
||||
|
||||
@@ -791,21 +791,23 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
|
||||
//TODO: This needs to change, if we are deleting a content type, we should just delete the data,
|
||||
// this method will recursively go lookup every content item, check if any of it's descendants are
|
||||
// of a different type, move them to the recycle bin, then permanently delete the content items.
|
||||
// The main problem with this is that for every content item being deleted, events are raised...
|
||||
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
|
||||
|
||||
_contentService.DeleteContentOfType(contentType.Id);
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
//TODO: This needs to change, if we are deleting a content type, we should just delete the data,
|
||||
// this method will recursively go lookup every content item, check if any of it's descendants are
|
||||
// of a different type, move them to the recycle bin, then permanently delete the content items.
|
||||
// The main problem with this is that for every content item being deleted, events are raised...
|
||||
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
|
||||
|
||||
var deletedContentTypes = new List<IContentType>() {contentType};
|
||||
deletedContentTypes.AddRange(contentType.Descendants().OfType<IContentType>());
|
||||
|
||||
foreach (var deletedContentType in deletedContentTypes)
|
||||
{
|
||||
_contentService.DeleteContentOfType(deletedContentType.Id);
|
||||
}
|
||||
|
||||
repository.Delete(contentType);
|
||||
uow.Commit();
|
||||
|
||||
@@ -833,11 +835,6 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
foreach (var contentType in asArray)
|
||||
{
|
||||
_contentService.DeleteContentOfType(contentType.Id);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
@@ -847,6 +844,15 @@ namespace Umbraco.Core.Services
|
||||
foreach (var contentType in asArray)
|
||||
{
|
||||
deletedContentTypes.AddRange(contentType.Descendants().OfType<IContentType>());
|
||||
}
|
||||
|
||||
foreach (var deletedContentType in deletedContentTypes)
|
||||
{
|
||||
_contentService.DeleteContentOfType(deletedContentType.Id);
|
||||
}
|
||||
|
||||
foreach (var contentType in asArray)
|
||||
{
|
||||
repository.Delete(contentType);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Xml;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
@@ -94,6 +95,12 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IContentService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// This builds the Xml document used for the XML cache
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
XmlDocument BuildXmlCache();
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds all xml content in the cmsContentXml table for all documents
|
||||
/// </summary>
|
||||
@@ -291,6 +298,14 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
IEnumerable<IContent> GetVersions(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all version Ids for the given content item ordered so latest is first
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="maxRows">The maximum number of rows to return</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<Guid> GetVersionIds(int id, int maxRows);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of <see cref="IContent"/> objects, which reside at the first level / root
|
||||
/// </summary>
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Services
|
||||
/// Deletes a redirect url.
|
||||
/// </summary>
|
||||
/// <param name="id">The redirect url identifier.</param>
|
||||
void Delete(int id);
|
||||
void Delete(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all redirect urls.
|
||||
@@ -72,5 +72,15 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="total">The total count of redirect urls.</param>
|
||||
/// <returns>The redirect urls.</returns>
|
||||
IEnumerable<IRedirectUrl> GetAllRedirectUrls(int rootContentId, long pageIndex, int pageSize, out long total);
|
||||
|
||||
/// <summary>
|
||||
/// Searches for all redirect urls that contain a given search term in their URL property.
|
||||
/// </summary>
|
||||
/// <param name="searchTerm">The term to search for.</param>
|
||||
/// <param name="pageIndex">The page index.</param>
|
||||
/// <param name="pageSize">The page size.</param>
|
||||
/// <param name="total">The total count of redirect urls.</param>
|
||||
/// <returns>The redirect urls.</returns>
|
||||
IEnumerable<IRedirectUrl> SearchRedirectUrls(string searchTerm, long pageIndex, int pageSize, out long total);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -15,7 +16,6 @@ using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Strings;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
@@ -55,38 +55,72 @@ namespace Umbraco.Core.Services
|
||||
Func<IUser, string[], string> createSubject,
|
||||
Func<IUser, string[], string> createBody)
|
||||
{
|
||||
if ((entity is IContent) == false)
|
||||
if (entity is IContent == false)
|
||||
throw new NotSupportedException();
|
||||
|
||||
var content = (IContent) entity;
|
||||
|
||||
// lazily get versions - into a list to ensure we can enumerate multiple times
|
||||
List<IContent> allVersions = null;
|
||||
var content = (IContent) entity;
|
||||
|
||||
int totalUsers;
|
||||
var allUsers = _userService.GetAll(0, int.MaxValue, out totalUsers);
|
||||
foreach (var u in allUsers.Where(x => x.IsApproved))
|
||||
// lazily get previous version
|
||||
IContentBase prevVersion = null;
|
||||
|
||||
// do not load *all* users in memory at once
|
||||
// do not load notifications *per user* (N+1 select)
|
||||
// cannot load users & notifications in 1 query (combination btw User2AppDto and User2NodeNotifyDto)
|
||||
// => get batches of users, get all their notifications in 1 query
|
||||
// re. users:
|
||||
// users being (dis)approved = not an issue, filtered in memory not in SQL
|
||||
// users being modified or created = not an issue, ordering by ID, as long as we don't *insert* low IDs
|
||||
// users being deleted = not an issue for GetNextUsers
|
||||
var id = 0;
|
||||
var nodeIds = content.Path.Split(',').Select(int.Parse).ToArray();
|
||||
const int pagesz = 400; // load batches of 400 users
|
||||
do
|
||||
{
|
||||
var userNotifications = GetUserNotifications(u, content.Path);
|
||||
var notificationForAction = userNotifications.FirstOrDefault(x => x.Action == action);
|
||||
if (notificationForAction == null) continue;
|
||||
// users are returned ordered by id, notifications are returned ordered by user id
|
||||
var users = ((UserService) _userService).GetNextUsers(id, pagesz).Where(x => x.IsApproved).ToList();
|
||||
var notifications = GetUsersNotifications(users.Select(x => x.Id), action, nodeIds, Constants.ObjectTypes.DocumentGuid).ToList();
|
||||
if (notifications.Count == 0) break;
|
||||
|
||||
if (allVersions == null) // lazy load
|
||||
allVersions = _contentService.GetVersions(entity.Id).ToList();
|
||||
|
||||
try
|
||||
var i = 0;
|
||||
foreach (var user in users)
|
||||
{
|
||||
SendNotification(operatingUser, u, content, allVersions,
|
||||
actionName, http, createSubject, createBody);
|
||||
// continue if there's no notification for this user
|
||||
if (notifications[i].UserId != user.Id) continue; // next user
|
||||
|
||||
_logger.Debug<NotificationService>(string.Format("Notification type: {0} sent to {1} ({2})",
|
||||
action, u.Name, u.Email));
|
||||
// lazy load prev version
|
||||
if (prevVersion == null)
|
||||
{
|
||||
prevVersion = GetPreviousVersion(entity.Id);
|
||||
}
|
||||
|
||||
// queue notification
|
||||
var req = CreateNotificationRequest(operatingUser, user, content, prevVersion, actionName, http, createSubject, createBody);
|
||||
Enqueue(req);
|
||||
|
||||
// skip other notifications for this user
|
||||
while (i < notifications.Count && notifications[i++].UserId == user.Id) ;
|
||||
if (i >= notifications.Count) break; // break if no more notifications
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<NotificationService>("An error occurred sending notification", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// load more users if any
|
||||
id = users.Count == pagesz ? users.Last().Id + 1 : -1;
|
||||
|
||||
} while (id > 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the previous version to the latest version of the content item if there is one
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
/// <returns></returns>
|
||||
private IContentBase GetPreviousVersion(int contentId)
|
||||
{
|
||||
// Regarding this: http://issues.umbraco.org/issue/U4-5180
|
||||
// we know they are descending from the service so we know that newest is first
|
||||
// we are only selecting the top 2 rows since that is all we need
|
||||
var allVersions = _contentService.GetVersionIds(contentId, 2).ToList();
|
||||
var prevVersionIndex = allVersions.Count > 1 ? 1 : 0;
|
||||
return _contentService.GetByVersion(allVersions[prevVersionIndex]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,47 +140,76 @@ namespace Umbraco.Core.Services
|
||||
Func<IUser, string[], string> createSubject,
|
||||
Func<IUser, string[], string> createBody)
|
||||
{
|
||||
if ((entities is IEnumerable<IContent>) == false)
|
||||
if (entities is IEnumerable<IContent> == false)
|
||||
throw new NotSupportedException();
|
||||
|
||||
// ensure we can enumerate multiple times
|
||||
var entitiesL = entities as List<IContent> ?? entities.Cast<IContent>().ToList();
|
||||
|
||||
// lazily get versions - into lists to ensure we can enumerate multiple times
|
||||
var allVersionsDictionary = new Dictionary<int, List<IContent>>();
|
||||
//exit if there are no entities
|
||||
if (entitiesL.Count == 0) return;
|
||||
|
||||
int totalUsers;
|
||||
var allUsers = _userService.GetAll(0, int.MaxValue, out totalUsers);
|
||||
foreach (var u in allUsers.Where(x => x.IsApproved))
|
||||
//put all entity's paths into a list with the same indicies
|
||||
var paths = entitiesL.Select(x => x.Path.Split(',').Select(int.Parse).ToArray()).ToArray();
|
||||
|
||||
// lazily get versions
|
||||
var prevVersionDictionary = new Dictionary<int, IContentBase>();
|
||||
|
||||
// see notes above
|
||||
var id = 0;
|
||||
const int pagesz = 400; // load batches of 400 users
|
||||
do
|
||||
{
|
||||
var userNotifications = GetUserNotifications(u).ToArray();
|
||||
|
||||
foreach (var content in entitiesL)
|
||||
// users are returned ordered by id, notifications are returned ordered by user id
|
||||
var users = ((UserService)_userService).GetNextUsers(id, pagesz).Where(x => x.IsApproved).ToList();
|
||||
var notifications = GetUsersNotifications(users.Select(x => x.Id), action, Enumerable.Empty<int>(), Constants.ObjectTypes.DocumentGuid).ToList();
|
||||
if (notifications.Count == 0) break;
|
||||
|
||||
var i = 0;
|
||||
foreach (var user in users)
|
||||
{
|
||||
var userNotificationsByPath = FilterUserNotificationsByPath(userNotifications, content.Path);
|
||||
var notificationForAction = userNotificationsByPath.FirstOrDefault(x => x.Action == action);
|
||||
if (notificationForAction == null) continue;
|
||||
// continue if there's no notification for this user
|
||||
if (notifications[i].UserId != user.Id) continue; // next user
|
||||
|
||||
var allVersions = allVersionsDictionary.ContainsKey(content.Id) // lazy load
|
||||
? allVersionsDictionary[content.Id]
|
||||
: allVersionsDictionary[content.Id] = _contentService.GetVersions(content.Id).ToList();
|
||||
|
||||
try
|
||||
for (var j = 0; j < entitiesL.Count; j++)
|
||||
{
|
||||
SendNotification(operatingUser, u, content, allVersions,
|
||||
actionName, http, createSubject, createBody);
|
||||
var content = entitiesL[j];
|
||||
var path = paths[j];
|
||||
|
||||
// test if the notification applies to the path ie to this entity
|
||||
if (path.Contains(notifications[i].EntityId) == false) continue; // next entity
|
||||
|
||||
if (prevVersionDictionary.ContainsKey(content.Id) == false)
|
||||
{
|
||||
prevVersionDictionary[content.Id] = GetPreviousVersion(content.Id);
|
||||
}
|
||||
|
||||
// queue notification
|
||||
var req = CreateNotificationRequest(operatingUser, user, content, prevVersionDictionary[content.Id], actionName, http, createSubject, createBody);
|
||||
Enqueue(req);
|
||||
}
|
||||
|
||||
_logger.Debug<NotificationService>(string.Format("Notification type: {0} sent to {1} ({2})",
|
||||
action, u.Name, u.Email));
|
||||
}
|
||||
catch (Exception ex)
|
||||
// skip other notifications for this user, essentially this means moving i to the next index of notifications
|
||||
// for the next user.
|
||||
do
|
||||
{
|
||||
_logger.Error<NotificationService>("An error occurred sending notification", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} while (i < notifications.Count && notifications[i].UserId == user.Id);
|
||||
|
||||
if (i >= notifications.Count) break; // break if no more notifications
|
||||
}
|
||||
|
||||
// load more users if any
|
||||
id = users.Count == pagesz ? users.Last().Id + 1 : -1;
|
||||
|
||||
} while (id > 0);
|
||||
}
|
||||
|
||||
private IEnumerable<Notification> GetUsersNotifications(IEnumerable<int> userIds, string action, IEnumerable<int> nodeIds, Guid objectType)
|
||||
{
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
var repository = new NotificationsRepository(uow);
|
||||
return repository.GetUsersNotifications(userIds, action, nodeIds, objectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the notifications for the user
|
||||
@@ -184,7 +247,7 @@ namespace Umbraco.Core.Services
|
||||
public IEnumerable<Notification> FilterUserNotificationsByPath(IEnumerable<Notification> userNotifications, string path)
|
||||
{
|
||||
var pathParts = path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
|
||||
return userNotifications.Where(r => pathParts.InvariantContains(r.EntityId.ToString(CultureInfo.InvariantCulture))).ToList();
|
||||
return userNotifications.Where(r => pathParts.InvariantContains(r.EntityId.ToString(CultureInfo.InvariantCulture))).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -254,29 +317,23 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="performingUser"></param>
|
||||
/// <param name="mailingUser"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="allVersions"></param>
|
||||
/// <param name="oldDoc"></param>
|
||||
/// <param name="actionName">The action readable name - currently an action is just a single letter, this is the name associated with the letter </param>
|
||||
/// <param name="http"></param>
|
||||
/// <param name="createSubject">Callback to create the mail subject</param>
|
||||
/// <param name="createBody">Callback to create the mail body</param>
|
||||
private void SendNotification(IUser performingUser, IUser mailingUser, IContent content, IEnumerable<IContent> allVersions, string actionName, HttpContextBase http,
|
||||
private NotificationRequest CreateNotificationRequest(IUser performingUser, IUser mailingUser, IContentBase content, IContentBase oldDoc,
|
||||
string actionName, HttpContextBase http,
|
||||
Func<IUser, string[], string> createSubject,
|
||||
Func<IUser, string[], string> createBody)
|
||||
{
|
||||
if (performingUser == null) throw new ArgumentNullException("performingUser");
|
||||
if (mailingUser == null) throw new ArgumentNullException("mailingUser");
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
if (allVersions == null) throw new ArgumentNullException("allVersions");
|
||||
if (http == null) throw new ArgumentNullException("http");
|
||||
if (createSubject == null) throw new ArgumentNullException("createSubject");
|
||||
if (createBody == null) throw new ArgumentNullException("createBody");
|
||||
|
||||
//Ensure they are sorted: http://issues.umbraco.org/issue/U4-5180
|
||||
var allVersionsAsArray = allVersions.OrderBy(x => x.UpdateDate).ToArray();
|
||||
|
||||
int versionCount = (allVersionsAsArray.Length > 1) ? (allVersionsAsArray.Length - 2) : (allVersionsAsArray.Length - 1);
|
||||
var oldDoc = _contentService.GetByVersion(allVersionsAsArray[versionCount].Version);
|
||||
|
||||
if (createBody == null) throw new ArgumentNullException("createBody");
|
||||
|
||||
// build summary
|
||||
var summary = new StringBuilder();
|
||||
var props = content.Properties.ToArray();
|
||||
@@ -290,16 +347,16 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var oldProperty = oldDoc.Properties[p.PropertyType.Alias];
|
||||
oldText = oldProperty.Value != null ? oldProperty.Value.ToString() : "";
|
||||
|
||||
|
||||
// replace html with char equivalent
|
||||
ReplaceHtmlSymbols(ref oldText);
|
||||
ReplaceHtmlSymbols(ref newText);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// make sure to only highlight changes done using TinyMCE editor... other changes will be displayed using default summary
|
||||
// TODO: We should probably allow more than just tinymce??
|
||||
if ((p.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.TinyMCEAlias)
|
||||
if ((p.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.TinyMCEAlias)
|
||||
&& string.CompareOrdinal(oldText, newText) != 0)
|
||||
{
|
||||
summary.Append("<tr>");
|
||||
@@ -308,26 +365,31 @@ namespace Umbraco.Core.Services
|
||||
"<td style='text-align: left; vertical-align: top;'> <span style='background-color:red;'>Red for deleted characters</span> <span style='background-color:yellow;'>Yellow for inserted characters</span></td>");
|
||||
summary.Append("</tr>");
|
||||
summary.Append("<tr>");
|
||||
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'> New " +
|
||||
p.PropertyType.Name + "</th>");
|
||||
summary.Append("<td style='text-align: left; vertical-align: top;'>" +
|
||||
ReplaceLinks(CompareText(oldText, newText, true, false, "<span style='background-color:yellow;'>", string.Empty), http.Request) +
|
||||
"</td>");
|
||||
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'> New ");
|
||||
summary.Append(p.PropertyType.Name);
|
||||
summary.Append("</th>");
|
||||
summary.Append("<td style='text-align: left; vertical-align: top;'>");
|
||||
summary.Append(ReplaceLinks(CompareText(oldText, newText, true, false, "<span style='background-color:yellow;'>", string.Empty), http.Request));
|
||||
summary.Append("</td>");
|
||||
summary.Append("</tr>");
|
||||
summary.Append("<tr>");
|
||||
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'> Old " +
|
||||
p.PropertyType.Name + "</th>");
|
||||
summary.Append("<td style='text-align: left; vertical-align: top;'>" +
|
||||
ReplaceLinks(CompareText(newText, oldText, true, false, "<span style='background-color:red;'>", string.Empty), http.Request) +
|
||||
"</td>");
|
||||
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'> Old ");
|
||||
summary.Append(p.PropertyType.Name);
|
||||
summary.Append("</th>");
|
||||
summary.Append("<td style='text-align: left; vertical-align: top;'>");
|
||||
summary.Append(ReplaceLinks(CompareText(newText, oldText, true, false, "<span style='background-color:red;'>", string.Empty), http.Request));
|
||||
summary.Append("</td>");
|
||||
summary.Append("</tr>");
|
||||
}
|
||||
else
|
||||
{
|
||||
summary.Append("<tr>");
|
||||
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'>" +
|
||||
p.PropertyType.Name + "</th>");
|
||||
summary.Append("<td style='text-align: left; vertical-align: top;'>" + newText + "</td>");
|
||||
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'>");
|
||||
summary.Append(p.PropertyType.Name);
|
||||
summary.Append("</th>");
|
||||
summary.Append("<td style='text-align: left; vertical-align: top;'>");
|
||||
summary.Append(newText);
|
||||
summary.Append("</td>");
|
||||
summary.Append("</tr>");
|
||||
}
|
||||
summary.Append(
|
||||
@@ -338,29 +400,27 @@ namespace Umbraco.Core.Services
|
||||
|
||||
|
||||
string[] subjectVars = {
|
||||
http.Request.ServerVariables["SERVER_NAME"] + ":" +
|
||||
http.Request.Url.Port +
|
||||
IOHelper.ResolveUrl(SystemDirectories.Umbraco),
|
||||
string.Concat(http.Request.ServerVariables["SERVER_NAME"], ":", http.Request.Url.Port, IOHelper.ResolveUrl(SystemDirectories.Umbraco)),
|
||||
actionName,
|
||||
content.Name
|
||||
};
|
||||
string[] bodyVars = {
|
||||
mailingUser.Name,
|
||||
actionName,
|
||||
content.Name,
|
||||
mailingUser.Name,
|
||||
actionName,
|
||||
content.Name,
|
||||
performingUser.Name,
|
||||
http.Request.ServerVariables["SERVER_NAME"] + ":" + http.Request.Url.Port + IOHelper.ResolveUrl(SystemDirectories.Umbraco),
|
||||
string.Concat(http.Request.ServerVariables["SERVER_NAME"], ":", http.Request.Url.Port, IOHelper.ResolveUrl(SystemDirectories.Umbraco)),
|
||||
content.Id.ToString(CultureInfo.InvariantCulture), summary.ToString(),
|
||||
string.Format("{2}://{0}/{1}",
|
||||
http.Request.ServerVariables["SERVER_NAME"] + ":" + http.Request.Url.Port,
|
||||
string.Concat(http.Request.ServerVariables["SERVER_NAME"], ":", http.Request.Url.Port),
|
||||
//TODO: RE-enable this so we can have a nice url
|
||||
/*umbraco.library.NiceUrl(documentObject.Id))*/
|
||||
content.Id + ".aspx",
|
||||
string.Concat(content.Id, ".aspx"),
|
||||
protocol)
|
||||
|
||||
|
||||
};
|
||||
|
||||
// create the mail message
|
||||
// create the mail message
|
||||
var mail = new MailMessage(UmbracoConfig.For.UmbracoSettings().Content.NotificationEmailAddress, mailingUser.Email);
|
||||
|
||||
// populate the message
|
||||
@@ -374,10 +434,10 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
mail.IsBodyHtml = true;
|
||||
mail.Body =
|
||||
@"<html><head>
|
||||
string.Concat(@"<html><head>
|
||||
</head>
|
||||
<body style='font-family: Trebuchet MS, arial, sans-serif; font-color: black;'>
|
||||
" + createBody(mailingUser, bodyVars);
|
||||
", createBody(mailingUser, bodyVars));
|
||||
}
|
||||
|
||||
// nh, issue 30724. Due to hardcoded http strings in resource files, we need to check for https replacements here
|
||||
@@ -390,32 +450,17 @@ namespace Umbraco.Core.Services
|
||||
string.Format("https://{0}", serverName));
|
||||
}
|
||||
|
||||
|
||||
// send it asynchronously, we don't want to got up all of the request time to send emails!
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using (mail)
|
||||
{
|
||||
using (var sender = new SmtpClient())
|
||||
{
|
||||
sender.Send(mail);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<NotificationService>("An error occurred sending notification", ex);
|
||||
}
|
||||
});
|
||||
return new NotificationRequest(mail, actionName, mailingUser.Name, mailingUser.Email);
|
||||
}
|
||||
|
||||
private static string ReplaceLinks(string text, HttpRequestBase request)
|
||||
{
|
||||
string domain = GlobalSettings.UseSSL ? "https://" : "http://";
|
||||
domain += request.ServerVariables["SERVER_NAME"] + ":" + request.Url.Port + "/";
|
||||
var sb = new StringBuilder(GlobalSettings.UseSSL ? "https://" : "http://");
|
||||
sb.Append(request.ServerVariables["SERVER_NAME"]);
|
||||
sb.Append(":");
|
||||
sb.Append(request.Url.Port);
|
||||
sb.Append("/");
|
||||
var domain = sb.ToString();
|
||||
text = text.Replace("href=\"/", "href=\"" + domain);
|
||||
text = text.Replace("src=\"/", "src=\"" + domain);
|
||||
return text;
|
||||
@@ -484,7 +529,7 @@ namespace Umbraco.Core.Services
|
||||
pos++;
|
||||
} // while
|
||||
sb.Append("</span>");
|
||||
} // if
|
||||
} // if
|
||||
} // while
|
||||
|
||||
// write rest of unchanged chars
|
||||
@@ -495,8 +540,95 @@ namespace Umbraco.Core.Services
|
||||
} // while
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
// manage notifications
|
||||
// ideally, would need to use IBackgroundTasks - but they are not part of Core!
|
||||
|
||||
private static readonly object Locker = new object();
|
||||
private static readonly BlockingCollection<NotificationRequest> Queue = new BlockingCollection<NotificationRequest>();
|
||||
private static volatile bool _running;
|
||||
|
||||
private void Enqueue(NotificationRequest notification)
|
||||
{
|
||||
Queue.Add(notification);
|
||||
if (_running) return;
|
||||
lock (Locker)
|
||||
{
|
||||
if (_running) return;
|
||||
Process(Queue);
|
||||
_running = true;
|
||||
}
|
||||
}
|
||||
|
||||
private class NotificationRequest
|
||||
{
|
||||
public NotificationRequest(MailMessage mail, string action, string userName, string email)
|
||||
{
|
||||
Mail = mail;
|
||||
Action = action;
|
||||
UserName = userName;
|
||||
Email = email;
|
||||
}
|
||||
|
||||
public MailMessage Mail { get; private set; }
|
||||
|
||||
public string Action { get; private set; }
|
||||
|
||||
public string UserName { get; private set; }
|
||||
|
||||
public string Email { get; private set; }
|
||||
}
|
||||
|
||||
private void Process(BlockingCollection<NotificationRequest> notificationRequests)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
var s = new SmtpClient();
|
||||
try
|
||||
{
|
||||
_logger.Debug<NotificationService>("Begin processing notifications.");
|
||||
while (true)
|
||||
{
|
||||
NotificationRequest request;
|
||||
while (notificationRequests.TryTake(out request, 8 * 1000)) // stay on for 8s
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Sendmail != null) Sendmail(s, request.Mail, _logger); else s.Send(request.Mail);
|
||||
_logger.Debug<NotificationService>(string.Format("Notification \"{0}\" sent to {1} ({2})", request.Action, request.UserName, request.Email));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<NotificationService>("An error occurred sending notification", ex);
|
||||
s.Dispose();
|
||||
s = new SmtpClient();
|
||||
}
|
||||
finally
|
||||
{
|
||||
request.Mail.Dispose();
|
||||
}
|
||||
}
|
||||
lock (Locker)
|
||||
{
|
||||
if (notificationRequests.Count > 0) continue; // last chance
|
||||
_running = false; // going down
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
s.Dispose();
|
||||
}
|
||||
_logger.Debug<NotificationService>("Done processing notifications.");
|
||||
});
|
||||
}
|
||||
|
||||
// for tests
|
||||
internal static Action<SmtpClient, MailMessage, ILogger> Sendmail;
|
||||
//= (_, msg, logger) => logger.Debug<NotificationService>("Email " + msg.To.ToString());
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Services
|
||||
if (redir != null)
|
||||
redir.CreateDateUtc = DateTime.UtcNow;
|
||||
else
|
||||
redir = new RedirectUrl { Url = url, ContentKey = contentKey };
|
||||
redir = new RedirectUrl { Key = Guid.NewGuid(), Url = url, ContentKey = contentKey };
|
||||
repo.AddOrUpdate(redir);
|
||||
uow.Commit();
|
||||
}
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
public void Delete(Guid id)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var repo = RepositoryFactory.CreateRedirectUrlRepository(uow))
|
||||
@@ -75,7 +75,6 @@ namespace Umbraco.Core.Services
|
||||
using (var repo = RepositoryFactory.CreateRedirectUrlRepository(uow))
|
||||
{
|
||||
var rule = repo.GetMostRecentUrl(url);
|
||||
uow.Commit();
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
@@ -86,7 +85,6 @@ namespace Umbraco.Core.Services
|
||||
using (var repo = RepositoryFactory.CreateRedirectUrlRepository(uow))
|
||||
{
|
||||
var rules = repo.GetContentUrls(contentKey);
|
||||
uow.Commit();
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
@@ -97,7 +95,6 @@ namespace Umbraco.Core.Services
|
||||
using (var repo = RepositoryFactory.CreateRedirectUrlRepository(uow))
|
||||
{
|
||||
var rules = repo.GetAllUrls(pageIndex, pageSize, out total);
|
||||
uow.Commit();
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
@@ -108,7 +105,15 @@ namespace Umbraco.Core.Services
|
||||
using (var repo = RepositoryFactory.CreateRedirectUrlRepository(uow))
|
||||
{
|
||||
var rules = repo.GetAllUrls(rootContentId, pageIndex, pageSize, out total);
|
||||
uow.Commit();
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
public IEnumerable<IRedirectUrl> SearchRedirectUrls(string searchTerm, long pageIndex, int pageSize, out long total)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var repo = RepositoryFactory.CreateRedirectUrlRepository(uow))
|
||||
{
|
||||
var rules = repo.SearchUrls(searchTerm, pageIndex, pageSize, out total);
|
||||
return rules;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
@@ -506,6 +507,15 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
internal IEnumerable<IUser> GetNextUsers(int id, int count)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = (UserRepository) RepositoryFactory.CreateUserRepository(uow))
|
||||
{
|
||||
return repository.GetNextUsers(id, count);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IUserService
|
||||
|
||||
@@ -666,31 +666,12 @@ namespace Umbraco.Core
|
||||
return compare.Contains(compareTo, StringComparer.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the string is a Guid
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="withHyphens"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use Guid.TryParse instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static bool IsGuid(this string str, bool withHyphens)
|
||||
{
|
||||
var isGuid = false;
|
||||
|
||||
if (!String.IsNullOrEmpty(str))
|
||||
{
|
||||
Regex guidRegEx;
|
||||
if (withHyphens)
|
||||
{
|
||||
guidRegEx = new Regex(@"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$");
|
||||
}
|
||||
else
|
||||
{
|
||||
guidRegEx = new Regex(@"^(\{{0,1}([0-9a-fA-F]){8}([0-9a-fA-F]){4}([0-9a-fA-F]){4}([0-9a-fA-F]){4}([0-9a-fA-F]){12}\}{0,1})$");
|
||||
}
|
||||
isGuid = guidRegEx.IsMatch(str);
|
||||
}
|
||||
|
||||
return isGuid;
|
||||
Guid g;
|
||||
return Guid.TryParse(str, out g);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -712,7 +693,7 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
public static object ParseInto(this string val, Type type)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(val))
|
||||
if (string.IsNullOrEmpty(val) == false)
|
||||
{
|
||||
TypeConverter tc = TypeDescriptor.GetConverter(type);
|
||||
return tc.ConvertFrom(val);
|
||||
@@ -750,6 +731,36 @@ namespace Umbraco.Core
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the string to SHA1
|
||||
/// </summary>
|
||||
/// <param name="stringToConvert">referrs to itself</param>
|
||||
/// <returns>the md5 hashed string</returns>
|
||||
public static string ToSHA1(this string stringToConvert)
|
||||
{
|
||||
//create an instance of the SHA1CryptoServiceProvider
|
||||
var md5Provider = new SHA1CryptoServiceProvider();
|
||||
|
||||
//convert our string into byte array
|
||||
var byteArray = Encoding.UTF8.GetBytes(stringToConvert);
|
||||
|
||||
//get the hashed values created by our SHA1CryptoServiceProvider
|
||||
var hashedByteArray = md5Provider.ComputeHash(byteArray);
|
||||
|
||||
//create a StringBuilder object
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
//loop to each each byte
|
||||
foreach (var b in hashedByteArray)
|
||||
{
|
||||
//append it to our StringBuilder
|
||||
stringBuilder.Append(b.ToString("x2").ToLower());
|
||||
}
|
||||
|
||||
//return the hashed value
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a string that was encoded with UrlTokenEncode
|
||||
|
||||
@@ -26,5 +26,9 @@ namespace Umbraco.Core.Strings
|
||||
/// per content, in 1-to-1 multilingual configurations. Then there would be one
|
||||
/// url per culture.</remarks>
|
||||
string GetUrlSegment(IContentBase content, CultureInfo culture);
|
||||
|
||||
//TODO: For the 301 tracking, we need to add another extended interface to this so that
|
||||
// the RedirectTrackingEventHandler can ask the IUrlSegmentProvider if the URL is changing.
|
||||
// Currently the way it works is very hacky, see notes in: RedirectTrackingEventHandler.ContentService_Publishing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,8 @@ namespace Umbraco.Core.Sync
|
||||
? ":" + request.ServerVariables["SERVER_PORT"]
|
||||
: "";
|
||||
|
||||
var ssl = GlobalSettings.UseSSL ? "s" : ""; // force, whatever the first request
|
||||
var useSsl = GlobalSettings.UseSSL || port == "443";
|
||||
var ssl = useSsl ? "s" : ""; // force, whatever the first request
|
||||
var url = "http" + ssl + "://" + request.ServerVariables["SERVER_NAME"] + port + IOHelper.ResolveUrl(SystemDirectories.Umbraco);
|
||||
|
||||
appContext._umbracoApplicationUrl = url.TrimEnd('/');
|
||||
|
||||
@@ -37,12 +37,12 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
@@ -52,8 +52,8 @@
|
||||
<Reference Include="ICSharpCode.SharpZipLib">
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ImageProcessor, Version=2.4.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.4.1.0\lib\net45\ImageProcessor.dll</HintPath>
|
||||
<Reference Include="ImageProcessor, Version=2.4.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.4.5.0\lib\net45\ImageProcessor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
@@ -114,6 +114,7 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
@@ -427,9 +428,6 @@
|
||||
<Compile Include="Persistence\Mappers\MigrationEntryMapper.cs" />
|
||||
<Compile Include="Persistence\Migrations\LocalMigrationContext.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionFourOneZero\AddPreviewXmlTable.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\AddRedirectUrlTable4.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\AddRedirectUrlTable3.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\AddRedirectUrlTable2.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\EnsureServersLockObject.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\AddRedirectUrlTable.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFiveZero\RemoveStylesheetDataAndTablesAgain.cs" />
|
||||
@@ -504,15 +502,19 @@
|
||||
<Compile Include="PropertyEditors\ValueConverters\ImageCropperValueConverter.cs" />
|
||||
<Compile Include="Publishing\UnPublishedStatusType.cs" />
|
||||
<Compile Include="Publishing\UnPublishStatus.cs" />
|
||||
<Compile Include="Security\ActiveDirectoryBackOfficeUserPasswordChecker.cs" />
|
||||
<Compile Include="Security\BackOfficeClaimsIdentityFactory.cs" />
|
||||
<Compile Include="Security\BackOfficeCookieAuthenticationProvider.cs" />
|
||||
<Compile Include="Security\BackOfficeSignInManager.cs" />
|
||||
<Compile Include="Security\BackOfficeUserManager.cs" />
|
||||
<Compile Include="Security\BackOfficeUserManagerMarker.cs" />
|
||||
<Compile Include="Security\BackOfficeUserPasswordCheckerResult.cs" />
|
||||
<Compile Include="Security\BackOfficeUserStore.cs" />
|
||||
<Compile Include="Security\IBackOfficeUserManagerMarker.cs" />
|
||||
<Compile Include="Security\IBackOfficeUserPasswordChecker.cs" />
|
||||
<Compile Include="Security\MembershipPasswordHasher.cs" />
|
||||
<Compile Include="Security\EmailService.cs" />
|
||||
<Compile Include="Security\OwinExtensions.cs" />
|
||||
<Compile Include="SemVersionExtensions.cs" />
|
||||
<Compile Include="Serialization\NoTypeConverterJsonConverter.cs" />
|
||||
<Compile Include="ServiceProviderExtensions.cs" />
|
||||
@@ -1095,7 +1097,6 @@
|
||||
<Compile Include="Profiling\LogProfiler.cs" />
|
||||
<Compile Include="Profiling\ProfilerExtensions.cs" />
|
||||
<Compile Include="Profiling\ProfilerResolver.cs" />
|
||||
<Compile Include="Profiling\WebProfiler.cs" />
|
||||
<Compile Include="PropertyEditors\DelimitedManifestValueValidator.cs" />
|
||||
<Compile Include="PropertyEditors\IntegerValidator.cs" />
|
||||
<Compile Include="PropertyEditors\ManifestPropertyValidator.cs" />
|
||||
@@ -1451,6 +1452,7 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace Umbraco.Core
|
||||
LogHelper.Error<UmbracoApplicationBase>(msg, exception);
|
||||
};
|
||||
|
||||
// this only gets called when an assembly can't be resolved
|
||||
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
|
||||
|
||||
//boot up the application
|
||||
GetBootManager()
|
||||
.Initialize()
|
||||
@@ -58,6 +61,22 @@ namespace Umbraco.Core
|
||||
ApplicationEventsResolver.Current.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when an assembly can't be resolved. In here we can do magic with the assembly name and try loading another.
|
||||
/// This is used for loading a signed assembly of AutoMapper (v. 3.1+) without having to recompile old code.
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
|
||||
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
|
||||
if (args.Name.StartsWith("AutoMapper") && args.Name.EndsWith("PublicKeyToken=null"))
|
||||
return Assembly.Load(args.Name.Replace(", PublicKeyToken=null", ", PublicKeyToken=be96cd2c38ef1005"));
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Umbraco application
|
||||
/// </summary>
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Core
|
||||
return;
|
||||
}
|
||||
if (n.Attributes[name] == null)
|
||||
{
|
||||
{
|
||||
var a = xml.CreateAttribute(name);
|
||||
a.Value = value;
|
||||
n.Attributes.Append(a);
|
||||
@@ -155,7 +155,7 @@ namespace Umbraco.Core
|
||||
elt = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the children of a parentNode.
|
||||
/// </summary>
|
||||
@@ -163,7 +163,7 @@ namespace Umbraco.Core
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
internal static void SortNodes(
|
||||
XmlNode parentNode,
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
@@ -227,7 +227,7 @@ namespace Umbraco.Core
|
||||
/// <param name="node">The child node to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
/// <returns>A value indicating whether sorting was needed.</returns>
|
||||
/// <remarks>Assuming all nodes but <paramref name="node"/> are sorted, this will move the node to
|
||||
/// <remarks>Assuming all nodes but <paramref name="node"/> are sorted, this will move the node to
|
||||
/// the right position without moving all the nodes (as SortNodes would do) - should improve perfs.</remarks>
|
||||
internal static bool SortNode(
|
||||
XmlNode parentNode,
|
||||
@@ -415,6 +415,25 @@ namespace Umbraco.Core
|
||||
return AddTextNode(xd, name, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets or creates an Xml node from its inner Xml.
|
||||
/// </summary>
|
||||
/// <param name="xd">The xmldocument.</param>
|
||||
/// <param name="parent">The node to set or create the child text node on</param>
|
||||
/// <param name="name">The node name.</param>
|
||||
/// <param name="value">The node inner Xml.</param>
|
||||
/// <returns>a XmlNode</returns>
|
||||
public static XmlNode SetInnerXmlNode(XmlDocument xd, XmlNode parent, string name, string value)
|
||||
{
|
||||
if (xd == null) throw new ArgumentNullException("xd");
|
||||
if (parent == null) throw new ArgumentNullException("parent");
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
|
||||
|
||||
var child = parent.SelectSingleNode(name) ?? xd.CreateNode(XmlNodeType.Element, name, "");
|
||||
child.InnerXml = value;
|
||||
return child;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cdata XmlNode with the specified name and value
|
||||
/// </summary>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.4.1.0" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.4.5.0" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" />
|
||||
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net45" />
|
||||
|
||||
@@ -28,5 +28,11 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
|
||||
{
|
||||
Assert.IsTrue(SettingsSection.WebRouting.DisableFindContentByIdPath == false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DisableRedirectUrlTracking()
|
||||
{
|
||||
Assert.IsTrue(SettingsSection.WebRouting.DisableRedirectUrlTracking == false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web;
|
||||
|
||||
namespace Umbraco.Tests.FrontEnd
|
||||
@@ -48,5 +45,38 @@ namespace Umbraco.Tests.FrontEnd
|
||||
Assert.AreEqual("Hello world, this is some text <a href='blah'>with…</a>", result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Create_Encrypted_RouteString_From_Anonymous_Object()
|
||||
{
|
||||
var additionalRouteValues = new
|
||||
{
|
||||
key1 = "value1",
|
||||
key2 = "value2",
|
||||
Key3 = "Value3",
|
||||
keY4 = "valuE4"
|
||||
};
|
||||
var encryptedRouteString = UmbracoHelper.CreateEncryptedRouteString("FormController", "FormAction", "", additionalRouteValues);
|
||||
var result = encryptedRouteString.DecryptWithMachineKey();
|
||||
var expectedResult = "c=FormController&a=FormAction&ar=&key1=value1&key2=value2&Key3=Value3&keY4=valuE4";
|
||||
|
||||
Assert.AreEqual(expectedResult, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Create_Encrypted_RouteString_From_Dictionary()
|
||||
{
|
||||
var additionalRouteValues = new Dictionary<string, object>()
|
||||
{
|
||||
{"key1", "value1"},
|
||||
{"key2", "value2"},
|
||||
{"Key3", "Value3"},
|
||||
{"keY4", "valuE4"}
|
||||
};
|
||||
var encryptedRouteString = UmbracoHelper.CreateEncryptedRouteString("FormController", "FormAction", "", additionalRouteValues);
|
||||
var result = encryptedRouteString.DecryptWithMachineKey();
|
||||
var expectedResult = "c=FormController&a=FormAction&ar=&key1=value1&key2=value2&Key3=Value3&keY4=valuE4";
|
||||
|
||||
Assert.AreEqual(expectedResult, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,13 +119,10 @@ namespace Umbraco.Tests.Migrations
|
||||
|
||||
//pass in explicit migrations
|
||||
new DeleteRedirectUrlTable(SqlSyntax, logger),
|
||||
new AddRedirectUrlTable(SqlSyntax, logger),
|
||||
new AddRedirectUrlTable2(SqlSyntax, logger),
|
||||
new AddRedirectUrlTable3(SqlSyntax, logger),
|
||||
new AddRedirectUrlTable4(SqlSyntax, logger)
|
||||
new AddRedirectUrlTable(SqlSyntax, logger)
|
||||
);
|
||||
|
||||
var db = new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;", "System.Data.SqlServerCe.4.0", Logger);
|
||||
var db = new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;", Constants.DatabaseProviders.SqlCe, Logger);
|
||||
|
||||
var upgraded = migrationRunner.Execute(db, DatabaseProviders.SqlServerCE, true);
|
||||
Assert.IsTrue(upgraded);
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Tests.Migrations
|
||||
|
||||
public UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;", "System.Data.SqlServerCe.4.0", Mock.Of<ILogger>());
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;", Constants.DatabaseProviders.SqlCe, Mock.Of<ILogger>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
@@ -26,7 +27,7 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public override UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
return new UmbracoDatabase("Server = 169.254.120.3; Database = upgradetest; Uid = umbraco; Pwd = umbraco", "MySql.Data.MySqlClient", Mock.Of<ILogger>());
|
||||
return new UmbracoDatabase("Server = 169.254.120.3; Database = upgradetest; Uid = umbraco; Pwd = umbraco", Constants.DatabaseProviders.MySql, Mock.Of<ILogger>());
|
||||
}
|
||||
|
||||
public override DatabaseProviders GetDatabaseProvider()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user