Compare commits
357 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b8a6e532e | |||
| d497659f1f | |||
| 0cafeac6eb | |||
| 4516305f3c | |||
| 04c8390a4f | |||
| fc94d92b37 | |||
| 84171c6b98 | |||
| 3ff88bc4fa | |||
| 4b54edf660 | |||
| 1bc9d1d9c3 | |||
| b5cbe63a4e | |||
| 4882df43bd | |||
| cb03178d99 | |||
| 361fa8836b | |||
| 194ebb57b9 | |||
| 5effe5015e | |||
| ee2943b9fb | |||
| a3b03988b3 | |||
| 6d5f7c4293 | |||
| cc32e73235 | |||
| 92ef4d8055 | |||
| e57e2f5b5f | |||
| 0b4efe4eeb | |||
| c250fa560e | |||
| 6eeae52333 | |||
| c38c18fed8 | |||
| 0af47963c6 | |||
| b017e8690a | |||
| 916e442ee4 | |||
| ecae9c47b7 | |||
| 836a99128f | |||
| abefbc7581 | |||
| 365addedf4 | |||
| 44f5439a2c | |||
| 8a9680e75c | |||
| ae0991bc67 | |||
| 0caaaa500c | |||
| 36c66e676a | |||
| a14baeb111 | |||
| 5b4d8ed6f3 | |||
| 25ea4003f9 | |||
| 30cef671dc | |||
| 250e627b1d | |||
| 5b00501d21 | |||
| 06e5350c43 | |||
| ba530061a0 | |||
| 89ae3bc143 | |||
| 484afccf89 | |||
| 3951f59d09 | |||
| 2589ec8367 | |||
| a6aeada197 | |||
| cd8c998ebf | |||
| 2a9e32e8fd | |||
| 603724ddd6 | |||
| 902cfc5a22 | |||
| 2cb544591b | |||
| db7aa99b85 | |||
| 031ceccf5d | |||
| 7127706c43 | |||
| d078ef8f5e | |||
| 289b9743c5 | |||
| eda9ba07f4 | |||
| 1b1b5c047c | |||
| fa5b9e5689 | |||
| 6948d70b75 | |||
| 3f9b022ae4 | |||
| 990ab7f87f | |||
| 861198eec9 | |||
| c26df8da6f | |||
| b5aefdce04 | |||
| adfb7cfaa4 | |||
| 0a88ba05c8 | |||
| 9ee295d49e | |||
| 1e02d85fca | |||
| 7173b44b4f | |||
| 69f6edadb3 | |||
| d1dc2331f8 | |||
| bb2f3a1732 | |||
| 4b29d7ba2e | |||
| d503deb8c5 | |||
| 0859b92aaf | |||
| b409740da5 | |||
| a888e0564c | |||
| fef96e8b43 | |||
| 429522a0bc | |||
| e9b2261aab | |||
| 02adb6e112 | |||
| 695d26434c | |||
| 00d408e6bc | |||
| 0498161367 | |||
| 0d3d4693b4 | |||
| a19de645e4 | |||
| f0a53ea9c0 | |||
| fbcabc94f2 | |||
| de9a27db10 | |||
| d494b061f3 | |||
| ebc8443e70 | |||
| 48ee59b94e | |||
| 560dcad90a | |||
| 7498b2f994 | |||
| df4f92197a | |||
| 13b1191aad | |||
| adaec42982 | |||
| b6d5b7d603 | |||
| 93d7cf4dc3 | |||
| e9f2546c2a | |||
| 007c4d5862 | |||
| f3621aa743 | |||
| 46cf4398a0 | |||
| 1599f493fa | |||
| b5d79ebb74 | |||
| 1cc8367fa9 | |||
| 7e5087ae7d | |||
| d6f9909bec | |||
| 0c42596dc8 | |||
| 9b4da4c8f8 | |||
| cfc81d0e84 | |||
| 00e10deecb | |||
| 46e67e4a92 | |||
| 520a7f238d | |||
| 3c41871e59 | |||
| 8cf9c1ba97 | |||
| e2d806f5d9 | |||
| 7a47d63b48 | |||
| 596c4ac329 | |||
| 8ad8a3239a | |||
| c0fa011cc3 | |||
| 4648a8c103 | |||
| 2df05da7fc | |||
| 87947871d1 | |||
| 87fee572ff | |||
| e00c0fc447 | |||
| 7137c57ac9 | |||
| d68b4d97f6 | |||
| 89f7a3ec63 | |||
| 96a62b57fb | |||
| 7092a9ccbb | |||
| e9ea9b5e1b | |||
| fd1efb29ec | |||
| cf4781153e | |||
| 46687429fb | |||
| ce7aa43aa7 | |||
| ebed142cd5 | |||
| 76e5304233 | |||
| d162aba14a | |||
| 387398b044 | |||
| 635b8bd82e | |||
| f2071379fc | |||
| ec075f5807 | |||
| eb8875066c | |||
| dca90e6316 | |||
| 2a47b384d2 | |||
| 29e5872a0f | |||
| df31fafec5 | |||
| 5f28f279e0 | |||
| 828dc64035 | |||
| 1d9e445a42 | |||
| 1aa137e9da | |||
| 042eb47c17 | |||
| a6556d0195 | |||
| 0b74164a8e | |||
| 807b32fb0d | |||
| 62be1b1267 | |||
| bda3fbc698 | |||
| 85ae7e764f | |||
| c744e47665 | |||
| 3daa624627 | |||
| 9a7894df76 | |||
| d8af1aaf7b | |||
| f2d105d8b9 | |||
| c93193c5c8 | |||
| 6734420c6f | |||
| fd795e14c6 | |||
| d622f76393 | |||
| d4fc82dae1 | |||
| d4058bd81f | |||
| bc824ba66a | |||
| 4201286038 | |||
| e333ad2b23 | |||
| a8eeabb73d | |||
| b06620f56e | |||
| e8524963dd | |||
| 5b0a8c0668 | |||
| 5d931d1146 | |||
| 879c77c68d | |||
| e71dd3008d | |||
| 597c888d36 | |||
| ef4c02f759 | |||
| 452a0a43b0 | |||
| c3ccf3a609 | |||
| 60bbede408 | |||
| 0751aff31f | |||
| a2ea20de70 | |||
| 3bfa1be60c | |||
| 8d38cf3c44 | |||
| a3a9ab069a | |||
| da908501e5 | |||
| 995ed22401 | |||
| c9cd4c721c | |||
| c059c14d7a | |||
| 04c9771978 | |||
| 9c8b5cd97e | |||
| 8bb447065c | |||
| 1d0299af89 | |||
| 5b8beceea8 | |||
| e4568520a9 | |||
| cbba628eaf | |||
| c2d0e255df | |||
| e096890400 | |||
| ec4b1c8f70 | |||
| 1af904435a | |||
| 7b2f03ba50 | |||
| 005d3e7d64 | |||
| 12f8638223 | |||
| 137b0754d6 | |||
| 7d1e9cfd72 | |||
| d01a39e0c6 | |||
| 73bd0137e3 | |||
| e3f9e8c842 | |||
| 7a38726b26 | |||
| a475f72d50 | |||
| 36cadf39e9 | |||
| a559ef9f90 | |||
| b45f6e0393 | |||
| b99ff6c981 | |||
| 81021f5821 | |||
| 29724b352b | |||
| be83302b14 | |||
| 83d7ea9ef1 | |||
| 95024442de | |||
| 69f54b5f22 | |||
| 3404f95b2e | |||
| e56738481b | |||
| cb59dc353b | |||
| d1b75eac08 | |||
| 1f7651d0e3 | |||
| 8fabd4e4ed | |||
| 564d92bed7 | |||
| d73dd47e7b | |||
| 95f103ccc2 | |||
| c21b232a33 | |||
| 0ace2fdae7 | |||
| dfb2a31f26 | |||
| 5da3541584 | |||
| ef86d2f1f1 | |||
| be98425956 | |||
| 61d1f87611 | |||
| 598d66ac7f | |||
| a10a6d1af8 | |||
| 7640908781 | |||
| b101e25e7a | |||
| 319f257ee5 | |||
| 14d40697b2 | |||
| 6e6b1beffd | |||
| e22de5c9a0 | |||
| 1eea4dab33 | |||
| 83518de981 | |||
| 6d87174cc1 | |||
| 2da18d4500 | |||
| 9af9c3fe77 | |||
| 9cedf5da4c | |||
| d50396ce68 | |||
| f7d4080472 | |||
| e24ff1b92b | |||
| 0c05cbc9db | |||
| 906d675dca | |||
| 860ef73fab | |||
| ec6158792a | |||
| f1b3105202 | |||
| 3ebb213916 | |||
| 97536086c0 | |||
| 0853f8da85 | |||
| 32d36d66c9 | |||
| 2aef75a70a | |||
| fc21d10192 | |||
| c6bd94532d | |||
| a65ca205de | |||
| c8e08b8ef8 | |||
| 683d793460 | |||
| d430efa7ab | |||
| c828c6ede3 | |||
| 3e1120612b | |||
| 8d06d39a62 | |||
| f64d4c9272 | |||
| b2f6620d80 | |||
| 812d38878c | |||
| da7fea47c6 | |||
| 71ddaf04b9 | |||
| 6e1316cb95 | |||
| f2442b25f6 | |||
| bfb8912518 | |||
| 300d3ff09b | |||
| e6337b8f14 | |||
| 39d45ba4b0 | |||
| 2be785ace3 | |||
| 5e2d991fab | |||
| 536cb4caf1 | |||
| 27745ea141 | |||
| 5289c55740 | |||
| 791773fc8a | |||
| 3179b2794b | |||
| 1da27e6c2b | |||
| bea6031de1 | |||
| 3608242b25 | |||
| 5602701645 | |||
| a909b7904e | |||
| 6e0af6827e | |||
| 51ff861e44 | |||
| aa092ab3f3 | |||
| aaaace8dd3 | |||
| 1b1abce7da | |||
| fbc10be381 | |||
| 61f2647b62 | |||
| a5bea7fc59 | |||
| b9be5c2561 | |||
| 97556de447 | |||
| ea805a7af8 | |||
| c9d55a4a5e | |||
| d404970c74 | |||
| 66bf667100 | |||
| c5d1439422 | |||
| 5e9f4559b6 | |||
| 4bbb0441a6 | |||
| 4cf1d7d9a4 | |||
| a6a3ddca75 | |||
| 27cfa85d3a | |||
| a9e1e7b634 | |||
| 9f5f920c81 | |||
| 09c19512d9 | |||
| 212b86d8f6 | |||
| a86b831735 | |||
| f9a0d91299 | |||
| d5bde0d8df | |||
| cc5ca0b5fe | |||
| 0cb9cc6840 | |||
| d38d7b1ff4 | |||
| 2d87f933d5 | |||
| a734a0cff7 | |||
| d0ace55d03 | |||
| 3fda0308ac | |||
| d796b2afc1 | |||
| f95cfc2ee0 | |||
| 82c2560822 | |||
| f467b8cb6c | |||
| aea1a03453 | |||
| 1568e5f19c | |||
| 8dff47db78 | |||
| 987e48733a | |||
| ac5142443a | |||
| 44360d83aa | |||
| 021cb817d4 | |||
| f4f91fba78 | |||
| dec5e8ad6c | |||
| 4321c8d24e | |||
| 6cb3fcf9ad | |||
| e5878554bd | |||
| 44c8c4b5b8 |
@@ -24,3 +24,5 @@ f6da531fbb4c251ff61d314e2a7effb13c71e74a Release-4.10.0
|
||||
54cde33b809dcb3a1f7e7ae0d5375f6dd0d89c8d Release-4.11.2.2
|
||||
ff3bb24ea0c915878396a6ae27f1ff164e8ac150 Release-6.0.0-beta
|
||||
56015ac26f5ab60e3c61b1d09075297b660afa07 Release-6.0.0-RC
|
||||
1719fbd857f28b376639ac2aa0abada0ef2e7560 Release-6.0.0
|
||||
e02f5aebb87e3f07d27376647756caa9762931d8 Release-4.11.4
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
@ECHO OFF
|
||||
SET release=6.0.0
|
||||
SET release=6.0.2
|
||||
SET comment=
|
||||
SET version=%release%
|
||||
|
||||
|
||||
+48
-1
@@ -1,3 +1,4 @@
|
||||
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!--
|
||||
@@ -13,7 +14,45 @@
|
||||
|
||||
<Import Project="..\tools\UmbracoMSBuildTasks\Umbraco.MSBuild.Tasks.Targets" />
|
||||
<Import Project="..\tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
|
||||
|
||||
<UsingTask TaskName="GenerateHash" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
<InputFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
|
||||
<OutputFile ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Linq" />
|
||||
<Using Namespace="System.Security.Cryptography" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
foreach (var item in InputFiles)
|
||||
{
|
||||
string path = item.ItemSpec;
|
||||
|
||||
using (FileStream stream = new FileStream(path, FileMode.Open))
|
||||
{
|
||||
using (var cryptoProvider = new SHA1CryptoServiceProvider())
|
||||
{
|
||||
|
||||
var fileHash = cryptoProvider.ComputeHash(stream);
|
||||
|
||||
using (TextWriter w = new StreamWriter(OutputFile, false))
|
||||
{
|
||||
w.WriteLine(string.Join("", fileHash.Select(b => b.ToString("x2"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
|
||||
<!--
|
||||
****************************************************
|
||||
VARIABLES
|
||||
@@ -71,10 +110,18 @@
|
||||
*****************************************************
|
||||
-->
|
||||
|
||||
<Target Name="Build" DependsOnTargets="ZipWebPiApp">
|
||||
<Target Name="Build" DependsOnTargets="GenerateWebPiHash">
|
||||
<Message Text="Build finished" />
|
||||
</Target>
|
||||
|
||||
<Target Name="GenerateWebPiHash" DependsOnTargets="ZipWebPiApp">
|
||||
<ItemGroup>
|
||||
<WebPiFile Include="$(BuildZipFileNameWebPi)" />
|
||||
</ItemGroup>
|
||||
<Message Text="Calculating hash for $(BuildZipFileNameWebPi)" />
|
||||
<GenerateHash InputFiles="@(WebPiFile)" OutputFile="webpihash.txt" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CleanUp" DependsOnTargets="ZipWebPiApp">
|
||||
<Message Text="Deleting $(BuildFolder)" Importance="high" />
|
||||
<RemoveDir Directories="$(BuildFolder)" />
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="$version$" />
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -21,29 +21,44 @@ echo ^<?xml version="1.0" encoding="utf-8"?^>^<packages^>^</packages^> >..\src\U
|
||||
echo Removing plugin cache files
|
||||
del ..\src\Umbraco.Web.UI\App_Data\TEMP\PluginCache\*.*
|
||||
|
||||
echo Removing cache files and examine index
|
||||
del ..\src\Umbraco.Web.UI\App_Data\TEMP\*.*
|
||||
|
||||
echo Removing log files
|
||||
del ..\src\Umbraco.Web.UI\App_Data\Logs\*.*
|
||||
|
||||
echo Removing packages
|
||||
del ..\src\Umbraco.Web.UI\App_Data\packages\*.*
|
||||
|
||||
echo Removing previews
|
||||
del ..\src\Umbraco.Web.UI\App_Data\preview\*.*
|
||||
|
||||
echo Removing app code files (typically added by starterkits)
|
||||
del ..\src\Umbraco.Web.UI\App_Code\*.*
|
||||
|
||||
echo Removing xslt files
|
||||
del ..\src\Umbraco.Web.UI\Xslt\*.*
|
||||
del ..\src\Umbraco.Web.UI\xslt\*.*
|
||||
|
||||
echo Removing user control files
|
||||
del ..\src\Umbraco.Web.UI\UserControls\*.*
|
||||
|
||||
echo Removing masterpage files
|
||||
del ..\src\Umbraco.Web.UI\masterpages\*.*
|
||||
|
||||
echo Removing view files
|
||||
del ..\src\Umbraco.Web.UI\Views\*.*
|
||||
|
||||
echo Removing razor files
|
||||
del ..\src\Umbraco.Web.UI\MacroScripts\*.*
|
||||
del ..\src\Umbraco.Web.UI\macroScripts\*.*
|
||||
|
||||
echo Removing media files
|
||||
del ..\src\Umbraco.Web.UI\Media\*.*
|
||||
del ..\src\Umbraco.Web.UI\media\*.*
|
||||
|
||||
echo Removing script files
|
||||
del ..\src\Umbraco.Web.UI\Scripts\*.*
|
||||
del ..\src\Umbraco.Web.UI\scripts\*.*
|
||||
|
||||
echo Removing css files
|
||||
del ..\src\Umbraco.Web.UI\Css\*.*
|
||||
del ..\src\Umbraco.Web.UI\css\*.*
|
||||
|
||||
echo "Umbraco install reverted to clean install"
|
||||
pause
|
||||
@@ -64,29 +79,44 @@ echo ^<?xml version="1.0" encoding="utf-8"?^>^<packages^>^</packages^> >..\src\U
|
||||
echo Removing plugin cache files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\TEMP\PluginCache\*.*) DO DEL %%A
|
||||
|
||||
echo Removing cache files and examine index
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\TEMP\*.*) DO DEL %%A
|
||||
|
||||
echo Removing log files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\Logs\*.*) DO DEL %%A
|
||||
|
||||
echo Removing packages
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\packages\*.*) DO DEL %%A
|
||||
|
||||
echo Removing previews
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\preview\*.*) DO DEL %%A
|
||||
|
||||
echo Removing app code files (typically added by starterkits)
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Code\*.*) DO DEL %%A
|
||||
|
||||
echo Removing xslt files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Xslt\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\xslt\*.*) DO DEL %%A
|
||||
|
||||
echo Removing masterpage files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\masterpages\*.*) DO DEL %%A
|
||||
|
||||
echo Removing user control files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\UserControls\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\usercontrols\*.*) DO DEL %%A
|
||||
|
||||
echo Removing view files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Views\*.*) DO DEL %%A
|
||||
|
||||
echo Removing razor files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\MacroScripts\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\macroScripts\*.*) DO DEL %%A
|
||||
|
||||
echo Removing media files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Media\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\media\*.*) DO DEL %%A
|
||||
|
||||
echo Removing script files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Scripts\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\scripts\*.*) DO DEL %%A
|
||||
|
||||
echo Removing css files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Css\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\css\*.*) DO DEL %%A
|
||||
|
||||
echo "Umbraco install reverted to clean install"
|
||||
pause
|
||||
|
||||
@@ -50,35 +50,90 @@ namespace SqlCE4Umbraco
|
||||
/// </summary>
|
||||
internal void ClearDatabase()
|
||||
{
|
||||
// drop constraints before tables to avoid exceptions
|
||||
// looping on try/catching exceptions was not really nice
|
||||
|
||||
// http://stackoverflow.com/questions/536350/drop-all-the-tables-stored-procedures-triggers-constriants-and-all-the-depend
|
||||
|
||||
var localConnection = new SqlCeConnection(ConnectionString);
|
||||
if (System.IO.File.Exists(ReplaceDataDirectory(localConnection.Database)))
|
||||
{
|
||||
var tables = new List<string>();
|
||||
using (var reader = ExecuteReader("select table_name from information_schema.tables where TABLE_TYPE <> 'VIEW'"))
|
||||
List<string> tables;
|
||||
|
||||
// drop foreign keys
|
||||
// SQL may need "where constraint_catalog=DB_NAME() and ..."
|
||||
tables = new List<string>();
|
||||
using (var reader = ExecuteReader("select table_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' order by table_name"))
|
||||
{
|
||||
while (reader.Read())
|
||||
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
|
||||
}
|
||||
|
||||
foreach (var table in tables)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name = '" + table + "' order by constraint_name"))
|
||||
{
|
||||
tables.Add(reader.GetString("TABLE_NAME"));
|
||||
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
|
||||
}
|
||||
foreach (var constraint in constraints)
|
||||
{
|
||||
// SQL may need "[dbo].[table]"
|
||||
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
|
||||
}
|
||||
}
|
||||
|
||||
while(tables.Any())
|
||||
// drop primary keys
|
||||
// SQL may need "where constraint_catalog=DB_NAME() and ..."
|
||||
tables = new List<string>();
|
||||
using (var reader = ExecuteReader("select table_name from information_schema.table_constraints where constraint_type = 'PRIMARY KEY' order by table_name"))
|
||||
{
|
||||
for (var i = 0; i < tables.Count; i++)
|
||||
{
|
||||
var dropTable = "DROP TABLE " + tables[i];
|
||||
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ExecuteNonQuery(dropTable);
|
||||
tables.Remove(tables[i]);
|
||||
}
|
||||
catch (SqlHelperException ex)
|
||||
{
|
||||
//this will occur because there is no cascade option, so we just wanna try the next one
|
||||
}
|
||||
foreach (var table in tables)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'PRIMARY KEY' and table_name = '" + table + "' order by constraint_name"))
|
||||
{
|
||||
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
|
||||
}
|
||||
foreach (var constraint in constraints)
|
||||
{
|
||||
// SQL may need "[dbo].[table]"
|
||||
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
|
||||
}
|
||||
}
|
||||
|
||||
// drop tables
|
||||
tables = new List<string>();
|
||||
using (var reader = ExecuteReader("select table_name from information_schema.tables where table_type <> 'VIEW' order by table_name"))
|
||||
{
|
||||
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
|
||||
}
|
||||
|
||||
foreach (var table in tables)
|
||||
{
|
||||
ExecuteNonQuery("drop table [" + table + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops all foreign keys on a table.
|
||||
/// </summary>
|
||||
/// <param name="table">The name of the table.</param>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal void DropForeignKeys(string table)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name = '" + table + "' order by constraint_name"))
|
||||
{
|
||||
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
|
||||
}
|
||||
foreach (var constraint in constraints)
|
||||
{
|
||||
// SQL may need "[dbo].[table]"
|
||||
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// A resolver to return all IAction objects
|
||||
/// </summary>
|
||||
internal sealed class ActionsResolver : ManyObjectsResolverBase<ActionsResolver, IAction>
|
||||
internal sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="packageActions"></param>
|
||||
internal ActionsResolver(IEnumerable<Type> packageActions)
|
||||
internal ActionsResolver(Func<IEnumerable<Type>> packageActions)
|
||||
: base(packageActions)
|
||||
{
|
||||
|
||||
@@ -34,9 +34,9 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
protected override IEnumerable<IAction> CreateInstances()
|
||||
{
|
||||
{
|
||||
var actions = new List<IAction>();
|
||||
var foundIActions = PluginManager.Current.ResolveActions();
|
||||
var foundIActions = InstanceTypes;
|
||||
foreach (var type in foundIActions)
|
||||
{
|
||||
IAction typeInstance;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="refreshers"></param>
|
||||
internal CacheRefreshersResolver(IEnumerable<Type> refreshers)
|
||||
internal CacheRefreshersResolver(Func<IEnumerable<Type>> refreshers)
|
||||
: base(refreshers)
|
||||
{
|
||||
|
||||
|
||||
@@ -28,24 +28,49 @@ namespace Umbraco.Core.Configuration
|
||||
#region Private static fields
|
||||
|
||||
private static Version _version;
|
||||
private static string _reservedUrlsCache;
|
||||
private static readonly object Locker = new object();
|
||||
//make this volatile so that we can ensure thread safety with a double check lock
|
||||
private static volatile string _reservedUrlsCache;
|
||||
private static string _reservedPathsCache;
|
||||
private static StartsWithContainer _reservedList = new StartsWithContainer();
|
||||
private static string _reservedPaths;
|
||||
private static string _reservedUrls;
|
||||
//ensure the built on (non-changeable) reserved paths are there at all times
|
||||
private const string StaticReservedPaths = "~/app_plugins/,~/install/,";
|
||||
private const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,";
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// used for unit tests
|
||||
/// </summary>
|
||||
internal static void ResetCache()
|
||||
{
|
||||
_reservedUrlsCache = null;
|
||||
_reservedPaths = null;
|
||||
_reservedUrls = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reserved urls from web.config.
|
||||
/// </summary>
|
||||
/// <value>The reserved urls.</value>
|
||||
public static string ReservedUrls
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfigurationManager.AppSettings.ContainsKey("umbracoReservedUrls")
|
||||
? ConfigurationManager.AppSettings["umbracoReservedUrls"]
|
||||
: string.Empty;
|
||||
{
|
||||
if (_reservedUrls == null)
|
||||
{
|
||||
var urls = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedUrls")
|
||||
? ConfigurationManager.AppSettings["umbracoReservedUrls"]
|
||||
: string.Empty;
|
||||
|
||||
//ensure the built on (non-changeable) reserved paths are there at all times
|
||||
_reservedUrls = StaticReservedUrls + urls;
|
||||
}
|
||||
return _reservedUrls;
|
||||
}
|
||||
internal set { _reservedUrls = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -56,10 +81,25 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfigurationManager.AppSettings.ContainsKey("umbracoReservedPaths")
|
||||
? ConfigurationManager.AppSettings["umbracoReservedPaths"]
|
||||
: string.Empty;
|
||||
if (_reservedPaths == null)
|
||||
{
|
||||
var reservedPaths = StaticReservedPaths;
|
||||
//always add the umbraco path to the list
|
||||
if (ConfigurationManager.AppSettings.ContainsKey("umbracoPath")
|
||||
&& !ConfigurationManager.AppSettings["umbracoPath"].IsNullOrWhiteSpace())
|
||||
{
|
||||
reservedPaths += ConfigurationManager.AppSettings["umbracoPath"].EnsureEndsWith(',');
|
||||
}
|
||||
|
||||
var allPaths = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedPaths")
|
||||
? ConfigurationManager.AppSettings["umbracoReservedPaths"]
|
||||
: string.Empty;
|
||||
|
||||
_reservedPaths = reservedPaths + allPaths;
|
||||
}
|
||||
return _reservedPaths;
|
||||
}
|
||||
internal set { _reservedPaths = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -201,6 +241,7 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a setting into the configuration file.
|
||||
/// </summary>
|
||||
@@ -622,38 +663,42 @@ namespace Umbraco.Core.Configuration
|
||||
/// </returns>
|
||||
public static bool IsReservedPathOrUrl(string url)
|
||||
{
|
||||
// check if GlobalSettings.ReservedPaths and GlobalSettings.ReservedUrls are unchanged
|
||||
if (!object.ReferenceEquals(_reservedPathsCache, GlobalSettings.ReservedPaths)
|
||||
|| !object.ReferenceEquals(_reservedUrlsCache, GlobalSettings.ReservedUrls))
|
||||
if (_reservedUrlsCache == null)
|
||||
{
|
||||
// store references to strings to determine changes
|
||||
_reservedPathsCache = GlobalSettings.ReservedPaths;
|
||||
_reservedUrlsCache = GlobalSettings.ReservedUrls;
|
||||
|
||||
string _root = SystemDirectories.Root.Trim().ToLower();
|
||||
|
||||
// add URLs and paths to a new list
|
||||
StartsWithContainer _newReservedList = new StartsWithContainer();
|
||||
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
lock (Locker)
|
||||
{
|
||||
//resolves the url to support tilde chars
|
||||
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl).Trim().ToLower();
|
||||
if (reservedUrlTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedUrlTrimmed);
|
||||
if (_reservedUrlsCache == null)
|
||||
{
|
||||
// store references to strings to determine changes
|
||||
_reservedPathsCache = GlobalSettings.ReservedPaths;
|
||||
_reservedUrlsCache = GlobalSettings.ReservedUrls;
|
||||
|
||||
string _root = SystemDirectories.Root.Trim().ToLower();
|
||||
|
||||
// add URLs and paths to a new list
|
||||
StartsWithContainer _newReservedList = new StartsWithContainer();
|
||||
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
//resolves the url to support tilde chars
|
||||
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl).Trim().ToLower();
|
||||
if (reservedUrlTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedUrlTrimmed);
|
||||
}
|
||||
|
||||
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
bool trimEnd = !reservedPath.EndsWith("/");
|
||||
//resolves the url to support tilde chars
|
||||
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath).Trim().ToLower();
|
||||
|
||||
if (reservedPathTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
|
||||
}
|
||||
|
||||
// use the new list from now on
|
||||
_reservedList = _newReservedList;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
bool trimEnd = !reservedPath.EndsWith("/");
|
||||
//resolves the url to support tilde chars
|
||||
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath).Trim().ToLower();
|
||||
|
||||
if (reservedPathTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
|
||||
}
|
||||
|
||||
// use the new list from now on
|
||||
_reservedList = _newReservedList;
|
||||
}
|
||||
|
||||
//The url should be cleaned up before checking:
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.InfrastructureSettings
|
||||
{
|
||||
public class Infrastructure : ConfigurationSection
|
||||
{
|
||||
private const string InfrastructureSectionName = "umbraco/infrastructure";
|
||||
|
||||
public static Infrastructure Instance
|
||||
{
|
||||
get { return (Infrastructure) ConfigurationManager.GetSection(InfrastructureSectionName); }
|
||||
}
|
||||
|
||||
#region RepositoriesSection Property
|
||||
|
||||
internal const string RepositoriesPropertyName = "repositories";
|
||||
|
||||
[ConfigurationProperty(RepositoriesPropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public Repositories Repositories
|
||||
{
|
||||
get { return ((Repositories)base[RepositoriesPropertyName]); }
|
||||
set { base[RepositoriesPropertyName] = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublishingStrategy Property
|
||||
|
||||
internal const string PublishingStrategyPropertyName = "publishingStrategy";
|
||||
|
||||
[ConfigurationProperty(PublishingStrategyPropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public PublishingProvider PublishingStrategy
|
||||
{
|
||||
get { return ((PublishingProvider)base[PublishingStrategyPropertyName]); }
|
||||
set { base[PublishingStrategyPropertyName] = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class Repositories : ConfigurationElement
|
||||
{
|
||||
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
|
||||
public RepositoryElementCollection Repository
|
||||
{
|
||||
get { return ((RepositoryElementCollection)(base[""])); }
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationCollection(typeof(Repository), CollectionType = ConfigurationElementCollectionType.BasicMapAlternate, AddItemName = RepositoryPropertyName)]
|
||||
public class RepositoryElementCollection : ConfigurationElementCollection
|
||||
{
|
||||
internal const string RepositoryPropertyName = "repository";
|
||||
|
||||
public override ConfigurationElementCollectionType CollectionType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfigurationElementCollectionType.BasicMapAlternate;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string ElementName
|
||||
{
|
||||
get
|
||||
{
|
||||
return RepositoryPropertyName;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsElementName(string elementName)
|
||||
{
|
||||
return elementName == RepositoryPropertyName;
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((Repository)element).InterfaceShortTypeName;
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new Repository();
|
||||
}
|
||||
|
||||
#region Indexer
|
||||
|
||||
public Repository this[int index]
|
||||
{
|
||||
get { return (Repository)base.BaseGet(index); }
|
||||
}
|
||||
|
||||
public Repository this[string interfaceShortTypeName]
|
||||
{
|
||||
get { return (Repository)base.BaseGet(interfaceShortTypeName); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Add
|
||||
|
||||
public void Add(Repository repository)
|
||||
{
|
||||
BaseAdd(repository);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Remove
|
||||
|
||||
public void Remove(Repository repository)
|
||||
{
|
||||
BaseRemove(repository);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetItem
|
||||
|
||||
public Repository GetItemAt(int index)
|
||||
{
|
||||
return (Repository)BaseGet(index);
|
||||
}
|
||||
|
||||
public Repository GetItemByKey(string interfaceShortTypeName)
|
||||
{
|
||||
return (Repository)BaseGet(interfaceShortTypeName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool ContainsKey(string interfaceShortName)
|
||||
{
|
||||
bool result = false;
|
||||
object[] keys = this.BaseGetAllKeys();
|
||||
foreach (object key in keys)
|
||||
{
|
||||
if ((string)key == interfaceShortName)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class Repository : ConfigurationElement
|
||||
{
|
||||
internal const string InterfaceShortTypeNamePropertyName = "interfaceShortTypeName";
|
||||
|
||||
[ConfigurationPropertyAttribute(InterfaceShortTypeNamePropertyName, IsRequired = true, IsKey = true, IsDefaultCollection = false)]
|
||||
public string InterfaceShortTypeName
|
||||
{
|
||||
get { return (string) base[InterfaceShortTypeNamePropertyName]; }
|
||||
set { base[InterfaceShortTypeNamePropertyName] = value; }
|
||||
}
|
||||
|
||||
internal const string RepositoryFullTypeNamePropertyName = "repositoryFullTypeName";
|
||||
|
||||
[ConfigurationPropertyAttribute(RepositoryFullTypeNamePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public string RepositoryFullTypeName
|
||||
{
|
||||
get { return (string)base[RepositoryFullTypeNamePropertyName]; }
|
||||
set { base[RepositoryFullTypeNamePropertyName] = value; }
|
||||
}
|
||||
|
||||
internal const string CacheProviderFullTypeNamePropertyName = "cacheProviderFullTypeName";
|
||||
|
||||
[ConfigurationPropertyAttribute(CacheProviderFullTypeNamePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public string CacheProviderFullTypeName
|
||||
{
|
||||
get { return (string)base[CacheProviderFullTypeNamePropertyName]; }
|
||||
set { base[CacheProviderFullTypeNamePropertyName] = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class PublishingProvider : ConfigurationElement
|
||||
{
|
||||
internal const string TypePropertyName = "type";
|
||||
|
||||
[ConfigurationPropertyAttribute(TypePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public string Type
|
||||
{
|
||||
get { return (string)base[TypePropertyName]; }
|
||||
set { base[TypePropertyName] = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,31 @@ namespace Umbraco.Core.Configuration
|
||||
/// </summary>
|
||||
internal class UmbracoSettings
|
||||
{
|
||||
/// <summary>
|
||||
private static bool GetKeyValue(string key, bool defaultValue)
|
||||
{
|
||||
bool value;
|
||||
string stringValue = GetKey(key);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(stringValue))
|
||||
return defaultValue;
|
||||
if (bool.TryParse(stringValue, out value))
|
||||
return value;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private static int GetKeyValue(string key, int defaultValue)
|
||||
{
|
||||
int value;
|
||||
string stringValue = GetKey(key);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(stringValue))
|
||||
return defaultValue;
|
||||
if (int.TryParse(stringValue, out value))
|
||||
return value;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
|
||||
/// </summary>
|
||||
internal static void ResetSetters()
|
||||
@@ -35,6 +59,7 @@ namespace Umbraco.Core.Configuration
|
||||
_useLegacySchema = null;
|
||||
_useDomainPrefixes = null;
|
||||
_umbracoLibraryCacheDuration = null;
|
||||
_trySkipIisCustomErrors = null;
|
||||
SettingsFilePath = null;
|
||||
}
|
||||
|
||||
@@ -126,11 +151,32 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
EnsureSettingsDocument();
|
||||
|
||||
string attrName = null;
|
||||
var pos = key.IndexOf('@');
|
||||
if (pos > 0)
|
||||
{
|
||||
attrName = key.Substring(pos + 1);
|
||||
key = key.Substring(0, pos - 1);
|
||||
}
|
||||
|
||||
var node = UmbracoSettingsXmlDoc.DocumentElement.SelectSingleNode(key);
|
||||
if (node == null || node.FirstChild == null || node.FirstChild.Value == null)
|
||||
return string.Empty;
|
||||
return node.FirstChild.Value;
|
||||
}
|
||||
if (node == null)
|
||||
return string.Empty;
|
||||
|
||||
if (pos < 0)
|
||||
{
|
||||
if (node.FirstChild == null || node.FirstChild.Value == null)
|
||||
return string.Empty;
|
||||
return node.FirstChild.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var attr = node.Attributes[attrName];
|
||||
if (attr == null)
|
||||
return string.Empty;
|
||||
return attr.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the media library will create new directories in the /media directory.
|
||||
@@ -203,6 +249,7 @@ namespace Umbraco.Core.Configuration
|
||||
return value != null ? value.Attributes["assembly"].Value : "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of an external logger that can be used to store log items in 3rd party systems
|
||||
/// </summary>
|
||||
@@ -351,24 +398,13 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_useDomainPrefixes.HasValue)
|
||||
return _useDomainPrefixes.Value;
|
||||
bool result;
|
||||
if (bool.TryParse(GetKey("/settings/requestHandler/useDomainPrefixes"), out result))
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// default: false
|
||||
return _useDomainPrefixes ?? GetKeyValue("/settings/requestHandler/useDomainPrefixes", false);
|
||||
}
|
||||
// for unit tests only
|
||||
internal set
|
||||
{
|
||||
_useDomainPrefixes = value;
|
||||
// for unit tests only
|
||||
_useDomainPrefixes = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,31 +418,14 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
if (GlobalSettings.UseDirectoryUrls)
|
||||
{
|
||||
if (_addTrailingSlash.HasValue)
|
||||
return _addTrailingSlash.Value;
|
||||
bool result;
|
||||
if (bool.TryParse(GetKey("/settings/requestHandler/addTrailingSlash"), out result))
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// default: false
|
||||
return GlobalSettings.UseDirectoryUrls
|
||||
&& (_addTrailingSlash ?? GetKeyValue("/settings/requestHandler/addTrailingSlash", false));
|
||||
}
|
||||
// for unit tests only
|
||||
internal set
|
||||
{
|
||||
_addTrailingSlash = value;
|
||||
// for unit tests only
|
||||
_addTrailingSlash = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,31 +642,34 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_forceSafeAliases.HasValue)
|
||||
return _forceSafeAliases.Value;
|
||||
|
||||
string forceSafeAlias = GetKey("/settings/content/ForceSafeAliases");
|
||||
if (String.IsNullOrEmpty(forceSafeAlias))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
return bool.Parse(forceSafeAlias);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// default: true
|
||||
return _forceSafeAliases ?? GetKeyValue("/settings/content/ForceSafeAliases", true);
|
||||
}
|
||||
internal set
|
||||
{
|
||||
//used for unit testing
|
||||
// used for unit testing
|
||||
_forceSafeAliases = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool? _trySkipIisCustomErrors;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating where to try to skip IIS custom errors.
|
||||
/// </summary>
|
||||
public static bool TrySkipIisCustomErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
// default: false
|
||||
return _trySkipIisCustomErrors ?? GetKeyValue("/settings/web.routing/@trySkipIisCustomErrors", false);
|
||||
}
|
||||
internal set
|
||||
{
|
||||
// used for unit testing
|
||||
_trySkipIisCustomErrors = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the allowed image file types.
|
||||
@@ -677,26 +699,14 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_umbracoLibraryCacheDuration.HasValue)
|
||||
return _umbracoLibraryCacheDuration.Value;
|
||||
|
||||
string libraryCacheDuration = GetKey("/settings/content/UmbracoLibraryCacheDuration");
|
||||
if (String.IsNullOrEmpty(libraryCacheDuration))
|
||||
return 1800;
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
return int.Parse(libraryCacheDuration);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 1800;
|
||||
}
|
||||
}
|
||||
|
||||
// default: 1800
|
||||
return _umbracoLibraryCacheDuration ?? GetKeyValue("/settings/content/UmbracoLibraryCacheDuration", 1800);
|
||||
}
|
||||
internal set { _umbracoLibraryCacheDuration = value; }
|
||||
internal set
|
||||
{
|
||||
// for unit tests only
|
||||
_umbracoLibraryCacheDuration = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1052,27 +1062,12 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_useLegacySchema.HasValue)
|
||||
return _useLegacySchema.Value;
|
||||
|
||||
string value = GetKey("/settings/content/UseLegacyXmlSchema");
|
||||
bool result;
|
||||
if (!string.IsNullOrEmpty(value) && bool.TryParse(value, out result))
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//default. TODO: When we change this to a real config section we won't have to worry about parse errors
|
||||
// and should handle defaults with unit tests properly.
|
||||
return false;
|
||||
}
|
||||
// default: true
|
||||
return _useLegacySchema ?? GetKeyValue("/settings/content/UseLegacyXmlSchema", false);
|
||||
}
|
||||
internal set
|
||||
{
|
||||
//used for unit testing
|
||||
// used for unit testing
|
||||
_useLegacySchema = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("6.0.0");
|
||||
private static readonly Version Version = new Version("6.0.2");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
|
||||
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Publishing;
|
||||
@@ -110,15 +111,15 @@ namespace Umbraco.Core
|
||||
if (_isStarted)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
|
||||
if (afterStartup != null)
|
||||
{
|
||||
afterStartup(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationStarting(UmbracoApplication, ApplicationContext));
|
||||
|
||||
if (afterStartup != null)
|
||||
{
|
||||
afterStartup(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
_isStarted = true;
|
||||
|
||||
return this;
|
||||
@@ -140,15 +141,18 @@ namespace Umbraco.Core
|
||||
//stop the timer and log the output
|
||||
_timer.Dispose();
|
||||
|
||||
if (afterComplete != null)
|
||||
{
|
||||
afterComplete(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationStarted(UmbracoApplication, ApplicationContext));
|
||||
|
||||
//Now, startup all of our legacy startup handler
|
||||
ApplicationEventsResolver.Current.InstantiateLegacyStartupHanlders();
|
||||
|
||||
if (afterComplete != null)
|
||||
{
|
||||
afterComplete(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
_isComplete = true;
|
||||
|
||||
// we're ready to serve content!
|
||||
@@ -166,19 +170,19 @@ namespace Umbraco.Core
|
||||
new RepositoryFactory());
|
||||
|
||||
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
|
||||
PluginManager.Current.ResolveCacheRefreshers());
|
||||
() => PluginManager.Current.ResolveCacheRefreshers());
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
|
||||
PluginManager.Current.ResolveMacroRenderings());
|
||||
() => PluginManager.Current.ResolveMacroRenderings());
|
||||
|
||||
PackageActionsResolver.Current = new PackageActionsResolver(
|
||||
PluginManager.Current.ResolvePackageActions());
|
||||
() => PluginManager.Current.ResolvePackageActions());
|
||||
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
PluginManager.Current.ResolveActions());
|
||||
() => PluginManager.Current.ResolveActions());
|
||||
|
||||
MacroPropertyTypeResolver.Current = new MacroPropertyTypeResolver(
|
||||
PluginManager.Current.ResolveMacroPropertyTypes());
|
||||
@@ -201,7 +205,8 @@ namespace Umbraco.Core
|
||||
typeof (UpdateCmsContentTypeAllowedContentTypeTable),
|
||||
typeof (UpdateCmsContentTypeTable),
|
||||
typeof (UpdateCmsContentVersionTable),
|
||||
typeof (UpdateCmsPropertyTypeGroupTable)
|
||||
typeof (UpdateCmsPropertyTypeGroupTable),
|
||||
typeof (UpdatePropertyTypesAndGroups)
|
||||
});
|
||||
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.Core
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dataTypes"></param>
|
||||
internal DataTypesResolver(IEnumerable<Type> dataTypes)
|
||||
internal DataTypesResolver(Func<IEnumerable<Type>> dataTypes)
|
||||
: base(dataTypes)
|
||||
{
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
else if (databaseProvider.ToLower().Contains("azure"))
|
||||
{
|
||||
connectionString = string.Format("Server=tcp:{0}.database.windows.net;Database={1};User ID={2}@{0};Password={3}", server, databaseName, user, password);
|
||||
connectionString = BuildAzureConnectionString(server, databaseName, user, password);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -169,6 +169,52 @@ namespace Umbraco.Core
|
||||
Initialize(providerName);
|
||||
}
|
||||
|
||||
internal string BuildAzureConnectionString(string server, string databaseName, string user, string password)
|
||||
{
|
||||
if (server.Contains(".") && ServerStartsWithTcp(server) == false)
|
||||
server = string.Format("tcp:{0}", server);
|
||||
|
||||
if (server.Contains(".") == false && ServerStartsWithTcp(server))
|
||||
{
|
||||
string serverName = server.Contains(",")
|
||||
? server.Substring(0, server.IndexOf(",", StringComparison.Ordinal))
|
||||
: server;
|
||||
|
||||
var portAddition = string.Empty;
|
||||
|
||||
if (server.Contains(","))
|
||||
portAddition = server.Substring(server.IndexOf(",", StringComparison.Ordinal));
|
||||
|
||||
server = string.Format("{0}.database.windows.net{1}", serverName, portAddition);
|
||||
}
|
||||
|
||||
if (ServerStartsWithTcp(server) == false)
|
||||
server = string.Format("tcp:{0}.database.windows.net", server);
|
||||
|
||||
if (server.Contains(",") == false)
|
||||
server = string.Format("{0},1433", server);
|
||||
|
||||
if (user.Contains("@") == false)
|
||||
{
|
||||
var userDomain = server;
|
||||
|
||||
if (ServerStartsWithTcp(server))
|
||||
userDomain = userDomain.Substring(userDomain.IndexOf(":", StringComparison.Ordinal) + 1);
|
||||
|
||||
if (userDomain.Contains("."))
|
||||
userDomain = userDomain.Substring(0, userDomain.IndexOf(".", StringComparison.Ordinal));
|
||||
|
||||
user = string.Format("{0}@{1}", user, userDomain);
|
||||
}
|
||||
|
||||
return string.Format("Server={0};Database={1};User ID={2};Password={3}", server, databaseName, user, password);
|
||||
}
|
||||
|
||||
private static bool ServerStartsWithTcp(string server)
|
||||
{
|
||||
return server.ToLower().StartsWith("tcp:".ToLower());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the connection string as a proper .net ConnectionString and the legacy AppSettings key/value.
|
||||
/// </summary>
|
||||
@@ -218,7 +264,7 @@ namespace Umbraco.Core
|
||||
|
||||
xml.Save(fileName, SaveOptions.DisableFormatting);
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Configured new ConnectionString: " + connectionString);
|
||||
LogHelper.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -232,7 +278,8 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
internal void Initialize()
|
||||
{
|
||||
if (ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName] != null)
|
||||
var databaseSettings = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName];
|
||||
if (databaseSettings != null && string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) == false && string.IsNullOrWhiteSpace(databaseSettings.ProviderName) == false)
|
||||
{
|
||||
var providerName = "System.Data.SqlClient";
|
||||
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName))
|
||||
@@ -254,8 +301,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
ConfigureEmbeddedDatabaseConnection();
|
||||
}
|
||||
else if (legacyConnString.ToLowerInvariant().Contains("database.windows.net") &&
|
||||
legacyConnString.ToLowerInvariant().Contains("tcp:"))
|
||||
else if (legacyConnString.ToLowerInvariant().Contains("tcp:"))
|
||||
{
|
||||
//Must be sql azure
|
||||
SaveConnectionString(legacyConnString, "System.Data.SqlClient");
|
||||
@@ -337,16 +383,56 @@ namespace Umbraco.Core
|
||||
|
||||
try
|
||||
{
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: Started");
|
||||
|
||||
var message = string.Empty;
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
var supportsCaseInsensitiveQueries = SyntaxConfig.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
if (supportsCaseInsensitiveQueries == false)
|
||||
{
|
||||
message = "<p> </p><p>The database you're trying to use does not support case insensitive queries. <br />We currently do not support these types of databases.</p>" +
|
||||
"<p>You can fix this by changing the following two settings in your my.ini file in your MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
|
||||
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
|
||||
return new Result { Message = message, Success = false, Percentage = "15" };
|
||||
}
|
||||
else if (supportsCaseInsensitiveQueries == null)
|
||||
{
|
||||
message = "<p> </p><p>Warning! Could not check if your database type supports case insensitive queries. <br />We currently do not support these databases that do not support case insensitive queries.</p>" +
|
||||
"<p>You can check this by looking for the following two settings in your my.ini file in your MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
|
||||
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SyntaxConfig.SqlSyntaxProvider == MySqlSyntaxProvider.Instance)
|
||||
{
|
||||
message = "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
|
||||
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>They can check this by looking for the following two settings in the my.ini file in their MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
}
|
||||
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedVersion = schemaResult.DetermineInstalledVersion();
|
||||
string message;
|
||||
|
||||
|
||||
//If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedVersion.Equals(new Version(0, 0, 0)))
|
||||
{
|
||||
database.CreateDatabaseSchema();
|
||||
message = "Installation completed!";
|
||||
message = message + "<p>Installation completed!</p>";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -356,9 +442,11 @@ namespace Umbraco.Core
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
var runner = new MigrationRunner(configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
|
||||
var upgraded = runner.Execute(database, true);
|
||||
message = "Upgrade completed!";
|
||||
message = message + "<p>Upgrade completed!</p>";
|
||||
}
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -374,7 +462,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
Message =
|
||||
"The database configuration failed with the following message: " + ex.Message +
|
||||
"\n Please check log file for addtional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
|
||||
"\n Please check log file for additional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
|
||||
Success = false,
|
||||
Percentage = "90"
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Dictionary
|
||||
/// <summary>
|
||||
/// Resolves the current CultureDictionaryFactory
|
||||
/// </summary>
|
||||
internal class CultureDictionaryFactoryResolver : SingleObjectResolverBase<CultureDictionaryFactoryResolver, ICultureDictionaryFactory>
|
||||
internal sealed class CultureDictionaryFactoryResolver : SingleObjectResolverBase<CultureDictionaryFactoryResolver, ICultureDictionaryFactory>
|
||||
{
|
||||
internal CultureDictionaryFactoryResolver(ICultureDictionaryFactory factory)
|
||||
: base(factory)
|
||||
|
||||
@@ -9,35 +9,106 @@ using System.Xml.XPath;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
[TypeConverter(typeof(DynamicXmlConverter))]
|
||||
public class DynamicXml : DynamicObject, IEnumerable<DynamicXml>, IEnumerable<XElement>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the XElement used to create the DynamicXml structure
|
||||
/// </summary>
|
||||
public XElement BaseElement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the raw XElement used to create the DynamicXml structure if one was specified otherwise returns the
|
||||
/// same value as BaseElement.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is purely used for when an instance of DynamicXml is created with the overload that supports
|
||||
/// passing in both a raw xml version and a dash-stripped xml version. Otherwise this value is exactly the
|
||||
/// same as BaseElement.
|
||||
/// </remarks>
|
||||
public XElement RawXmlElement { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="baseElement"></param>
|
||||
public DynamicXml(XElement baseElement)
|
||||
{
|
||||
this.BaseElement = baseElement;
|
||||
if (baseElement == null) return;
|
||||
|
||||
//same
|
||||
RawXmlElement = baseElement;
|
||||
BaseElement = baseElement;
|
||||
}
|
||||
public DynamicXml(string xml)
|
||||
|
||||
/// <summary>
|
||||
/// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure
|
||||
/// </summary>
|
||||
/// <param name="strippedXml"></param>
|
||||
/// <param name="rawXml"></param>
|
||||
internal DynamicXml(XElement strippedXml, XElement rawXml)
|
||||
{
|
||||
var baseElement = XElement.Parse(xml);
|
||||
this.BaseElement = baseElement;
|
||||
if (rawXml == null) return;
|
||||
if (strippedXml == null) return;
|
||||
|
||||
RawXmlElement = rawXml;
|
||||
BaseElement = strippedXml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure
|
||||
/// </summary>
|
||||
/// <param name="strippedXml"></param>
|
||||
/// <param name="rawXml"></param>
|
||||
internal DynamicXml(string strippedXml, string rawXml)
|
||||
{
|
||||
if (rawXml == null) return;
|
||||
if (strippedXml == null) return;
|
||||
|
||||
RawXmlElement = XElement.Parse(rawXml);
|
||||
BaseElement = XElement.Parse(strippedXml);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
public DynamicXml(string xml)
|
||||
{
|
||||
if (xml.IsNullOrWhiteSpace()) return;
|
||||
|
||||
var baseElement = XElement.Parse(xml);
|
||||
|
||||
//same
|
||||
RawXmlElement = baseElement;
|
||||
BaseElement = baseElement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="xpni"></param>
|
||||
public DynamicXml(XPathNodeIterator xpni)
|
||||
{
|
||||
if (xpni != null)
|
||||
{
|
||||
if (xpni.Current != null)
|
||||
{
|
||||
var xml = xpni.Current.OuterXml;
|
||||
var baseElement = XElement.Parse(xml);
|
||||
this.BaseElement = baseElement;
|
||||
}
|
||||
}
|
||||
if (xpni == null) return;
|
||||
if (xpni.Current == null) return;
|
||||
|
||||
//TODO: OuterXml is really bad for performance! Should actually use the XPathNodeIterator api
|
||||
var xml = xpni.Current.OuterXml;
|
||||
var baseElement = XElement.Parse(xml);
|
||||
|
||||
//same
|
||||
RawXmlElement = baseElement;
|
||||
BaseElement = baseElement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the InnertText based on the BaseElement object
|
||||
/// </summary>
|
||||
public string InnerText
|
||||
{
|
||||
get
|
||||
@@ -45,17 +116,34 @@ namespace Umbraco.Core.Dynamics
|
||||
return BaseElement.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the string representation of the BaseElement object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string ToXml()
|
||||
{
|
||||
return BaseElement.ToString(SaveOptions.DisableFormatting);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the string representation of the RawXmlElement object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string ToRawXml()
|
||||
{
|
||||
return RawXmlElement.ToString(SaveOptions.DisableFormatting);
|
||||
}
|
||||
|
||||
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
|
||||
{
|
||||
int index = 0;
|
||||
if (indexes.Length > 0)
|
||||
{
|
||||
index = (int)indexes[0];
|
||||
result = new DynamicXml(this.BaseElement.Elements().ToList()[index]);
|
||||
result = new DynamicXml(
|
||||
RawXmlElement.Elements().ElementAt(index),
|
||||
BaseElement.Elements().ElementAt(index));
|
||||
return true;
|
||||
}
|
||||
return base.TryGetIndex(binder, indexes, out result);
|
||||
@@ -64,12 +152,12 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
if (args.Length == 0 && binder.Name == "ToXml")
|
||||
{
|
||||
result = this.BaseElement.ToString();
|
||||
result = BaseElement.ToString();
|
||||
return true;
|
||||
}
|
||||
if (args.Length == 1 && binder.Name == "XPath")
|
||||
{
|
||||
var elements = this.BaseElement.XPathSelectElements(args[0].ToString());
|
||||
var elements = BaseElement.XPathSelectElements(args[0].ToString());
|
||||
HandleIEnumerableXElement(elements, out result);
|
||||
return true; //anyway
|
||||
}
|
||||
@@ -102,7 +190,9 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
else if (attempt.Result.ObjectResult is IEnumerable<DynamicXml>)
|
||||
{
|
||||
result = ((IEnumerable<DynamicXml>)attempt.Result.ObjectResult).Select(x => new DynamicXml(x.BaseElement));
|
||||
result = ((IEnumerable<DynamicXml>) attempt.Result.ObjectResult).Select(x => new DynamicXml(
|
||||
x.RawXmlElement,
|
||||
x.BaseElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,55 +213,102 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
if (BaseElement == null || binder == null)
|
||||
if (RawXmlElement == null || binder == null)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
//Go ahead and try to fetch all of the elements matching the member name, and wrap them
|
||||
var elements = BaseElement.Elements(binder.Name);
|
||||
if (!elements.Any() && BaseElement.Name == "root" && BaseElement.Elements().Count() == 1)
|
||||
{
|
||||
//no elements matched, lets try first child
|
||||
elements = BaseElement.Elements().ElementAt(0).Elements(binder.Name);
|
||||
}
|
||||
if (HandleIEnumerableXElement(elements, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//Ok, so no elements matched, so lets try attributes
|
||||
IEnumerable<string> attributes = BaseElement.Attributes(binder.Name).Select(attr => attr.Value);
|
||||
int count = attributes.Count();
|
||||
|
||||
if (count > 0)
|
||||
//Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped)
|
||||
var elementByNameAttempt = CheckNodeNameMatch(binder.Name, BaseElement);
|
||||
if (elementByNameAttempt.Success)
|
||||
{
|
||||
if (HandleIEnumerableXElement(elementByNameAttempt.Result, out result))
|
||||
{
|
||||
if (count > 1)
|
||||
result = attributes; //more than one attribute matched, lets return the collection
|
||||
else
|
||||
result = attributes.FirstOrDefault(); //only one attribute matched, lets just return it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // return true because we matched
|
||||
//Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped)
|
||||
var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, BaseElement);
|
||||
if (attributeByNameAttempt.Success)
|
||||
{
|
||||
if (attributeByNameAttempt.Result.Count() > 1)
|
||||
{
|
||||
//more than one attribute matched, lets return the collection
|
||||
result = attributeByNameAttempt.Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
//no attributes matched, lets try first child
|
||||
if (BaseElement.Name == "root" && BaseElement.Elements().Count() == 1)
|
||||
{
|
||||
attributes = BaseElement.Elements().ElementAt(0).Attributes(binder.Name).Select(attr => attr.Value);
|
||||
count = attributes.Count();
|
||||
if (count > 1)
|
||||
result = attributes; //more than one attribute matched, lets return the collection
|
||||
else
|
||||
result = attributes.FirstOrDefault(); //only one attribute matched, lets just return it
|
||||
//only one attribute matched, lets just return it
|
||||
result = attributeByNameAttempt.Result.FirstOrDefault();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return true; // return true because we matched
|
||||
}
|
||||
return base.TryGetMember(binder, out result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the 'name' matches any attributes of xmlElement
|
||||
/// </summary>
|
||||
/// <param name="name">The name to match</param>
|
||||
/// <param name="xmlElement">The xml element to check against</param>
|
||||
/// <returns></returns>
|
||||
private static Attempt<IEnumerable<string>> CheckAttributeNameMatch(string name, XElement xmlElement)
|
||||
{
|
||||
var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray();
|
||||
if (attributes.Any())
|
||||
{
|
||||
return new Attempt<IEnumerable<string>>(true, attributes);
|
||||
}
|
||||
|
||||
if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1)
|
||||
{
|
||||
//no elements matched and this node is called 'root' and only has one child... lets see if it matches.
|
||||
var childElements = xmlElement.Elements().ElementAt(0).Attributes(name).Select(attr => attr.Value).ToArray();
|
||||
if (childElements.Any())
|
||||
{
|
||||
//we've found a match by the first child of an element called 'root' (strange, but sure)
|
||||
return new Attempt<IEnumerable<string>>(true, childElements);
|
||||
}
|
||||
}
|
||||
|
||||
//no deal
|
||||
return Attempt<IEnumerable<string>>.False;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the 'name' matches any elements of xmlElement
|
||||
/// </summary>
|
||||
/// <param name="name">The name to match</param>
|
||||
/// <param name="xmlElement">The xml element to check against</param>
|
||||
/// <returns></returns>
|
||||
private Attempt<IEnumerable<XElement>> CheckNodeNameMatch(string name, XElement xmlElement)
|
||||
{
|
||||
//Go ahead and try to fetch all of the elements matching the member name, and wrap them
|
||||
var elements = xmlElement.Elements(name).ToArray();
|
||||
|
||||
//Check if we've got any matches, if so then return true
|
||||
if (elements.Any())
|
||||
{
|
||||
return new Attempt<IEnumerable<XElement>>(true, elements);
|
||||
}
|
||||
|
||||
if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1)
|
||||
{
|
||||
//no elements matched and this node is called 'root' and only has one child... lets see if it matches.
|
||||
var childElements = xmlElement.Elements().ElementAt(0).Elements(name).ToArray();
|
||||
if (childElements.Any())
|
||||
{
|
||||
//we've found a match by the first child of an element called 'root' (strange, but sure)
|
||||
return new Attempt<IEnumerable<XElement>>(true, childElements);
|
||||
}
|
||||
}
|
||||
return base.TryGetMember(binder, out result);
|
||||
|
||||
//no deal
|
||||
return Attempt<IEnumerable<XElement>>.False;
|
||||
}
|
||||
|
||||
private bool HandleIEnumerableXElement(IEnumerable<XElement> elements, out object result)
|
||||
@@ -193,7 +330,7 @@ namespace Umbraco.Core.Dynamics
|
||||
//We have more than one matching element, so let's return the collection
|
||||
//elements is IEnumerable<DynamicXml>
|
||||
//but we want to be able to re-enter this code
|
||||
XElement root = new XElement(XName.Get("root"));
|
||||
var root = new XElement(XName.Get("root"));
|
||||
root.Add(elements);
|
||||
result = new DynamicXml(root);
|
||||
|
||||
@@ -205,10 +342,16 @@ namespace Umbraco.Core.Dynamics
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes an XPath expression over the BaseElement object
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
public DynamicXml XPath(string expression)
|
||||
{
|
||||
var matched = this.BaseElement.XPathSelectElements(expression);
|
||||
DynamicXml root = new DynamicXml("<results/>");
|
||||
var matched = BaseElement.XPathSelectElements(expression);
|
||||
var root = new DynamicXml("<results/>");
|
||||
foreach (var element in matched)
|
||||
{
|
||||
root.BaseElement.Add(element);
|
||||
@@ -217,7 +360,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the string version of Xml
|
||||
/// Return the string version of the BaseElement object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
@@ -231,23 +374,23 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public DynamicXml Find(string expression)
|
||||
{
|
||||
return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault());
|
||||
return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault());
|
||||
}
|
||||
|
||||
public DynamicXml Find(string attributeName, object value)
|
||||
{
|
||||
string expression = string.Format("//*[{0}='{1}']", attributeName, value);
|
||||
return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault());
|
||||
return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault());
|
||||
}
|
||||
|
||||
IEnumerator<XElement> IEnumerable<XElement>.GetEnumerator()
|
||||
{
|
||||
return this.BaseElement.Elements().GetEnumerator();
|
||||
return BaseElement.Elements().GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<DynamicXml> GetEnumerator()
|
||||
{
|
||||
return this.BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
|
||||
return BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
@@ -310,7 +453,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public bool IsPosition(int index)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -318,7 +461,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsPosition(int index, string valueIfTrue)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
@@ -326,7 +469,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(valueIfFalse);
|
||||
}
|
||||
@@ -334,7 +477,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public bool IsModZero(int modulus)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -342,7 +485,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsModZero(int modulus, string valueIfTrue)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
@@ -350,7 +493,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(valueIfFalse);
|
||||
}
|
||||
@@ -359,7 +502,7 @@ namespace Umbraco.Core.Dynamics
|
||||
|
||||
public bool IsNotModZero(int modulus)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -367,7 +510,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsNotModZero(int modulus, string valueIfTrue)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || this.BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
@@ -573,7 +716,8 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public IEnumerable<DynamicXml> Descendants(Func<XElement, bool> func)
|
||||
{
|
||||
var flattenedNodes = this.BaseElement.Elements().Map(func, (XElement n) => { return n.Elements(); });
|
||||
//var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
|
||||
var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func);
|
||||
return flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n));
|
||||
}
|
||||
public IEnumerable<DynamicXml> DescendantsOrSelf()
|
||||
@@ -582,7 +726,8 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public IEnumerable<DynamicXml> DescendantsOrSelf(Func<XElement, bool> func)
|
||||
{
|
||||
var flattenedNodes = this.BaseElement.Elements().Map(func, (XElement n) => { return n.Elements(); });
|
||||
//var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
|
||||
var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func);
|
||||
var list = new List<DynamicXml>();
|
||||
list.Add(this);
|
||||
list.AddRange(flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n)));
|
||||
@@ -689,57 +834,10 @@ namespace Umbraco.Core.Dynamics
|
||||
return test(this) ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse);
|
||||
}
|
||||
|
||||
[Obsolete("Use XmlHelper.StripDashesInElementOrAttributeNames instead")]
|
||||
public static string StripDashesInElementOrAttributeNames(string xml)
|
||||
{
|
||||
using (MemoryStream outputms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter outputtw = new StreamWriter(outputms))
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter tw = new StreamWriter(ms))
|
||||
{
|
||||
tw.Write(xml);
|
||||
tw.Flush();
|
||||
ms.Position = 0;
|
||||
using (TextReader tr = new StreamReader(ms))
|
||||
{
|
||||
bool IsInsideElement = false, IsInsideQuotes = false;
|
||||
int ic = 0;
|
||||
while ((ic = tr.Read()) != -1)
|
||||
{
|
||||
if (ic == (int)'<' && !IsInsideQuotes)
|
||||
{
|
||||
if (tr.Peek() != (int)'!')
|
||||
{
|
||||
IsInsideElement = true;
|
||||
}
|
||||
}
|
||||
if (ic == (int)'>' && !IsInsideQuotes)
|
||||
{
|
||||
IsInsideElement = false;
|
||||
}
|
||||
if (ic == (int)'"')
|
||||
{
|
||||
IsInsideQuotes = !IsInsideQuotes;
|
||||
}
|
||||
if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes)
|
||||
{
|
||||
outputtw.Write((char)ic);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
outputtw.Flush();
|
||||
outputms.Position = 0;
|
||||
using (TextReader outputtr = new StreamReader(outputms))
|
||||
{
|
||||
return outputtr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
return XmlHelper.StripDashesInElementOrAttributeNames(xml);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,58 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to return the raw xml string value from DynamicXml when using type converters
|
||||
/// </summary>
|
||||
public class RawXmlString
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
|
||||
public RawXmlString(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to return the raw xml XElement value from DynamicXml when using type converters
|
||||
/// </summary>
|
||||
public class RawXElement
|
||||
{
|
||||
public XElement Value { get; private set; }
|
||||
|
||||
public RawXElement(XElement value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to return the raw xml XElement value from DynamicXml when using type converters
|
||||
/// </summary>
|
||||
public class RawXmlElement
|
||||
{
|
||||
public XmlElement Value { get; private set; }
|
||||
|
||||
public RawXmlElement(XmlElement value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to return the raw xml XmlDocument value from DynamicXml when using type converters
|
||||
/// </summary>
|
||||
public class RawXmlDocument
|
||||
{
|
||||
public XmlDocument Value { get; private set; }
|
||||
|
||||
public RawXmlDocument(XmlDocument value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A custom type converter for DynamicXml
|
||||
/// </summary>
|
||||
@@ -14,7 +66,17 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
var convertableTypes = new[] {typeof(string), typeof(XElement), typeof(XmlElement), typeof(XmlDocument)};
|
||||
var convertableTypes = new[]
|
||||
{
|
||||
typeof(string),
|
||||
typeof(XElement),
|
||||
typeof(XmlElement),
|
||||
typeof(XmlDocument),
|
||||
typeof(RawXmlString),
|
||||
typeof(RawXElement),
|
||||
typeof(RawXmlElement),
|
||||
typeof(RawXmlDocument)
|
||||
};
|
||||
|
||||
return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, sourceType))
|
||||
|| base.CanConvertFrom(context, sourceType);
|
||||
@@ -34,6 +96,7 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
//XElement
|
||||
if (TypeHelper.IsTypeAssignableFrom<XElement>(destinationType))
|
||||
{
|
||||
@@ -53,6 +116,34 @@ namespace Umbraco.Core.Dynamics
|
||||
xDoc.LoadXml(dxml.ToString());
|
||||
return xDoc;
|
||||
}
|
||||
|
||||
//RAW values:
|
||||
//string
|
||||
if (TypeHelper.IsTypeAssignableFrom<RawXmlString>(destinationType))
|
||||
{
|
||||
return new RawXmlString(dxml.ToRawXml());
|
||||
}
|
||||
//XElement
|
||||
if (TypeHelper.IsTypeAssignableFrom<RawXElement>(destinationType))
|
||||
{
|
||||
return new RawXElement(dxml.RawXmlElement);
|
||||
}
|
||||
//XmlElement
|
||||
if (TypeHelper.IsTypeAssignableFrom<RawXmlElement>(destinationType))
|
||||
{
|
||||
var xDoc = new XmlDocument();
|
||||
xDoc.LoadXml(dxml.ToRawXml());
|
||||
return new RawXmlElement(xDoc.DocumentElement);
|
||||
}
|
||||
//XmlDocument
|
||||
if (TypeHelper.IsTypeAssignableFrom<RawXmlDocument>(destinationType))
|
||||
{
|
||||
var xDoc = new XmlDocument();
|
||||
xDoc.LoadXml(dxml.ToRawXml());
|
||||
return new RawXmlDocument(xDoc);
|
||||
}
|
||||
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,36 +5,35 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
[Obsolete("This class should not be used, it is just referenced by already obsoleted code and will be removed in the future")]
|
||||
internal static class ExtensionMethods
|
||||
{
|
||||
public static IEnumerable<TSource> Map<TSource>(
|
||||
this IEnumerable<TSource> source,
|
||||
Func<TSource, bool> selectorFunction,
|
||||
Func<TSource, IEnumerable<TSource>> getChildrenFunction)
|
||||
{
|
||||
if (!source.Any())
|
||||
{
|
||||
return source;
|
||||
}
|
||||
// Add what we have to the stack
|
||||
var flattenedList = source.Where(selectorFunction);
|
||||
// Go through the input enumerable looking for children,
|
||||
// and add those if we have them
|
||||
foreach (TSource element in source)
|
||||
{
|
||||
var secondInner = getChildrenFunction(element);
|
||||
if (secondInner.Any())
|
||||
{
|
||||
secondInner = secondInner.Map(selectorFunction, getChildrenFunction);
|
||||
}
|
||||
flattenedList = flattenedList.Concat(secondInner);
|
||||
}
|
||||
return flattenedList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//public static IEnumerable<TSource> Map<TSource>(
|
||||
// this IEnumerable<TSource> source,
|
||||
// Func<TSource, bool> selectorFunction,
|
||||
// Func<TSource, IEnumerable<TSource>> getChildrenFunction)
|
||||
//{
|
||||
// if (!source.Any())
|
||||
// {
|
||||
// return source;
|
||||
// }
|
||||
// // Add what we have to the stack
|
||||
// var flattenedList = source.Where(selectorFunction);
|
||||
// // Go through the input enumerable looking for children,
|
||||
// // and add those if we have them
|
||||
// foreach (TSource element in source)
|
||||
// {
|
||||
// var secondInner = getChildrenFunction(element);
|
||||
// if (secondInner.Any())
|
||||
// {
|
||||
// secondInner = secondInner.Map(selectorFunction, getChildrenFunction);
|
||||
// }
|
||||
// flattenedList = flattenedList.Concat(secondInner);
|
||||
// }
|
||||
// return flattenedList;
|
||||
//}
|
||||
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
@@ -44,6 +43,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, params string[] needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
@@ -53,6 +53,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, StringComparison comparison, IEnumerable<string> needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
@@ -62,6 +63,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, StringComparison comparison, params string[] needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
@@ -71,12 +73,13 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsInsensitive(this string haystack, string needle)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
return haystack.IndexOf(needle, StringComparison.CurrentCultureIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool HasValue(this string s)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(s);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
@@ -27,6 +25,15 @@ namespace Umbraco.Core.IO
|
||||
return propertyId.ToString() + seperator + fileName;
|
||||
}
|
||||
|
||||
public string GetRelativePath(string subfolder, string fileName)
|
||||
{
|
||||
var seperator = UmbracoSettings.UploadAllowDirectories
|
||||
? Path.DirectorySeparatorChar
|
||||
: '-';
|
||||
|
||||
return subfolder + seperator + fileName;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetThumbnails(string path)
|
||||
{
|
||||
var parentDirectory = System.IO.Path.GetDirectoryName(path);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Media
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal singleton to handle the numbering of subfolders within the Media-folder.
|
||||
/// When this class is initiated it will look for numbered subfolders and select the highest number,
|
||||
/// which will be the start point for the naming of the next subfolders. If no subfolders exists
|
||||
/// then the starting point will be 1000, ie. /media/1000/koala.jpg
|
||||
/// </summary>
|
||||
internal class MediaSubfolderCounter
|
||||
{
|
||||
#region Singleton
|
||||
|
||||
private long _numberedFolder = 1000;//Default starting point
|
||||
private static readonly ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim();
|
||||
private static readonly Lazy<MediaSubfolderCounter> Lazy = new Lazy<MediaSubfolderCounter>(() => new MediaSubfolderCounter());
|
||||
|
||||
public static MediaSubfolderCounter Current { get { return Lazy.Value; } }
|
||||
|
||||
private MediaSubfolderCounter()
|
||||
{
|
||||
var folders = new List<long>();
|
||||
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
|
||||
var directories = fs.GetDirectories("");
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
long dirNum;
|
||||
if (long.TryParse(directory, out dirNum))
|
||||
{
|
||||
folders.Add(dirNum);
|
||||
}
|
||||
}
|
||||
var last = folders.OrderBy(x => x).LastOrDefault();
|
||||
if(last != default(long))
|
||||
_numberedFolder = last;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns an increment of the numbered media subfolders.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="System.Int64"/> value</returns>
|
||||
public long Increment()
|
||||
{
|
||||
using (new ReadLock(ClearLock))
|
||||
{
|
||||
_numberedFolder = _numberedFolder + 1;
|
||||
return _numberedFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Media;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
@@ -57,16 +58,22 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFileBase object as the property value
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to add property value to</param>
|
||||
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFileBase"/> containing the file that will be uploaded</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value)
|
||||
{
|
||||
// Ensure we get the filename without the path in IE in intranet mode
|
||||
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
|
||||
var fileName = value.FileName;
|
||||
if (fileName.LastIndexOf(@"\") > 0)
|
||||
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
|
||||
|
||||
var name =
|
||||
IOHelper.SafeFileName(
|
||||
value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
fileName.Substring(fileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
fileName.Length - fileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
|
||||
if (string.IsNullOrEmpty(name) == false)
|
||||
SetFileOnContent(content, propertyTypeAlias, name, value.InputStream);
|
||||
@@ -75,16 +82,22 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFile object as the property value
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to add property value to</param>
|
||||
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFile"/> containing the file that will be uploaded</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFile value)
|
||||
{
|
||||
// Ensure we get the filename without the path in IE in intranet mode
|
||||
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
|
||||
var fileName = value.FileName;
|
||||
if (fileName.LastIndexOf(@"\") > 0)
|
||||
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
|
||||
|
||||
var name =
|
||||
IOHelper.SafeFileName(
|
||||
value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
fileName.Substring(fileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
fileName.Length - fileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
|
||||
if (string.IsNullOrEmpty(name) == false)
|
||||
SetFileOnContent(content, propertyTypeAlias, name, value.InputStream);
|
||||
@@ -93,13 +106,33 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFileWrapper object as the property value
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to add property value to</param>
|
||||
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFileWrapper"/> containing the file that will be uploaded</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileWrapper value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value.FileName) == false)
|
||||
SetFileOnContent(content, propertyTypeAlias, value.FileName, value.InputStream);
|
||||
// Ensure we get the filename without the path in IE in intranet mode
|
||||
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
|
||||
var fileName = value.FileName;
|
||||
if (fileName.LastIndexOf(@"\") > 0)
|
||||
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
|
||||
|
||||
if (string.IsNullOrEmpty(fileName) == false)
|
||||
SetFileOnContent(content, propertyTypeAlias, fileName, value.InputStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a <see cref="Stream"/> as the property value
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="fileName">Name of the file</param>
|
||||
/// <param name="fileStream"><see cref="Stream"/> to save to disk</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, string fileName,
|
||||
Stream fileStream)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileName) == false && fileStream != null)
|
||||
SetFileOnContent(content, propertyTypeAlias, fileName, fileStream);
|
||||
}
|
||||
|
||||
private static void SetFileOnContent(IContentBase content, string propertyTypeAlias, string name, Stream fileStream)
|
||||
@@ -109,10 +142,12 @@ namespace Umbraco.Core.Models
|
||||
return;
|
||||
|
||||
bool supportsResizing = false;
|
||||
var numberedFolder = MediaSubfolderCounter.Current.Increment();
|
||||
string fileName = UmbracoSettings.UploadAllowDirectories
|
||||
? Path.Combine(property.Id.ToString(), name)
|
||||
: property.Id + "-" + name;
|
||||
string extension = Path.GetExtension(name);
|
||||
? Path.Combine(numberedFolder.ToString(CultureInfo.InvariantCulture), name)
|
||||
: numberedFolder + "-" + name;
|
||||
|
||||
string extension = Path.GetExtension(name).Substring(1).ToLowerInvariant();
|
||||
|
||||
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
|
||||
fs.AddFile(fileName, fileStream);
|
||||
@@ -182,7 +217,7 @@ namespace Umbraco.Core.Models
|
||||
private static void SetPropertyValue(IContentBase content, XmlNode uploadFieldConfigNode, string propertyAlias, string propertyValue)
|
||||
{
|
||||
XmlNode propertyNode = uploadFieldConfigNode.SelectSingleNode(propertyAlias);
|
||||
if (propertyNode != null && string.IsNullOrEmpty(propertyNode.FirstChild.Value) == false)
|
||||
if (propertyNode != null && string.IsNullOrEmpty(propertyNode.FirstChild.Value) == false && content.HasProperty(propertyNode.FirstChild.Value))
|
||||
{
|
||||
content.SetValue(propertyNode.FirstChild.Value, propertyValue);
|
||||
}
|
||||
@@ -407,7 +442,7 @@ namespace Umbraco.Core.Models
|
||||
//Check for umbracoUrlName convention
|
||||
if (property.Alias == "umbracoUrlName" && property.Value != null &&
|
||||
property.Value.ToString().Trim() != string.Empty)
|
||||
xml.SetAttributeValue("urlName", property.Value);
|
||||
xml.SetAttributeValue("urlName", property.Value.ToString().FormatUrl().ToLower());
|
||||
}
|
||||
|
||||
return xml;
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -323,6 +322,74 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a PropertyType with a given alias already exists
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
|
||||
public abstract bool PropertyTypeExists(string propertyTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyGroup.
|
||||
/// This method will also check if a group already exists with the same name and link it to the parent.
|
||||
/// </summary>
|
||||
/// <param name="groupName">Name of the PropertyGroup to add</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
|
||||
public abstract bool AddPropertyGroup(string groupName);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType to a specific PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
public abstract bool AddPropertyType(PropertyType propertyType, string propertyGroupName);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType, which does not belong to a PropertyGroup.
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
public bool AddPropertyType(PropertyType propertyType)
|
||||
{
|
||||
if (PropertyTypeExists(propertyType.Alias) == false)
|
||||
{
|
||||
_propertyTypes.Add(propertyType);
|
||||
_propertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves a PropertyType to a specified PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType to move</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to move the PropertyType to</param>
|
||||
/// <returns></returns>
|
||||
public bool MovePropertyType(string propertyTypeAlias, string propertyGroupName)
|
||||
{
|
||||
if (PropertyTypes.Any(x => x.Alias == propertyTypeAlias) == false || PropertyGroups.Any(x => x.Name == propertyGroupName) == false)
|
||||
return false;
|
||||
|
||||
var propertyType = PropertyTypes.First(x => x.Alias == propertyTypeAlias);
|
||||
//The PropertyType already belongs to a PropertyGroup, so we have to remove the PropertyType from that group
|
||||
if (PropertyGroups.Any(x => x.PropertyTypes.Any(y => y.Alias == propertyTypeAlias)))
|
||||
{
|
||||
var oldPropertyGroup = PropertyGroups.First(x => x.PropertyTypes.Any(y => y.Alias == propertyTypeAlias));
|
||||
oldPropertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
|
||||
propertyType.PropertyGroupId = default(int);
|
||||
propertyType.ResetDirtyProperties();
|
||||
|
||||
var propertyGroup = PropertyGroups.First(x => x.Name == propertyGroupName);
|
||||
propertyGroup.PropertyTypes.Add(propertyType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a PropertyType from the current ContentType
|
||||
/// </summary>
|
||||
@@ -333,6 +400,11 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
propertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
|
||||
if (_propertyTypes.Any(x => x.Alias == propertyTypeAlias))
|
||||
{
|
||||
_propertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -343,9 +415,5 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
_parentId = id;
|
||||
}
|
||||
|
||||
//TODO Implement moving PropertyType between groups.
|
||||
/*public bool MovePropertyTypeToGroup(string propertyTypeAlias, string groupName)
|
||||
{}*/
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models
|
||||
public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition
|
||||
{
|
||||
private readonly List<IContentTypeComposition> _contentTypeComposition = new List<IContentTypeComposition>();
|
||||
internal List<int> RemovedContentTypeKeyTracker = new List<int>();
|
||||
|
||||
protected ContentTypeCompositionBase(int parentId) : base(parentId)
|
||||
{
|
||||
@@ -44,7 +45,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var groups = PropertyGroups.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups));
|
||||
var groups = ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups).Union(PropertyGroups);
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
@@ -57,8 +58,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var propertyTypes =
|
||||
PropertyTypes.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes));
|
||||
var propertyTypes = ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes).Union(PropertyTypes);
|
||||
return propertyTypes;
|
||||
}
|
||||
}
|
||||
@@ -89,9 +89,11 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>True if ContentType was removed, otherwise returns False</returns>
|
||||
public bool RemoveContentType(string alias)
|
||||
{
|
||||
if (!ContentTypeCompositionExists(alias))
|
||||
if (ContentTypeCompositionExists(alias))
|
||||
{
|
||||
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
|
||||
RemovedContentTypeKeyTracker.Add(contentTypeComposition.Id);
|
||||
OnPropertyChanged(ContentTypeCompositionSelector);
|
||||
return _contentTypeComposition.Remove(contentTypeComposition);
|
||||
}
|
||||
return false;
|
||||
@@ -113,6 +115,82 @@ namespace Umbraco.Core.Models
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a PropertyType with a given alias already exists
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
|
||||
public override bool PropertyTypeExists(string propertyTypeAlias)
|
||||
{
|
||||
return CompositionPropertyTypes.Any(x => x.Alias == propertyTypeAlias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyGroup.
|
||||
/// This method will also check if a group already exists with the same name and link it to the parent.
|
||||
/// </summary>
|
||||
/// <param name="groupName">Name of the PropertyGroup to add</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
|
||||
public override bool AddPropertyGroup(string groupName)
|
||||
{
|
||||
if (PropertyGroups.Any(x => x.Name == groupName))
|
||||
return false;
|
||||
|
||||
var propertyGroup = new PropertyGroup {Name = groupName, SortOrder = 0};
|
||||
|
||||
if (CompositionPropertyGroups.Any(x => x.Name == groupName))
|
||||
{
|
||||
var first = CompositionPropertyGroups.First(x => x.Name == groupName && x.ParentId.HasValue == false);
|
||||
propertyGroup.ParentId = first.Id;
|
||||
}
|
||||
|
||||
if (PropertyGroups.Any())
|
||||
{
|
||||
var last = PropertyGroups.Last();
|
||||
propertyGroup.SortOrder = last.SortOrder + 1;
|
||||
}
|
||||
|
||||
PropertyGroups.Add(propertyGroup);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType to a specific PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
public override bool AddPropertyType(PropertyType propertyType, string propertyGroupName)
|
||||
{
|
||||
if (PropertyTypeExists(propertyType.Alias) == false)
|
||||
{
|
||||
if (PropertyGroups.Contains(propertyGroupName))
|
||||
{
|
||||
propertyType.PropertyGroupId = PropertyGroups[propertyGroupName].Id;
|
||||
PropertyGroups[propertyGroupName].PropertyTypes.Add(propertyType);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the PropertyGroup doesn't already exist we create a new one
|
||||
var propertyTypes = new List<PropertyType> { propertyType };
|
||||
var propertyGroup = new PropertyGroup(new PropertyTypeCollection(propertyTypes)) { Name = propertyGroupName, SortOrder = 1 };
|
||||
//and check if its an inherited PropertyGroup, which exists in the composition
|
||||
if (CompositionPropertyGroups.Any(x => x.Name == propertyGroupName))
|
||||
{
|
||||
var parentPropertyGroup = CompositionPropertyGroups.First(x => x.Name == propertyGroupName && x.ParentId.HasValue == false);
|
||||
propertyGroup.SortOrder = parentPropertyGroup.SortOrder;
|
||||
propertyGroup.ParentId = parentPropertyGroup.Id;
|
||||
}
|
||||
|
||||
PropertyGroups.Add(propertyGroup);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of ContentType aliases from the current composition
|
||||
/// </summary>
|
||||
|
||||
@@ -69,5 +69,43 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the Parent</param>
|
||||
void SetLazyParentId(Lazy<int> id);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a PropertyType with a given alias already exists
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
|
||||
bool PropertyTypeExists(string propertyTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType to a specific PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
bool AddPropertyType(PropertyType propertyType, string propertyGroupName);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType, which does not belong to a PropertyGroup.
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
bool AddPropertyType(PropertyType propertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyGroup.
|
||||
/// This method will also check if a group already exists with the same name and link it to the parent.
|
||||
/// </summary>
|
||||
/// <param name="groupName">Name of the PropertyGroup to add</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
|
||||
bool AddPropertyGroup(string groupName);
|
||||
|
||||
/// <summary>
|
||||
/// Moves a PropertyType to a specified PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType to move</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to move the PropertyType to</param>
|
||||
/// <returns></returns>
|
||||
bool MovePropertyType(string propertyTypeAlias, string propertyGroupName);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
int SessionTimeout { get; set; }
|
||||
int StartContentId { get; set; }
|
||||
int StartMediaId { get; set; }
|
||||
string Lanuguage { get; set; }
|
||||
string Language { get; set; }
|
||||
bool DefaultToLiveEditing { get; set; }
|
||||
IEnumerable<string> Applications { get; set; }
|
||||
bool NoConsole { get; set; }
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
#region Implementation of IUser
|
||||
|
||||
[DataMember]
|
||||
public string Lanuguage { get; set; }
|
||||
public string Language { get; set; }
|
||||
[DataMember]
|
||||
public string Permissions { get; set; }
|
||||
[DataMember]
|
||||
|
||||
@@ -19,6 +19,14 @@ namespace Umbraco.Core.Models
|
||||
var xd = new XmlDocument();
|
||||
XmlNode xmlNode = xd.CreateNode(XmlNodeType.Element, nodeName, "");
|
||||
|
||||
//Add the property alias to the legacy schema
|
||||
if (UmbracoSettings.UseLegacyXmlSchema)
|
||||
{
|
||||
var alias = xd.CreateAttribute("alias");
|
||||
alias.Value = property.Alias.ToSafeAlias();
|
||||
xmlNode.Attributes.Append(alias);
|
||||
}
|
||||
|
||||
//This seems to fail during testing
|
||||
xmlNode.AppendChild(property.PropertyType.DataType(property.Id).Data.ToXMl(xd));
|
||||
|
||||
|
||||
@@ -51,8 +51,12 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name of the Group, which corresponds to the Tab-name in the UI
|
||||
/// Gets or sets the Id of the Parent PropertyGroup.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A Parent PropertyGroup corresponds to an inherited PropertyGroup from a composition.
|
||||
/// If a PropertyType is inserted into an inherited group then a new group will be created with an Id reference to the parent.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public int? ParentId
|
||||
{
|
||||
|
||||
@@ -8,27 +8,49 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// A resolver to return all IApplicationEvents objects
|
||||
/// </summary>
|
||||
internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>
|
||||
internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationEventHandler>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
private readonly LegacyStartupHandlerResolver _legacyResolver;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="applicationEventHandlers"></param>
|
||||
internal ApplicationEventsResolver(IEnumerable<Type> applicationEventHandlers)
|
||||
: base(applicationEventHandlers)
|
||||
{
|
||||
|
||||
//create the legacy resolver and only include the legacy types
|
||||
_legacyResolver = new LegacyStartupHandlerResolver(
|
||||
applicationEventHandlers.Where(x => !TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>(x)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Override in order to only return types of IApplicationEventHandler and above,
|
||||
/// do not include the legacy types of IApplicationStartupHandler
|
||||
/// </summary>
|
||||
protected override IEnumerable<Type> InstanceTypes
|
||||
{
|
||||
get { return base.InstanceTypes.Where(TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IApplicationEventHandler"/> implementations.
|
||||
/// </summary>
|
||||
public IEnumerable<IApplicationEventHandler> ApplicationEventHandlers
|
||||
{
|
||||
get { return Values.OfType<IApplicationEventHandler>(); }
|
||||
get { return Values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create instances of all of the legacy startup handlers
|
||||
/// </summary>
|
||||
public void InstantiateLegacyStartupHanlders()
|
||||
{
|
||||
//this will instantiate them all
|
||||
var handlers = _legacyResolver.LegacyStartupHandlers;
|
||||
}
|
||||
|
||||
protected override bool SupportsClear
|
||||
{
|
||||
get { return false; }
|
||||
@@ -44,5 +66,19 @@ namespace Umbraco.Core.ObjectResolution
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private class LegacyStartupHandlerResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>
|
||||
{
|
||||
internal LegacyStartupHandlerResolver(IEnumerable<Type> legacyStartupHandlers)
|
||||
: base(legacyStartupHandlers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<IApplicationStartupHandler> LegacyStartupHandlers
|
||||
{
|
||||
get { return Values; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for lazily resolving types for a resolver
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver"></typeparam>
|
||||
/// <typeparam name="TResolved"></typeparam>
|
||||
/// <remarks>
|
||||
/// This is a special case resolver for when types get lazily resolved in order to resolve the actual types. This is useful
|
||||
/// for when there is some processing overhead (i.e. Type finding in assemblies) to return the Types used to instantiate the instances.
|
||||
/// In some these cases we don't want to have to type find during application startup, only when we need to resolve the instances.
|
||||
///
|
||||
/// Important notes about this resolver: This does not support Insert or Remove and therefore does not support any ordering unless
|
||||
/// the types are marked with the WeightedPluginAttribute.
|
||||
/// </remarks>
|
||||
internal abstract class LazyManyObjectsResolverBase<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: base(scope)
|
||||
{
|
||||
}
|
||||
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext)
|
||||
: base(httpContext)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a list of lazy types
|
||||
/// </summary>
|
||||
/// <param name="listOfLazyTypes"></param>
|
||||
/// <param name="scope"></param>
|
||||
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> listOfLazyTypes, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
AddTypes(listOfLazyTypes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a delegate to return a list of types
|
||||
/// </summary>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
/// <param name="scope"></param>
|
||||
protected LazyManyObjectsResolverBase(Func<IEnumerable<Type>> typeListDelegate, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a list of lazy types
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="listOfLazyTypes"></param>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Lazy<Type>> listOfLazyTypes)
|
||||
: this(httpContext)
|
||||
{
|
||||
AddTypes(listOfLazyTypes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a delegate to return a list of types
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func<IEnumerable<Type>> typeListDelegate)
|
||||
: this(httpContext)
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly List<Lazy<Type>> _lazyTypeList = new List<Lazy<Type>>();
|
||||
private readonly List<Func<IEnumerable<Type>>> _listOfTypeListDelegates = new List<Func<IEnumerable<Type>>>();
|
||||
private List<Type> _resolvedTypes = null;
|
||||
private readonly ReaderWriterLockSlim _typeResolutionLock = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Used for unit tests
|
||||
/// </summary>
|
||||
internal bool HasResolvedTypes
|
||||
{
|
||||
get { return _resolvedTypes != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Once this is called this will resolve all types registered in the lazy list
|
||||
/// </summary>
|
||||
protected override IEnumerable<Type> InstanceTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
using (var lck = new UpgradeableReadLock(_typeResolutionLock))
|
||||
{
|
||||
var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray();
|
||||
var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray();
|
||||
|
||||
//we need to validate each resolved type now since we could not do it before when inserting the lazy delegates
|
||||
if (!HasResolvedTypes)
|
||||
{
|
||||
lck.UpgradeToWriteLock();
|
||||
|
||||
_resolvedTypes = new List<Type>();
|
||||
|
||||
//first iterate the lazy type list
|
||||
foreach (var l in lazyTypeList)
|
||||
{
|
||||
UpdateUniqueList(_resolvedTypes, l);
|
||||
}
|
||||
|
||||
//next iterate the list of list type delegates
|
||||
foreach (var l in listofTypeListDelegates)
|
||||
{
|
||||
UpdateUniqueList(_resolvedTypes, l);
|
||||
}
|
||||
}
|
||||
|
||||
return _resolvedTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateUniqueList(List<Type> uniqueList, Type toAdd)
|
||||
{
|
||||
EnsureCorrectType(toAdd);
|
||||
if (uniqueList.Contains(toAdd))
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + toAdd + " already exists in the collection");
|
||||
}
|
||||
uniqueList.Add(toAdd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows adding of multiple lazy types at once
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
protected void AddTypes(IEnumerable<Lazy<Type>> types)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
foreach (var t in types)
|
||||
{
|
||||
_lazyTypeList.Add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a type list delegate to the collection
|
||||
/// </summary>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
public void AddTypeListDelegate(Func<IEnumerable<Type>> typeListDelegate)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a lazy type to the list
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void AddType(Lazy<Type> value)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_lazyTypeList.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the static type added to a lazy type and adds it to the internal list
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public override void AddType(Type value)
|
||||
{
|
||||
AddType(new Lazy<Type>(() => value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all lazy types
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
EnsureClearSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_lazyTypeList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does not support removal
|
||||
/// </summary>
|
||||
protected override bool SupportsRemove
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does not support insert
|
||||
/// </summary>
|
||||
protected override bool SupportsInsert
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// these old classes don't contain metadata, the objects need to be instantiated first to get their metadata, we then store this
|
||||
/// for use in the GetById method.
|
||||
/// </remarks>
|
||||
internal abstract class LegacyTransientObjectsResolver<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
|
||||
internal abstract class LegacyTransientObjectsResolver<TResolver, TResolved> : LazyManyObjectsResolverBase<TResolver, TResolved>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
{
|
||||
@@ -27,16 +27,15 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="refreshers"></param>
|
||||
/// <param name="types"></param>
|
||||
/// <remarks>
|
||||
/// We are creating Transient instances (new instances each time) because this is how the legacy code worked and
|
||||
/// I don't want to muck anything up by changing them to application based instances.
|
||||
/// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier.
|
||||
/// </remarks>
|
||||
protected LegacyTransientObjectsResolver(IEnumerable<Type> refreshers)
|
||||
: base(ObjectLifetimeScope.Transient) // new objects every time
|
||||
{
|
||||
AddTypes(refreshers);
|
||||
protected LegacyTransientObjectsResolver(Func<IEnumerable<Type>> types)
|
||||
: base(types, ObjectLifetimeScope.Transient) // new objects every time
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -55,7 +54,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
protected abstract Guid GetUniqueIdentifier(TResolved obj);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new ICacheRefresher instance by id
|
||||
/// Returns a new TResolved instance by id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using Umbraco.Core.Macros;
|
||||
@@ -14,14 +15,14 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Much of this classes methods are based on legacy code from umbraco.editorControls.macrocontainer.MacroControlFactory
|
||||
/// this code should probably be reviewed and cleaned up if necessary.
|
||||
/// </remarks>
|
||||
internal sealed class MacroFieldEditorsResolver : ManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
|
||||
internal sealed class MacroFieldEditorsResolver : LazyManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="macroEditors"></param>
|
||||
internal MacroFieldEditorsResolver(IEnumerable<Type> macroEditors)
|
||||
internal MacroFieldEditorsResolver(Func<IEnumerable<Type>> macroEditors)
|
||||
: base(macroEditors, ObjectLifetimeScope.Transient)
|
||||
{
|
||||
|
||||
@@ -56,7 +57,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </remarks>
|
||||
internal List<Type> MacroControlTypes
|
||||
{
|
||||
get { return InstanceTypes; }
|
||||
get { return InstanceTypes.ToList(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,14 +6,14 @@ using System.Web;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
|
||||
internal abstract class ManyObjectsResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
{
|
||||
private List<TResolved> _applicationInstances = null;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
|
||||
private readonly List<Type> _instanceTypes = new List<Type>();
|
||||
|
||||
#region Constructors
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
|
||||
LifetimeScope = scope;
|
||||
InstanceTypes = new List<Type>();
|
||||
_instanceTypes = new List<Type>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -48,7 +48,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
if (httpContext == null) throw new ArgumentNullException("httpContext");
|
||||
LifetimeScope = ObjectLifetimeScope.HttpRequest;
|
||||
CurrentHttpContext = httpContext;
|
||||
InstanceTypes = new List<Type>();
|
||||
_instanceTypes = new List<Type>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,8 +58,8 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <param name="scope">If set to true will resolve singleton objects which will be created once for the lifetime of the application</param>
|
||||
protected ManyObjectsResolverBase(IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
InstanceTypes = new List<Type>(value);
|
||||
{
|
||||
_instanceTypes = new List<Type>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,7 +71,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
protected ManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Type> value)
|
||||
: this(httpContext)
|
||||
{
|
||||
InstanceTypes = new List<Type>(value);
|
||||
_instanceTypes = new List<Type>(value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -83,7 +83,10 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Returns the list of Types registered that instances will be created from
|
||||
/// </summary>
|
||||
protected List<Type> InstanceTypes { get; private set; }
|
||||
protected virtual IEnumerable<Type> InstanceTypes
|
||||
{
|
||||
get { return _instanceTypes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Current HttpContextBase used to construct this object if one exists.
|
||||
@@ -97,11 +100,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
protected ObjectLifetimeScope LifetimeScope { get; private set; }
|
||||
|
||||
private int _defaultPluginWeight = 10;
|
||||
private bool _supportsAdd = true;
|
||||
private bool _supportsInsert = true;
|
||||
private bool _supportsClear = true;
|
||||
private bool _supportsRemove = true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used in conjunction with GetSortedValues and WeightedPluginAttribute, if any of the objects
|
||||
/// being resolved do not contain the WeightedPluginAttribute then this will be the default weight applied
|
||||
@@ -189,15 +188,16 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Removes a type.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to remove.</param>
|
||||
public void RemoveType(Type value)
|
||||
public virtual void RemoveType(Type value)
|
||||
{
|
||||
if (!SupportsRemove)
|
||||
throw new InvalidOperationException("This resolver does not support Removing types");
|
||||
EnsureRemoveSupport();
|
||||
|
||||
using (new WriteLock(_lock))
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
InstanceTypes.Remove(value);
|
||||
_instanceTypes.Remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,8 +215,12 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
protected void AddTypes(IEnumerable<Type> types)
|
||||
{
|
||||
using (var l = new WriteLock(_lock))
|
||||
{
|
||||
EnsureAddSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
foreach(var t in types)
|
||||
{
|
||||
@@ -225,7 +229,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + t + " already exists in the collection");
|
||||
};
|
||||
InstanceTypes.Add(t);
|
||||
_instanceTypes.Add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,19 +238,20 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Adds a Type to the end of the list.
|
||||
/// </summary>
|
||||
/// <param name="value">The object to be added.</param>
|
||||
public void AddType(Type value)
|
||||
public virtual void AddType(Type value)
|
||||
{
|
||||
if (!SupportsAdd)
|
||||
throw new InvalidOperationException("This resolver does not support Adding new types");
|
||||
EnsureAddSupport();
|
||||
|
||||
using (var l = new WriteLock(_lock))
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
if (InstanceTypes.Contains(value))
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
|
||||
};
|
||||
InstanceTypes.Add(value);
|
||||
_instanceTypes.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,14 +267,15 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Clears the list.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
public virtual void Clear()
|
||||
{
|
||||
if (!SupportsClear)
|
||||
throw new InvalidOperationException("This resolver does not support Clearing types");
|
||||
EnsureClearSupport();
|
||||
|
||||
using (new WriteLock(_lock))
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
InstanceTypes.Clear();
|
||||
_instanceTypes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,12 +284,13 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index at which the object should be inserted.</param>
|
||||
/// <param name="value">The object to insert.</param>
|
||||
public void InsertType(int index, Type value)
|
||||
public virtual void InsertType(int index, Type value)
|
||||
{
|
||||
if (!SupportsInsert)
|
||||
throw new InvalidOperationException("This resolver does not support Inserting new types");
|
||||
EnsureInsertSupport();
|
||||
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (var l = GetWriteLock())
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
if (InstanceTypes.Contains(value))
|
||||
@@ -291,8 +298,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
|
||||
};
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
InstanceTypes.Insert(index, value);
|
||||
_instanceTypes.Insert(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +312,65 @@ namespace Umbraco.Core.ObjectResolution
|
||||
InsertType(index, typeof (T));
|
||||
}
|
||||
|
||||
private void EnsureCorrectType(Type t)
|
||||
/// <summary>
|
||||
/// Returns a WriteLock to use when modifying collections
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected WriteLock GetWriteLock()
|
||||
{
|
||||
return new WriteLock(_lock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if resolution is frozen
|
||||
/// </summary>
|
||||
protected void EnsureResolutionNotFrozen()
|
||||
{
|
||||
if (Resolution.IsFrozen)
|
||||
throw new InvalidOperationException("The type list cannot be modified after resolution has been frozen");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Remove
|
||||
/// </summary>
|
||||
protected void EnsureRemoveSupport()
|
||||
{
|
||||
if (!SupportsRemove)
|
||||
throw new InvalidOperationException("This resolver does not support Removing types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Clear
|
||||
/// </summary>
|
||||
protected void EnsureClearSupport()
|
||||
{
|
||||
if (!SupportsClear)
|
||||
throw new InvalidOperationException("This resolver does not support Clearing types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Add
|
||||
/// </summary>
|
||||
protected void EnsureAddSupport()
|
||||
{
|
||||
if (!SupportsAdd)
|
||||
throw new InvalidOperationException("This resolver does not support Adding new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support insert
|
||||
/// </summary>
|
||||
protected void EnsureInsertSupport()
|
||||
{
|
||||
if (!SupportsInsert)
|
||||
throw new InvalidOperationException("This resolver does not support Inserting new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if the type is not of the TResolved type
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
protected void EnsureCorrectType(Type t)
|
||||
{
|
||||
if (!TypeHelper.IsTypeAssignableFrom<TResolved>(t))
|
||||
throw new InvalidOperationException("The resolver " + this.GetType() + " can only accept types of " + typeof(TResolved) + ". The Type passed in to this method is " + t);
|
||||
@@ -314,22 +378,22 @@ namespace Umbraco.Core.ObjectResolution
|
||||
|
||||
protected virtual bool SupportsAdd
|
||||
{
|
||||
get { return _supportsAdd; }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsInsert
|
||||
{
|
||||
get { return _supportsInsert; }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsClear
|
||||
{
|
||||
get { return _supportsClear; }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsRemove
|
||||
{
|
||||
get { return _supportsRemove; }
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,14 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// A resolver to return all IPackageAction objects
|
||||
/// </summary>
|
||||
internal sealed class PackageActionsResolver : ManyObjectsResolverBase<PackageActionsResolver, IPackageAction>
|
||||
internal sealed class PackageActionsResolver : LazyManyObjectsResolverBase<PackageActionsResolver, IPackageAction>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="packageActions"></param>
|
||||
internal PackageActionsResolver(IEnumerable<Type> packageActions)
|
||||
internal PackageActionsResolver(Func<IEnumerable<Type>> packageActions)
|
||||
: base(packageActions)
|
||||
{
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to the PetaPoco database as Singleton, so the database is created once in app lifecycle.
|
||||
/// This is necessary for transactions to work properly
|
||||
/// </summary>
|
||||
public sealed class DatabaseFactory
|
||||
{
|
||||
#region Singleton
|
||||
|
||||
private static readonly Database _database = new Database(GlobalSettings.DbDsn);
|
||||
private static readonly Lazy<DatabaseFactory> lazy = new Lazy<DatabaseFactory>(() => new DatabaseFactory());
|
||||
|
||||
public static DatabaseFactory Current { get { return lazy.Value; } }
|
||||
|
||||
private DatabaseFactory()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of the PetaPoco database
|
||||
/// </summary>
|
||||
public Database Database
|
||||
{
|
||||
get { return _database; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,9 +127,8 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
private NodeDto BuildNodeDto(IContent entity)
|
||||
{
|
||||
//TODO: Change this once the Language property is public on IContent
|
||||
var content = entity as Content;
|
||||
var nodeName = content != null && string.IsNullOrEmpty(content.NodeName) == false ? content.NodeName : entity.Name;
|
||||
//TODO: Change this once the Language property is public on IContent
|
||||
var nodeName = entity.Name;
|
||||
|
||||
var nodeDto = new NodeDto
|
||||
{
|
||||
|
||||
@@ -33,16 +33,17 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
var properties = new List<Property>();
|
||||
|
||||
foreach (var dto in dtos)
|
||||
foreach (var propertyType in _contentType.CompositionPropertyTypes)
|
||||
{
|
||||
if (_contentType.CompositionPropertyTypes.Any(x => x.Id == dto.PropertyTypeId))
|
||||
{
|
||||
var propertyType = _contentType.CompositionPropertyTypes.First(x => x.Id == dto.PropertyTypeId);
|
||||
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
|
||||
var propertyDataDto = dtos.LastOrDefault(x => x.PropertyTypeId == propertyType.Id);
|
||||
var property = propertyDataDto == null
|
||||
? propertyType.CreatePropertyFromValue(null)
|
||||
: propertyType.CreatePropertyFromRawValue(propertyDataDto.GetValue,
|
||||
propertyDataDto.VersionId.Value,
|
||||
propertyDataDto.Id);
|
||||
|
||||
property.ResetDirtyProperties();
|
||||
properties.Add(property);
|
||||
}
|
||||
property.ResetDirtyProperties();
|
||||
properties.Add(property);
|
||||
}
|
||||
|
||||
return properties;
|
||||
|
||||
@@ -22,9 +22,21 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
foreach (var groupDto in dto)
|
||||
{
|
||||
var group = new PropertyGroup();
|
||||
group.Id = groupDto.Id;
|
||||
//Only assign an Id if the PropertyGroup belongs to this ContentType
|
||||
if (groupDto.ContentTypeNodeId == _id)
|
||||
{
|
||||
group.Id = groupDto.Id;
|
||||
|
||||
if (groupDto.ParentGroupId.HasValue)
|
||||
group.ParentId = groupDto.ParentGroupId.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the PropertyGroup is inherited, we add a reference to the group as a Parent.
|
||||
group.ParentId = groupDto.Id;
|
||||
}
|
||||
|
||||
group.Name = groupDto.Text;
|
||||
group.ParentId = groupDto.ParentGroupId;
|
||||
group.SortOrder = groupDto.SortOrder;
|
||||
group.PropertyTypes = new PropertyTypeCollection();
|
||||
|
||||
@@ -32,7 +44,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
var typeDtos = groupDto.PropertyTypeDtos.Where(x => x.Id > 0);
|
||||
foreach (var typeDto in typeDtos)
|
||||
{
|
||||
group.PropertyTypes.Add(new PropertyType(typeDto.DataTypeDto.ControlId,
|
||||
var propertyType = new PropertyType(typeDto.DataTypeDto.ControlId,
|
||||
typeDto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true))
|
||||
{
|
||||
Alias = typeDto.Alias,
|
||||
@@ -43,9 +55,12 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
HelpText = typeDto.HelpText,
|
||||
Mandatory = typeDto.Mandatory,
|
||||
SortOrder = typeDto.SortOrder,
|
||||
ValidationRegExp = typeDto.ValidationRegExp,
|
||||
PropertyGroupId = groupDto.Id
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
propertyType.ResetDirtyProperties();
|
||||
group.PropertyTypes.Add(propertyType);
|
||||
}
|
||||
group.ResetDirtyProperties();
|
||||
propertyGroups.Add(group);
|
||||
@@ -67,10 +82,12 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
ContentTypeNodeId = _id,
|
||||
SortOrder = propertyGroup.SortOrder,
|
||||
Text = propertyGroup.Name,
|
||||
ParentGroupId = propertyGroup.ParentId
|
||||
Text = propertyGroup.Name
|
||||
};
|
||||
|
||||
if (propertyGroup.ParentId.HasValue)
|
||||
dto.ParentGroupId = propertyGroup.ParentId.Value;
|
||||
|
||||
if (propertyGroup.HasIdentity)
|
||||
dto.Id = propertyGroup.Id;
|
||||
|
||||
@@ -90,11 +107,18 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
HelpText = propertyType.HelpText,
|
||||
Mandatory = propertyType.Mandatory,
|
||||
Name = propertyType.Name,
|
||||
SortOrder = propertyType.SortOrder
|
||||
SortOrder = propertyType.SortOrder,
|
||||
ValidationRegExp = propertyType.ValidationRegExp
|
||||
};
|
||||
|
||||
if (tabId != default(int))
|
||||
{
|
||||
propertyTypeDto.PropertyTypeGroupId = tabId;
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyTypeDto.PropertyTypeGroupId = null;
|
||||
}
|
||||
|
||||
if (propertyType.HasIdentity)
|
||||
propertyTypeDto.Id = propertyType.Id;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
IsLockedOut = dto.Disabled,
|
||||
IsApproved = dto.Disabled == false,
|
||||
Email = dto.Email,
|
||||
Lanuguage = dto.UserLanguage,
|
||||
Language = dto.UserLanguage,
|
||||
DefaultToLiveEditing = dto.DefaultToLiveEditing,
|
||||
NoConsole = dto.NoConsole,
|
||||
Permissions = dto.DefaultPermissions
|
||||
@@ -48,7 +48,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
Login = entity.Username,
|
||||
NoConsole = entity.NoConsole,
|
||||
Password = entity.Password,
|
||||
UserLanguage = entity.Lanuguage,
|
||||
UserLanguage = entity.Language,
|
||||
UserName = entity.Name,
|
||||
Type = short.Parse(entity.UserType.Id.ToString()),
|
||||
DefaultPermissions = entity.Permissions
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Mappers
|
||||
{
|
||||
internal class ModelDtoMapper : IMapper
|
||||
{
|
||||
public void GetTableInfo(Type t, TableInfo ti)
|
||||
{ }
|
||||
|
||||
public bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn)
|
||||
{
|
||||
if (pi.DeclaringType == typeof(Content) || pi.DeclaringType == typeof(IContent))
|
||||
{
|
||||
switch (pi.Name)
|
||||
{
|
||||
case "Trashed":
|
||||
columnName = "[umbracoNode].[trashed]";
|
||||
return true;
|
||||
case "ParentId":
|
||||
columnName = "[umbracoNode].[parentID]";
|
||||
return true;
|
||||
case "UserId":
|
||||
columnName = "[umbracoNode].[nodeUser]";
|
||||
return true;
|
||||
case "Level":
|
||||
columnName = "[umbracoNode].[level]";
|
||||
return true;
|
||||
case "Path":
|
||||
columnName = "[umbracoNode].[path]";
|
||||
return true;
|
||||
case "SortOrder":
|
||||
columnName = "[umbracoNode].[sortOrder]";
|
||||
return true;
|
||||
case "NodeId":
|
||||
columnName = "[umbracoNode].[id]";
|
||||
return true;
|
||||
case "Published":
|
||||
columnName = "[cmsDocument].[published]";
|
||||
return true;
|
||||
case "Key":
|
||||
columnName = "[umbracoNode].[uniqueID]";
|
||||
return true;
|
||||
case "CreateDate":
|
||||
columnName = "[umbracoNode].[createDate]";
|
||||
return true;
|
||||
case "Name":
|
||||
columnName = "[umbracoNode].[text]";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(ContentType) || pi.DeclaringType == typeof(IContentType))
|
||||
{
|
||||
switch (pi.Name)
|
||||
{
|
||||
case "Alias":
|
||||
columnName = "[cmsContentType].[alias]";
|
||||
return true;
|
||||
case "Icon":
|
||||
columnName = "[cmsContentType].[icon]";
|
||||
return true;
|
||||
case "Thumbnail":
|
||||
columnName = "[cmsContentType].[thumbnail]";
|
||||
return true;
|
||||
case "Description":
|
||||
columnName = "[cmsContentType].[description]";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Func<object, object> GetFromDbConverter(PropertyInfo pi, Type sourceType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Func<object, object> GetToDbConverter(Type sourceType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<User, UserDto>(src => src.IsApproved, dto => dto.Disabled);
|
||||
CacheMap<User, UserDto>(src => src.NoConsole, dto => dto.NoConsole);
|
||||
CacheMap<User, UserDto>(src => src.UserType, dto => dto.Type);
|
||||
CacheMap<User, UserDto>(src => src.Lanuguage, dto => dto.UserLanguage);
|
||||
CacheMap<User, UserDto>(src => src.Language, dto => dto.UserLanguage);
|
||||
}
|
||||
|
||||
internal override string Map(string propertyName)
|
||||
|
||||
@@ -42,8 +42,10 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
if(ValidTables.Count == 0)
|
||||
return new Version(0, 0, 0);
|
||||
|
||||
//If Errors is empty then we're at current version
|
||||
if (Errors.Any() == false)
|
||||
//If Errors is empty or if TableDefinitions tables + columns correspond to valid tables + columns then we're at current version
|
||||
if (Errors.Any() == false ||
|
||||
TableDefinitions.Any(x => ValidTables.Contains(x.Name) == false) == false &&
|
||||
TableDefinitions.SelectMany(definition => definition.Columns).Any(x => ValidColumns.Contains(x.Name) == false) == false)
|
||||
return UmbracoVersion.Current;
|
||||
|
||||
//If Errors contains umbracoApp or umbracoAppTree its pre-6.0.0 -> new Version(4, 10, 0);
|
||||
@@ -64,7 +66,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
return new Version(4, 9, 0);
|
||||
}
|
||||
|
||||
return new Version(0, 0, 0);
|
||||
return UmbracoVersion.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
migrationAttribute.TargetVersion > _configuredVersion &&
|
||||
migrationAttribute.TargetVersion <= _targetVersion &&
|
||||
migrationAttribute.ProductName == _productName
|
||||
orderby migrationAttribute.SortOrder ascending
|
||||
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder ascending
|
||||
select migration);
|
||||
return migrations;
|
||||
}
|
||||
@@ -119,7 +119,8 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
migrationAttribute.TargetVersion > _configuredVersion &&
|
||||
migrationAttribute.TargetVersion <= _targetVersion &&
|
||||
migrationAttribute.ProductName == _productName
|
||||
orderby migrationAttribute.SortOrder descending
|
||||
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder descending
|
||||
|
||||
select migration);
|
||||
return migrations;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions;
|
||||
using System;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
|
||||
{
|
||||
@@ -21,5 +22,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
|
||||
_databaseProviders) {SqlStatement = sqlStatement};
|
||||
_context.Expressions.Add(expression);
|
||||
}
|
||||
|
||||
public void Code(Func<Database, string> codeStatement)
|
||||
{
|
||||
var expression = _databaseProviders == null
|
||||
? new ExecuteCodeStatementExpression { CodeStatement = codeStatement }
|
||||
: new ExecuteCodeStatementExpression(_context.CurrentDatabaseProvider,
|
||||
_databaseProviders) { CodeStatement = codeStatement };
|
||||
_context.Expressions.Add(expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions
|
||||
{
|
||||
public class ExecuteCodeStatementExpression : MigrationExpressionBase
|
||||
{
|
||||
public ExecuteCodeStatementExpression()
|
||||
{
|
||||
}
|
||||
|
||||
public ExecuteCodeStatementExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
|
||||
: base(current, databaseProviders)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual Func<Database, string> CodeStatement { get; set; }
|
||||
|
||||
public override string Process(Database database)
|
||||
{
|
||||
if(CodeStatement != null)
|
||||
return CodeStatement(database);
|
||||
|
||||
return base.Process(database);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
|
||||
{
|
||||
public interface IExecuteBuilder : IFluentSyntax
|
||||
{
|
||||
void Sql(string sqlStatement);
|
||||
void Code(Func<Database, string> codeStatement);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
{
|
||||
[Migration("6.0.2", 0, GlobalSettings.UmbracoMigrationName)]
|
||||
public class UpdatePropertyTypesAndGroups : MigrationBase
|
||||
{
|
||||
public override void Up()
|
||||
{
|
||||
Execute.Code(UpdatePropertyTypesAndGroupsDo);
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static string UpdatePropertyTypesAndGroupsDo(Database database)
|
||||
{
|
||||
if (database != null)
|
||||
{
|
||||
//Fetch all PropertyTypes that belongs to a PropertyTypeGroup
|
||||
var propertyTypes = database.Fetch<PropertyTypeDto>("WHERE propertyTypeGroupId > 0");
|
||||
var propertyGroups = database.Fetch<PropertyTypeGroupDto>("WHERE id > 0");
|
||||
|
||||
foreach (var propertyType in propertyTypes)
|
||||
{
|
||||
//Get the PropertyTypeGroup that the current PropertyType references
|
||||
var parentPropertyTypeGroup = propertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyTypeGroupId);
|
||||
if (parentPropertyTypeGroup != null)
|
||||
{
|
||||
//If the ContentType is the same on the PropertyType and the PropertyTypeGroup the group is valid and we skip to the next
|
||||
if (parentPropertyTypeGroup.ContentTypeNodeId == propertyType.ContentTypeId) continue;
|
||||
|
||||
//Check if the 'new' PropertyTypeGroup has already been created
|
||||
var existingPropertyTypeGroup =
|
||||
propertyGroups.FirstOrDefault(
|
||||
x =>
|
||||
x.ParentGroupId == parentPropertyTypeGroup.Id && x.Text == parentPropertyTypeGroup.Text &&
|
||||
x.ContentTypeNodeId == propertyType.ContentTypeId);
|
||||
|
||||
//This should ensure that we don't create duplicate groups for a single ContentType
|
||||
if (existingPropertyTypeGroup == null)
|
||||
{
|
||||
|
||||
//Create a new PropertyTypeGroup that references the parent group that the PropertyType was referencing pre-6.0.1
|
||||
var propertyGroup = new PropertyTypeGroupDto
|
||||
{
|
||||
ContentTypeNodeId = propertyType.ContentTypeId,
|
||||
ParentGroupId = parentPropertyTypeGroup.Id,
|
||||
Text = parentPropertyTypeGroup.Text,
|
||||
SortOrder = parentPropertyTypeGroup.SortOrder
|
||||
};
|
||||
|
||||
//Save the PropertyTypeGroup in the database and update the list of groups with this new group
|
||||
int id = Convert.ToInt16(database.Insert(propertyGroup));
|
||||
propertyGroup.Id = id;
|
||||
propertyGroups.Add(propertyGroup);
|
||||
//Update the reference to the new PropertyTypeGroup on the current PropertyType
|
||||
propertyType.PropertyTypeGroupId = id;
|
||||
database.Update(propertyType);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Update the reference to the existing PropertyTypeGroup on the current PropertyType
|
||||
propertyType.PropertyTypeGroupId = existingPropertyTypeGroup.Id;
|
||||
database.Update(propertyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,14 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
public static void CreateDatabaseSchema(this Database db)
|
||||
{
|
||||
CreateDatabaseSchema(db, true);
|
||||
}
|
||||
|
||||
internal static void CreateDatabaseSchema(this Database db, bool guardConfiguration)
|
||||
{
|
||||
if (guardConfiguration && ApplicationContext.Current.IsConfigured)
|
||||
throw new Exception("Umbraco is already configured!");
|
||||
|
||||
NewTable += PetaPocoExtensions_NewTable;
|
||||
|
||||
LogHelper.Info<Database>("Initializing database schema creation");
|
||||
@@ -143,6 +151,8 @@ namespace Umbraco.Core.Persistence
|
||||
var creation = new DatabaseSchemaCreation(db);
|
||||
creation.InitializeDatabaseSchema();
|
||||
|
||||
LogHelper.Info<Database>("Finalized database schema creation");
|
||||
|
||||
NewTable -= PetaPocoExtensions_NewTable;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,572 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
internal class ExpressionHelper<T>
|
||||
{
|
||||
private string selectExpression = string.Empty;
|
||||
private string whereExpression;
|
||||
private string groupBy = string.Empty;
|
||||
private string havingExpression;
|
||||
private string orderBy = string.Empty;
|
||||
|
||||
IList<string> updateFields = new List<string>();
|
||||
IList<string> insertFields = new List<string>();
|
||||
|
||||
private string sep = string.Empty;
|
||||
private bool useFieldName = false;
|
||||
private Database.PocoData pd;
|
||||
|
||||
public ExpressionHelper()
|
||||
{
|
||||
Database.Mapper = new ModelDtoMapper();
|
||||
pd = new Database.PocoData(typeof(T));
|
||||
}
|
||||
|
||||
protected internal virtual string Visit(Expression exp)
|
||||
{
|
||||
|
||||
if (exp == null) return string.Empty;
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.Lambda:
|
||||
return VisitLambda(exp as LambdaExpression);
|
||||
case ExpressionType.MemberAccess:
|
||||
return VisitMemberAccess(exp as MemberExpression);
|
||||
case ExpressionType.Constant:
|
||||
return VisitConstant(exp as ConstantExpression);
|
||||
case ExpressionType.Add:
|
||||
case ExpressionType.AddChecked:
|
||||
case ExpressionType.Subtract:
|
||||
case ExpressionType.SubtractChecked:
|
||||
case ExpressionType.Multiply:
|
||||
case ExpressionType.MultiplyChecked:
|
||||
case ExpressionType.Divide:
|
||||
case ExpressionType.Modulo:
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.AndAlso:
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.OrElse:
|
||||
case ExpressionType.LessThan:
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
case ExpressionType.GreaterThan:
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
case ExpressionType.Equal:
|
||||
case ExpressionType.NotEqual:
|
||||
case ExpressionType.Coalesce:
|
||||
case ExpressionType.ArrayIndex:
|
||||
case ExpressionType.RightShift:
|
||||
case ExpressionType.LeftShift:
|
||||
case ExpressionType.ExclusiveOr:
|
||||
return "(" + VisitBinary(exp as BinaryExpression) + ")";
|
||||
case ExpressionType.Negate:
|
||||
case ExpressionType.NegateChecked:
|
||||
case ExpressionType.Not:
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
case ExpressionType.ArrayLength:
|
||||
case ExpressionType.Quote:
|
||||
case ExpressionType.TypeAs:
|
||||
return VisitUnary(exp as UnaryExpression);
|
||||
case ExpressionType.Parameter:
|
||||
return VisitParameter(exp as ParameterExpression);
|
||||
case ExpressionType.Call:
|
||||
return VisitMethodCall(exp as MethodCallExpression);
|
||||
case ExpressionType.New:
|
||||
return VisitNew(exp as NewExpression);
|
||||
case ExpressionType.NewArrayInit:
|
||||
case ExpressionType.NewArrayBounds:
|
||||
return VisitNewArray(exp as NewArrayExpression);
|
||||
default:
|
||||
return exp.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitLambda(LambdaExpression lambda)
|
||||
{
|
||||
if (lambda.Body.NodeType == ExpressionType.MemberAccess && sep == " ")
|
||||
{
|
||||
MemberExpression m = lambda.Body as MemberExpression;
|
||||
|
||||
if (m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
return string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
|
||||
}
|
||||
return Visit(lambda.Body);
|
||||
}
|
||||
|
||||
protected virtual string VisitBinary(BinaryExpression b)
|
||||
{
|
||||
string left, right;
|
||||
var operand = BindOperant(b.NodeType); //sep= " " ??
|
||||
if (operand == "AND" || operand == "OR")
|
||||
{
|
||||
MemberExpression m = b.Left as MemberExpression;
|
||||
if (m != null && m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
left = string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
}
|
||||
m = b.Right as MemberExpression;
|
||||
if (m != null && m.Expression != null)
|
||||
{
|
||||
string r = VisitMemberAccess(m);
|
||||
right = string.Format("{0}={1}", r, GetQuotedTrueValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
|
||||
if (operand == "=" && right == "null") operand = "is";
|
||||
else if (operand == "<>" && right == "null") operand = "is not";
|
||||
else if (operand == "=" || operand == "<>")
|
||||
{
|
||||
if (IsTrueExpression(right)) right = GetQuotedTrueValue();
|
||||
else if (IsFalseExpression(right)) right = GetQuotedFalseValue();
|
||||
|
||||
if (IsTrueExpression(left)) left = GetQuotedTrueValue();
|
||||
else if (IsFalseExpression(left)) left = GetQuotedFalseValue();
|
||||
|
||||
}
|
||||
|
||||
switch (operand)
|
||||
{
|
||||
case "MOD":
|
||||
case "COALESCE":
|
||||
return string.Format("{0}({1},{2})", operand, left, right);
|
||||
default:
|
||||
return left + sep + operand + sep + right;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
if (m.Expression != null &&
|
||||
m.Expression.NodeType == ExpressionType.Parameter
|
||||
&& m.Expression.Type == typeof(T))
|
||||
{
|
||||
string field = GetFieldName(pd, m.Member.Name);
|
||||
return field;
|
||||
}
|
||||
|
||||
if (m.Expression != null && m.Expression.NodeType != ExpressionType.Constant)
|
||||
{
|
||||
Database.Mapper = new ModelDtoMapper();
|
||||
var def = new Database.PocoData(m.Expression.Type);
|
||||
string field = GetFieldName(def, m.Member.Name);
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
var member = Expression.Convert(m, typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
object o = getter();
|
||||
return GetQuotedValue(o, o != null ? o.GetType() : null);
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitNew(NewExpression nex)
|
||||
{
|
||||
// TODO : check !
|
||||
var member = Expression.Convert(nex, typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
try
|
||||
{
|
||||
var getter = lambda.Compile();
|
||||
object o = getter();
|
||||
return GetQuotedValue(o, o.GetType());
|
||||
}
|
||||
catch (System.InvalidOperationException)
|
||||
{ // FieldName ?
|
||||
List<Object> exprs = VisitExpressionList(nex.Arguments);
|
||||
var r = new StringBuilder();
|
||||
foreach (Object e in exprs)
|
||||
{
|
||||
r.AppendFormat("{0}{1}",
|
||||
r.Length > 0 ? "," : "",
|
||||
e);
|
||||
}
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitParameter(ParameterExpression p)
|
||||
{
|
||||
return p.Name;
|
||||
}
|
||||
|
||||
protected virtual string VisitConstant(ConstantExpression c)
|
||||
{
|
||||
if (c.Value == null)
|
||||
return "null";
|
||||
else if (c.Value.GetType() == typeof(bool))
|
||||
{
|
||||
object o = GetQuotedValue(c.Value, c.Value.GetType());
|
||||
return string.Format("({0}={1})", GetQuotedTrueValue(), o);
|
||||
}
|
||||
else
|
||||
return GetQuotedValue(c.Value, c.Value.GetType());
|
||||
}
|
||||
|
||||
protected virtual string VisitUnary(UnaryExpression u)
|
||||
{
|
||||
switch (u.NodeType)
|
||||
{
|
||||
case ExpressionType.Not:
|
||||
string o = Visit(u.Operand);
|
||||
if (IsFieldName(o)) o = o + "=" + GetQuotedValue(true, typeof(bool));
|
||||
return "NOT (" + o + ")";
|
||||
default:
|
||||
return Visit(u.Operand);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual string VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
List<Object> args = this.VisitExpressionList(m.Arguments);
|
||||
|
||||
Object r;
|
||||
if (m.Object != null)
|
||||
r = Visit(m.Object);
|
||||
else
|
||||
{
|
||||
r = args[0];
|
||||
args.RemoveAt(0);
|
||||
}
|
||||
|
||||
switch (m.Method.Name)
|
||||
{
|
||||
case "ToUpper":
|
||||
return string.Format("upper({0})", r);
|
||||
case "ToLower":
|
||||
return string.Format("lower({0})", r);
|
||||
case "StartsWith":
|
||||
return string.Format("upper({0}) starting with {1} ", r, args[0].ToString().ToUpper());
|
||||
case "EndsWith":
|
||||
return string.Format("upper({0}) like '%{1}'", r, RemoveQuote(args[0].ToString()).ToUpper());
|
||||
case "Contains":
|
||||
return string.Format("upper({0}) like '%{1}%'", r, RemoveQuote(args[0].ToString()).ToUpper());
|
||||
case "Substring":
|
||||
var startIndex = Int32.Parse(args[0].ToString()) + 1;
|
||||
if (args.Count == 2)
|
||||
{
|
||||
var length = Int32.Parse(args[1].ToString());
|
||||
return string.Format("substring({0} from {1} for {2})",
|
||||
r,
|
||||
startIndex,
|
||||
length);
|
||||
}
|
||||
else
|
||||
return string.Format("substring({0} from {1})",
|
||||
r,
|
||||
startIndex);
|
||||
case "Round":
|
||||
case "Floor":
|
||||
case "Ceiling":
|
||||
case "Coalesce":
|
||||
case "Abs":
|
||||
case "Sum":
|
||||
return string.Format("{0}({1}{2})",
|
||||
m.Method.Name,
|
||||
r,
|
||||
args.Count == 1 ? string.Format(",{0}", args[0]) : "");
|
||||
case "Concat":
|
||||
var s = new StringBuilder();
|
||||
foreach (Object e in args)
|
||||
{
|
||||
s.AppendFormat(" || {0}", e);
|
||||
}
|
||||
return string.Format("{0}{1}", r, s.ToString());
|
||||
|
||||
case "In":
|
||||
|
||||
var member = Expression.Convert(m.Arguments[1], typeof(object));
|
||||
var lambda = Expression.Lambda<Func<object>>(member);
|
||||
var getter = lambda.Compile();
|
||||
|
||||
var inArgs = getter() as object[];
|
||||
|
||||
var sIn = new StringBuilder();
|
||||
foreach (Object e in inArgs)
|
||||
{
|
||||
if (e.GetType().ToString() != "System.Collections.Generic.List`1[System.Object]")
|
||||
{
|
||||
sIn.AppendFormat("{0}{1}",
|
||||
sIn.Length > 0 ? "," : "",
|
||||
GetQuotedValue(e, e.GetType()));
|
||||
}
|
||||
else
|
||||
{
|
||||
var listArgs = e as IList<Object>;
|
||||
foreach (Object el in listArgs)
|
||||
{
|
||||
sIn.AppendFormat("{0}{1}",
|
||||
sIn.Length > 0 ? "," : "",
|
||||
GetQuotedValue(el, el.GetType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Format("{0} {1} ({2})", r, m.Method.Name, sIn.ToString());
|
||||
case "Desc":
|
||||
return string.Format("{0} DESC", r);
|
||||
case "Alias":
|
||||
case "As":
|
||||
return string.Format("{0} As {1}", r,
|
||||
GetQuotedColumnName(RemoveQuoteFromAlias(RemoveQuote(args[0].ToString()))));
|
||||
case "ToString":
|
||||
return r.ToString();
|
||||
default:
|
||||
var s2 = new StringBuilder();
|
||||
foreach (Object e in args)
|
||||
{
|
||||
s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType()));
|
||||
}
|
||||
return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual List<Object> VisitExpressionList(ReadOnlyCollection<Expression> original)
|
||||
{
|
||||
var list = new List<Object>();
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
if (original[i].NodeType == ExpressionType.NewArrayInit ||
|
||||
original[i].NodeType == ExpressionType.NewArrayBounds)
|
||||
{
|
||||
|
||||
list.AddRange(VisitNewArrayFromExpressionList(original[i] as NewArrayExpression));
|
||||
}
|
||||
else
|
||||
list.Add(Visit(original[i]));
|
||||
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
protected virtual string VisitNewArray(NewArrayExpression na)
|
||||
{
|
||||
|
||||
List<Object> exprs = VisitExpressionList(na.Expressions);
|
||||
var r = new StringBuilder();
|
||||
foreach (Object e in exprs)
|
||||
{
|
||||
r.Append(r.Length > 0 ? "," + e : e);
|
||||
}
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
protected virtual List<Object> VisitNewArrayFromExpressionList(NewArrayExpression na)
|
||||
{
|
||||
|
||||
List<Object> exprs = VisitExpressionList(na.Expressions);
|
||||
return exprs;
|
||||
}
|
||||
|
||||
|
||||
protected virtual string BindOperant(ExpressionType e)
|
||||
{
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case ExpressionType.Equal:
|
||||
return "=";
|
||||
case ExpressionType.NotEqual:
|
||||
return "<>";
|
||||
case ExpressionType.GreaterThan:
|
||||
return ">";
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
return ">=";
|
||||
case ExpressionType.LessThan:
|
||||
return "<";
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
return "<=";
|
||||
case ExpressionType.AndAlso:
|
||||
return "AND";
|
||||
case ExpressionType.OrElse:
|
||||
return "OR";
|
||||
case ExpressionType.Add:
|
||||
return "+";
|
||||
case ExpressionType.Subtract:
|
||||
return "-";
|
||||
case ExpressionType.Multiply:
|
||||
return "*";
|
||||
case ExpressionType.Divide:
|
||||
return "/";
|
||||
case ExpressionType.Modulo:
|
||||
return "MOD";
|
||||
case ExpressionType.Coalesce:
|
||||
return "COALESCE";
|
||||
default:
|
||||
return e.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("\"{0}\"", tableName);
|
||||
}
|
||||
|
||||
public virtual string GetQuotedColumnName(string columnName)
|
||||
{
|
||||
return string.Format("\"{0}\"", columnName);
|
||||
}
|
||||
|
||||
public virtual string GetQuotedName(string name)
|
||||
{
|
||||
return string.Format("\"{0}\"", name);
|
||||
}
|
||||
|
||||
private string GetQuotedTrueValue()
|
||||
{
|
||||
return GetQuotedValue(true, typeof(bool));
|
||||
}
|
||||
|
||||
private string GetQuotedFalseValue()
|
||||
{
|
||||
return GetQuotedValue(false, typeof(bool));
|
||||
}
|
||||
|
||||
public virtual string GetQuotedValue(object value, Type fieldType)
|
||||
{
|
||||
if (value == null) return "NULL";
|
||||
|
||||
if (!fieldType.UnderlyingSystemType.IsValueType && fieldType != typeof(string))
|
||||
{
|
||||
//if (TypeSerializer.CanCreateFromString(fieldType))
|
||||
//{
|
||||
// return "'" + EscapeParam(TypeSerializer.SerializeToString(value)) + "'";
|
||||
//}
|
||||
|
||||
throw new NotSupportedException(
|
||||
string.Format("Property of type: {0} is not supported", fieldType.FullName));
|
||||
}
|
||||
|
||||
if (fieldType == typeof(int))
|
||||
return ((int)value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (fieldType == typeof(float))
|
||||
return ((float)value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (fieldType == typeof(double))
|
||||
return ((double)value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (fieldType == typeof(decimal))
|
||||
return ((decimal)value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
return ShouldQuoteValue(fieldType)
|
||||
? "'" + EscapeParam(value) + "'"
|
||||
: value.ToString();
|
||||
}
|
||||
|
||||
public virtual string EscapeParam(object paramValue)
|
||||
{
|
||||
return paramValue.ToString().Replace("'", "''");
|
||||
}
|
||||
|
||||
public virtual bool ShouldQuoteValue(Type fieldType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual string GetFieldName(Database.PocoData pocoData, string name)
|
||||
{
|
||||
var column = pocoData.Columns.FirstOrDefault(x => x.Value.PropertyInfo.Name == name);
|
||||
return column.Value.ColumnName;
|
||||
}
|
||||
|
||||
protected virtual string GetFieldName(string name)
|
||||
{
|
||||
|
||||
if (useFieldName)
|
||||
{
|
||||
//FieldDefinition fd = modelDef.FieldDefinitions.FirstOrDefault(x => x.Name == name);
|
||||
//string fn = fd != default(FieldDefinition) ? fd.FieldName : name;
|
||||
//return OrmLiteConfig.DialectProvider.GetQuotedColumnName(fn);
|
||||
return "[" + name + "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
protected string RemoveQuote(string exp)
|
||||
{
|
||||
|
||||
if (exp.StartsWith("'") && exp.EndsWith("'"))
|
||||
{
|
||||
exp = exp.Remove(0, 1);
|
||||
exp = exp.Remove(exp.Length - 1, 1);
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
|
||||
protected string RemoveQuoteFromAlias(string exp)
|
||||
{
|
||||
|
||||
if ((exp.StartsWith("\"") || exp.StartsWith("`") || exp.StartsWith("'"))
|
||||
&&
|
||||
(exp.EndsWith("\"") || exp.EndsWith("`") || exp.EndsWith("'")))
|
||||
{
|
||||
exp = exp.Remove(0, 1);
|
||||
exp = exp.Remove(exp.Length - 1, 1);
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
|
||||
private string GetTrueExpression()
|
||||
{
|
||||
object o = GetQuotedTrueValue();
|
||||
return string.Format("({0}={1})", o, o);
|
||||
}
|
||||
|
||||
private string GetFalseExpression()
|
||||
{
|
||||
|
||||
return string.Format("({0}={1})",
|
||||
GetQuotedTrueValue(),
|
||||
GetQuotedFalseValue());
|
||||
}
|
||||
|
||||
private bool IsTrueExpression(string exp)
|
||||
{
|
||||
return (exp == GetTrueExpression());
|
||||
}
|
||||
|
||||
private bool IsFalseExpression(string exp)
|
||||
{
|
||||
return (exp == GetFalseExpression());
|
||||
}
|
||||
|
||||
protected bool IsFieldName(string quotedExp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContent>(sqlClause, query);
|
||||
var sql = translator.Translate();
|
||||
var sql = translator.Translate()
|
||||
.Where<DocumentDto>(x => x.Newest)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
//NOTE: This doesn't allow properties to be part of the query
|
||||
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql);
|
||||
@@ -368,7 +371,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Loop through properties to check if the content contains images/files that should be deleted
|
||||
foreach (var property in entity.Properties)
|
||||
{
|
||||
if (property.PropertyType.DataTypeId == uploadFieldId &&
|
||||
if (property.PropertyType.DataTypeId == uploadFieldId && property.Value != null &&
|
||||
string.IsNullOrEmpty(property.Value.ToString()) == false
|
||||
&& fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
|
||||
{
|
||||
@@ -450,6 +453,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var propertyDataDtos = Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql);
|
||||
var propertyFactory = new PropertyFactory(contentType, versionId, id);
|
||||
var properties = propertyFactory.BuildEntity(propertyDataDtos);
|
||||
|
||||
var newProperties = properties.Where(x => x.HasIdentity == false);
|
||||
foreach (var property in newProperties)
|
||||
{
|
||||
var propertyDataDto = new PropertyDataDto{ NodeId = id, PropertyTypeId = property.PropertyTypeId, VersionId = versionId };
|
||||
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
|
||||
|
||||
property.Version = versionId;
|
||||
property.Id = primaryKey;
|
||||
}
|
||||
|
||||
return new PropertyCollection(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
@@ -139,82 +140,148 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected void PersistUpdatedBaseContentType(ContentTypeDto dto, IContentTypeComposition entity)
|
||||
{
|
||||
var propertyFactory = new PropertyGroupFactory(entity.Id);
|
||||
var propertyGroupFactory = new PropertyGroupFactory(entity.Id);
|
||||
|
||||
var nodeDto = dto.NodeDto;
|
||||
var o = Database.Update(nodeDto);
|
||||
|
||||
//Look up ContentType entry to get PrimaryKey for updating the DTO
|
||||
var dtoPk = Database.First<ContentTypeDto>("WHERE nodeId = @Id", new { Id = entity.Id });
|
||||
var dtoPk = Database.First<ContentTypeDto>("WHERE nodeId = @Id", new {Id = entity.Id});
|
||||
dto.PrimaryKey = dtoPk.PrimaryKey;
|
||||
Database.Update(dto);
|
||||
|
||||
//Delete the ContentType composition entries before adding the updated collection
|
||||
Database.Delete<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id", new { Id = entity.Id });
|
||||
Database.Delete<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id", new {Id = entity.Id});
|
||||
//Update ContentType composition in new table
|
||||
foreach (var composition in entity.ContentTypeComposition)
|
||||
{
|
||||
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id });
|
||||
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
|
||||
var compositionBase = entity as ContentTypeCompositionBase;
|
||||
if (compositionBase != null && compositionBase.RemovedContentTypeKeyTracker != null &&
|
||||
compositionBase.RemovedContentTypeKeyTracker.Any())
|
||||
{
|
||||
//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)
|
||||
.Where<NodeDto>(x => x.NodeObjectType == new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"))
|
||||
.Where<ContentDto>(x => x.ContentTypeId == entity.Id);
|
||||
|
||||
var contentDtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql);
|
||||
//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
|
||||
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.
|
||||
foreach (var contentDto in contentDtos)
|
||||
{
|
||||
foreach (var propertyType in propertyTypes)
|
||||
{
|
||||
var nodeId = contentDto.NodeId;
|
||||
var propertyTypeId = propertyType.Id;
|
||||
var propertySql = new Sql().Select("*")
|
||||
.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);
|
||||
|
||||
//Finally delete the properties that match our criteria for removing a ContentType from the composition
|
||||
Database.Delete<PropertyDataDto>(propertySql);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Delete the allowed content type entries before adding the updated collection
|
||||
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new { Id = entity.Id });
|
||||
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new {Id = entity.Id});
|
||||
//Insert collection of allowed content types
|
||||
foreach (var allowedContentType in entity.AllowedContentTypes)
|
||||
{
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id.Value, SortOrder = allowedContentType.SortOrder });
|
||||
Database.Insert(new ContentTypeAllowedContentTypeDto
|
||||
{
|
||||
Id = entity.Id,
|
||||
AllowedId = allowedContentType.Id.Value,
|
||||
SortOrder = allowedContentType.SortOrder
|
||||
});
|
||||
}
|
||||
|
||||
//Check Dirty properties for Tabs/Groups and PropertyTypes - insert and delete accordingly
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
if (((ICanBeDirty) 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.Alias.ToLowerInvariant());
|
||||
var entityPropertyTypes = entity.PropertyTypes.Select(x => x.Alias.ToLowerInvariant());
|
||||
var aliases = dbPropertyTypeAlias.Except(entityPropertyTypes);
|
||||
foreach (var alias in aliases)
|
||||
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.
|
||||
var propertyType = dbPropertyTypes.FirstOrDefault(x => x.Alias.ToLowerInvariant() == alias);
|
||||
if (propertyType != null)
|
||||
{
|
||||
Database.Delete<PropertyDataDto>("WHERE propertytypeid = @Id", new { Id = propertyType.Id });
|
||||
}
|
||||
|
||||
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND Alias = @Alias", new { Id = entity.Id, Alias = alias });
|
||||
Database.Delete<PropertyDataDto>("WHERE propertytypeid = @Id", new {Id = item});
|
||||
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND id = @PropertyTypeId",
|
||||
new {Id = entity.Id, PropertyTypeId = item});
|
||||
}
|
||||
}
|
||||
|
||||
if (((ICanBeDirty) entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
{
|
||||
//Delete Tabs/Groups by excepting entries from db with entries from collections
|
||||
var dbPropertyGroups = Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new { Id = entity.Id }).Select(x => x.Text);
|
||||
var entityPropertyGroups = entity.PropertyGroups.Select(x => x.Name);
|
||||
var dbPropertyGroups =
|
||||
Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new {Id = entity.Id})
|
||||
.Select(x => new Tuple<int, string>(x.Id, x.Text));
|
||||
var entityPropertyGroups = entity.PropertyGroups.Select(x => new Tuple<int, string>(x.Id, x.Name));
|
||||
var tabs = dbPropertyGroups.Except(entityPropertyGroups);
|
||||
foreach (var tabName in tabs)
|
||||
foreach (var tab in tabs)
|
||||
{
|
||||
Database.Delete<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name", new { Id = entity.Id, Name = tabName });
|
||||
Database.Update<PropertyTypeDto>("SET propertyTypeGroupId = NULL WHERE propertyTypeGroupId = @PropertyGroupId",
|
||||
new {PropertyGroupId = tab.Item1});
|
||||
Database.Update<PropertyTypeGroupDto>("SET parentGroupId = NULL WHERE parentGroupId = @TabId",
|
||||
new {TabId = tab.Item1});
|
||||
Database.Delete<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name",
|
||||
new {Id = entity.Id, Name = tab.Item2});
|
||||
}
|
||||
}
|
||||
|
||||
//Run through all groups to insert or update entries
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
|
||||
int groupPrimaryKey = propertyGroup.HasIdentity
|
||||
? Database.Update(tabDto)
|
||||
: Convert.ToInt32(Database.Insert(tabDto));
|
||||
if (!propertyGroup.HasIdentity)
|
||||
propertyGroup.Id = groupPrimaryKey;//Set Id on new PropertyGroup
|
||||
}
|
||||
//Run through all groups to insert or update entries
|
||||
foreach (var propertyGroup in entity.PropertyGroups)
|
||||
{
|
||||
var tabDto = propertyGroupFactory.BuildGroupDto(propertyGroup);
|
||||
int groupPrimaryKey = propertyGroup.HasIdentity
|
||||
? Database.Update(tabDto)
|
||||
: Convert.ToInt32(Database.Insert(tabDto));
|
||||
if (propertyGroup.HasIdentity == false)
|
||||
propertyGroup.Id = groupPrimaryKey; //Set Id on new PropertyGroup
|
||||
|
||||
//Run through all PropertyTypes to insert or update entries
|
||||
foreach (var propertyType in entity.PropertyTypes)
|
||||
//Ensure that the PropertyGroup's Id is set on the PropertyTypes within a group
|
||||
//unless the PropertyGroupId has already been changed.
|
||||
foreach (var propertyType in propertyGroup.PropertyTypes)
|
||||
{
|
||||
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyType.PropertyGroupId, propertyType);
|
||||
int typePrimaryKey = propertyType.HasIdentity
|
||||
? Database.Update(propertyTypeDto)
|
||||
: Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
if (!propertyType.HasIdentity)
|
||||
propertyType.Id = typePrimaryKey;//Set Id on new PropertyType
|
||||
if (propertyType.IsPropertyDirty("PropertyGroupId") == false)
|
||||
propertyType.PropertyGroupId = propertyGroup.Id;
|
||||
}
|
||||
}
|
||||
|
||||
//Run through all PropertyTypes to insert or update entries
|
||||
foreach (var propertyType in entity.PropertyTypes)
|
||||
{
|
||||
var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(propertyType.PropertyGroupId,
|
||||
propertyType);
|
||||
int typePrimaryKey = propertyType.HasIdentity
|
||||
? Database.Update(propertyTypeDto)
|
||||
: Convert.ToInt32(Database.Insert(propertyTypeDto));
|
||||
if (propertyType.HasIdentity == false)
|
||||
propertyType.Id = typePrimaryKey; //Set Id on new PropertyType
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
|
||||
@@ -242,8 +309,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new GroupPropertyTypeRelator().Map, sql);
|
||||
|
||||
var propertyFactory = new PropertyGroupFactory(id);
|
||||
var propertyGroups = propertyFactory.BuildEntity(dtos);
|
||||
var propertyGroupFactory = new PropertyGroupFactory(id);
|
||||
var propertyGroups = propertyGroupFactory.BuildEntity(dtos);
|
||||
return new PropertyGroupCollection(propertyGroups);
|
||||
}
|
||||
|
||||
@@ -272,9 +339,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
Name = dto.Name,
|
||||
HelpText = dto.HelpText,
|
||||
Mandatory = dto.Mandatory,
|
||||
SortOrder = dto.SortOrder
|
||||
});
|
||||
|
||||
SortOrder = dto.SortOrder,
|
||||
ValidationRegExp = dto.ValidationRegExp
|
||||
}).ToList();
|
||||
|
||||
//Reset dirty properties
|
||||
Parallel.ForEach(list, currentFile => currentFile.ResetDirtyProperties());
|
||||
|
||||
return new PropertyTypeCollection(list);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContentType>(sqlClause, query);
|
||||
var sql = translator.Translate();
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text);
|
||||
|
||||
var dtos = Database.Fetch<DocumentTypeDto, ContentTypeDto, NodeDto>(sql);
|
||||
|
||||
|
||||
@@ -26,13 +26,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public TemplateRepository(IDatabaseUnitOfWork work)
|
||||
: base(work)
|
||||
{
|
||||
EnsureDepedencies();
|
||||
EnsureDependencies();
|
||||
}
|
||||
|
||||
public TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
|
||||
: base(work, cache)
|
||||
{
|
||||
EnsureDepedencies();
|
||||
EnsureDependencies();
|
||||
}
|
||||
|
||||
internal TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem)
|
||||
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
_viewsFileSystem = viewFileSystem;
|
||||
}
|
||||
|
||||
private void EnsureDepedencies()
|
||||
private void EnsureDependencies()
|
||||
{
|
||||
_masterpagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages);
|
||||
_viewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews);
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
string FormatTableRename(string oldName, string newName);
|
||||
bool SupportsClustered();
|
||||
bool SupportsIdentityInsert();
|
||||
bool? SupportsCaseInsensitiveQueries(Database db);
|
||||
IEnumerable<string> GetTablesInSchema(Database db);
|
||||
IEnumerable<ColumnInfo> GetColumnsInSchema(Database db);
|
||||
IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db);
|
||||
|
||||
@@ -309,5 +309,33 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } }
|
||||
|
||||
public override string RenameColumn { get { return "ALTER TABLE {0} CHANGE {1} {2}"; } }
|
||||
|
||||
public override bool? SupportsCaseInsensitiveQueries(Database db)
|
||||
{
|
||||
bool? supportsCaseInsensitiveQueries = null;
|
||||
|
||||
try
|
||||
{
|
||||
db.OpenSharedConnection();
|
||||
// Need 4 @ signs as it is regarded as a parameter, @@ escapes it once, @@@@ escapes it twice
|
||||
var lowerCaseFileSystem = db.Fetch<int>("SELECT @@@@Global.lower_case_file_system");
|
||||
var lowerCaseTableNames = db.Fetch<int>("SELECT @@@@Global.lower_case_table_names");
|
||||
|
||||
if(lowerCaseFileSystem.Any() && lowerCaseTableNames.Any())
|
||||
supportsCaseInsensitiveQueries = lowerCaseFileSystem.First() == 1 && lowerCaseTableNames.First() == 1;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logging.LogHelper.Error<MySqlSyntaxProvider>("Error querying for lower_case support", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
db.CloseSharedConnection();
|
||||
}
|
||||
|
||||
// Could return null, which means testing failed,
|
||||
// add message to check with their hosting provider
|
||||
return supportsCaseInsensitiveQueries;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,6 +151,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return "NVARCHAR";
|
||||
}
|
||||
|
||||
public virtual bool? SupportsCaseInsensitiveQueries(Database db)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<string> GetTablesInSchema(Database db)
|
||||
{
|
||||
return new List<string>();
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <summary>
|
||||
/// Manages the list of IPropertyEditorValueConverter's
|
||||
/// </summary>
|
||||
internal class PropertyEditorValueConvertersResolver : ManyObjectsResolverBase<PropertyEditorValueConvertersResolver, IPropertyEditorValueConverter>
|
||||
internal sealed class PropertyEditorValueConvertersResolver : ManyObjectsResolverBase<PropertyEditorValueConvertersResolver, IPropertyEditorValueConverter>
|
||||
{
|
||||
public PropertyEditorValueConvertersResolver(IEnumerable<Type> converters)
|
||||
: base(converters)
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
var e = XElement.Parse(DynamicXml.StripDashesInElementOrAttributeNames(sResult), LoadOptions.None);
|
||||
var e = XElement.Parse(sResult, LoadOptions.None);
|
||||
|
||||
//check that the document element is not one of the disallowed elements
|
||||
//allows RTE to still return as html if it's valid xhtml
|
||||
|
||||
@@ -78,6 +78,7 @@ namespace Umbraco.Core.Publishing
|
||||
{
|
||||
//Fire Publishing event
|
||||
if (Publishing.IsRaisedEventCancelled(new PublishEventArgs<IContent>(item), this))
|
||||
return false;
|
||||
|
||||
//Check if the Content is Expired to verify that it can in fact be published
|
||||
if (item.Status == ContentStatus.Expired)
|
||||
|
||||
@@ -352,7 +352,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<IContent>.Builder.Where(x => x.ParentId == -20);
|
||||
var query = Query<IContent>.Builder.Where(x => x.Path.Contains("-20"));
|
||||
var contents = repository.GetByQuery(query);
|
||||
|
||||
return contents;
|
||||
@@ -737,9 +737,18 @@ namespace Umbraco.Core.Services
|
||||
return;
|
||||
|
||||
content.WriterId = userId;
|
||||
var parent = GetById(parentId);
|
||||
content.Path = string.Concat(parent.Path, ",", content.Id);
|
||||
content.Level = parent.Level + 1;
|
||||
if (parentId == -1)
|
||||
{
|
||||
content.Path = string.Concat("-1,", content.Id);
|
||||
content.Level = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parent = GetById(parentId);
|
||||
content.Path = string.Concat(parent.Path, ",", content.Id);
|
||||
content.Level = parent.Level + 1;
|
||||
}
|
||||
|
||||
|
||||
//If Content is being moved away from Recycle Bin, its state should be un-trashed
|
||||
if (content.Trashed && parentId != -20)
|
||||
@@ -807,8 +816,8 @@ namespace Umbraco.Core.Services
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateContentRepository(uow))
|
||||
{
|
||||
var query = Query<IContent>.Builder.Where(x => x.ParentId == -20);
|
||||
var contents = repository.GetByQuery(query);
|
||||
var query = Query<IContent>.Builder.Where(x => x.Path.Contains("-20"));
|
||||
var contents = repository.GetByQuery(query).OrderByDescending(x => x.ParentId);
|
||||
|
||||
foreach (var content in contents)
|
||||
{
|
||||
@@ -1261,6 +1270,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
//Has this content item previously been published? If so, we don't need to refresh the children
|
||||
var previouslyPublished = HasPublishedVersion(content.Id);
|
||||
var validForPublishing = true;
|
||||
|
||||
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
|
||||
if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false)
|
||||
@@ -1269,7 +1279,7 @@ namespace Umbraco.Core.Services
|
||||
string.Format(
|
||||
"Content '{0}' with Id '{1}' could not be published because its parent is not published.",
|
||||
content.Name, content.Id));
|
||||
return false;
|
||||
validForPublishing = false;
|
||||
}
|
||||
|
||||
//Content contains invalid property values and can therefore not be published - fire event?
|
||||
@@ -1279,11 +1289,11 @@ namespace Umbraco.Core.Services
|
||||
string.Format(
|
||||
"Content '{0}' with Id '{1}' could not be published because of invalid properties.",
|
||||
content.Name, content.Id));
|
||||
return false;
|
||||
validForPublishing = false;
|
||||
}
|
||||
|
||||
//Publish and then update the database with new status
|
||||
bool published = _publishingStrategy.Publish(content, userId);
|
||||
bool published = validForPublishing && _publishingStrategy.Publish(content, userId);
|
||||
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateContentRepository(uow))
|
||||
@@ -1295,37 +1305,38 @@ namespace Umbraco.Core.Services
|
||||
|
||||
uow.Commit();
|
||||
|
||||
var xml = content.ToXml();
|
||||
//Preview Xml
|
||||
var previewPoco = new PreviewXmlDto
|
||||
{
|
||||
NodeId = content.Id,
|
||||
Timestamp = DateTime.Now,
|
||||
VersionId = content.Version,
|
||||
Xml = xml.ToString(SaveOptions.None)
|
||||
};
|
||||
var previewExists =
|
||||
uow.Database.ExecuteScalar<int>("SELECT COUNT(nodeId) FROM cmsPreviewXml WHERE nodeId = @Id AND versionId = @Version",
|
||||
new { Id = content.Id, Version = content.Version }) != 0;
|
||||
int previewResult = previewExists
|
||||
? uow.Database.Update<PreviewXmlDto>(
|
||||
"SET xml = @Xml, timestamp = @Timestamp WHERE nodeId = @Id AND versionId = @Version",
|
||||
new
|
||||
{
|
||||
Xml = previewPoco.Xml,
|
||||
Timestamp = previewPoco.Timestamp,
|
||||
Id = previewPoco.NodeId,
|
||||
Version = previewPoco.VersionId
|
||||
})
|
||||
: Convert.ToInt32(uow.Database.Insert(previewPoco));
|
||||
|
||||
if (published)
|
||||
{
|
||||
var xml = content.ToXml();
|
||||
//Content Xml
|
||||
var contentPoco = new ContentXmlDto { NodeId = content.Id, Xml = xml.ToString(SaveOptions.None) };
|
||||
var contentExists = uow.Database.ExecuteScalar<int>("SELECT COUNT(nodeId) FROM cmsContentXml WHERE nodeId = @Id", new { Id = content.Id }) != 0;
|
||||
int contentResult = contentExists
|
||||
? uow.Database.Update(contentPoco)
|
||||
: Convert.ToInt32(uow.Database.Insert(contentPoco));
|
||||
//Preview Xml
|
||||
var previewPoco = new PreviewXmlDto
|
||||
{
|
||||
NodeId = content.Id,
|
||||
Timestamp = DateTime.Now,
|
||||
VersionId = content.Version,
|
||||
Xml = xml.ToString(SaveOptions.None)
|
||||
};
|
||||
var previewExists =
|
||||
uow.Database.ExecuteScalar<int>("SELECT COUNT(nodeId) FROM cmsPreviewXml WHERE nodeId = @Id AND versionId = @Version",
|
||||
new {Id = content.Id, Version = content.Version}) != 0;
|
||||
int previewResult = previewExists
|
||||
? uow.Database.Update<PreviewXmlDto>(
|
||||
"SET xml = @Xml, timestamp = @Timestamp WHERE nodeId = @Id AND versionId = @Version",
|
||||
new
|
||||
{
|
||||
Xml = previewPoco.Xml,
|
||||
Timestamp = previewPoco.Timestamp,
|
||||
Id = previewPoco.NodeId,
|
||||
Version = previewPoco.VersionId
|
||||
})
|
||||
: Convert.ToInt32(uow.Database.Insert(previewPoco));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1334,11 +1345,11 @@ namespace Umbraco.Core.Services
|
||||
Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);
|
||||
|
||||
//Save xml to db and call following method to fire event through PublishingStrategy to update cache
|
||||
if (omitCacheRefresh == false)
|
||||
if (published && omitCacheRefresh == false)
|
||||
_publishingStrategy.PublishingFinalized(content);
|
||||
|
||||
//We need to check if children and their publish state to ensure that we 'republish' content that was previously published
|
||||
if (omitCacheRefresh == false && previouslyPublished == false && HasChildren(content.Id))
|
||||
if (published && omitCacheRefresh == false && previouslyPublished == false && HasChildren(content.Id))
|
||||
{
|
||||
var descendants = GetPublishedDescendants(content);
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ namespace Umbraco.Core.Services
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
|
||||
return;
|
||||
|
||||
_mediaService.DeleteMediaOfType(mediaType.Id);
|
||||
_mediaService.DeleteMediaOfType(mediaType.Id, userId);
|
||||
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMediaTypeRepository(uow))
|
||||
|
||||
@@ -276,7 +276,7 @@ namespace Umbraco.Core.Services
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
var query = Query<IMedia>.Builder.Where(x => x.ParentId == -21);
|
||||
var query = Query<IMedia>.Builder.Where(x => x.Path.Contains("-21"));
|
||||
var medias = repository.GetByQuery(query);
|
||||
|
||||
return medias;
|
||||
@@ -378,8 +378,8 @@ namespace Umbraco.Core.Services
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
var query = Query<IMedia>.Builder.Where(x => x.ParentId == -21);
|
||||
var contents = repository.GetByQuery(query);
|
||||
var query = Query<IMedia>.Builder.Where(x => x.Path.Contains("-21"));
|
||||
var contents = repository.GetByQuery(query).OrderByDescending(x => x.ParentId);
|
||||
|
||||
foreach (var content in contents)
|
||||
{
|
||||
@@ -554,7 +554,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if(raiseEvents)
|
||||
{
|
||||
if (SavingCollection.IsRaisedEventCancelled(new SaveEventArgs<IEnumerable<IMedia>>(medias), this))
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMedia>(medias), this))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -572,7 +572,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if(raiseEvents)
|
||||
SavedCollection.RaiseEvent(new SaveEventArgs<IEnumerable<IMedia>>(medias, false), this);
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMedia>(medias, false), this);
|
||||
|
||||
Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId, -1);
|
||||
}
|
||||
@@ -635,16 +635,6 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMediaService, SaveEventArgs<IMedia>> Saved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before saving a collection
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMediaService, SaveEventArgs<IEnumerable<IMedia>>> SavingCollection;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after saving a collection
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMediaService, SaveEventArgs<IEnumerable<IMedia>>> SavedCollection;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Create
|
||||
/// </summary>
|
||||
|
||||
@@ -21,15 +21,62 @@ namespace Umbraco.Core
|
||||
///</summary>
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string EncryptWithMachineKey(this string toEncrypt)
|
||||
/// <summary>
|
||||
/// Encrypt the string using the MachineKey in medium trust
|
||||
/// </summary>
|
||||
/// <param name="value">The string value to be encrypted.</param>
|
||||
/// <returns>The encrypted string.</returns>
|
||||
public static string EncryptWithMachineKey(this string value)
|
||||
{
|
||||
var output = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(0, "temp", DateTime.Now, DateTime.MaxValue, false, toEncrypt));
|
||||
return output;
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
string valueToEncrypt = value;
|
||||
List<string> parts = new List<string>();
|
||||
|
||||
const int EncrpytBlockSize = 500;
|
||||
|
||||
while (valueToEncrypt.Length > EncrpytBlockSize)
|
||||
{
|
||||
parts.Add(valueToEncrypt.Substring(0, EncrpytBlockSize));
|
||||
valueToEncrypt = valueToEncrypt.Remove(0, EncrpytBlockSize);
|
||||
}
|
||||
|
||||
if (valueToEncrypt.Length > 0)
|
||||
{
|
||||
parts.Add(valueToEncrypt);
|
||||
}
|
||||
|
||||
StringBuilder encrpytedValue = new StringBuilder();
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
var encrpytedBlock = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(0, string.Empty, DateTime.Now, DateTime.MaxValue, false, part));
|
||||
encrpytedValue.AppendLine(encrpytedBlock);
|
||||
}
|
||||
|
||||
return encrpytedValue.ToString().TrimEnd();
|
||||
}
|
||||
public static string DecryptWithMachineKey(this string encrypted)
|
||||
/// <summary>
|
||||
/// Decrypt the encrypted string using the Machine key in medium trust
|
||||
/// </summary>
|
||||
/// <param name="value">The string value to be decrypted</param>
|
||||
/// <returns>The decrypted string.</returns>
|
||||
public static string DecryptWithMachineKey(this string value)
|
||||
{
|
||||
var output = FormsAuthentication.Decrypt(encrypted);
|
||||
return output.UserData;
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
string[] parts = value.Split('\n');
|
||||
|
||||
StringBuilder decryptedValue = new StringBuilder();
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
decryptedValue.Append(FormsAuthentication.Decrypt(part.TrimEnd()).UserData);
|
||||
}
|
||||
|
||||
return decryptedValue.ToString();
|
||||
}
|
||||
//this is from SqlMetal and just makes it a bit of fun to allow pluralisation
|
||||
public static string MakePluralName(this string name)
|
||||
@@ -157,22 +204,22 @@ namespace Umbraco.Core
|
||||
|
||||
public static string EnsureStartsWith(this string input, char value)
|
||||
{
|
||||
return input.StartsWith(value.ToString()) ? input : value + input;
|
||||
return input.StartsWith(value.ToString(CultureInfo.InvariantCulture)) ? input : value + input;
|
||||
}
|
||||
|
||||
public static string EnsureEndsWith(this string input, char value)
|
||||
{
|
||||
return input.EndsWith(value.ToString()) ? input : input + value;
|
||||
return input.EndsWith(value.ToString(CultureInfo.InvariantCulture)) ? input : input + value;
|
||||
}
|
||||
|
||||
public static bool IsLowerCase(this char ch)
|
||||
{
|
||||
return ch.ToString(CultureInfo.InvariantCulture) == ch.ToString(CultureInfo.InvariantCulture).ToLower();
|
||||
return ch.ToString(CultureInfo.InvariantCulture) == ch.ToString(CultureInfo.InvariantCulture).ToLowerInvariant();
|
||||
}
|
||||
|
||||
public static bool IsUpperCase(this char ch)
|
||||
{
|
||||
return ch.ToString(CultureInfo.InvariantCulture) == ch.ToString(CultureInfo.InvariantCulture).ToUpper();
|
||||
return ch.ToString(CultureInfo.InvariantCulture) == ch.ToString(CultureInfo.InvariantCulture).ToUpperInvariant();
|
||||
}
|
||||
|
||||
/// <summary>Is null or white space.</summary>
|
||||
@@ -294,7 +341,7 @@ namespace Umbraco.Core
|
||||
Enumerable.Range(97, 26));
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var c in value.Where(c => charReplacements.Values.Contains(c.ToString()) || validCodeRanges.Contains(c)))
|
||||
foreach (var c in value.Where(c => charReplacements.Values.Contains(c.ToString(CultureInfo.InvariantCulture)) || validCodeRanges.Contains(c)))
|
||||
{
|
||||
sb.Append(c);
|
||||
}
|
||||
@@ -366,7 +413,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
if (splittedPhraseChars.Length > 0)
|
||||
{
|
||||
splittedPhraseChars[0] = ((new String(splittedPhraseChars[0], 1)).ToUpper().ToCharArray())[0];
|
||||
splittedPhraseChars[0] = ((new String(splittedPhraseChars[0], 1)).ToUpperInvariant().ToCharArray())[0];
|
||||
}
|
||||
sb.Append(new String(splittedPhraseChars));
|
||||
}
|
||||
@@ -381,15 +428,15 @@ namespace Umbraco.Core
|
||||
var match = pattern.Match(result);
|
||||
if (match.Success)
|
||||
{
|
||||
result = match.Groups[1].Value.ToLower() + match.Groups[2].Value;
|
||||
result = match.Groups[1].Value.ToLowerInvariant() + match.Groups[2].Value;
|
||||
|
||||
return result.Substring(0, 1).ToLower() + result.Substring(1);
|
||||
return result.Substring(0, 1).ToLowerInvariant() + result.Substring(1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result.ToLower();
|
||||
return result.ToLowerInvariant();
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -709,7 +756,6 @@ namespace Umbraco.Core
|
||||
return currentFolder;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Truncates the specified text string.
|
||||
/// </summary>
|
||||
@@ -791,17 +837,17 @@ namespace Umbraco.Core
|
||||
for (int i = 0; i < aliasLength; i++)
|
||||
{
|
||||
string currentChar = alias.Substring(i, 1);
|
||||
if (validAliasCharacters.Contains(currentChar.ToLower()))
|
||||
if (validAliasCharacters.Contains(currentChar.ToLowerInvariant()))
|
||||
{
|
||||
// check for camel (if previous character is a space, we'll upper case the current one
|
||||
if (safeString.Length == 0 && invalidFirstCharacters.Contains(currentChar.ToLower()))
|
||||
if (safeString.Length == 0 && invalidFirstCharacters.Contains(currentChar.ToLowerInvariant()))
|
||||
{
|
||||
currentChar = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i < aliasLength - 1 && i > 0 && alias.Substring(i - 1, 1) == " ")
|
||||
currentChar = currentChar.ToUpper();
|
||||
currentChar = currentChar.ToUpperInvariant();
|
||||
|
||||
safeString.Append(currentChar);
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
<Compile Include="Events\SendToPublishEventArgs.cs" />
|
||||
<Compile Include="IApplicationEventHandler.cs" />
|
||||
<Compile Include="MacroPropertyTypeResolver.cs" />
|
||||
<Compile Include="Media\MediaSubfolderCounter.cs" />
|
||||
<Compile Include="Models\ContentBase.cs" />
|
||||
<Compile Include="Models\ContentExtensions.cs" />
|
||||
<Compile Include="Enum.cs" />
|
||||
@@ -347,6 +348,7 @@
|
||||
<Compile Include="Persistence\Migrations\Syntax\Delete\Index\IDeleteIndexOnColumnSyntax.cs" />
|
||||
<Compile Include="Persistence\Migrations\Syntax\Delete\Table\DeleteTableBuilder.cs" />
|
||||
<Compile Include="Persistence\Migrations\Syntax\Execute\ExecuteBuilder.cs" />
|
||||
<Compile Include="Persistence\Migrations\Syntax\Execute\Expressions\ExecuteCodeStatementExpression.cs" />
|
||||
<Compile Include="Persistence\Migrations\Syntax\Execute\Expressions\ExecuteSqlStatementExpression.cs" />
|
||||
<Compile Include="Persistence\Migrations\Syntax\Execute\IExecuteBuilder.cs" />
|
||||
<Compile Include="Persistence\Migrations\Syntax\ExpressionBuilder.cs" />
|
||||
@@ -381,6 +383,7 @@
|
||||
<Compile Include="Persistence\Migrations\Syntax\Update\UpdateBuilder.cs" />
|
||||
<Compile Include="Persistence\Migrations\Syntax\Update\UpdateDataBuilder.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionFourNineZero\RemoveUmbracoAppConstraints.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSixZeroOne\UpdatePropertyTypesAndGroups.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\DeleteAppTables.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\EnsureAppsTreesUpdated.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSix\MoveMasterContentTypeData.cs" />
|
||||
@@ -440,6 +443,7 @@
|
||||
<Compile Include="Persistence\Repositories\UserTypeRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\VersionableRepositoryBase.cs" />
|
||||
<Compile Include="Persistence\RepositoryFactory.cs" />
|
||||
<Compile Include="ObjectResolution\LazyManyObjectsResolverbase.cs" />
|
||||
<Compile Include="Persistence\RepositoryResolver.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\ColumnInfo.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\DbTypes.cs" />
|
||||
@@ -682,6 +686,11 @@
|
||||
<Compile Include="WriteLock.cs" />
|
||||
<Compile Include="XmlExtensions.cs" />
|
||||
<Compile Include="XmlHelper.cs" />
|
||||
<Compile Include="Xml\DynamicContext.cs" />
|
||||
<Compile Include="Xml\XmlNamespaces.cs" />
|
||||
<Compile Include="Xml\XmlNodeListFactory.cs" />
|
||||
<Compile Include="Xml\XmlNodeExtensions.cs" />
|
||||
<Compile Include="Xml\XPathVariable.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Xml.Xsl;
|
||||
using System.Xml.XPath;
|
||||
|
||||
// source: mvpxml.codeplex.com
|
||||
|
||||
namespace Umbraco.Core.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the evaluation context for fast execution and custom
|
||||
/// variables resolution.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is responsible for resolving variables during dynamic expression execution.
|
||||
/// <para>Discussed in http://weblogs.asp.net/cazzu/archive/2003/10/07/30888.aspx</para>
|
||||
/// <para>Author: Daniel Cazzulino, <a href="http://clariusconsulting.net/kzu">blog</a></para>
|
||||
/// </remarks>
|
||||
public class DynamicContext : XsltContext
|
||||
{
|
||||
#region Private vars
|
||||
|
||||
readonly IDictionary<string, IXsltContextVariable> _variables =
|
||||
new Dictionary<string, IXsltContextVariable>();
|
||||
|
||||
#endregion Private
|
||||
|
||||
#region Constructors & Initialization
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicContext"/> class.
|
||||
/// </summary>
|
||||
public DynamicContext()
|
||||
: base(new NameTable())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicContext"/>
|
||||
/// class with the specified <see cref="NameTable"/>.
|
||||
/// </summary>
|
||||
/// <param name="table">The NameTable to use.</param>
|
||||
public DynamicContext(NameTable table)
|
||||
: base(table)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="context">A previously filled context with the namespaces to use.</param>
|
||||
public DynamicContext(XmlNamespaceManager context)
|
||||
: this(context, new NameTable())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="context">A previously filled context with the namespaces to use.</param>
|
||||
/// <param name="table">The NameTable to use.</param>
|
||||
public DynamicContext(XmlNamespaceManager context, NameTable table)
|
||||
: base(table)
|
||||
{
|
||||
object xml = table.Add(XmlNamespaces.Xml);
|
||||
object xmlns = table.Add(XmlNamespaces.XmlNs);
|
||||
|
||||
if (context == null) return;
|
||||
|
||||
foreach (string prefix in context)
|
||||
{
|
||||
var uri = context.LookupNamespace(prefix);
|
||||
// Use fast object reference comparison to omit forbidden namespace declarations.
|
||||
if (Equals(uri, xml) || Equals(uri, xmlns))
|
||||
continue;
|
||||
if (uri == null)
|
||||
continue;
|
||||
base.AddNamespace(prefix, uri);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Constructors & Initialization
|
||||
|
||||
#region Common Overrides
|
||||
|
||||
/// <summary>
|
||||
/// Implementation equal to <see cref="XsltContext"/>.
|
||||
/// </summary>
|
||||
public override int CompareDocument(string baseUri, string nextbaseUri)
|
||||
{
|
||||
return String.Compare(baseUri, nextbaseUri, false, System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as <see cref="XmlNamespaceManager"/>.
|
||||
/// </summary>
|
||||
public override string LookupNamespace(string prefix)
|
||||
{
|
||||
var key = NameTable.Get(prefix);
|
||||
return key == null ? null : base.LookupNamespace(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as <see cref="XmlNamespaceManager"/>.
|
||||
/// </summary>
|
||||
public override string LookupPrefix(string uri)
|
||||
{
|
||||
var key = NameTable.Get(uri);
|
||||
return key == null ? null : base.LookupPrefix(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as <see cref="XsltContext"/>.
|
||||
/// </summary>
|
||||
public override bool PreserveWhitespace(XPathNavigator node)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as <see cref="XsltContext"/>.
|
||||
/// </summary>
|
||||
public override bool Whitespace
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
#endregion Common Overrides
|
||||
|
||||
#region Public Members
|
||||
|
||||
/// <summary>
|
||||
/// Shortcut method that compiles an expression using an empty navigator.
|
||||
/// </summary>
|
||||
/// <param name="xpath">The expression to compile</param>
|
||||
/// <returns>A compiled <see cref="XPathExpression"/>.</returns>
|
||||
public static XPathExpression Compile(string xpath)
|
||||
{
|
||||
return new XmlDocument().CreateNavigator().Compile(xpath);
|
||||
}
|
||||
|
||||
#endregion Public Members
|
||||
|
||||
#region Variable Handling Code
|
||||
|
||||
/// <summary>
|
||||
/// Adds the variable to the dynamic evaluation context.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the variable to add to the context.</param>
|
||||
/// <param name="value">The value of the variable to add to the context.</param>
|
||||
/// <remarks>
|
||||
/// Value type conversion for XPath evaluation is as follows:
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>CLR Type</term>
|
||||
/// <description>XPath type</description>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>System.String</term>
|
||||
/// <description>XPathResultType.String</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>System.Double (or types that can be converted to)</term>
|
||||
/// <description>XPathResultType.Number</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>System.Boolean</term>
|
||||
/// <description>XPathResultType.Boolean</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>System.Xml.XPath.XPathNavigator</term>
|
||||
/// <description>XPathResultType.Navigator</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>System.Xml.XPath.XPathNodeIterator</term>
|
||||
/// <description>XPathResultType.NodeSet</description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Others</term>
|
||||
/// <description>XPathResultType.Any</description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// <note type="note">See the topic "Compile, Select, Evaluate, and Matches with
|
||||
/// XPath and XPathExpressions" in MSDN documentation for additional information.</note>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentNullException">The <paramref name="value"/> is null.</exception>
|
||||
public void AddVariable(string name, object value)
|
||||
{
|
||||
if (value == null) throw new ArgumentNullException("value");
|
||||
_variables[name] = new DynamicVariable(name, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="XsltContext"/>. Not used in our implementation.
|
||||
/// </summary>
|
||||
public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] argTypes)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the dynamic variables added to the context. See <see cref="XsltContext"/>.
|
||||
/// </summary>
|
||||
public override IXsltContextVariable ResolveVariable(string prefix, string name)
|
||||
{
|
||||
IXsltContextVariable var;
|
||||
_variables.TryGetValue(name, out var);
|
||||
return var;
|
||||
}
|
||||
|
||||
#endregion Variable Handling Code
|
||||
|
||||
#region Internal DynamicVariable class
|
||||
|
||||
/// <summary>
|
||||
/// Represents a variable during dynamic expression execution.
|
||||
/// </summary>
|
||||
internal class DynamicVariable : IXsltContextVariable
|
||||
{
|
||||
readonly string _name;
|
||||
readonly object _value;
|
||||
|
||||
#region Public Members
|
||||
|
||||
public string Name { get { return _name; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the variable.</param>
|
||||
/// <param name="value">The value of the variable.</param>
|
||||
public DynamicVariable(string name, object value)
|
||||
{
|
||||
|
||||
_name = name;
|
||||
_value = value;
|
||||
|
||||
if (value is String)
|
||||
_type = XPathResultType.String;
|
||||
else if (value is bool)
|
||||
_type = XPathResultType.Boolean;
|
||||
else if (value is XPathNavigator)
|
||||
_type = XPathResultType.Navigator;
|
||||
else if (value is XPathNodeIterator)
|
||||
_type = XPathResultType.NodeSet;
|
||||
else
|
||||
{
|
||||
// Try to convert to double (native XPath numeric type)
|
||||
if (value is double)
|
||||
{
|
||||
_type = XPathResultType.Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value is IConvertible)
|
||||
{
|
||||
try
|
||||
{
|
||||
_value = Convert.ToDouble(value);
|
||||
// We suceeded, so it's a number.
|
||||
_type = XPathResultType.Number;
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
_type = XPathResultType.Any;
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
_type = XPathResultType.Any;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_type = XPathResultType.Any;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Members
|
||||
|
||||
#region IXsltContextVariable Implementation
|
||||
|
||||
XPathResultType IXsltContextVariable.VariableType
|
||||
{
|
||||
get { return _type; }
|
||||
}
|
||||
|
||||
readonly XPathResultType _type;
|
||||
|
||||
object IXsltContextVariable.Evaluate(XsltContext context)
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
bool IXsltContextVariable.IsLocal
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
bool IXsltContextVariable.IsParam
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
#endregion IXsltContextVariable Implementation
|
||||
}
|
||||
|
||||
#endregion Internal DynamicVariable class
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// source: mvpxml.codeplex.com
|
||||
|
||||
namespace Umbraco.Core.Xml
|
||||
{
|
||||
internal class XPathVariable
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Value { get; set; }
|
||||
|
||||
public XPathVariable(string name, string value)
|
||||
{
|
||||
Name = name;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// source: mvpxml.codeplex.com
|
||||
|
||||
namespace Umbraco.Core.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides public constants for wellknown XML namespaces.
|
||||
/// </summary>
|
||||
/// <remarks>Author: Daniel Cazzulino, <a href="http://clariusconsulting.net/kzu">blog</a></remarks>
|
||||
public static class XmlNamespaces
|
||||
{
|
||||
/// <summary>
|
||||
/// The public XML 1.0 namespace.
|
||||
/// </summary>
|
||||
/// <remarks>See http://www.w3.org/TR/2004/REC-xml-20040204/</remarks>
|
||||
public const string Xml = "http://www.w3.org/XML/1998/namespace";
|
||||
|
||||
/// <summary>
|
||||
/// Public Xml Namespaces specification namespace.
|
||||
/// </summary>
|
||||
/// <remarks>See http://www.w3.org/TR/REC-xml-names/</remarks>
|
||||
public const string XmlNs = "http://www.w3.org/2000/xmlns/";
|
||||
|
||||
/// <summary>
|
||||
/// Public Xml Namespaces prefix.
|
||||
/// </summary>
|
||||
/// <remarks>See http://www.w3.org/TR/REC-xml-names/</remarks>
|
||||
public const string XmlNsPrefix = "xmlns";
|
||||
|
||||
/// <summary>
|
||||
/// XML Schema instance namespace.
|
||||
/// </summary>
|
||||
/// <remarks>See http://www.w3.org/TR/xmlschema-1/</remarks>
|
||||
public const string Xsi = "http://www.w3.org/2001/XMLSchema-instance";
|
||||
|
||||
/// <summary>
|
||||
/// XML 1.0 Schema namespace.
|
||||
/// </summary>
|
||||
/// <remarks>See http://www.w3.org/TR/xmlschema-1/</remarks>
|
||||
public const string Xsd = "http://www.w3.org/2001/XMLSchema";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.XPath;
|
||||
|
||||
// source: mvpxml.codeplex.com
|
||||
|
||||
namespace Umbraco.Core.Xml
|
||||
{
|
||||
internal static class XmlNodeExtensions
|
||||
{
|
||||
static XPathNodeIterator Select(string expression, XPathNavigator source, params XPathVariable[] variables)
|
||||
{
|
||||
var expr = source.Compile(expression);
|
||||
var context = new DynamicContext();
|
||||
foreach (var variable in variables)
|
||||
context.AddVariable(variable.Name, variable.Value);
|
||||
expr.SetContext(context);
|
||||
return source.Select(expr);
|
||||
}
|
||||
|
||||
public static XmlNodeList SelectNodes(this XmlNode source, string expression, IEnumerable<XPathVariable> variables)
|
||||
{
|
||||
var av = variables == null ? null : variables.ToArray();
|
||||
return SelectNodes(source, expression, av);
|
||||
}
|
||||
|
||||
public static XmlNodeList SelectNodes(this XmlNode source, string expression, params XPathVariable[] variables)
|
||||
{
|
||||
if (variables == null || variables.Length == 0 || variables[0] == null)
|
||||
return source.SelectNodes(expression);
|
||||
|
||||
var iterator = Select(expression, source.CreateNavigator(), variables);
|
||||
return XmlNodeListFactory.CreateNodeList(iterator);
|
||||
}
|
||||
|
||||
public static XmlNode SelectSingleNode(this XmlNode source, string expression, IEnumerable<XPathVariable> variables)
|
||||
{
|
||||
var av = variables == null ? null : variables.ToArray();
|
||||
return SelectSingleNode(source, expression, av);
|
||||
}
|
||||
|
||||
public static XmlNode SelectSingleNode(this XmlNode source, string expression, params XPathVariable[] variables)
|
||||
{
|
||||
if (variables == null || variables.Length == 0 || variables[0] == null)
|
||||
return source.SelectSingleNode(expression);
|
||||
|
||||
return SelectNodes(source, expression, variables).Cast<XmlNode>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Xml.XPath;
|
||||
|
||||
// source: mvpxml.codeplex.com
|
||||
|
||||
namespace Umbraco.Core.Xml
|
||||
{
|
||||
class XmlNodeListFactory
|
||||
{
|
||||
private XmlNodeListFactory() { }
|
||||
|
||||
#region Public members
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of a <see cref="XmlNodeList"/> that allows
|
||||
/// enumerating <see cref="XmlNode"/> elements in the iterator.
|
||||
/// </summary>
|
||||
/// <param name="iterator">The result of a previous node selection
|
||||
/// through an <see cref="XPathNavigator"/> query.</param>
|
||||
/// <returns>An initialized list ready to be enumerated.</returns>
|
||||
/// <remarks>The underlying XML store used to issue the query must be
|
||||
/// an object inheriting <see cref="XmlNode"/>, such as
|
||||
/// <see cref="XmlDocument"/>.</remarks>
|
||||
public static XmlNodeList CreateNodeList(XPathNodeIterator iterator)
|
||||
{
|
||||
return new XmlNodeListIterator(iterator);
|
||||
}
|
||||
|
||||
#endregion Public members
|
||||
|
||||
#region XmlNodeListIterator
|
||||
|
||||
private class XmlNodeListIterator : XmlNodeList
|
||||
{
|
||||
readonly XPathNodeIterator _iterator;
|
||||
readonly IList<XmlNode> _nodes = new List<XmlNode>();
|
||||
|
||||
public XmlNodeListIterator(XPathNodeIterator iterator)
|
||||
{
|
||||
_iterator = iterator.Clone();
|
||||
}
|
||||
|
||||
public override System.Collections.IEnumerator GetEnumerator()
|
||||
{
|
||||
return new XmlNodeListEnumerator(this);
|
||||
}
|
||||
|
||||
public override XmlNode Item(int index)
|
||||
{
|
||||
|
||||
if (index >= _nodes.Count)
|
||||
ReadTo(index);
|
||||
// Compatible behavior with .NET
|
||||
if (index >= _nodes.Count || index < 0)
|
||||
return null;
|
||||
return _nodes[index];
|
||||
}
|
||||
|
||||
public override int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_done) ReadToEnd();
|
||||
return _nodes.Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads the entire iterator.
|
||||
/// </summary>
|
||||
private void ReadToEnd()
|
||||
{
|
||||
while (_iterator.MoveNext())
|
||||
{
|
||||
var node = _iterator.Current as IHasXmlNode;
|
||||
// Check IHasXmlNode interface.
|
||||
if (node == null)
|
||||
throw new ArgumentException("IHasXmlNode is missing.");
|
||||
_nodes.Add(node.GetNode());
|
||||
}
|
||||
_done = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads up to the specified index, or until the
|
||||
/// iterator is consumed.
|
||||
/// </summary>
|
||||
private void ReadTo(int to)
|
||||
{
|
||||
while (_nodes.Count <= to)
|
||||
{
|
||||
if (_iterator.MoveNext())
|
||||
{
|
||||
var node = _iterator.Current as IHasXmlNode;
|
||||
// Check IHasXmlNode interface.
|
||||
if (node == null)
|
||||
throw new ArgumentException("IHasXmlNode is missing.");
|
||||
_nodes.Add(node.GetNode());
|
||||
}
|
||||
else
|
||||
{
|
||||
_done = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flags that the iterator has been consumed.
|
||||
/// </summary>
|
||||
private bool Done
|
||||
{
|
||||
get { return _done; }
|
||||
}
|
||||
|
||||
bool _done;
|
||||
|
||||
/// <summary>
|
||||
/// Current count of nodes in the iterator (read so far).
|
||||
/// </summary>
|
||||
private int CurrentPosition
|
||||
{
|
||||
get { return _nodes.Count; }
|
||||
}
|
||||
|
||||
#region XmlNodeListEnumerator
|
||||
|
||||
private class XmlNodeListEnumerator : System.Collections.IEnumerator
|
||||
{
|
||||
readonly XmlNodeListIterator _iterator;
|
||||
int _position = -1;
|
||||
|
||||
public XmlNodeListEnumerator(XmlNodeListIterator iterator)
|
||||
{
|
||||
_iterator = iterator;
|
||||
}
|
||||
|
||||
#region IEnumerator Members
|
||||
|
||||
void System.Collections.IEnumerator.Reset()
|
||||
{
|
||||
_position = -1;
|
||||
}
|
||||
|
||||
|
||||
bool System.Collections.IEnumerator.MoveNext()
|
||||
{
|
||||
_position++;
|
||||
_iterator.ReadTo(_position);
|
||||
|
||||
// If we reached the end and our index is still
|
||||
// bigger, there're no more items.
|
||||
if (_iterator.Done && _position >= _iterator.CurrentPosition)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
object System.Collections.IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return _iterator[_position];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#endregion XmlNodeListEnumerator
|
||||
}
|
||||
|
||||
#endregion XmlNodeListIterator
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
@@ -14,6 +15,59 @@ namespace Umbraco.Core
|
||||
public class XmlHelper
|
||||
{
|
||||
|
||||
public static string StripDashesInElementOrAttributeNames(string xml)
|
||||
{
|
||||
using (var outputms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter outputtw = new StreamWriter(outputms))
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var tw = new StreamWriter(ms))
|
||||
{
|
||||
tw.Write(xml);
|
||||
tw.Flush();
|
||||
ms.Position = 0;
|
||||
using (var tr = new StreamReader(ms))
|
||||
{
|
||||
bool IsInsideElement = false, IsInsideQuotes = false;
|
||||
int ic = 0;
|
||||
while ((ic = tr.Read()) != -1)
|
||||
{
|
||||
if (ic == (int)'<' && !IsInsideQuotes)
|
||||
{
|
||||
if (tr.Peek() != (int)'!')
|
||||
{
|
||||
IsInsideElement = true;
|
||||
}
|
||||
}
|
||||
if (ic == (int)'>' && !IsInsideQuotes)
|
||||
{
|
||||
IsInsideElement = false;
|
||||
}
|
||||
if (ic == (int)'"')
|
||||
{
|
||||
IsInsideQuotes = !IsInsideQuotes;
|
||||
}
|
||||
if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes)
|
||||
{
|
||||
outputtw.Write((char)ic);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
outputtw.Flush();
|
||||
outputms.Position = 0;
|
||||
using (TextReader outputtr = new StreamReader(outputms))
|
||||
{
|
||||
return outputtr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imports a XML node from text.
|
||||
/// </summary>
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Web;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Tests.BootManagers
|
||||
{
|
||||
@@ -53,12 +54,14 @@ namespace Umbraco.Tests.BootManagers
|
||||
protected override void InitializeApplicationEventsResolver()
|
||||
{
|
||||
//create an empty resolver so we can add our own custom ones (don't type find)
|
||||
ApplicationEventsResolver.Current = new ApplicationEventsResolver(
|
||||
Enumerable.Empty<Type>())
|
||||
ApplicationEventsResolver.Current = new ApplicationEventsResolver(new Type[]
|
||||
{
|
||||
typeof(LegacyStartupHandler),
|
||||
typeof(TestApplicationEventHandler)
|
||||
})
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
ApplicationEventsResolver.Current.AddType<TestApplicationEventHandler>();
|
||||
}
|
||||
|
||||
protected override void InitializeResolvers()
|
||||
@@ -67,6 +70,19 @@ namespace Umbraco.Tests.BootManagers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test legacy startup handler
|
||||
/// </summary>
|
||||
public class LegacyStartupHandler : IApplicationStartupHandler
|
||||
{
|
||||
public static bool Initialized = false;
|
||||
|
||||
public LegacyStartupHandler()
|
||||
{
|
||||
Initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// test event handler
|
||||
/// </summary>
|
||||
@@ -102,5 +118,29 @@ namespace Umbraco.Tests.BootManagers
|
||||
Assert.IsTrue(TestApplicationEventHandler.Started);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensure_Legacy_Startup_Handlers_Not_Started_Until_Complete()
|
||||
{
|
||||
EventHandler starting = (sender, args) =>
|
||||
{
|
||||
Assert.IsTrue(TestApplicationEventHandler.Initialized);
|
||||
Assert.IsTrue(TestApplicationEventHandler.Starting);
|
||||
Assert.IsFalse(LegacyStartupHandler.Initialized);
|
||||
};
|
||||
EventHandler started = (sender, args) =>
|
||||
{
|
||||
Assert.IsTrue(TestApplicationEventHandler.Started);
|
||||
Assert.IsTrue(LegacyStartupHandler.Initialized);
|
||||
};
|
||||
TestApp.ApplicationStarting += starting;
|
||||
TestApp.ApplicationStarted += started;
|
||||
|
||||
_testApp.StartApplication(_testApp, new EventArgs());
|
||||
|
||||
TestApp.ApplicationStarting -= starting;
|
||||
TestApp.ApplicationStarting -= started;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Tests
|
||||
};
|
||||
|
||||
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
|
||||
PluginManager.Current.ResolveCacheRefreshers());
|
||||
() => PluginManager.Current.ResolveCacheRefreshers());
|
||||
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Umbraco.Tests.CodeFirst
|
||||
};
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
base.Initialize();
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Configuration;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Configuration.InfrastructureSettings;
|
||||
|
||||
namespace Umbraco.Tests.Configurations
|
||||
{
|
||||
[TestFixture]
|
||||
public class RepositorySettingsTests
|
||||
{
|
||||
[Test]
|
||||
public void Can_Get_Repository_From_Config()
|
||||
{
|
||||
Infrastructure infrastructure = Infrastructure.Instance;
|
||||
Repositories repositories = infrastructure.Repositories;
|
||||
Repository repository = repositories.Repository["IContentRepository"];
|
||||
|
||||
Assert.That(repository, Is.Not.Null);
|
||||
Assert.AreEqual(repository.InterfaceShortTypeName, "IContentRepository");
|
||||
Assert.AreEqual(repository.RepositoryFullTypeName, "Umbraco.Core.Persistence.Repositories.ContentRepository, Umbraco.Core");
|
||||
Assert.AreEqual(repository.CacheProviderFullTypeName, "Umbraco.Core.Persistence.Caching.RuntimeCacheProvider, Umbraco.Core");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_PublishingStrategy_From_Config()
|
||||
{
|
||||
Infrastructure infrastructure = Infrastructure.Instance;
|
||||
PublishingProvider strategy = infrastructure.PublishingStrategy;
|
||||
|
||||
Assert.That(strategy.Type, Is.EqualTo("Umbraco.Web.Publishing.PublishingStrategy, Umbraco.Web"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System.Linq;
|
||||
using System.Xml;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Routing;
|
||||
@@ -54,6 +55,8 @@ namespace Umbraco.Tests.ContentStores
|
||||
</Home>
|
||||
<Home id=""1175"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub 2"" urlName=""sub-2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1175"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
<Home id=""1177"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""2"" createDate=""2012-07-20T18:08:01"" updateDate=""2012-07-20T18:49:32"" nodeName=""Sub'Apostrophe"" urlName=""sub'apostrophe"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1177"" isDoc=""""><content><![CDATA[]]></content>
|
||||
</Home>
|
||||
</Home>
|
||||
<Home id=""1172"" parentID=""-1"" level=""1"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""1045"" sortOrder=""3"" createDate=""2012-07-16T15:26:59"" updateDate=""2012-07-18T14:23:35"" nodeName=""Test"" urlName=""test"" writerName=""admin"" creatorName=""admin"" path=""-1,1172"" isDoc="""" />
|
||||
</root>";
|
||||
@@ -63,7 +66,7 @@ namespace Umbraco.Tests.ContentStores
|
||||
public void SetUp()
|
||||
{
|
||||
TestHelper.SetupLog4NetForTests();
|
||||
Umbraco.Core.Configuration.UmbracoSettings.UseLegacyXmlSchema = false;
|
||||
|
||||
_httpContextFactory = new FakeHttpContextFactory("~/Home");
|
||||
//ensure the StateHelper is using our custom context
|
||||
StateHelper.HttpContext = _httpContextFactory.HttpContext;
|
||||
@@ -103,9 +106,7 @@ namespace Umbraco.Tests.ContentStores
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
//TODO: need to reset everything!
|
||||
|
||||
Umbraco.Core.Configuration.UmbracoSettings.UseLegacyXmlSchema = false;
|
||||
UmbracoSettings.ResetSetters();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -155,6 +156,7 @@ namespace Umbraco.Tests.ContentStores
|
||||
[TestCase("/home/sub1", 1173)]
|
||||
[TestCase("/Home/sub1", 1173)]
|
||||
[TestCase("/home/Sub1", 1173)] //test different cases
|
||||
[TestCase("/home/Sub'Apostrophe", 1177)]
|
||||
public void Get_Node_By_Route(string route, int nodeId)
|
||||
{
|
||||
var result = _publishedContentStore.GetDocumentByRoute(_umbracoContext, route, false);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Examine;
|
||||
@@ -14,19 +15,26 @@ using umbraco.BusinessLogic;
|
||||
namespace Umbraco.Tests.ContentStores
|
||||
{
|
||||
[TestFixture]
|
||||
public class PublishMediaStoreTests : BaseWebTest
|
||||
public class PublishMediaStoreTests : PublishedContentTestBase
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
//we're going to use the same initialization as the PublishedMediaTests
|
||||
PublishedMediaTests.DoInitialization(GetUmbracoContext("/test", 1234));
|
||||
|
||||
var currDir = new DirectoryInfo(TestHelper.CurrentAssemblyDirectory);
|
||||
System.IO.File.Copy(
|
||||
currDir.Parent.Parent.Parent.GetDirectories("Umbraco.Web.UI")
|
||||
.First()
|
||||
.GetDirectories("config").First()
|
||||
.GetFiles("umbracoSettings.Release.config").First().FullName,
|
||||
Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config"),
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
PublishedMediaTests.DoTearDown();
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Umbraco.Tests
|
||||
};
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
@@ -16,18 +16,16 @@ namespace Umbraco.Tests
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
{
|
||||
base.Initialize();
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedPaths", "~/umbraco,~/install/");
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedUrls", "~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd");
|
||||
SettingsForTests.UmbracoPath = "~/umbraco";
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
//reset the app config
|
||||
base.TearDown();
|
||||
//reset the app config
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedPaths", "");
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedUrls", "");
|
||||
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
@@ -78,8 +76,8 @@ namespace Umbraco.Tests
|
||||
public void Is_Reserved_By_Route(string url, bool shouldMatch)
|
||||
{
|
||||
//reset the app config, we only want to test routes not the hard coded paths
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedPaths", "");
|
||||
ConfigurationManager.AppSettings.Set("umbracoReservedUrls", "");
|
||||
Umbraco.Core.Configuration.GlobalSettings.ReservedPaths = "";
|
||||
Umbraco.Core.Configuration.GlobalSettings.ReservedUrls = "";
|
||||
|
||||
var routes = new RouteCollection();
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ using Umbraco.Tests.BusinessLogic;
|
||||
|
||||
namespace Umbraco.Tests.IO
|
||||
{
|
||||
[TestFixture]
|
||||
[TestFixture, RequiresSTA]
|
||||
internal abstract class AbstractFileSystemTests
|
||||
{
|
||||
protected IFileSystem _fileSystem;
|
||||
@@ -110,7 +110,6 @@ namespace Umbraco.Tests.IO
|
||||
_fileSystem.DeleteDirectory("test", true);
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
[Test]
|
||||
public void Can_Get_File_Dates()
|
||||
{
|
||||
|
||||
@@ -9,14 +9,32 @@ using Umbraco.Tests.BusinessLogic;
|
||||
|
||||
namespace Umbraco.Tests.IO
|
||||
{
|
||||
[TestFixture]
|
||||
[TestFixture, RequiresSTA]
|
||||
internal class PhysicalFileSystemTests : AbstractFileSystemTests
|
||||
{
|
||||
public PhysicalFileSystemTests()
|
||||
: base(new PhysicalFileSystem(AppDomain.CurrentDomain.BaseDirectory,
|
||||
: base(new PhysicalFileSystem(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests"),
|
||||
"/Media/"))
|
||||
{ }
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests");
|
||||
var files = Directory.GetFiles(path);
|
||||
foreach (var f in files)
|
||||
{
|
||||
File.Delete(f);
|
||||
}
|
||||
Directory.Delete(path, true);
|
||||
}
|
||||
|
||||
protected override string ConstructUrl(string path)
|
||||
{
|
||||
return "/Media/" + path;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
@@ -26,6 +27,17 @@ namespace Umbraco.Tests
|
||||
|
||||
var routingContext = GetRoutingContext("/test", 1234);
|
||||
UmbracoContext.Current = routingContext.UmbracoContext;
|
||||
|
||||
var currDir = new DirectoryInfo(TestHelper.CurrentAssemblyDirectory);
|
||||
File.Copy(
|
||||
currDir.Parent.Parent.Parent.GetDirectories("Umbraco.Web.UI")
|
||||
.First()
|
||||
.GetDirectories("config").First()
|
||||
.GetFiles("umbracoSettings.Release.config").First().FullName,
|
||||
Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config"),
|
||||
true);
|
||||
|
||||
Core.Configuration.UmbracoSettings.SettingsFilePath = Core.IO.IOHelper.MapPath(Core.IO.SystemDirectories.Config + Path.DirectorySeparatorChar, false);
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
This file is just here to make sure the directory gets created.
|
||||
@@ -28,8 +28,6 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
Path = TestHelper.CurrentAssemblyDirectory;
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", Path);
|
||||
|
||||
UmbracoSettings.UseLegacyXmlSchema = false;
|
||||
|
||||
MigrationResolver.Current = new MigrationResolver(new List<Type>
|
||||
{
|
||||
|
||||
@@ -56,8 +56,6 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
Path = TestHelper.CurrentAssemblyDirectory;
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", Path);
|
||||
|
||||
UmbracoSettings.UseLegacyXmlSchema = false;
|
||||
|
||||
Resolution.Freeze();
|
||||
|
||||
//Delete database file before continueing
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Tests.Models
|
||||
};
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
base.Initialize();
|
||||
}
|
||||
@@ -35,10 +35,10 @@ namespace Umbraco.Tests.Models
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
//reset the app context
|
||||
DataTypesResolver.Reset();
|
||||
|
||||
base.TearDown();
|
||||
}
|
||||
[Test]
|
||||
public void Can_Generate_Xml_Representation_Of_Content()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Xml.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
@@ -16,6 +17,8 @@ namespace Umbraco.Tests.Models
|
||||
[SetUp]
|
||||
public override void Initialize()
|
||||
{
|
||||
Resolution.IsFrozen = false;
|
||||
|
||||
//this ensures its reset
|
||||
PluginManager.Current = new PluginManager();
|
||||
|
||||
@@ -26,8 +29,9 @@ namespace Umbraco.Tests.Models
|
||||
typeof(tinyMCE3dataType).Assembly
|
||||
};
|
||||
|
||||
DataTypesResolver.Reset();
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
base.Initialize();
|
||||
}
|
||||
@@ -35,10 +39,10 @@ namespace Umbraco.Tests.Models
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
//reset the app context
|
||||
DataTypesResolver.Reset();
|
||||
|
||||
base.TearDown();
|
||||
}
|
||||
[Test]
|
||||
public void Can_Generate_Xml_Representation_Of_Media()
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Tests.Persistence
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntaxProvider.Instance;
|
||||
|
||||
//Create the umbraco database
|
||||
_dbContext.Database.CreateDatabaseSchema();
|
||||
_dbContext.Database.CreateDatabaseSchema(false);
|
||||
|
||||
bool umbracoNodeTable = _dbContext.Database.TableExist("umbracoNode");
|
||||
bool umbracoUserTable = _dbContext.Database.TableExist("umbracoUser");
|
||||
@@ -88,5 +88,31 @@ namespace Umbraco.Tests.Persistence
|
||||
Assert.That(umbracoUserTable, Is.True);
|
||||
Assert.That(cmsTagsTable, Is.True);
|
||||
}
|
||||
|
||||
[TestCase("MyServer", "MyDatabase", "MyUser", "MyPassword")]
|
||||
[TestCase("MyServer", "MyDatabase", "MyUser@MyServer", "MyPassword")]
|
||||
[TestCase("tcp:MyServer", "MyDatabase", "MyUser", "MyPassword")]
|
||||
[TestCase("tcp:MyServer", "MyDatabase", "MyUser@MyServer", "MyPassword")]
|
||||
[TestCase("tcp:MyServer,1433", "MyDatabase", "MyUser", "MyPassword")]
|
||||
[TestCase("tcp:MyServer,1433", "MyDatabase", "MyUser@MyServer", "MyPassword")]
|
||||
[TestCase("tcp:MyServer.database.windows.net", "MyDatabase", "MyUser", "MyPassword")]
|
||||
[TestCase("tcp:MyServer.database.windows.net", "MyDatabase", "MyUser@MyServer", "MyPassword")]
|
||||
[TestCase("tcp:MyServer.database.windows.net,1433", "MyDatabase", "MyUser", "MyPassword")]
|
||||
[TestCase("tcp:MyServer.database.windows.net,1433", "MyDatabase", "MyUser@MyServer", "MyPassword")]
|
||||
public void Build_Azure_Connection_String_Regular(string server, string databaseName, string userName, string password)
|
||||
{
|
||||
var connectionString = _dbContext.BuildAzureConnectionString(server, databaseName, userName, password);
|
||||
Assert.AreEqual(connectionString, "Server=tcp:MyServer.database.windows.net,1433;Database=MyDatabase;User ID=MyUser@MyServer;Password=MyPassword");
|
||||
}
|
||||
|
||||
[TestCase("tcp:kzeej5z8ty.ssmsawacluster4.windowsazure.mscds.com,1433", "MyDatabase", "MyUser", "MyPassword")]
|
||||
[TestCase("tcp:kzeej5z8ty.ssmsawacluster4.windowsazure.mscds.com,1433", "MyDatabase", "MyUser@kzeej5z8ty", "MyPassword")]
|
||||
[TestCase("tcp:kzeej5z8ty.ssmsawacluster4.windowsazure.mscds.com", "MyDatabase", "MyUser", "MyPassword")]
|
||||
[TestCase("tcp:kzeej5z8ty.ssmsawacluster4.windowsazure.mscds.com", "MyDatabase", "MyUser@kzeej5z8ty", "MyPassword")]
|
||||
public void Build_Azure_Connection_String_CustomServer(string server, string databaseName, string userName, string password)
|
||||
{
|
||||
var connectionString = _dbContext.BuildAzureConnectionString(server, databaseName, userName, password);
|
||||
Assert.AreEqual(connectionString, "Server=tcp:kzeej5z8ty.ssmsawacluster4.windowsazure.mscds.com,1433;Database=MyDatabase;User ID=MyUser@kzeej5z8ty;Password=MyPassword");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
namespace Umbraco.Tests.Persistence
|
||||
{
|
||||
[TestFixture]
|
||||
public class DatabaseFactoryTests
|
||||
{
|
||||
[Test]
|
||||
public void Can_Verify_Single_Database_Instance()
|
||||
{
|
||||
var db1 = DatabaseFactory.Current.Database;
|
||||
var db2 = DatabaseFactory.Current.Database;
|
||||
|
||||
Assert.AreSame(db1, db2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,6 @@ namespace Umbraco.Tests.Persistence
|
||||
string path = TestHelper.CurrentAssemblyDirectory;
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", path);
|
||||
|
||||
UmbracoSettings.UseLegacyXmlSchema = false;
|
||||
|
||||
RepositoryResolver.Current = new RepositoryResolver(
|
||||
new RepositoryFactory());
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
};
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
base.Initialize();
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
};
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
base.Initialize();
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
};
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
base.Initialize();
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@ namespace Umbraco.Tests.Persistence
|
||||
var engine = new SqlCeEngine("Datasource=|DataDirectory|test.sdf");
|
||||
engine.CreateDatabase();
|
||||
|
||||
UmbracoSettings.UseLegacyXmlSchema = false;
|
||||
|
||||
RepositoryResolver.Current = new RepositoryResolver(
|
||||
new RepositoryFactory());
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ namespace Umbraco.Tests.Persistence
|
||||
string path = TestHelper.CurrentAssemblyDirectory;
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", path);
|
||||
|
||||
UmbracoSettings.UseLegacyXmlSchema = false;
|
||||
|
||||
RepositoryResolver.Current = new RepositoryResolver(
|
||||
new RepositoryFactory());
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,68 +12,89 @@ using System.Linq;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
[TestFixture]
|
||||
public class DynamicNodeTests : DynamicDocumentTestsBase<DynamicNode, DynamicNodeList>
|
||||
{
|
||||
protected override bool RequiresDbSetup
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
[TestFixture]
|
||||
public class DynamicNodeTests : DynamicDocumentTestsBase<DynamicNode, DynamicNodeList>
|
||||
{
|
||||
protected override bool RequiresDbSetup
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
//copy the umbraco settings file over
|
||||
var currDir = new DirectoryInfo(TestHelper.CurrentAssemblyDirectory);
|
||||
File.Copy(
|
||||
currDir.Parent.Parent.Parent.GetDirectories("Umbraco.Web.UI")
|
||||
.First()
|
||||
.GetDirectories("config").First()
|
||||
.GetFiles("umbracoSettings.Release.config").First().FullName,
|
||||
Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config"),
|
||||
true);
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
//copy the umbraco settings file over
|
||||
var currDir = new DirectoryInfo(TestHelper.CurrentAssemblyDirectory);
|
||||
File.Copy(
|
||||
currDir.Parent.Parent.Parent.GetDirectories("Umbraco.Web.UI")
|
||||
.First()
|
||||
.GetDirectories("config").First()
|
||||
.GetFiles("umbracoSettings.Release.config").First().FullName,
|
||||
Path.Combine(currDir.Parent.Parent.FullName, "config", "umbracoSettings.config"),
|
||||
true);
|
||||
|
||||
UmbracoSettings.SettingsFilePath = IOHelper.MapPath(SystemDirectories.Config + Path.DirectorySeparatorChar, false);
|
||||
|
||||
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
|
||||
PluginManager.Current.AssembliesToScan = new[]
|
||||
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
|
||||
PluginManager.Current.AssembliesToScan = new[]
|
||||
{
|
||||
typeof(DynamicNode).Assembly
|
||||
};
|
||||
|
||||
//need to specify a custom callback for unit tests
|
||||
DynamicNode.GetDataTypeCallback = (docTypeAlias, propertyAlias) =>
|
||||
{
|
||||
if (propertyAlias == "content")
|
||||
{
|
||||
//return the rte type id
|
||||
return Guid.Parse("5e9b75ae-face-41c8-b47e-5f4b0fd82f83");
|
||||
}
|
||||
return Guid.Empty;
|
||||
};
|
||||
//need to specify a custom callback for unit tests
|
||||
DynamicNode.GetDataTypeCallback = (docTypeAlias, propertyAlias) =>
|
||||
{
|
||||
if (propertyAlias == "content")
|
||||
{
|
||||
//return the rte type id
|
||||
return Guid.Parse("5e9b75ae-face-41c8-b47e-5f4b0fd82f83");
|
||||
}
|
||||
return Guid.Empty;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
[Test]
|
||||
[Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")]
|
||||
public override void Is_First_Root_Nodes()
|
||||
{
|
||||
base.Is_First_Root_Nodes();
|
||||
}
|
||||
|
||||
PluginManager.Current.AssembliesToScan = null;
|
||||
[Test]
|
||||
[Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")]
|
||||
public override void Is_Not_First_Root_Nodes()
|
||||
{
|
||||
base.Is_Not_First_Root_Nodes();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("This test will never work unless DynamicNode is refactored a lot in order to get a list of root nodes since root nodes don't have a parent to look up")]
|
||||
public override void Is_Position_Root_Nodes()
|
||||
{
|
||||
base.Is_Position_Root_Nodes();
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
PluginManager.Current.AssembliesToScan = null;
|
||||
|
||||
UmbracoSettings.ResetSetters();
|
||||
}
|
||||
}
|
||||
|
||||
protected override dynamic GetDynamicNode(int id)
|
||||
{
|
||||
//var template = Template.MakeNew("test", new User(0));
|
||||
//var ctx = GetUmbracoContext("/test", template.Id);
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var contentStore = new DefaultPublishedContentStore();
|
||||
var node = new DynamicNode(
|
||||
new DynamicBackingItem(
|
||||
new Node(ctx.GetXml().SelectSingleNode("//*[@id='" + id + "' and @isDoc]"))));
|
||||
Assert.IsNotNull(node);
|
||||
return (dynamic) node;
|
||||
}
|
||||
}
|
||||
protected override dynamic GetDynamicNode(int id)
|
||||
{
|
||||
//var template = Template.MakeNew("test", new User(0));
|
||||
//var ctx = GetUmbracoContext("/test", template.Id);
|
||||
var ctx = GetUmbracoContext("/test", 1234);
|
||||
var contentStore = new DefaultPublishedContentStore();
|
||||
var node = new DynamicNode(
|
||||
new DynamicBackingItem(
|
||||
new Node(ctx.GetXml().SelectSingleNode("//*[@id='" + id + "' and @isDoc]"))));
|
||||
Assert.IsNotNull(node);
|
||||
return (dynamic)node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,22 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
[TestFixture]
|
||||
[TestFixture]
|
||||
public class DynamicPublishedContentTests : DynamicDocumentTestsBase<DynamicPublishedContent, DynamicPublishedContentList>
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
new[]
|
||||
{
|
||||
typeof(DatePickerPropertyEditorValueConverter),
|
||||
typeof(TinyMcePropertyEditorValueConverter),
|
||||
typeof(YesNoPropertyEditorValueConverter)
|
||||
});
|
||||
|
||||
//need to specify a custom callback for unit tests
|
||||
PublishedContentHelper.GetDataTypeCallback = (docTypeAlias, propertyAlias) =>
|
||||
{
|
||||
if (propertyAlias == "content")
|
||||
{
|
||||
//return the rte type id
|
||||
return Guid.Parse("5e9b75ae-face-41c8-b47e-5f4b0fd82f83");
|
||||
}
|
||||
return Guid.Empty;
|
||||
};
|
||||
|
||||
var rCtx = GetRoutingContext("/test", 1234);
|
||||
UmbracoContext.Current = rCtx.UmbracoContext;
|
||||
PublishedContentStoreResolver.Current = new PublishedContentStoreResolver(new DefaultPublishedContentStore());
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
PropertyEditorValueConvertersResolver.Reset();
|
||||
PublishedContentStoreResolver.Reset();
|
||||
UmbracoContext.Current = null;
|
||||
}
|
||||
|
||||
internal DynamicPublishedContent GetNode(int id)
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Tests.PartialTrust;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
[TestFixture]
|
||||
public class DynamicXmlConverterTests : AbstractPartialTrustFixture<DynamicXmlConverterTests>
|
||||
{
|
||||
[Test]
|
||||
public void Convert_To_Raw_String()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\" test-attribute=\"someValue\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(
|
||||
XmlHelper.StripDashesInElementOrAttributeNames(xml),
|
||||
xml);
|
||||
var result = dXml.TryConvertTo<RawXmlString>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_Raw_XElement()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\" test-attribute=\"someValue\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(
|
||||
XmlHelper.StripDashesInElementOrAttributeNames(xml),
|
||||
xml);
|
||||
var result = dXml.TryConvertTo<RawXElement>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.Value.ToString(SaveOptions.DisableFormatting));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_Raw_XmlElement()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\" test-attribute=\"someValue\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(
|
||||
XmlHelper.StripDashesInElementOrAttributeNames(xml),
|
||||
xml);
|
||||
var result = dXml.TryConvertTo<RawXmlElement>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.Value.OuterXml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_Raw_XmlDocument()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\" test-attribute=\"someValue\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(
|
||||
XmlHelper.StripDashesInElementOrAttributeNames(xml),
|
||||
xml);
|
||||
var result = dXml.TryConvertTo<RawXmlDocument>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.Value.InnerXml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_String()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\" test-attribute=\"someValue\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(xml);
|
||||
var result = dXml.TryConvertTo<string>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_XElement()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\" test-attribute=\"someValue\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(xml);
|
||||
var result = dXml.TryConvertTo<XElement>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.ToString(SaveOptions.DisableFormatting));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_XmlElement()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\" test-attribute=\"someValue\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(xml);
|
||||
var result = dXml.TryConvertTo<XmlElement>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.OuterXml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_XmlDocument()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\" test-attribute=\"someValue\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(xml);
|
||||
var result = dXml.TryConvertTo<XmlDocument>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.InnerXml);
|
||||
}
|
||||
|
||||
public override void TestSetup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void TestTearDown()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +1,50 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using System.Linq;
|
||||
using Umbraco.Tests.PartialTrust;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
[TestFixture]
|
||||
public class DynamicXmlConverterTests : AbstractPartialTrustFixture<DynamicXmlConverterTests>
|
||||
{
|
||||
[Test]
|
||||
public void Convert_To_String()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(xml);
|
||||
var result = dXml.TryConvertTo<string>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_XElement()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(xml);
|
||||
var result = dXml.TryConvertTo<XElement>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.ToString(SaveOptions.DisableFormatting));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_XmlElement()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(xml);
|
||||
var result = dXml.TryConvertTo<XmlElement>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.OuterXml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Convert_To_XmlDocument()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
var dXml = new DynamicXml(xml);
|
||||
var result = dXml.TryConvertTo<XmlDocument>();
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(xml, result.Result.InnerXml);
|
||||
}
|
||||
|
||||
public override void TestSetup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void TestTearDown()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
[TestFixture]
|
||||
public class DynamicXmlTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures that when we return the xml structure we get the real structure, not the replaced hyphen structure
|
||||
/// see: http://issues.umbraco.org/issue/U4-1405#comment=67-5113
|
||||
/// http://issues.umbraco.org/issue/U4-1636
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Deals_With_Hyphenated_values()
|
||||
{
|
||||
var xml = @"<banner1Link>
|
||||
<url-picker some-attribute='Content'>
|
||||
<new-window>True</new-window>
|
||||
<node-id>1161</node-id>
|
||||
<url>/content/</url>
|
||||
<link-title>12 december Zorgbeurs Care</link-title>
|
||||
</url-picker>
|
||||
</banner1Link>";
|
||||
|
||||
[Test]
|
||||
var typedXml = new DynamicXml(
|
||||
XmlHelper.StripDashesInElementOrAttributeNames(xml),
|
||||
xml);
|
||||
dynamic dynamicXml = typedXml;
|
||||
|
||||
var typedElement = typedXml.RawXmlElement.Element("url-picker");
|
||||
var dynamicElementByCleanedName = dynamicXml.urlpicker;
|
||||
|
||||
Assert.IsNotNull(typedElement);
|
||||
Assert.IsNotNull(dynamicElementByCleanedName);
|
||||
|
||||
Assert.AreEqual(
|
||||
typedElement.Attribute("some-attribute").Value,
|
||||
dynamicElementByCleanedName.someattribute);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Custom_Extension_Method_Legacy()
|
||||
{
|
||||
var xml = "<DAMP fullMedia=\"\"><mediaItem><Image id=\"1057\" version=\"d58d5c16-153e-4896-892f-a722e45a69af\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:55:29\" updateDate=\"2012-11-05T16:55:44\" nodeName=\"test12\" urlName=\"test12\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1057\"><umbracoFile>/media/54/tulips.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>620888</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:55:34\"><crop name=\"thumbCrop\" x=\"154\" y=\"1\" x2=\"922\" y2=\"768\" url=\"/media/54/tulips_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem><mediaItem><Image id=\"1055\" version=\"4df1f08a-3552-45f2-b4bf-fa980c762f4a\" parentID=\"-1\" level=\"1\" writerID=\"0\" nodeType=\"1032\" template=\"0\" sortOrder=\"1\" createDate=\"2012-11-05T16:29:58\" updateDate=\"2012-11-05T16:30:27\" nodeName=\"Test\" urlName=\"test\" writerName=\"admin\" nodeTypeAlias=\"Image\" path=\"-1,1055\"><umbracoFile>/media/41/hydrangeas.jpg</umbracoFile><umbracoWidth>1024</umbracoWidth><umbracoHeight>768</umbracoHeight><umbracoBytes>595284</umbracoBytes><umbracoExtension>jpg</umbracoExtension><newsCrops><crops date=\"2012-11-05T16:30:18\"><crop name=\"thumbCrop\" x=\"133\" y=\"0\" x2=\"902\" y2=\"768\" url=\"/media/41/hydrangeas_thumbCrop.jpg\" /></crops></newsCrops></Image></mediaItem></DAMP>";
|
||||
@@ -92,7 +68,7 @@ namespace Umbraco.Tests.PublishedContent
|
||||
//we haven't explicitly defined ElementAt so this will dynamically invoke this method
|
||||
var element = dynamicXml.ElementAt(0);
|
||||
|
||||
Assert.AreEqual("1057", Enumerable.First(element.BaseElement.Elements()).Attribute("id").Value);
|
||||
Assert.AreEqual("1057", Enumerable.First(element.BaseElement.Elements()).Attribute("id").Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -123,8 +99,8 @@ namespace Umbraco.Tests.PublishedContent
|
||||
Assert.AreEqual(1, typedTaken.Count());
|
||||
Assert.AreEqual(1, Enumerable.Count(dynamicTaken));
|
||||
|
||||
Assert.AreEqual("1057", typedTaken.ElementAt(0).BaseElement.Elements().First().Attribute("id").Value);
|
||||
Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).BaseElement.Elements()).Attribute("id").Value);
|
||||
Assert.AreEqual("1057", typedTaken.ElementAt(0).BaseElement.Elements().First().Attribute("id").Value);
|
||||
Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).BaseElement.Elements()).Attribute("id").Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user