Compare commits
334 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0695839717 | |||
| 12dba80553 | |||
| f1d26d0990 | |||
| 83d5eda63c | |||
| 2f80d5466d | |||
| e90766ad06 | |||
| 379c629e9c | |||
| 49417cbce4 | |||
| 6153c70ef6 | |||
| dffe09af58 | |||
| 07e9a3a4ea | |||
| e3973de880 | |||
| 8e114f1e8f | |||
| b21289a32f | |||
| 52cf5b5ec3 | |||
| 3fbf90e56d | |||
| 3890353ff5 | |||
| f285af8a4e | |||
| 3b77c301c3 | |||
| 61718f9450 | |||
| 115ba8dcb8 | |||
| 9b086c7fdd | |||
| b788a6c642 | |||
| a94f7e6ec0 | |||
| 260ec800c2 | |||
| 9e223eb891 | |||
| bea7387459 | |||
| 99ff86aefb | |||
| 918bb761b2 | |||
| 031f70f529 | |||
| 25f9fecc16 | |||
| 76a10fc776 | |||
| 1d0b5f3251 | |||
| b01f8799ae | |||
| 76fb595a55 | |||
| fbb46c9ffe | |||
| 628f5b283f | |||
| 73c34fda9c | |||
| b442fecca7 | |||
| 9e1d3220c2 | |||
| de7294335f | |||
| 416dcdf90f | |||
| 2cd5b252d5 | |||
| 64cbeb4c9d | |||
| d2deaf0375 | |||
| 95ff94c532 | |||
| 9f82ae1db7 | |||
| 11b5123bbb | |||
| d0dc5406cc | |||
| 3be1cd8b0d | |||
| 7134373933 | |||
| e2a821c257 | |||
| ed54301914 | |||
| 6849274b98 | |||
| 8fa838e8fb | |||
| 2f9753cc12 | |||
| 66263a44a5 | |||
| 425df19c5c | |||
| f9babe1882 | |||
| cd2f512284 | |||
| 624975b4c9 | |||
| 85cdc79fd2 | |||
| 374bbc0973 | |||
| 5a3b97c669 | |||
| 570b71820f | |||
| 442160bb7a | |||
| f87764f9d5 | |||
| 9d4e0f1e3d | |||
| 800b8b5f7e | |||
| c10c1f8fac | |||
| dbd9240142 | |||
| c3ca651e4a | |||
| f2e319a01f | |||
| d6589960f2 | |||
| 2847a28e74 | |||
| e29668a01b | |||
| 757108446d | |||
| 19715ef45f | |||
| a1c7352da1 | |||
| ae3c17073b | |||
| 59dd6e0941 | |||
| a321d4d1b8 | |||
| 22ac571c7d | |||
| 40d3f2ffb9 | |||
| 0c0802e964 | |||
| 2a6d5846d1 | |||
| a43847bc8b | |||
| df6bb36876 | |||
| d185f93c35 | |||
| df2ce2c133 | |||
| 5e90e74969 | |||
| 924ee5c413 | |||
| bceed10bd8 | |||
| dec7ef8f3f | |||
| f019900619 | |||
| ad92006f54 | |||
| 439935430a | |||
| 1de9dbf18c | |||
| 394cab5ab4 | |||
| 6efd14eff3 | |||
| e468492064 | |||
| 140d3c0268 | |||
| 349cb91e3a | |||
| abf70cd302 | |||
| 880c9cf679 | |||
| bf59510c68 | |||
| b67250c3d5 | |||
| 86833aa8bf | |||
| 4dcc4807ed | |||
| 90b562a0a1 | |||
| fc2b3d7fc7 | |||
| 4d50dcea61 | |||
| 1f9594eef4 | |||
| 5a88ff774c | |||
| b269760b21 | |||
| 3efd038906 | |||
| 2d72a66879 | |||
| 7dc50fda26 | |||
| ff602da0fa | |||
| 4b156ba27e | |||
| d9cf9cee88 | |||
| afa4c7b697 | |||
| a2a8c8fbd7 | |||
| 52c4d80cfc | |||
| 5d4d209030 | |||
| d9f453d860 | |||
| 8c51e8bad8 | |||
| d4b21243ca | |||
| 927add6f44 | |||
| 48317d7e61 | |||
| 93df2edec2 | |||
| 028ddfe290 | |||
| 39a4f141d7 | |||
| c350904219 | |||
| 3d09157091 | |||
| 040486c32b | |||
| 3b6d557dd4 | |||
| 74f4b60a21 | |||
| 5464107a9a | |||
| 84345a7e37 | |||
| cd3191012f | |||
| ef9cc2da3a | |||
| 12fd5c642d | |||
| a9b71f8533 | |||
| c73749ea54 | |||
| e001ed93c1 | |||
| 4e195543ea | |||
| 2c918a2015 | |||
| 182d671e31 | |||
| f15301a7a0 | |||
| 3b2ae6bc4a | |||
| b714cbbd72 | |||
| 09afb93ec3 | |||
| ab4cb08c7d | |||
| 2e877aa446 | |||
| d3eff734aa | |||
| b52f234c02 | |||
| 5baaed19d0 | |||
| 183e7e5910 | |||
| 173392f26e | |||
| be26527b27 | |||
| 414374498f | |||
| 1443618857 | |||
| a7075422dc | |||
| 9213304161 | |||
| 46fdd605ae | |||
| 99598ec060 | |||
| 0ae1453fb1 | |||
| f63e8d7aed | |||
| 5342d819d9 | |||
| ca20fb799d | |||
| c760a7c50d | |||
| 2a3019f1b4 | |||
| 896d7aa788 | |||
| b7eb81dc76 | |||
| a72fae333a | |||
| 4eef90fe25 | |||
| 428df7ae4a | |||
| 1fd4995edc | |||
| 667a731164 | |||
| 0c5acb7f32 | |||
| 470ccd1ffc | |||
| e12984af4c | |||
| 7a6a6409c4 | |||
| 7c0f8db31b | |||
| f87ba4f0d5 | |||
| fed5a14e1b | |||
| b681ca5e17 | |||
| cb853168c6 | |||
| c3640f2a3d | |||
| 70b325a189 | |||
| 80b23f8fa7 | |||
| 6d08d9b7b0 | |||
| 6b0292db64 | |||
| 1d80fc66af | |||
| 010e4edc83 | |||
| b7f2152535 | |||
| 5f0dc4a58e | |||
| 5667256d2c | |||
| c092d871c1 | |||
| e1e73f5e5f | |||
| 23a8777cde | |||
| 0e2e47d4ee | |||
| dc8a37b489 | |||
| 47ec2572f5 | |||
| bff9dfedcc | |||
| 1b161c8dbe | |||
| 5a76e380de | |||
| 6a4966136d | |||
| 0a0e34d806 | |||
| 214db84f9d | |||
| 61fd3fc505 | |||
| 70789e3676 | |||
| a7de549e4f | |||
| efab275c99 | |||
| f8600725b2 | |||
| a5c1b0b2f2 | |||
| bd5833ec5f | |||
| 070fc368b2 | |||
| 50ed207211 | |||
| 4ea0fa0a19 | |||
| b5dd742257 | |||
| 0f4185b6a5 | |||
| ccea64f0fa | |||
| b892f98834 | |||
| 2f86813a21 | |||
| 2cd92353ec | |||
| 42ad3af48b | |||
| afb0aa8099 | |||
| e13e86b25f | |||
| 6b9930df6a | |||
| ae92c8219d | |||
| 512e59871e | |||
| 7545c0c1da | |||
| 3f8df66385 | |||
| 44257e361a | |||
| e94b6fa3a8 | |||
| 3621c20f80 | |||
| ef4d28299a | |||
| d4b718d615 | |||
| 280826f3e8 | |||
| 0a0d845173 | |||
| a999fca349 | |||
| c853263894 | |||
| 16f63b7fd9 | |||
| d41035cb2d | |||
| 1cb0cd296c | |||
| 8f100a7e9f | |||
| ed95ccc18e | |||
| e88264d0f7 | |||
| d9d8bae376 | |||
| 6f76377a9e | |||
| 3fdf13a8b1 | |||
| 23ea9e71fd | |||
| 19037ee1ba | |||
| 8abf6fc2b5 | |||
| 5a6e63e8d4 | |||
| 23341d8c76 | |||
| 5cbfa7bd91 | |||
| b3a93e369a | |||
| 5d7902a9a7 | |||
| c41c727e06 | |||
| 10aad7e048 | |||
| cc396c8b96 | |||
| 1a7fbf5927 | |||
| b28d719ee6 | |||
| d5c8430cd2 | |||
| e3acdbe85b | |||
| ef2c46b6ab | |||
| b9398375f1 | |||
| 274819f75f | |||
| fb3b99a49a | |||
| ffd4e9507b | |||
| 7212015127 | |||
| 31a1ee9145 | |||
| 53fbb18f1c | |||
| 43cfabe9e7 | |||
| caf972cd0f | |||
| 5bef3593dd | |||
| 3f233ad4a4 | |||
| 9252dc222a | |||
| fafe056db0 | |||
| 9f30a9b0fc | |||
| 86f6c4a39d | |||
| 32470e9bd2 | |||
| 97c18980d8 | |||
| defc9d3bc2 | |||
| 77e672aec1 | |||
| 519b06fe30 | |||
| 7e1b20e600 | |||
| 023c7f3fe7 | |||
| 89b8fe93b7 | |||
| f6cd597841 | |||
| fa48af02a1 | |||
| 8509aef99a | |||
| 46e939715a | |||
| 8a32f02781 | |||
| 573192c33f | |||
| 56f5789976 | |||
| f21265c7ae | |||
| eace046342 | |||
| 0a6a41e4c2 | |||
| b449973403 | |||
| 911e81e4af | |||
| 458e7dde94 | |||
| 0c7826b250 | |||
| ef0ad41c8e | |||
| fff1da2a12 | |||
| f91f25e5c0 | |||
| 3f35ca1e77 | |||
| 8c619e92d9 | |||
| d4fd58e038 | |||
| 2961370b83 | |||
| c71e00b3dc | |||
| 641c7dfa04 | |||
| 95845c8f2e | |||
| c656bb632e | |||
| bf82a70744 | |||
| 520955a8db | |||
| 2b25815eee | |||
| 7cfcab4011 | |||
| 787e10bbe1 | |||
| 8328f09d6b | |||
| 04823c23a0 | |||
| 5af67facad | |||
| be9e4c9623 | |||
| e03988dd81 | |||
| 79990b6a6c | |||
| 7f78aef05f | |||
| df3d427c0b | |||
| e558918432 | |||
| e6d1eb0ba0 | |||
| f32a46c546 | |||
| a4de37efb9 |
+9
-9
@@ -1,9 +1,9 @@
|
||||
# The MIT License (MIT) #
|
||||
|
||||
Copyright (c) 2013 Umbraco
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
# The MIT License (MIT) #
|
||||
|
||||
Copyright (c) 2013 Umbraco
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -266,6 +266,7 @@
|
||||
<Message Text="Finished compiling projects" Importance="high" />
|
||||
</Target>
|
||||
|
||||
|
||||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<PropertyGroup>
|
||||
<NewVersion>$(BUILD_RELEASE)</NewVersion>
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.30506.0,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[4.0.30506,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi.WebHost" version="[4.0.30506, 6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi.Core" version="[4.0.30506, 6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi.Client" version="[4.0.30506, 6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.40804.0,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.1" />
|
||||
<dependency id="Microsoft.Net.Http" version="[2.0.20710.0, 3.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.0, 3.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.Cookies" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.OAuth" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoExamine.PDF</id>
|
||||
<version>0.7.0</version>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>UmbracoExmine.PDF</description>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[7.0.0, 8.0.0)" />
|
||||
<dependency id="iTextSharp" version="[5.5.3, 6.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\UmbracoExamine.PDF\UmbracoExamine.PDF.dll" target="lib\UmbracoExamine.PDF.dll" />
|
||||
<file src="..\_BuildOutput\UmbracoExamine.PDF\UmbracoExamine.PDF.XML" target="lib\UmbracoExamine.PDF.XML" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -21,6 +21,7 @@
|
||||
<appSettings xdt:Transform="InsertIfMissing" />
|
||||
<appSettings>
|
||||
<add key="ValidationSettings:UnobtrusiveValidationMode" value="None" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
</appSettings>
|
||||
|
||||
<umbracoConfiguration xdt:Transform="InsertIfMissing">
|
||||
@@ -143,6 +144,7 @@
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Newtonsoft.Json')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Mvc')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Htttp')" xdt:Transform="Remove" />
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
@@ -160,6 +162,10 @@
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.2.6
|
||||
7.3.0
|
||||
beta
|
||||
Binary file not shown.
@@ -77,8 +77,9 @@
|
||||
<Compile Include="SqlCEUtility.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="app.config" />
|
||||
<None Include="app.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -14,6 +14,22 @@
|
||||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.2.6")]
|
||||
[assembly: AssemblyInformationalVersion("7.2.6")]
|
||||
[assembly: AssemblyFileVersion("7.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.3.0-beta")]
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
@@ -12,13 +13,14 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
internal sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="packageActions"></param>
|
||||
internal ActionsResolver(Func<IEnumerable<Type>> packageActions)
|
||||
: base(packageActions)
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="packageActions"></param>
|
||||
internal ActionsResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> packageActions)
|
||||
: base(serviceProvider, logger, packageActions)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -55,7 +57,7 @@ namespace Umbraco.Core
|
||||
var instance = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
|
||||
//if the singletone initializer is not found, try simply creating an instance of the IAction if it supports public constructors
|
||||
if (instance == null)
|
||||
typeInstance = PluginManager.Current.CreateInstance<IAction>(type);
|
||||
typeInstance = ServiceProvider.GetService(type) as IAction;
|
||||
else
|
||||
typeInstance = instance.GetValue(null, null) as IAction;
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Helper methods for Activation
|
||||
/// </summary>
|
||||
internal static class ActivatorHelper
|
||||
@@ -14,7 +12,9 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
public static T CreateInstance<T>() where T : class, new()
|
||||
{
|
||||
return Activator.CreateInstance(typeof(T)) as T;
|
||||
return new ActivatorServiceProvider().GetService(typeof (T)) as T;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
internal class ActivatorServiceProvider : IServiceProvider
|
||||
{
|
||||
public object GetService(Type serviceType)
|
||||
{
|
||||
return Activator.CreateInstance(serviceType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
|
||||
@@ -21,21 +22,35 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public class ApplicationContext : IDisposable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <param name="cache"></param>
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
|
||||
{
|
||||
/// <param name="logger"></param>
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, ProfilingLogger logger)
|
||||
{
|
||||
if (dbContext == null) throw new ArgumentNullException("dbContext");
|
||||
if (serviceContext == null) throw new ArgumentNullException("serviceContext");
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
_databaseContext = dbContext;
|
||||
_services = serviceContext;
|
||||
ApplicationCache = cache;
|
||||
ProfilingLogger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <param name="cache"></param>
|
||||
[Obsolete("Use the other constructor specifying an ILogger instead")]
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
|
||||
: this(dbContext, serviceContext, cache,
|
||||
new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,6 +98,7 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
[Obsolete("Use the other method specifying an ProfilingLogger instead")]
|
||||
public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, bool replaceContext)
|
||||
{
|
||||
if (ApplicationContext.Current != null)
|
||||
@@ -95,6 +111,33 @@ namespace Umbraco.Core
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A method used to create and ensure that a global ApplicationContext singleton is created.
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="replaceContext">
|
||||
/// If set to true will replace the current singleton instance - This should only be used for unit tests or on app
|
||||
/// startup if for some reason the boot manager is not the umbraco boot manager.
|
||||
/// </param>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, ProfilingLogger logger, bool replaceContext)
|
||||
{
|
||||
if (ApplicationContext.Current != null)
|
||||
{
|
||||
if (!replaceContext)
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
var ctx = new ApplicationContext(dbContext, serviceContext, cache, logger);
|
||||
ApplicationContext.Current = ctx;
|
||||
return ApplicationContext.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Singleton accessor
|
||||
/// </summary>
|
||||
@@ -108,7 +151,13 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public CacheHelper ApplicationCache { get; private set; }
|
||||
|
||||
// IsReady is set to true by the boot manager once it has successfully booted
|
||||
/// <summary>
|
||||
/// Exposes the global ProfilingLogger - this should generally not be accessed via the UmbracoContext and should normally just be exposed
|
||||
/// on most base classes or injected with IoC
|
||||
/// </summary>
|
||||
public ProfilingLogger ProfilingLogger { get; private set; }
|
||||
|
||||
// IsReady is set to true by the boot manager once it has successfully booted
|
||||
// note - the original umbraco module checks on content.Instance in umbraco.dll
|
||||
// now, the boot task that setup the content store ensures that it is ready
|
||||
bool _isReady = false;
|
||||
@@ -153,6 +202,25 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the db is configured, there is a database context and there is an umbraco schema, but we are not 'configured' , then it means we are upgrading
|
||||
/// </summary>
|
||||
public bool IsUpgrading
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsConfigured == false
|
||||
&& DatabaseContext != null
|
||||
&& DatabaseContext.IsDatabaseConfigured)
|
||||
{
|
||||
var schemaresult = DatabaseContext.ValidateDatabaseSchema();
|
||||
if (schemaresult.ValidTables.Count > 0) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The original/first url that the web application executes
|
||||
/// </summary>
|
||||
@@ -185,7 +253,7 @@ namespace Umbraco.Core
|
||||
// remember it's been reported so we don't flood the log
|
||||
// no thread-safety so there may be a few log entries, doesn't matter
|
||||
_versionsDifferenceReported = true;
|
||||
LogHelper.Info<ApplicationContext>("CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'");
|
||||
ProfilingLogger.Logger.Debug<ApplicationContext>("CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'");
|
||||
}
|
||||
|
||||
return ok;
|
||||
@@ -293,7 +361,7 @@ namespace Umbraco.Core
|
||||
this.ApplicationCache = null;
|
||||
if (_databaseContext != null) //need to check the internal field here
|
||||
{
|
||||
if (DatabaseContext.IsDatabaseConfigured)
|
||||
if (DatabaseContext.IsDatabaseConfigured && DatabaseContext.Database != null)
|
||||
{
|
||||
DatabaseContext.Database.Dispose();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
namespace Umbraco.Core.Auditing
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
/// <summary>
|
||||
/// Public method to create new audit trail
|
||||
/// </summary>
|
||||
[Obsolete("Use Umbraco.Core.Services.IAuditService instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static class Audit
|
||||
{
|
||||
public static void Add(AuditTypes type, string comment, int userId, int objectId)
|
||||
public static void Add(Umbraco.Core.Auditing.AuditTypes type, string comment, int userId, int objectId)
|
||||
{
|
||||
AuditTrail.Current.AddEntry(type, comment, userId, objectId);
|
||||
ApplicationContext.Current.Services.AuditService.Add(
|
||||
Enum<Umbraco.Core.Models.AuditType>.Parse(type.ToString()),
|
||||
comment, userId, objectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the Audit implementation
|
||||
/// </summary>
|
||||
internal class AuditTrail
|
||||
{
|
||||
#region Singleton
|
||||
|
||||
private static readonly Lazy<AuditTrail> lazy = new Lazy<AuditTrail>(() => new AuditTrail());
|
||||
|
||||
public static AuditTrail Current { get { return lazy.Value; } }
|
||||
|
||||
private AuditTrail()
|
||||
{
|
||||
WriteProvider = new DataAuditWriteProvider();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private IAuditWriteProvider WriteProvider { get; set; }
|
||||
|
||||
public void AddEntry(AuditTypes type, string comment, int userId, int objectId)
|
||||
{
|
||||
WriteProvider.WriteEntry(objectId, userId, DateTime.Now, type.ToString(), comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
namespace Umbraco.Core.Auditing
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
/// <summary>
|
||||
/// Enums for vailable types of auditing
|
||||
/// </summary>
|
||||
[Obsolete("Use Umbraco.Core.Models.AuditType instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public enum AuditTypes
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
internal class DataAuditWriteProvider : IAuditWriteProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes an audit entry to the underlaying datastore.
|
||||
/// </summary>
|
||||
/// <param name="objectId">Id of the object (Content, ContentType, Media, etc.)</param>
|
||||
/// <param name="userId">Id of the user</param>
|
||||
/// <param name="date">Datestamp</param>
|
||||
/// <param name="header">Audit header</param>
|
||||
/// <param name="comment">Audit comment</param>
|
||||
public void WriteEntry(int objectId, int userId, DateTime date, string header, string comment)
|
||||
{
|
||||
ApplicationContext.Current.DatabaseContext.Database.Insert(new LogDto
|
||||
{
|
||||
Comment = comment,
|
||||
Datestamp = date,
|
||||
Header = header,
|
||||
NodeId = objectId,
|
||||
UserId = userId
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Auditing
|
||||
{
|
||||
internal interface IAuditWriteProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes an audit entry to the underlaying datastore.
|
||||
/// </summary>
|
||||
/// <param name="objectId">Id of the object (Content, ContentType, Media, etc.)</param>
|
||||
/// <param name="userId">Id of the user</param>
|
||||
/// <param name="date">Datestamp</param>
|
||||
/// <param name="header">Audit header</param>
|
||||
/// <param name="comment">Audit comment</param>
|
||||
void WriteEntry(int objectId, int userId, DateTime date, string header, string comment);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ namespace Umbraco.Core.Cache
|
||||
public const string MemberBusinessLogicCacheKey = "MemberCacheItem_";
|
||||
|
||||
public const string TemplateFrontEndCacheKey = "template";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache";
|
||||
|
||||
public const string UserContextCacheKey = "UmbracoUserContext";
|
||||
@@ -45,11 +47,15 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string LanguageCacheKey = "UmbracoLanguageCache";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string DomainCacheKey = "UmbracoDomainList";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string StylesheetCacheKey = "UmbracoStylesheet";
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty";
|
||||
|
||||
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
|
||||
|
||||
@@ -105,6 +105,9 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
public virtual void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
var type = TypeFinder.GetTypeByName(typeName);
|
||||
if (type == null) return;
|
||||
var isInterface = type.IsInterface;
|
||||
using (WriteLock)
|
||||
{
|
||||
foreach (var entry in GetDictionaryEntries()
|
||||
@@ -114,7 +117,10 @@ namespace Umbraco.Core.Cache
|
||||
// remove null values as well, does not hurt
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
return value == null || value.GetType().ToString().InvariantEquals(typeName);
|
||||
|
||||
// if T is an interface remove anything that implements that interface
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return value == null || (isInterface ? (type.IsInstanceOfType(value)) : (value.GetType() == type));
|
||||
})
|
||||
.ToArray())
|
||||
RemoveEntry((string) entry.Key);
|
||||
@@ -124,6 +130,7 @@ namespace Umbraco.Core.Cache
|
||||
public virtual void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
var typeOfT = typeof(T);
|
||||
var isInterface = typeOfT.IsInterface;
|
||||
using (WriteLock)
|
||||
{
|
||||
foreach (var entry in GetDictionaryEntries()
|
||||
@@ -134,7 +141,10 @@ namespace Umbraco.Core.Cache
|
||||
// compare on exact type, don't use "is"
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
return value == null || value.GetType() == typeOfT;
|
||||
|
||||
// if T is an interface remove anything that implements that interface
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return value == null || (isInterface ? (value is T) : (value.GetType() == typeOfT));
|
||||
})
|
||||
.ToArray())
|
||||
RemoveEntry((string) entry.Key);
|
||||
@@ -144,6 +154,7 @@ namespace Umbraco.Core.Cache
|
||||
public virtual void ClearCacheObjectTypes<T>(Func<string, T, bool> predicate)
|
||||
{
|
||||
var typeOfT = typeof(T);
|
||||
var isInterface = typeOfT.IsInterface;
|
||||
var plen = CacheItemPrefix.Length + 1;
|
||||
using (WriteLock)
|
||||
{
|
||||
@@ -156,9 +167,12 @@ namespace Umbraco.Core.Cache
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
if (value == null) return true;
|
||||
return value.GetType() == typeOfT
|
||||
// run predicate on the 'public key' part only, ie without prefix
|
||||
&& predicate(((string)x.Key).Substring(plen), (T)value);
|
||||
|
||||
// if T is an interface remove anything that implements that interface
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return (isInterface ? (value is T) : (value.GetType() == typeOfT))
|
||||
// run predicate on the 'public key' part only, ie without prefix
|
||||
&& predicate(((string) x.Key).Substring(plen), (T) value);
|
||||
}))
|
||||
RemoveEntry((string) entry.Key);
|
||||
}
|
||||
|
||||
@@ -20,9 +20,15 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
private readonly System.Web.Caching.Cache _cache;
|
||||
|
||||
/// <summary>
|
||||
/// Used for debugging
|
||||
/// </summary>
|
||||
internal Guid InstanceId { get; private set; }
|
||||
|
||||
public HttpRuntimeCacheProvider(System.Web.Caching.Cache cache)
|
||||
{
|
||||
_cache = cache;
|
||||
InstanceId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
protected override IEnumerable<DictionaryEntry> GetDictionaryEntries()
|
||||
@@ -134,6 +140,7 @@ namespace Umbraco.Core.Cache
|
||||
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
|
||||
|
||||
lck.UpgradeToWriteLock();
|
||||
//NOTE: 'Insert' on System.Web.Caching.Cache actually does an add or update!
|
||||
_cache.Insert(cacheKey, result, dependency, absolute, sliding, priority, removedCallback);
|
||||
}
|
||||
}
|
||||
@@ -191,6 +198,7 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
using (new WriteLock(_locker))
|
||||
{
|
||||
//NOTE: 'Insert' on System.Web.Caching.Cache actually does an add or update!
|
||||
_cache.Insert(cacheKey, result, dependency, absolute, sliding, priority, removedCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,51 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
public interface ICacheProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Removes all items from the cache.
|
||||
/// </summary>
|
||||
void ClearAllCache();
|
||||
|
||||
/// <summary>
|
||||
/// Removes an item from the cache, identified by its key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the item.</param>
|
||||
void ClearCacheItem(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Removes items from the cache, of a specified type.
|
||||
/// </summary>
|
||||
/// <param name="typeName">The name of the type to remove.</param>
|
||||
/// <remarks>
|
||||
/// <para>If the type is an interface, then all items of a type implementing that interface are
|
||||
/// removed. Otherwise, only items of that exact type are removed (items of type inheriting from
|
||||
/// the specified type are not removed).</para>
|
||||
/// <para>Performs a case-sensitive search.</para>
|
||||
/// </remarks>
|
||||
void ClearCacheObjectTypes(string typeName);
|
||||
|
||||
/// <summary>
|
||||
/// Removes items from the cache, of a specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the items to remove.</typeparam>
|
||||
/// <remarks>If the type is an interface, then all items of a type implementing that interface are
|
||||
/// removed. Otherwise, only items of that exact type are removed (items of type inheriting from
|
||||
/// the specified type are not removed).</remarks>
|
||||
void ClearCacheObjectTypes<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Removes items from the cache, of a specified type, satisfying a predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the items to remove.</typeparam>
|
||||
/// <param name="predicate">The predicate to satisfy.</param>
|
||||
/// <remarks>If the type is an interface, then all items of a type implementing that interface are
|
||||
/// removed. Otherwise, only items of that exact type are removed (items of type inheriting from
|
||||
/// the specified type are not removed).</remarks>
|
||||
void ClearCacheObjectTypes<T>(Func<string, T, bool> predicate);
|
||||
|
||||
void ClearCacheByKeySearch(string keyStartsWith);
|
||||
void ClearCacheByKeyExpression(string regexString);
|
||||
|
||||
IEnumerable<object> GetCacheItemsByKeySearch(string keyStartsWith);
|
||||
IEnumerable<object> GetCacheItemsByKeyExpression(string regexString);
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache refresher that supports refreshing cache based on a custom payload
|
||||
/// </summary>
|
||||
interface IPayloadCacheRefresher : IJsonCacheRefresher
|
||||
{
|
||||
/// <summary>
|
||||
/// Refreshes, clears, etc... any cache based on the information provided in the payload
|
||||
/// </summary>
|
||||
/// <param name="payload"></param>
|
||||
void Refresh(object payload);
|
||||
}
|
||||
}
|
||||
@@ -4,17 +4,16 @@ using umbraco.interfaces;
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for json cache refreshers that ensures the correct events are raised when
|
||||
/// cache refreshing occurs.
|
||||
/// Provides a base class for "json" cache refreshers.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstanceType">The real cache refresher type, this is used for raising strongly typed events</typeparam>
|
||||
public abstract class JsonCacheRefresherBase<TInstanceType> : CacheRefresherBase<TInstanceType>, IJsonCacheRefresher
|
||||
where TInstanceType : ICacheRefresher
|
||||
/// <typeparam name="TInstance">The actual cache refresher type.</typeparam>
|
||||
/// <remarks>Ensures that the correct events are raised when cache refreshing occurs.</remarks>
|
||||
public abstract class JsonCacheRefresherBase<TInstance> : CacheRefresherBase<TInstance>, IJsonCacheRefresher
|
||||
where TInstance : ICacheRefresher
|
||||
{
|
||||
|
||||
public virtual void Refresh(string jsonPayload)
|
||||
public virtual void Refresh(string json)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(json, MessageType.RefreshByJson));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Caching;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
@@ -16,12 +17,19 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
internal class ObjectCacheRuntimeCacheProvider : IRuntimeCacheProvider
|
||||
{
|
||||
|
||||
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
internal ObjectCache MemoryCache;
|
||||
|
||||
/// <summary>
|
||||
/// Used for debugging
|
||||
/// </summary>
|
||||
internal Guid InstanceId { get; private set; }
|
||||
|
||||
public ObjectCacheRuntimeCacheProvider()
|
||||
{
|
||||
MemoryCache = new MemoryCache("in-memory");
|
||||
InstanceId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
#region Clear
|
||||
@@ -46,6 +54,9 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
public virtual void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
var type = TypeFinder.GetTypeByName(typeName);
|
||||
if (type == null) return;
|
||||
var isInterface = type.IsInterface;
|
||||
using (new WriteLock(_locker))
|
||||
{
|
||||
foreach (var key in MemoryCache
|
||||
@@ -55,7 +66,10 @@ namespace Umbraco.Core.Cache
|
||||
// remove null values as well, does not hurt
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
return value == null || value.GetType().ToString().InvariantEquals(typeName);
|
||||
|
||||
// if T is an interface remove anything that implements that interface
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return value == null || (isInterface ? (type.IsInstanceOfType(value)) : (value.GetType() == type));
|
||||
})
|
||||
.Select(x => x.Key)
|
||||
.ToArray()) // ToArray required to remove
|
||||
@@ -68,6 +82,7 @@ namespace Umbraco.Core.Cache
|
||||
using (new WriteLock(_locker))
|
||||
{
|
||||
var typeOfT = typeof (T);
|
||||
var isInterface = typeOfT.IsInterface;
|
||||
foreach (var key in MemoryCache
|
||||
.Where(x =>
|
||||
{
|
||||
@@ -75,7 +90,11 @@ namespace Umbraco.Core.Cache
|
||||
// remove null values as well, does not hurt
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
return value == null || value.GetType() == typeOfT;
|
||||
|
||||
// if T is an interface remove anything that implements that interface
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return value == null || (isInterface ? (value is T) : (value.GetType() == typeOfT));
|
||||
|
||||
})
|
||||
.Select(x => x.Key)
|
||||
.ToArray()) // ToArray required to remove
|
||||
@@ -88,6 +107,7 @@ namespace Umbraco.Core.Cache
|
||||
using (new WriteLock(_locker))
|
||||
{
|
||||
var typeOfT = typeof(T);
|
||||
var isInterface = typeOfT.IsInterface;
|
||||
foreach (var key in MemoryCache
|
||||
.Where(x =>
|
||||
{
|
||||
@@ -96,8 +116,11 @@ namespace Umbraco.Core.Cache
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
if (value == null) return true;
|
||||
return value.GetType() == typeOfT
|
||||
&& predicate(x.Key, (T) value);
|
||||
|
||||
// if T is an interface remove anything that implements that interface
|
||||
// otherwise remove exact types (not inherited types)
|
||||
return (isInterface ? (value is T) : (value.GetType() == typeOfT))
|
||||
&& predicate(x.Key, (T)value);
|
||||
})
|
||||
.Select(x => x.Key)
|
||||
.ToArray()) // ToArray required to remove
|
||||
@@ -193,6 +216,7 @@ namespace Umbraco.Core.Cache
|
||||
var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles);
|
||||
|
||||
lck.UpgradeToWriteLock();
|
||||
//NOTE: This does an add or update
|
||||
MemoryCache.Set(cacheKey, result, policy);
|
||||
}
|
||||
}
|
||||
@@ -219,6 +243,7 @@ namespace Umbraco.Core.Cache
|
||||
if (value == null) return; // do not store null values (backward compat)
|
||||
|
||||
var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles);
|
||||
//NOTE: This does an add or update
|
||||
MemoryCache.Set(cacheKey, result, policy);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using Umbraco.Core.Sync;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for "payload" cache refreshers.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstance">The actual cache refresher type.</typeparam>
|
||||
/// <remarks>Ensures that the correct events are raised when cache refreshing occurs.</remarks>
|
||||
public abstract class PayloadCacheRefresherBase<TInstance> : JsonCacheRefresherBase<TInstance>, IPayloadCacheRefresher
|
||||
where TInstance : ICacheRefresher
|
||||
{
|
||||
protected abstract object Deserialize(string json);
|
||||
|
||||
public override void Refresh(string json)
|
||||
{
|
||||
var payload = Deserialize(json);
|
||||
Refresh(payload);
|
||||
}
|
||||
|
||||
public virtual void Refresh(object payload)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(payload, MessageType.RefreshByPayload));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
@@ -12,13 +13,14 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
internal sealed class CacheRefreshersResolver : LegacyTransientObjectsResolver<CacheRefreshersResolver, ICacheRefresher>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="refreshers"></param>
|
||||
internal CacheRefreshersResolver(Func<IEnumerable<Type>> refreshers)
|
||||
: base(refreshers)
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="refreshers"></param>
|
||||
internal CacheRefreshersResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> refreshers)
|
||||
: base(serviceProvider, logger, refreshers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -8,10 +8,13 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
internal class ClientDependencyConfiguration
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly string _fileName;
|
||||
|
||||
public ClientDependencyConfiguration()
|
||||
public ClientDependencyConfiguration(ILogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_logger = logger;
|
||||
_fileName = IOHelper.MapPath(string.Format("{0}/ClientDependency.config", SystemDirectories.Config));
|
||||
}
|
||||
|
||||
@@ -35,13 +38,13 @@ namespace Umbraco.Core.Configuration
|
||||
versionAttribute.SetValue(newVersion);
|
||||
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
|
||||
|
||||
LogHelper.Info<ClientDependencyConfiguration>(string.Format("Updated version number from {0} to {1}", oldVersion, newVersion));
|
||||
_logger.Info<ClientDependencyConfiguration>(string.Format("Updated version number from {0} to {1}", oldVersion, newVersion));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
|
||||
_logger.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
|
||||
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
|
||||
/// </remarks>
|
||||
internal static string UmbracoMvcArea
|
||||
public static string UmbracoMvcArea
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -83,14 +83,20 @@ namespace Umbraco.Core.Configuration
|
||||
return _dashboardSection;
|
||||
}
|
||||
|
||||
//ONLY for unit testing
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
internal void SetDashboardSettings(IDashboardSection value)
|
||||
{
|
||||
_dashboardSection = value;
|
||||
}
|
||||
|
||||
//ONLY for unit testing
|
||||
internal void SetUmbracoSettings(IUmbracoSettingsSection value)
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetUmbracoSettings(IUmbracoSettingsSection value)
|
||||
{
|
||||
_umbracoSettings = value;
|
||||
}
|
||||
@@ -110,7 +116,10 @@ namespace Umbraco.Core.Configuration
|
||||
return _umbracoSettings;
|
||||
}
|
||||
|
||||
//ONLY for unit testing
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetBaseRestExtensions(IBaseRestSection value)
|
||||
{
|
||||
_baseRestExtensions = value;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
public interface ITemplatesSection : IUmbracoConfigurationSection
|
||||
{
|
||||
@@ -8,6 +10,7 @@
|
||||
|
||||
RenderingEngine DefaultRenderingEngine { get; }
|
||||
|
||||
[Obsolete("This has no affect and will be removed in future versions")]
|
||||
bool EnableTemplateFolders { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Configuration;
|
||||
using System;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
@@ -40,6 +41,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("This has no affect and will be removed in future versions")]
|
||||
[ConfigurationProperty("enableTemplateFolders")]
|
||||
internal InnerTextConfigurationElement<bool> EnableTemplateFolders
|
||||
{
|
||||
@@ -67,6 +69,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return DefaultRenderingEngine; }
|
||||
}
|
||||
|
||||
[Obsolete("This has no affect and will be removed in future versions")]
|
||||
bool ITemplatesSection.EnableTemplateFolders
|
||||
{
|
||||
get { return EnableTemplateFolders; }
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.2.6");
|
||||
private static readonly Version Version = new Version("7.3.0");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
public static string CurrentComment { get { return "beta"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -78,12 +78,12 @@
|
||||
/// </summary>
|
||||
public const string Dictionary = "dictionary";
|
||||
|
||||
//TODO: Fill in the rest!
|
||||
public const string Stylesheets = "stylesheets";
|
||||
|
||||
/// <summary>
|
||||
/// alias for the media tree.
|
||||
/// alias for the template tree.
|
||||
/// </summary>
|
||||
public const string Templates = "template";
|
||||
public const string Templates = "templates";
|
||||
|
||||
public const string RelationTypes = "relationTypes";
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
|
||||
public const string Languages = "languages";
|
||||
|
||||
//TODO: Fill in the rest!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,25 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public static class Conventions
|
||||
{
|
||||
public static class PublicAccess
|
||||
{
|
||||
public const string MemberUsernameRuleType = "MemberUsername";
|
||||
public const string MemberRoleRuleType = "MemberRole";
|
||||
|
||||
[Obsolete("No longer supported, this is here for backwards compatibility only")]
|
||||
public const string MemberIdRuleType = "MemberId";
|
||||
[Obsolete("No longer supported, this is here for backwards compatibility only")]
|
||||
public const string MemberGroupIdRuleType = "MemberGroupId";
|
||||
}
|
||||
|
||||
public static class Localization
|
||||
{
|
||||
/// <summary>
|
||||
/// The root id for all top level dictionary items
|
||||
/// </summary>
|
||||
public const string DictionaryItemRootId = "41c7638d-f529-4bff-853e-59a0c2fb1bde";
|
||||
}
|
||||
|
||||
public static class DataTypes
|
||||
{
|
||||
public const string ListViewPrefix = "List View - ";
|
||||
@@ -284,7 +303,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the alias identifiers for Umbraco relation types.
|
||||
/// Defines the alias identifiers for built-in Umbraco relation types.
|
||||
/// </summary>
|
||||
public static class RelationTypes
|
||||
{
|
||||
@@ -297,6 +316,16 @@ namespace Umbraco.Core
|
||||
/// ContentType alias for default relation type "Relate Document On Copy".
|
||||
/// </summary>
|
||||
public const string RelateDocumentOnCopyAlias = "relateDocumentOnCopy";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType name for default relation type "Relate Parent Document On Delete".
|
||||
/// </summary>
|
||||
public const string RelateParentDocumentOnDeleteName = "Relate Parent Document On Delete";
|
||||
|
||||
/// <summary>
|
||||
/// ContentType alias for default relation type "Relate Parent Document On Delete".
|
||||
/// </summary>
|
||||
public const string RelateParentDocumentOnDeleteAlias = "relateParentDocumentOnDelete";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Umbraco.Core
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
@@ -70,7 +72,11 @@
|
||||
/// <summary>
|
||||
/// Guid for a Stylesheet object.
|
||||
/// </summary>
|
||||
public const string Stylesheet = "9F68DA4F-A3A8-44C2-8226-DCBD125E4840";
|
||||
[Obsolete("This no longer exists in the database")]
|
||||
public const string Stylesheet = "9F68DA4F-A3A8-44C2-8226-DCBD125E4840";
|
||||
|
||||
[Obsolete("This no longer exists in the database")]
|
||||
internal const string StylesheetProperty = "5555da4f-a123-42b2-4488-dcdfb25e4111";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the System Root.
|
||||
|
||||
@@ -18,5 +18,29 @@
|
||||
public const string AuthCookieName = "UMB_UCONTEXT";
|
||||
|
||||
}
|
||||
|
||||
public static class Security
|
||||
{
|
||||
|
||||
public const string BackOfficeAuthenticationType = "UmbracoBackOffice";
|
||||
public const string BackOfficeExternalAuthenticationType = "UmbracoExternalCookie";
|
||||
public const string BackOfficeExternalCookieName = "UMB_EXTLOGIN";
|
||||
public const string BackOfficeTokenAuthenticationType = "UmbracoBackOfficeToken";
|
||||
|
||||
/// <summary>
|
||||
/// The prefix used for external identity providers for their authentication type
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default we don't want to interfere with front-end external providers and their default setup, for back office the
|
||||
/// providers need to be setup differently and each auth type for the back office will be prefixed with this value
|
||||
/// </remarks>
|
||||
public const string BackOfficeExternalAuthenticationTypePrefix = "Umbraco.";
|
||||
|
||||
public const string StartContentNodeIdClaimType = "http://umbraco.org/2015/02/identity/claims/backoffice/startcontentnode";
|
||||
public const string StartMediaNodeIdClaimType = "http://umbraco.org/2015/02/identity/claims/backoffice/startmedianode";
|
||||
public const string AllowedApplicationsClaimType = "http://umbraco.org/2015/02/identity/claims/backoffice/allowedapp";
|
||||
public const string SessionIdClaimType = "http://umbraco.org/2015/02/identity/claims/backoffice/sessionid";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+162
-116
@@ -32,66 +32,90 @@ using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrad
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A bootstrapper for the Umbraco application which initializes all objects for the Core of the application
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does not provide any startup functionality relating to web objects
|
||||
/// </remarks>
|
||||
public class CoreBootManager : IBootManager
|
||||
{
|
||||
|
||||
private DisposableTimer _timer;
|
||||
private bool _isInitialized = false;
|
||||
private bool _isStarted = false;
|
||||
private bool _isComplete = false;
|
||||
/// A bootstrapper for the Umbraco application which initializes all objects for the Core of the application
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does not provide any startup functionality relating to web objects
|
||||
/// </remarks>
|
||||
public class CoreBootManager : IBootManager
|
||||
{
|
||||
private ProfilingLogger _profilingLogger;
|
||||
private DisposableTimer _timer;
|
||||
private bool _isInitialized = false;
|
||||
private bool _isStarted = false;
|
||||
private bool _isComplete = false;
|
||||
private readonly IServiceProvider _serviceProvider = new ActivatorServiceProvider();
|
||||
private readonly UmbracoApplicationBase _umbracoApplication;
|
||||
protected ApplicationContext ApplicationContext { get; set; }
|
||||
protected ApplicationContext ApplicationContext { get; set; }
|
||||
protected CacheHelper ApplicationCache { get; set; }
|
||||
protected PluginManager PluginManager { get; private set; }
|
||||
|
||||
protected UmbracoApplicationBase UmbracoApplication
|
||||
{
|
||||
get { return _umbracoApplication; }
|
||||
}
|
||||
protected UmbracoApplicationBase UmbracoApplication
|
||||
{
|
||||
get { return _umbracoApplication; }
|
||||
}
|
||||
|
||||
public CoreBootManager(UmbracoApplicationBase umbracoApplication)
|
||||
{
|
||||
protected IServiceProvider ServiceProvider
|
||||
{
|
||||
get { return _serviceProvider; }
|
||||
}
|
||||
|
||||
public CoreBootManager(UmbracoApplicationBase umbracoApplication)
|
||||
{
|
||||
if (umbracoApplication == null) throw new ArgumentNullException("umbracoApplication");
|
||||
_umbracoApplication = umbracoApplication;
|
||||
}
|
||||
|
||||
public virtual IBootManager Initialize()
|
||||
{
|
||||
if (_isInitialized)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
public virtual IBootManager Initialize()
|
||||
{
|
||||
if (_isInitialized)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
|
||||
InitializeProfilerResolver();
|
||||
InitializeLoggerResolver();
|
||||
InitializeProfilerResolver();
|
||||
|
||||
_timer = DisposableTimer.TraceDuration<CoreBootManager>("Umbraco application starting", "Umbraco application startup complete");
|
||||
|
||||
CreateApplicationCache();
|
||||
_profilingLogger = new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler);
|
||||
|
||||
_timer = _profilingLogger.TraceDuration<CoreBootManager>("Umbraco application starting", "Umbraco application startup complete");
|
||||
|
||||
CreateApplicationCache();
|
||||
|
||||
//create and set the plugin manager (I'd much prefer to not use this singleton anymore but many things are using it unfortunately and
|
||||
// the way that it is setup, there must only ever be one per app so without IoC it would be hard to make this not a singleton)
|
||||
PluginManager = new PluginManager(ServiceProvider, ApplicationCache.RuntimeCache, _profilingLogger);
|
||||
PluginManager.Current = PluginManager;
|
||||
|
||||
//Create the legacy prop-eds mapping
|
||||
LegacyPropertyEditorIdToAliasConverter.CreateMappingsForCoreEditors();
|
||||
LegacyParameterEditorAliasConverter.CreateMappingsForCoreEditors();
|
||||
|
||||
//create database and service contexts for the app context
|
||||
var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName);
|
||||
Database.Mapper = new PetaPocoMapper();
|
||||
var dbContext = new DatabaseContext(dbFactory);
|
||||
var serviceContext = new ServiceContext(
|
||||
new PetaPocoUnitOfWorkProvider(dbFactory),
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy(),
|
||||
ApplicationCache);
|
||||
//create database and service contexts for the app context
|
||||
var dbFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, LoggerResolver.Current.Logger);
|
||||
Database.Mapper = new PetaPocoMapper();
|
||||
|
||||
var dbContext = new DatabaseContext(
|
||||
dbFactory,
|
||||
LoggerResolver.Current.Logger,
|
||||
SqlSyntaxProviders.CreateDefault(LoggerResolver.Current.Logger));
|
||||
|
||||
//initialize the DatabaseContext
|
||||
dbContext.Initialize();
|
||||
|
||||
var serviceContext = new ServiceContext(
|
||||
new RepositoryFactory(ApplicationCache, LoggerResolver.Current.Logger, dbContext.SqlSyntax, UmbracoConfig.For.UmbracoSettings()),
|
||||
new PetaPocoUnitOfWorkProvider(dbFactory),
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy(),
|
||||
ApplicationCache,
|
||||
LoggerResolver.Current.Logger);
|
||||
|
||||
CreateApplicationContext(dbContext, serviceContext);
|
||||
|
||||
InitializeApplicationEventsResolver();
|
||||
|
||||
InitializeResolvers();
|
||||
InitializeResolvers();
|
||||
|
||||
//initialize the DatabaseContext
|
||||
dbContext.Initialize();
|
||||
|
||||
|
||||
InitializeModelMappers();
|
||||
|
||||
@@ -99,10 +123,10 @@ namespace Umbraco.Core
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext));
|
||||
|
||||
_isInitialized = true;
|
||||
_isInitialized = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and assigns the application context singleton
|
||||
@@ -112,7 +136,7 @@ namespace Umbraco.Core
|
||||
protected virtual void CreateApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
|
||||
{
|
||||
//create the ApplicationContext
|
||||
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext, ApplicationCache);
|
||||
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext, ApplicationCache, _profilingLogger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -123,7 +147,7 @@ namespace Umbraco.Core
|
||||
var cacheHelper = new CacheHelper(
|
||||
new ObjectCacheRuntimeCacheProvider(),
|
||||
new StaticCacheProvider(),
|
||||
//we have no request based cache when not running in web-based context
|
||||
//we have no request based cache when not running in web-based context
|
||||
new NullCacheProvider());
|
||||
|
||||
ApplicationCache = cacheHelper;
|
||||
@@ -147,18 +171,31 @@ namespace Umbraco.Core
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special method to initialize the LoggerResolver
|
||||
/// </summary>
|
||||
protected virtual void InitializeLoggerResolver()
|
||||
{
|
||||
LoggerResolver.Current = new LoggerResolver(Logger.CreateWithDefaultLog4NetConfiguration())
|
||||
{
|
||||
//This is another special resolver that needs to be resolvable before resolution is frozen
|
||||
//since it is used for profiling the application startup
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special method to initialize the ProfilerResolver
|
||||
/// </summary>
|
||||
protected virtual void InitializeProfilerResolver()
|
||||
{
|
||||
//By default we'll initialize the Log profiler (in the web project, we'll override with the web profiler)
|
||||
ProfilerResolver.Current = new ProfilerResolver(new LogProfiler())
|
||||
{
|
||||
//This is another special resolver that needs to be resolvable before resolution is frozen
|
||||
//since it is used for profiling the application startup
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
ProfilerResolver.Current = new ProfilerResolver(new LogProfiler(LoggerResolver.Current.Logger))
|
||||
{
|
||||
//This is another special resolver that needs to be resolvable before resolution is frozen
|
||||
//since it is used for profiling the application startup
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -173,7 +210,9 @@ namespace Umbraco.Core
|
||||
//ApplicationStartupHandler.RegisterHandlers();
|
||||
//... and set the special flag to let us resolve before frozen resolution
|
||||
ApplicationEventsResolver.Current = new ApplicationEventsResolver(
|
||||
PluginManager.Current.ResolveApplicationStartupHandlers())
|
||||
ServiceProvider,
|
||||
LoggerResolver.Current.Logger,
|
||||
PluginManager.ResolveApplicationStartupHandlers())
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
@@ -190,16 +229,16 @@ namespace Umbraco.Core
|
||||
Umbraco.Core.IO.IOHelper.SetRootDirectory(rootPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires after initialization and calls the callback to allow for customizations to occur &
|
||||
/// <summary>
|
||||
/// Fires after initialization and calls the callback to allow for customizations to occur &
|
||||
/// Ensure that the OnApplicationStarting methods of the IApplicationEvents are called
|
||||
/// </summary>
|
||||
/// <param name="afterStartup"></param>
|
||||
/// <returns></returns>
|
||||
public virtual IBootManager Startup(Action<ApplicationContext> afterStartup)
|
||||
{
|
||||
if (_isStarted)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
/// </summary>
|
||||
/// <param name="afterStartup"></param>
|
||||
/// <returns></returns>
|
||||
public virtual IBootManager Startup(Action<ApplicationContext> afterStartup)
|
||||
{
|
||||
if (_isStarted)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
@@ -210,23 +249,23 @@ namespace Umbraco.Core
|
||||
afterStartup(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
_isStarted = true;
|
||||
_isStarted = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires after startup and calls the callback once customizations are locked
|
||||
/// </summary>
|
||||
/// <param name="afterComplete"></param>
|
||||
/// <returns></returns>
|
||||
public virtual IBootManager Complete(Action<ApplicationContext> afterComplete)
|
||||
{
|
||||
if (_isComplete)
|
||||
throw new InvalidOperationException("The boot manager has already been completed");
|
||||
/// <summary>
|
||||
/// Fires after startup and calls the callback once customizations are locked
|
||||
/// </summary>
|
||||
/// <param name="afterComplete"></param>
|
||||
/// <returns></returns>
|
||||
public virtual IBootManager Complete(Action<ApplicationContext> afterComplete)
|
||||
{
|
||||
if (_isComplete)
|
||||
throw new InvalidOperationException("The boot manager has already been completed");
|
||||
|
||||
FreezeResolution();
|
||||
|
||||
FreezeResolution();
|
||||
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationStarted(UmbracoApplication, ApplicationContext));
|
||||
@@ -239,15 +278,15 @@ namespace Umbraco.Core
|
||||
afterComplete(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
_isComplete = true;
|
||||
_isComplete = true;
|
||||
|
||||
// we're ready to serve content!
|
||||
ApplicationContext.IsReady = true;
|
||||
|
||||
//stop the timer and log the output
|
||||
_timer.Dispose();
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freeze resolution to not allow Resolvers to be modified
|
||||
@@ -256,21 +295,22 @@ namespace Umbraco.Core
|
||||
{
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the resolvers
|
||||
/// </summary>
|
||||
protected virtual void InitializeResolvers()
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Create the resolvers
|
||||
/// </summary>
|
||||
protected virtual void InitializeResolvers()
|
||||
{
|
||||
var builder = new ManifestBuilder(
|
||||
ApplicationCache.RuntimeCache,
|
||||
new ManifestParser(new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")), ApplicationCache.RuntimeCache));
|
||||
|
||||
PropertyEditorResolver.Current = new PropertyEditorResolver(() => PluginManager.Current.ResolvePropertyEditors(), builder);
|
||||
ParameterEditorResolver.Current = new ParameterEditorResolver(() => PluginManager.Current.ResolveParameterEditors(), builder);
|
||||
PropertyEditorResolver.Current = new PropertyEditorResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolvePropertyEditors(), builder);
|
||||
ParameterEditorResolver.Current = new ParameterEditorResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveParameterEditors(), builder);
|
||||
|
||||
//setup the validators resolver with our predefined validators
|
||||
ValidatorsResolver.Current = new ValidatorsResolver(new[]
|
||||
ValidatorsResolver.Current = new ValidatorsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger, new[]
|
||||
{
|
||||
new Lazy<Type>(() => typeof (RequiredManifestValueValidator)),
|
||||
new Lazy<Type>(() => typeof (RegexValidator)),
|
||||
@@ -281,63 +321,69 @@ namespace Umbraco.Core
|
||||
|
||||
//by default we'll use the standard configuration based sync
|
||||
ServerRegistrarResolver.Current = new ServerRegistrarResolver(
|
||||
new ConfigServerRegistrar());
|
||||
new ConfigServerRegistrar());
|
||||
|
||||
//by default (outside of the web) we'll use the default server messenger without
|
||||
//supplying a username/password, this will automatically disable distributed calls
|
||||
// .. we'll override this in the WebBootManager
|
||||
ServerMessengerResolver.Current = new ServerMessengerResolver(
|
||||
new DefaultServerMessenger());
|
||||
new WebServiceServerMessenger());
|
||||
|
||||
MappingResolver.Current = new MappingResolver(
|
||||
() => PluginManager.Current.ResolveAssignedMapperTypes());
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveAssignedMapperTypes());
|
||||
|
||||
RepositoryResolver.Current = new RepositoryResolver(
|
||||
new RepositoryFactory(ApplicationCache));
|
||||
|
||||
|
||||
SqlSyntaxProvidersResolver.Current = new SqlSyntaxProvidersResolver(
|
||||
new[] { typeof(MySqlSyntaxProvider), typeof(SqlCeSyntaxProvider), typeof(SqlServerSyntaxProvider) })
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
//RepositoryResolver.Current = new RepositoryResolver(
|
||||
// new RepositoryFactory(ApplicationCache));
|
||||
|
||||
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
|
||||
() => PluginManager.Current.ResolveCacheRefreshers());
|
||||
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveCacheRefreshers());
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveDataTypes());
|
||||
|
||||
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
|
||||
() => PluginManager.Current.ResolveMacroRenderings());
|
||||
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveMacroRenderings());
|
||||
|
||||
PackageActionsResolver.Current = new PackageActionsResolver(
|
||||
() => PluginManager.Current.ResolvePackageActions());
|
||||
PackageActionsResolver.Current = new PackageActionsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolvePackageActions());
|
||||
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
() => PluginManager.Current.ResolveActions());
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveActions());
|
||||
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(
|
||||
() => PluginManager.Current.ResolveTypes<IMigration>());
|
||||
LoggerResolver.Current.Logger,
|
||||
() => PluginManager.ResolveTypes<IMigration>());
|
||||
|
||||
// todo: remove once we drop IPropertyEditorValueConverter support.
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
PluginManager.Current.ResolvePropertyEditorValueConverters());
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
PluginManager.ResolvePropertyEditorValueConverters());
|
||||
|
||||
// need to filter out the ones we dont want!!
|
||||
PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(
|
||||
PluginManager.Current.ResolveTypes<IPropertyValueConverter>());
|
||||
// need to filter out the ones we dont want!!
|
||||
PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
PluginManager.ResolveTypes<IPropertyValueConverter>());
|
||||
|
||||
// use the new DefaultShortStringHelper
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
//new LegacyShortStringHelper());
|
||||
new DefaultShortStringHelper().WithDefaultConfig());
|
||||
|
||||
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
|
||||
typeof (DefaultUrlSegmentProvider));
|
||||
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
typeof(DefaultUrlSegmentProvider));
|
||||
|
||||
// by default, no factory is activated
|
||||
PublishedContentModelFactoryResolver.Current = new PublishedContentModelFactoryResolver();
|
||||
}
|
||||
}
|
||||
PublishedContentModelFactoryResolver.Current = new PublishedContentModelFactoryResolver();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
@@ -11,12 +12,14 @@ namespace Umbraco.Core
|
||||
[Obsolete("IDataType is obsolete and is no longer used, it will be removed from the codebase in future versions")]
|
||||
internal sealed class DataTypesResolver : LegacyTransientObjectsResolver<DataTypesResolver, IDataType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dataTypes"></param>
|
||||
internal DataTypesResolver(Func<IEnumerable<Type>> dataTypes)
|
||||
: base(dataTypes)
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="dataTypes"></param>
|
||||
internal DataTypesResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> dataTypes)
|
||||
: base(serviceProvider, logger, dataTypes)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace Umbraco.Core
|
||||
public class DatabaseContext
|
||||
{
|
||||
private readonly IDatabaseFactory _factory;
|
||||
private readonly ILogger _logger;
|
||||
private readonly SqlSyntaxProviders _syntaxProviders;
|
||||
private bool _configured;
|
||||
private bool _canConnect;
|
||||
private volatile bool _connectCheck = false;
|
||||
@@ -33,11 +35,53 @@ namespace Umbraco.Core
|
||||
private string _providerName;
|
||||
private DatabaseSchemaResult _result;
|
||||
|
||||
[Obsolete("Use the constructor specifying all dependencies instead")]
|
||||
public DatabaseContext(IDatabaseFactory factory)
|
||||
: this(factory, LoggerResolver.Current.Logger, new SqlSyntaxProviders(new ISqlSyntaxProvider[]
|
||||
{
|
||||
new MySqlSyntaxProvider(LoggerResolver.Current.Logger),
|
||||
new SqlCeSyntaxProvider(),
|
||||
new SqlServerSyntaxProvider()
|
||||
}))
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="syntaxProviders"></param>
|
||||
public DatabaseContext(IDatabaseFactory factory, ILogger logger, SqlSyntaxProviders syntaxProviders)
|
||||
{
|
||||
if (factory == null) throw new ArgumentNullException("factory");
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (syntaxProviders == null) throw new ArgumentNullException("syntaxProviders");
|
||||
|
||||
_factory = factory;
|
||||
_logger = logger;
|
||||
_syntaxProviders = syntaxProviders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a configured DatabaseContext
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="sqlSyntax"></param>
|
||||
/// <param name="providerName"></param>
|
||||
public DatabaseContext(IDatabaseFactory factory, ILogger logger, ISqlSyntaxProvider sqlSyntax, string providerName)
|
||||
{
|
||||
_providerName = providerName;
|
||||
SqlSyntax = sqlSyntax;
|
||||
SqlSyntaxContext.SqlSyntaxProvider = SqlSyntax;
|
||||
_factory = factory;
|
||||
_logger = logger;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public ISqlSyntaxProvider SqlSyntax { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Database"/> object for doing CRUD operations
|
||||
/// against custom tables that resides in the Umbraco database.
|
||||
@@ -324,7 +368,7 @@ namespace Umbraco.Core
|
||||
|
||||
xml.Save(fileName, SaveOptions.DisableFormatting);
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
|
||||
_logger.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -398,12 +442,23 @@ namespace Umbraco.Core
|
||||
|
||||
internal void Initialize(string providerName)
|
||||
{
|
||||
//only configure once!
|
||||
if (_configured == true) return;
|
||||
|
||||
_providerName = providerName;
|
||||
|
||||
try
|
||||
{
|
||||
SqlSyntaxContext.SqlSyntaxProvider =
|
||||
SqlSyntaxProvidersResolver.Current.GetByProviderNameOrDefault(providerName);
|
||||
if (_syntaxProviders != null)
|
||||
{
|
||||
SqlSyntax = _syntaxProviders.GetByProviderNameOrDefault(providerName);
|
||||
}
|
||||
else if (SqlSyntax == null)
|
||||
{
|
||||
throw new InvalidOperationException("No " + typeof(ISqlSyntaxProvider) + " specified or no " + typeof(SqlSyntaxProviders) + " instance specified");
|
||||
}
|
||||
|
||||
SqlSyntaxContext.SqlSyntaxProvider = SqlSyntax;
|
||||
|
||||
_configured = true;
|
||||
}
|
||||
@@ -411,8 +466,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
_configured = false;
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Initialization of the DatabaseContext failed with following error: " + e.Message);
|
||||
LogHelper.Info<DatabaseContext>(e.StackTrace);
|
||||
_logger.Info<DatabaseContext>("Initialization of the DatabaseContext failed with following error: " + e.Message);
|
||||
_logger.Info<DatabaseContext>(e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,8 +482,8 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
private void DetermineSqlServerVersion()
|
||||
{
|
||||
|
||||
var sqlServerSyntax = SqlSyntaxContext.SqlSyntaxProvider as SqlServerSyntaxProvider;
|
||||
|
||||
var sqlServerSyntax = SqlSyntax as SqlServerSyntaxProvider;
|
||||
if (sqlServerSyntax != null)
|
||||
{
|
||||
//this will not execute now, it is lazy so will only execute when we need to actually know
|
||||
@@ -479,8 +534,8 @@ namespace Umbraco.Core
|
||||
throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration");
|
||||
}
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
var dbSchema = new DatabaseSchemaCreation(database);
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName, _logger);
|
||||
var dbSchema = new DatabaseSchemaCreation(database, _logger, SqlSyntax);
|
||||
_result = dbSchema.ValidateSchema();
|
||||
}
|
||||
return _result;
|
||||
@@ -496,17 +551,17 @@ namespace Umbraco.Core
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: Started");
|
||||
_logger.Info<DatabaseContext>("Database configuration status: Started");
|
||||
|
||||
string message;
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName, _logger);
|
||||
|
||||
// If MySQL, we're going to ensure that database calls are maintaining proper casing as to remove the necessity for checks
|
||||
// for case insensitive queries. In an ideal situation (which is what we're striving for), all calls would be case sensitive.
|
||||
|
||||
/*
|
||||
var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
var supportsCaseInsensitiveQueries = SqlSyntax.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>" +
|
||||
@@ -532,12 +587,12 @@ namespace Umbraco.Core
|
||||
message = message + "<p>Installation completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
_logger.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
|
||||
//we need to do an upgrade so return a new status message and it will need to be done during the next step
|
||||
LogHelper.Info<DatabaseContext>("Database requires upgrade");
|
||||
_logger.Info<DatabaseContext>("Database requires upgrade");
|
||||
message = "<p>Upgrading database, this may take some time...</p>";
|
||||
return new Result
|
||||
{
|
||||
@@ -568,10 +623,10 @@ namespace Umbraco.Core
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Database upgrade started");
|
||||
_logger.Info<DatabaseContext>("Database upgrade started");
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
//var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName, _logger);
|
||||
//var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database);
|
||||
|
||||
var message = GetResultMessageForMySql();
|
||||
|
||||
@@ -584,13 +639,13 @@ namespace Umbraco.Core
|
||||
? installedVersion
|
||||
: new Version(GlobalSettings.ConfigurationStatus);
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
var runner = new MigrationRunner(currentVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
|
||||
var runner = new MigrationRunner(_logger, currentVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
|
||||
var upgraded = runner.Execute(database, true);
|
||||
message = message + "<p>Upgrade completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
_logger.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
@@ -602,7 +657,7 @@ namespace Umbraco.Core
|
||||
|
||||
private string GetResultMessageForMySql()
|
||||
{
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider.GetType() == typeof(MySqlSyntaxProvider))
|
||||
if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<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>" +
|
||||
@@ -628,7 +683,7 @@ namespace Umbraco.Core
|
||||
"<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>";
|
||||
}
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider.GetType() == typeof(MySqlSyntaxProvider))
|
||||
if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<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>" +
|
||||
@@ -665,11 +720,11 @@ namespace Umbraco.Core
|
||||
|
||||
private Result HandleInstallException(Exception ex)
|
||||
{
|
||||
LogHelper.Error<DatabaseContext>("Database configuration failed", ex);
|
||||
_logger.Error<DatabaseContext>("Database configuration failed", ex);
|
||||
|
||||
if (_result != null)
|
||||
{
|
||||
LogHelper.Info<DatabaseContext>("The database schema validation produced the following summary: \n" + _result.GetSummary());
|
||||
_logger.Info<DatabaseContext>("The database schema validation produced the following summary: \n" + _result.GetSummary());
|
||||
}
|
||||
|
||||
return new Result
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Dictionary
|
||||
@@ -12,15 +14,22 @@ namespace Umbraco.Core.Dictionary
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used by developers at runtime to set their ICultureDictionaryFactory at app startup
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
[Obsolete("Use SetDictionaryFactory instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void SetContentStore(ICultureDictionaryFactory factory)
|
||||
{
|
||||
Value = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used by developers at runtime to set their ICultureDictionaryFactory at app startup
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
public void SetDictionaryFactory(ICultureDictionaryFactory factory)
|
||||
{
|
||||
Value = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ICultureDictionaryFactory
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Umbraco.Core.Dictionary
|
||||
@@ -19,5 +20,12 @@ namespace Umbraco.Core.Dictionary
|
||||
/// Returns the current culture
|
||||
/// </summary>
|
||||
CultureInfo Culture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the child dictionary entries for a given key
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
IDictionary<string, string> GetChildren(string key);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -135,20 +134,6 @@ namespace Umbraco.Core
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a dictionary to a FormCollection
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <returns></returns>
|
||||
public static FormCollection ToFormCollection(this IDictionary<string, object> d)
|
||||
{
|
||||
var n = new FormCollection();
|
||||
foreach (var i in d)
|
||||
{
|
||||
n.Add(i.Key, Convert.ToString(i.Value));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges all key/values from the sources dictionaries into the destination dictionary
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -9,32 +10,65 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Starts the timer and invokes a callback upon disposal. Provides a simple way of timing an operation by wrapping it in a <code>using</code> (C#) statement.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
///
|
||||
/// using (DisposableTimer.TraceDuration{MyType}("starting", "finished"))
|
||||
/// {
|
||||
/// Thread.Sleep(567);
|
||||
/// }
|
||||
///
|
||||
/// Console.WriteLine("Testing Stopwatchdisposable, should be 567:");
|
||||
/// using (var timer = new DisposableTimer(result => Console.WriteLine("Took {0}ms", result)))
|
||||
/// {
|
||||
/// Thread.Sleep(567);
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class DisposableTimer : DisposableObject
|
||||
{
|
||||
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
|
||||
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
|
||||
private readonly Action<long> _callback;
|
||||
|
||||
protected DisposableTimer(Action<long> callback)
|
||||
{
|
||||
_callback = callback;
|
||||
}
|
||||
internal enum LogType
|
||||
{
|
||||
Debug, Info
|
||||
}
|
||||
|
||||
public Stopwatch Stopwatch
|
||||
internal DisposableTimer(ILogger logger, LogType logType, IProfiler profiler, Type loggerType, string startMessage, string endMessage)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (loggerType == null) throw new ArgumentNullException("loggerType");
|
||||
|
||||
_callback = x =>
|
||||
{
|
||||
if (profiler != null)
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
}
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Debug:
|
||||
logger.Debug(loggerType, () => endMessage + " (took " + x + "ms)");
|
||||
break;
|
||||
case LogType.Info:
|
||||
logger.Info(loggerType, () => endMessage + " (took " + x + "ms)");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("logType");
|
||||
}
|
||||
|
||||
};
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Debug:
|
||||
logger.Debug(loggerType, startMessage);
|
||||
break;
|
||||
case LogType.Info:
|
||||
logger.Info(loggerType, startMessage);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("logType");
|
||||
}
|
||||
|
||||
if (profiler != null)
|
||||
{
|
||||
profiler.Step(loggerType, startMessage);
|
||||
}
|
||||
}
|
||||
|
||||
protected internal DisposableTimer(Action<long> callback)
|
||||
{
|
||||
if (callback == null) throw new ArgumentNullException("callback");
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
public Stopwatch Stopwatch
|
||||
{
|
||||
get { return _stopwatch; }
|
||||
}
|
||||
@@ -51,25 +85,25 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
#region TraceDuration
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the other methods that specify strings instead of Func")]
|
||||
public static DisposableTimer TraceDuration<T>(Func<string> startMessage, Func<string> completeMessage)
|
||||
{
|
||||
return TraceDuration(typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the other methods that specify strings instead of Func")]
|
||||
public static DisposableTimer TraceDuration(Type loggerType, Func<string> startMessage, Func<string> completeMessage)
|
||||
{
|
||||
var startMsg = startMessage();
|
||||
LogHelper.Info(loggerType, startMsg);
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("Start: " + startMsg);
|
||||
var profiler = ActivateProfiler(loggerType, startMsg);
|
||||
return new DisposableTimer(x =>
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
LogHelper.Info(loggerType, () => completeMessage() + " (took " + x + "ms)");
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("End: " + startMsg);
|
||||
});
|
||||
return new DisposableTimer(
|
||||
LoggerResolver.Current.Logger,
|
||||
LogType.Info,
|
||||
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
|
||||
loggerType,
|
||||
startMessage(),
|
||||
completeMessage());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -79,11 +113,19 @@ namespace Umbraco.Core
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer TraceDuration<T>(string startMessage, string completeMessage)
|
||||
{
|
||||
return TraceDuration(typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a start and end log entry as Info and tracks how long it takes until disposed.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="startMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer TraceDuration<T>(string startMessage)
|
||||
{
|
||||
return TraceDuration(typeof(T), startMessage, "Complete");
|
||||
@@ -96,20 +138,18 @@ namespace Umbraco.Core
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage)
|
||||
{
|
||||
LogHelper.Info(loggerType, startMessage);
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("Start: " + startMessage);
|
||||
var profiler = ActivateProfiler(loggerType, startMessage);
|
||||
return new DisposableTimer(x =>
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
LogHelper.Info(loggerType, () => completeMessage + " (took " + x + "ms)");
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("End: " + startMessage);
|
||||
});
|
||||
}
|
||||
return new DisposableTimer(
|
||||
LoggerResolver.Current.Logger,
|
||||
LogType.Info,
|
||||
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
|
||||
loggerType,
|
||||
startMessage,
|
||||
completeMessage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DebugDuration
|
||||
@@ -120,23 +160,26 @@ namespace Umbraco.Core
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer DebugDuration<T>(string startMessage, string completeMessage)
|
||||
{
|
||||
return DebugDuration(typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
public static DisposableTimer DebugDuration<T>(string startMessage)
|
||||
{
|
||||
return DebugDuration(typeof(T), startMessage, "Complete");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer DebugDuration<T>(string startMessage)
|
||||
{
|
||||
return DebugDuration(typeof(T), startMessage, "Complete");
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the other methods that specify strings instead of Func")]
|
||||
public static DisposableTimer DebugDuration<T>(Func<string> startMessage, Func<string> completeMessage)
|
||||
{
|
||||
return DebugDuration(typeof(T), startMessage, completeMessage);
|
||||
@@ -149,42 +192,29 @@ namespace Umbraco.Core
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use the Umbraco.Core.Logging.ProfilingLogger to create instances of DisposableTimer")]
|
||||
public static DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage)
|
||||
{
|
||||
LogHelper.Debug(loggerType, startMessage);
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("Start: " + startMessage);
|
||||
var profiler = ActivateProfiler(loggerType, startMessage);
|
||||
return new DisposableTimer(x =>
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
LogHelper.Debug(loggerType, () => completeMessage + " (took " + x + "ms)");
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("End: " + startMessage);
|
||||
});
|
||||
return new DisposableTimer(
|
||||
LoggerResolver.Current.Logger,
|
||||
LogType.Debug,
|
||||
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
|
||||
loggerType,
|
||||
startMessage,
|
||||
completeMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a start and end log entry as Debug and tracks how long it takes until disposed.
|
||||
/// </summary>
|
||||
/// <param name="loggerType"></param>
|
||||
/// <param name="startMessage"></param>
|
||||
/// <param name="completeMessage"></param>
|
||||
/// <returns></returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the other methods that specify strings instead of Func")]
|
||||
public static DisposableTimer DebugDuration(Type loggerType, Func<string> startMessage, Func<string> completeMessage)
|
||||
{
|
||||
var msg = startMessage();
|
||||
LogHelper.Debug(loggerType, msg);
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("Start: " + startMessage);
|
||||
var profiler = ActivateProfiler(loggerType, msg);
|
||||
return new DisposableTimer(x =>
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
LogHelper.Debug(loggerType, () => completeMessage() + " (took " + x + "ms)");
|
||||
if (HttpContext.Current != null)
|
||||
HttpContext.Current.Trace.Write("End: " + startMessage);
|
||||
});
|
||||
return new DisposableTimer(
|
||||
LoggerResolver.Current.Logger,
|
||||
LogType.Debug,
|
||||
ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : null,
|
||||
loggerType,
|
||||
startMessage(),
|
||||
completeMessage());
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -196,18 +226,5 @@ namespace Umbraco.Core
|
||||
_callback.Invoke(Stopwatch.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
private static IDisposable ActivateProfiler(Type loggerType, string profileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ProfilerResolver.Current.Profiler.Step(loggerType, profileName);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
//swallow this exception, it will occur if the ProfilerResolver is not initialized... generally only in
|
||||
// unit tests.
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,11 +56,11 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
if (UmbracoConfig.For.UmbracoSettings().Content.ResolveUrlsFromTextString)
|
||||
{
|
||||
using (var timer = DisposableTimer.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete"))
|
||||
using (DisposableTimer.DebugDuration(typeof(IOHelper), "ResolveUrlsFromTextString starting", "ResolveUrlsFromTextString complete"))
|
||||
{
|
||||
// find all relative urls (ie. urls that contain ~)
|
||||
var tags = ResolveUrlPattern.Matches(text);
|
||||
LogHelper.Debug(typeof(IOHelper), "After regex: " + timer.Stopwatch.ElapsedMilliseconds + " matched: " + tags.Count);
|
||||
|
||||
foreach (Match tag in tags)
|
||||
{
|
||||
string url = "";
|
||||
|
||||
@@ -0,0 +1,450 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
internal class MasterPageHelper
|
||||
{
|
||||
private readonly IFileSystem _masterPageFileSystem;
|
||||
internal static readonly string DefaultMasterTemplate = SystemDirectories.Umbraco + "/masterpages/default.master";
|
||||
//private static readonly char[] NewLineChars = Environment.NewLine.ToCharArray();
|
||||
|
||||
public MasterPageHelper(IFileSystem masterPageFileSystem)
|
||||
{
|
||||
if (masterPageFileSystem == null) throw new ArgumentNullException("masterPageFileSystem");
|
||||
_masterPageFileSystem = masterPageFileSystem;
|
||||
}
|
||||
|
||||
public bool MasterPageExists(ITemplate t)
|
||||
{
|
||||
return _masterPageFileSystem.FileExists(GetFilePath(t));
|
||||
}
|
||||
|
||||
[Obsolete("This is only used for legacy purposes and will be removed in future versions")]
|
||||
internal string GetPhysicalFilePath(ITemplate t)
|
||||
{
|
||||
return _masterPageFileSystem.GetFullPath(GetFilePath(t.Alias));
|
||||
}
|
||||
|
||||
private string GetFilePath(ITemplate t)
|
||||
{
|
||||
return GetFilePath(t.Alias);
|
||||
}
|
||||
|
||||
private string GetFilePath(string alias)
|
||||
{
|
||||
return alias + ".master";
|
||||
}
|
||||
|
||||
public string CreateMasterPage(ITemplate t, ITemplateRepository templateRepo, bool overWrite = false)
|
||||
{
|
||||
string masterpageContent = "";
|
||||
|
||||
var filePath = GetFilePath(t);
|
||||
if (_masterPageFileSystem.FileExists(filePath) == false || overWrite)
|
||||
{
|
||||
masterpageContent = t.Content.IsNullOrWhiteSpace() ? CreateDefaultMasterPageContent(t, templateRepo) : t.Content;
|
||||
|
||||
var data = Encoding.UTF8.GetBytes(masterpageContent);
|
||||
var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
|
||||
|
||||
using (var ms = new MemoryStream(withBom))
|
||||
{
|
||||
_masterPageFileSystem.AddFile(filePath, ms, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var s = _masterPageFileSystem.OpenFile(filePath))
|
||||
using (var tr = new StreamReader(s, Encoding.UTF8))
|
||||
{
|
||||
masterpageContent = tr.ReadToEnd();
|
||||
tr.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return masterpageContent;
|
||||
}
|
||||
|
||||
//internal string GetFileContents(ITemplate t)
|
||||
//{
|
||||
// var masterpageContent = "";
|
||||
// if (_masterPageFileSystem.FileExists(GetFilePath(t)))
|
||||
// {
|
||||
// using (var s = _masterPageFileSystem.OpenFile(GetFilePath(t)))
|
||||
// using (var tr = new StreamReader(s))
|
||||
// {
|
||||
// masterpageContent = tr.ReadToEnd();
|
||||
// tr.Close();
|
||||
// }
|
||||
// }
|
||||
|
||||
// return masterpageContent;
|
||||
//}
|
||||
|
||||
public string UpdateMasterPageFile(ITemplate t, string currentAlias, ITemplateRepository templateRepo)
|
||||
{
|
||||
var template = UpdateMasterPageContent(t, currentAlias);
|
||||
UpdateChildTemplates(t, currentAlias, templateRepo);
|
||||
var filePath = GetFilePath(t);
|
||||
|
||||
var data = Encoding.UTF8.GetBytes(template);
|
||||
var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
|
||||
|
||||
using (var ms = new MemoryStream(withBom))
|
||||
{
|
||||
_masterPageFileSystem.AddFile(filePath, ms, true);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
private string CreateDefaultMasterPageContent(ITemplate template, ITemplateRepository templateRepo)
|
||||
{
|
||||
var design = new StringBuilder();
|
||||
design.Append(GetMasterPageHeader(template) + Environment.NewLine);
|
||||
|
||||
if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
var master = templateRepo.Get(template.MasterTemplateAlias);
|
||||
if (master != null)
|
||||
{
|
||||
foreach (var cpId in GetContentPlaceholderIds(master))
|
||||
{
|
||||
design.Append("<asp:content ContentPlaceHolderId=\"" + cpId + "\" runat=\"server\">" +
|
||||
Environment.NewLine +
|
||||
Environment.NewLine +
|
||||
"</asp:content>" +
|
||||
Environment.NewLine +
|
||||
Environment.NewLine);
|
||||
}
|
||||
|
||||
return design.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
design.Append(GetMasterContentElement(template) + Environment.NewLine);
|
||||
design.Append(template.Content + Environment.NewLine);
|
||||
design.Append("</asp:Content>" + Environment.NewLine);
|
||||
|
||||
return design.ToString();
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetContentPlaceholderIds(ITemplate template)
|
||||
{
|
||||
var retVal = new List<string>();
|
||||
|
||||
var mp = template.Content;
|
||||
var path = "<asp:ContentPlaceHolder+(\\s+[a-zA-Z]+\\s*=\\s*(\"([^\"]*)\"|'([^']*)'))*\\s*/?>";
|
||||
var r = new Regex(path, RegexOptions.IgnoreCase);
|
||||
var m = r.Match(mp);
|
||||
|
||||
while (m.Success)
|
||||
{
|
||||
var cc = m.Groups[3].Captures;
|
||||
retVal.AddRange(cc.Cast<Capture>().Where(c => c.Value != "server").Select(c => c.Value));
|
||||
|
||||
m = m.NextMatch();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private static string UpdateMasterPageContent(ITemplate template, string currentAlias)
|
||||
{
|
||||
var masterPageContent = template.Content;
|
||||
|
||||
if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias)
|
||||
{
|
||||
var masterHeader =
|
||||
masterPageContent.Substring(0, masterPageContent.IndexOf("%>", StringComparison.Ordinal) + 2).Trim(
|
||||
Environment.NewLine.ToCharArray());
|
||||
|
||||
// find the masterpagefile attribute
|
||||
var m = Regex.Matches(masterHeader, "(?<attributeName>\\S*)=\"(?<attributeValue>[^\"]*)\"",
|
||||
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
foreach (Match attributeSet in m)
|
||||
{
|
||||
if (attributeSet.Groups["attributeName"].Value.ToLower() == "masterpagefile")
|
||||
{
|
||||
// validate the masterpagefile
|
||||
var currentMasterPageFile = attributeSet.Groups["attributeValue"].Value;
|
||||
var currentMasterTemplateFile = ParentTemplatePath(template);
|
||||
|
||||
if (currentMasterPageFile != currentMasterTemplateFile)
|
||||
{
|
||||
masterPageContent =
|
||||
masterPageContent.Replace(
|
||||
attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterPageFile + "\"",
|
||||
attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterTemplateFile +
|
||||
"\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return masterPageContent;
|
||||
}
|
||||
|
||||
private void UpdateChildTemplates(ITemplate template, string currentAlias, ITemplateRepository templateRepo)
|
||||
{
|
||||
//if we have a Old Alias if the alias and therefor the masterpage file name has changed...
|
||||
//so before we save the new masterfile, we'll clear the old one, so we don't up with
|
||||
//Unused masterpage files
|
||||
if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias)
|
||||
{
|
||||
//Ensure that child templates have the right master masterpage file name
|
||||
if (template.IsMasterTemplate)
|
||||
{
|
||||
var children = templateRepo.GetChildren(template.Id);
|
||||
foreach (var t in children)
|
||||
UpdateMasterPageFile(t, null, templateRepo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//private void SaveDesignToFile(ITemplate t, string currentAlias, string design)
|
||||
//{
|
||||
// //kill the old file..
|
||||
// if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != t.Alias)
|
||||
// {
|
||||
// var oldFile =
|
||||
// IOHelper.MapPath(SystemDirectories.Masterpages + "/" + currentAlias.Replace(" ", "") + ".master");
|
||||
// if (System.IO.File.Exists(oldFile))
|
||||
// System.IO.File.Delete(oldFile);
|
||||
// }
|
||||
|
||||
// // save the file in UTF-8
|
||||
// System.IO.File.WriteAllText(GetFilePath(t), design, Encoding.UTF8);
|
||||
//}
|
||||
|
||||
//internal static void RemoveMasterPageFile(string alias)
|
||||
//{
|
||||
// if (string.IsNullOrWhiteSpace(alias) == false)
|
||||
// {
|
||||
// string file = IOHelper.MapPath(SystemDirectories.Masterpages + "/" + alias.Replace(" ", "") + ".master");
|
||||
// if (System.IO.File.Exists(file))
|
||||
// System.IO.File.Delete(file);
|
||||
// }
|
||||
//}
|
||||
|
||||
//internal string SaveTemplateToFile(ITemplate template, string currentAlias, ITemplateRepository templateRepo)
|
||||
//{
|
||||
// var masterPageContent = template.Content;
|
||||
// if (IsMasterPageSyntax(masterPageContent) == false)
|
||||
// masterPageContent = ConvertToMasterPageSyntax(template);
|
||||
|
||||
// // Add header to master page if it doesn't exist
|
||||
// if (masterPageContent.TrimStart().StartsWith("<%@") == false)
|
||||
// {
|
||||
// masterPageContent = GetMasterPageHeader(template) + Environment.NewLine + masterPageContent;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // verify that the masterpage attribute is the same as the masterpage
|
||||
// var masterHeader =
|
||||
// masterPageContent.Substring(0, masterPageContent.IndexOf("%>", StringComparison.Ordinal) + 2).Trim(NewLineChars);
|
||||
|
||||
// // find the masterpagefile attribute
|
||||
// var m = Regex.Matches(masterHeader, "(?<attributeName>\\S*)=\"(?<attributeValue>[^\"]*)\"",
|
||||
// RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
// foreach (Match attributeSet in m)
|
||||
// {
|
||||
// if (attributeSet.Groups["attributeName"].Value.ToLower() == "masterpagefile")
|
||||
// {
|
||||
// // validate the masterpagefile
|
||||
// var currentMasterPageFile = attributeSet.Groups["attributeValue"].Value;
|
||||
// var currentMasterTemplateFile = ParentTemplatePath(template);
|
||||
|
||||
// if (currentMasterPageFile != currentMasterTemplateFile)
|
||||
// {
|
||||
// masterPageContent =
|
||||
// masterPageContent.Replace(
|
||||
// attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterPageFile + "\"",
|
||||
// attributeSet.Groups["attributeName"].Value + "=\"" + currentMasterTemplateFile +
|
||||
// "\"");
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// //we have a Old Alias if the alias and therefor the masterpage file name has changed...
|
||||
// //so before we save the new masterfile, we'll clear the old one, so we don't up with
|
||||
// //Unused masterpage files
|
||||
// if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != template.Alias)
|
||||
// {
|
||||
|
||||
// //Ensure that child templates have the right master masterpage file name
|
||||
// if (template.IsMasterTemplate)
|
||||
// {
|
||||
// var children = templateRepo.GetChildren(template.Id);
|
||||
|
||||
// foreach (var t in children)
|
||||
// UpdateMasterPageFile(t, null, templateRepo);
|
||||
// }
|
||||
|
||||
// //then kill the old file..
|
||||
// var oldFile = GetFilePath(currentAlias);
|
||||
// if (_masterPageFileSystem.FileExists(oldFile))
|
||||
// _masterPageFileSystem.DeleteFile(oldFile);
|
||||
// }
|
||||
|
||||
// // save the file in UTF-8
|
||||
// System.IO.File.WriteAllText(GetFilePath(template), masterPageContent, Encoding.UTF8);
|
||||
|
||||
// return masterPageContent;
|
||||
//}
|
||||
|
||||
//internal static string ConvertToMasterPageSyntax(ITemplate template)
|
||||
//{
|
||||
// string masterPageContent = GetMasterContentElement(template) + Environment.NewLine;
|
||||
|
||||
// masterPageContent += template.Content;
|
||||
|
||||
// // Parse the design for getitems
|
||||
// masterPageContent = EnsureMasterPageSyntax(template.Alias, masterPageContent);
|
||||
|
||||
// // append ending asp:content element
|
||||
// masterPageContent += Environment.NewLine + "</asp:Content>" + Environment.NewLine;
|
||||
|
||||
// return masterPageContent;
|
||||
//}
|
||||
|
||||
public static bool IsMasterPageSyntax(string code)
|
||||
{
|
||||
return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) ||
|
||||
code.InvariantContains("<umbraco:Item") || code.InvariantContains("<asp:") || code.InvariantContains("<umbraco:Macro");
|
||||
}
|
||||
|
||||
private static string GetMasterPageHeader(ITemplate template)
|
||||
{
|
||||
return String.Format("<%@ Master Language=\"C#\" MasterPageFile=\"{0}\" AutoEventWireup=\"true\" %>", ParentTemplatePath(template)) + Environment.NewLine;
|
||||
}
|
||||
|
||||
private static string ParentTemplatePath(ITemplate template)
|
||||
{
|
||||
var masterTemplate = DefaultMasterTemplate;
|
||||
if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
masterTemplate = SystemDirectories.Masterpages + "/" + template.MasterTemplateAlias + ".master";
|
||||
|
||||
return masterTemplate;
|
||||
}
|
||||
|
||||
private static string GetMasterContentElement(ITemplate template)
|
||||
{
|
||||
if (template.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
string masterAlias = template.MasterTemplateAlias;
|
||||
return
|
||||
String.Format("<asp:Content ContentPlaceHolderID=\"{0}ContentPlaceHolder\" runat=\"server\">", masterAlias);
|
||||
}
|
||||
else
|
||||
return
|
||||
String.Format("<asp:Content ContentPlaceHolderID=\"ContentPlaceHolderDefault\" runat=\"server\">");
|
||||
|
||||
}
|
||||
|
||||
//internal static string EnsureMasterPageSyntax(string templateAlias, string masterPageContent)
|
||||
//{
|
||||
// ReplaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", true);
|
||||
// ReplaceElement(ref masterPageContent, "?UMBRACO_GETITEM", "umbraco:Item", false);
|
||||
|
||||
// // Parse the design for macros
|
||||
// ReplaceElement(ref masterPageContent, "?UMBRACO_MACRO", "umbraco:Macro", true);
|
||||
// ReplaceElement(ref masterPageContent, "?UMBRACO_MACRO", "umbraco:Macro", false);
|
||||
|
||||
// // Parse the design for load childs
|
||||
// masterPageContent = masterPageContent.Replace("<?UMBRACO_TEMPLATE_LOAD_CHILD/>", CreateDefaultPlaceHolder(templateAlias))
|
||||
// .Replace("<?UMBRACO_TEMPLATE_LOAD_CHILD />", CreateDefaultPlaceHolder(templateAlias));
|
||||
// // Parse the design for aspnet forms
|
||||
// GetAspNetMasterPageForm(ref masterPageContent, templateAlias);
|
||||
// masterPageContent = masterPageContent.Replace("</?ASPNET_FORM>", "</form>");
|
||||
// // Parse the design for aspnet heads
|
||||
// masterPageContent = masterPageContent.Replace("</ASPNET_HEAD>", String.Format("<head id=\"{0}Head\" runat=\"server\">", templateAlias.Replace(" ", "")));
|
||||
// masterPageContent = masterPageContent.Replace("</?ASPNET_HEAD>", "</head>");
|
||||
// return masterPageContent;
|
||||
//}
|
||||
|
||||
|
||||
//private static void GetAspNetMasterPageForm(ref string design, string templateAlias)
|
||||
//{
|
||||
// var formElement = Regex.Match(design, GetElementRegExp("?ASPNET_FORM", false), RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
// if (string.IsNullOrEmpty(formElement.Value) == false)
|
||||
// {
|
||||
// string formReplace = String.Format("<form id=\"{0}Form\" runat=\"server\">", templateAlias.Replace(" ", ""));
|
||||
// if (formElement.Groups.Count == 0)
|
||||
// {
|
||||
// formReplace += "<asp:scriptmanager runat=\"server\"></asp:scriptmanager>";
|
||||
// }
|
||||
// design = design.Replace(formElement.Value, formReplace);
|
||||
// }
|
||||
//}
|
||||
|
||||
//private static string CreateDefaultPlaceHolder(string templateAlias)
|
||||
//{
|
||||
// return String.Format("<asp:ContentPlaceHolder ID=\"{0}ContentPlaceHolder\" runat=\"server\"></asp:ContentPlaceHolder>", templateAlias.Replace(" ", ""));
|
||||
//}
|
||||
|
||||
//private static void ReplaceElement(ref string design, string elementName, string newElementName, bool checkForQuotes)
|
||||
//{
|
||||
// var m =
|
||||
// Regex.Matches(design, GetElementRegExp(elementName, checkForQuotes),
|
||||
// RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
// foreach (Match match in m)
|
||||
// {
|
||||
// GroupCollection groups = match.Groups;
|
||||
|
||||
// // generate new element (compensate for a closing trail on single elements ("/"))
|
||||
// string elementAttributes = groups[1].Value;
|
||||
// // test for macro alias
|
||||
// if (elementName == "?UMBRACO_MACRO")
|
||||
// {
|
||||
// var tags = XmlHelper.GetAttributesFromElement(match.Value);
|
||||
// if (tags["macroAlias"] != null)
|
||||
// elementAttributes = String.Format(" Alias=\"{0}\"", tags["macroAlias"]) + elementAttributes;
|
||||
// else if (tags["macroalias"] != null)
|
||||
// elementAttributes = String.Format(" Alias=\"{0}\"", tags["macroalias"]) + elementAttributes;
|
||||
// }
|
||||
// string newElement = "<" + newElementName + " runat=\"server\" " + elementAttributes.Trim() + ">";
|
||||
// if (elementAttributes.EndsWith("/"))
|
||||
// {
|
||||
// elementAttributes = elementAttributes.Substring(0, elementAttributes.Length - 1);
|
||||
// }
|
||||
// else if (groups[0].Value.StartsWith("</"))
|
||||
// // It's a closing element, so generate that instead of a starting element
|
||||
// newElement = "</" + newElementName + ">";
|
||||
|
||||
// if (checkForQuotes)
|
||||
// {
|
||||
// // if it's inside quotes, we'll change element attribute quotes to single quotes
|
||||
// newElement = newElement.Replace("\"", "'");
|
||||
// newElement = String.Format("\"{0}\"", newElement);
|
||||
// }
|
||||
// design = design.Replace(match.Value, newElement);
|
||||
// }
|
||||
//}
|
||||
|
||||
//private static string GetElementRegExp(string elementName, bool checkForQuotes)
|
||||
//{
|
||||
// if (checkForQuotes)
|
||||
// return String.Format("\"<[^>\\s]*\\b{0}(\\b[^>]*)>\"", elementName);
|
||||
// else
|
||||
// return String.Format("<[^>\\s]*\\b{0}(\\b[^>]*)>", elementName);
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Core.IO
|
||||
public PhysicalFileSystem(string virtualRoot)
|
||||
{
|
||||
if (virtualRoot == null) throw new ArgumentNullException("virtualRoot");
|
||||
if (!virtualRoot.StartsWith("~/"))
|
||||
if (virtualRoot.StartsWith("~/") == false)
|
||||
throw new ArgumentException("The virtualRoot argument must be a virtual path and start with '~/'");
|
||||
|
||||
RootPath = IOHelper.MapPath(virtualRoot);
|
||||
@@ -65,7 +65,7 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public void DeleteDirectory(string path, bool recursive)
|
||||
{
|
||||
if (!DirectoryExists(path))
|
||||
if (DirectoryExists(path) == false)
|
||||
return;
|
||||
|
||||
try
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
public class SystemFiles
|
||||
{
|
||||
|
||||
[Obsolete("This file is no longer used and should not be accessed!")]
|
||||
public static string AccessXml
|
||||
{
|
||||
get
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
internal class ViewHelper
|
||||
{
|
||||
private readonly IFileSystem _viewFileSystem;
|
||||
|
||||
public ViewHelper(IFileSystem viewFileSystem)
|
||||
{
|
||||
if (viewFileSystem == null) throw new ArgumentNullException("viewFileSystem");
|
||||
_viewFileSystem = viewFileSystem;
|
||||
}
|
||||
|
||||
internal bool ViewExists(ITemplate t)
|
||||
{
|
||||
return _viewFileSystem.FileExists(ViewPath(t.Alias));
|
||||
}
|
||||
|
||||
[Obsolete("This is only used for legacy purposes and will be removed in future versions")]
|
||||
internal string GetPhysicalFilePath(ITemplate t)
|
||||
{
|
||||
return _viewFileSystem.GetFullPath(ViewPath(t.Alias));
|
||||
}
|
||||
|
||||
internal string GetFileContents(ITemplate t)
|
||||
{
|
||||
string viewContent = "";
|
||||
string path = ViewPath(t.Alias);
|
||||
|
||||
if (_viewFileSystem.FileExists(path))
|
||||
{
|
||||
using (var tr = new StreamReader(_viewFileSystem.OpenFile(path)))
|
||||
{
|
||||
viewContent = tr.ReadToEnd();
|
||||
tr.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return viewContent;
|
||||
}
|
||||
|
||||
public string CreateView(ITemplate t, bool overWrite = false)
|
||||
{
|
||||
string viewContent;
|
||||
string path = ViewPath(t.Alias);
|
||||
|
||||
if (_viewFileSystem.FileExists(path) == false || overWrite)
|
||||
{
|
||||
viewContent = SaveTemplateToFile(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var tr = new StreamReader(_viewFileSystem.OpenFile(path)))
|
||||
{
|
||||
viewContent = tr.ReadToEnd();
|
||||
tr.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return viewContent;
|
||||
}
|
||||
|
||||
internal static string GetDefaultFileContent(string layoutPageAlias = null)
|
||||
{
|
||||
var design = @"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
|
||||
@{
|
||||
Layout = null;
|
||||
}";
|
||||
|
||||
if (layoutPageAlias.IsNullOrWhiteSpace() == false)
|
||||
design = design.Replace("null", string.Format("\"{0}.cshtml\"", layoutPageAlias));
|
||||
|
||||
return design;
|
||||
}
|
||||
|
||||
private string SaveTemplateToFile(ITemplate template)
|
||||
{
|
||||
var design = template.Content.IsNullOrWhiteSpace() ? EnsureInheritedLayout(template) : template.Content;
|
||||
var path = ViewPath(template.Alias);
|
||||
|
||||
var data = Encoding.UTF8.GetBytes(design);
|
||||
var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
|
||||
|
||||
using (var ms = new MemoryStream(withBom))
|
||||
{
|
||||
_viewFileSystem.AddFile(path, ms, true);
|
||||
}
|
||||
|
||||
return design;
|
||||
}
|
||||
|
||||
public string UpdateViewFile(ITemplate t, string currentAlias = null)
|
||||
{
|
||||
var path = ViewPath(t.Alias);
|
||||
|
||||
if (string.IsNullOrEmpty(currentAlias) == false && currentAlias != t.Alias)
|
||||
{
|
||||
//then kill the old file..
|
||||
var oldFile = ViewPath(currentAlias);
|
||||
if (_viewFileSystem.FileExists(oldFile))
|
||||
_viewFileSystem.DeleteFile(oldFile);
|
||||
}
|
||||
|
||||
var data = Encoding.UTF8.GetBytes(t.Content);
|
||||
var withBom = Encoding.UTF8.GetPreamble().Concat(data).ToArray();
|
||||
|
||||
using (var ms = new MemoryStream(withBom))
|
||||
{
|
||||
_viewFileSystem.AddFile(path, ms, true);
|
||||
}
|
||||
return t.Content;
|
||||
}
|
||||
|
||||
internal void RemoveViewFile(string alias)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(alias) == false)
|
||||
{
|
||||
var file = ViewPath(alias);
|
||||
if (_viewFileSystem.FileExists(file))
|
||||
_viewFileSystem.DeleteFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
public string ViewPath(string alias)
|
||||
{
|
||||
return _viewFileSystem.GetRelativePath(alias.Replace(" ", "") + ".cshtml");
|
||||
|
||||
//return SystemDirectories.MvcViews + "/" + alias.Replace(" ", "") + ".cshtml";
|
||||
}
|
||||
|
||||
private string EnsureInheritedLayout(ITemplate template)
|
||||
{
|
||||
string design = template.Content;
|
||||
|
||||
if (string.IsNullOrEmpty(design))
|
||||
{
|
||||
design = GetDefaultFileContent(template.MasterTemplateAlias);
|
||||
}
|
||||
|
||||
return design;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows for outputting a normalized appdomainappid token in a log format
|
||||
/// </summary>
|
||||
public sealed class AppDomainTokenConverter : log4net.Util.PatternConverter
|
||||
{
|
||||
protected override void Convert(TextWriter writer, object state)
|
||||
{
|
||||
writer.Write(HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
internal class DebugDiagnosticsLogger : ILogger
|
||||
{
|
||||
public void Error(Type callingType, string message, Exception exception)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(message + Environment.NewLine + exception, callingType.ToString());
|
||||
}
|
||||
|
||||
public void Warn(Type callingType, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(message, formatItems.Select(x => x()).ToArray()), callingType.ToString());
|
||||
}
|
||||
|
||||
public void WarnWithException(Type callingType, string message, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(message + Environment.NewLine + e, formatItems.Select(x => x()).ToArray()), callingType.ToString());
|
||||
}
|
||||
|
||||
public void Info(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(generateMessage(), callingType.ToString());
|
||||
}
|
||||
|
||||
public void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(generateMessageFormat, formatItems.Select(x => x()).ToArray()), type.ToString());
|
||||
}
|
||||
|
||||
public void Debug(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(generateMessage(), callingType.ToString());
|
||||
}
|
||||
|
||||
public void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(string.Format(generateMessageFormat, formatItems.Select(x => x()).ToArray()), type.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for logging service.
|
||||
/// </summary>
|
||||
public interface ILogger
|
||||
{
|
||||
void Error(Type callingType, string message, Exception exception);
|
||||
|
||||
void Warn(Type callingType, string message, params Func<object>[] formatItems);
|
||||
|
||||
void WarnWithException(Type callingType, string message, Exception e, params Func<object>[] formatItems);
|
||||
|
||||
void Info(Type callingType, Func<string> generateMessage);
|
||||
|
||||
void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems);
|
||||
|
||||
void Debug(Type callingType, Func<string> generateMessage);
|
||||
|
||||
void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems);
|
||||
}
|
||||
}
|
||||
@@ -6,43 +6,14 @@ using log4net;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
///<summary>
|
||||
/// Used for logging
|
||||
///<summary>
|
||||
/// Used for logging, ILogger should be used instead but this is available for static access to logging
|
||||
///</summary>
|
||||
/// <remarks>
|
||||
/// this wraps ILogger
|
||||
/// </remarks>
|
||||
public static class LogHelper
|
||||
{
|
||||
///<summary>
|
||||
/// Returns a logger for the type specified
|
||||
///</summary>
|
||||
///<typeparam name="T"></typeparam>
|
||||
///<returns></returns>
|
||||
internal static ILog LoggerFor<T>()
|
||||
{
|
||||
return LogManager.GetLogger(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a logger for the object's type
|
||||
/// </summary>
|
||||
/// <param name="getTypeFromInstance"></param>
|
||||
/// <returns></returns>
|
||||
internal static ILog LoggerFor(object getTypeFromInstance)
|
||||
{
|
||||
if (getTypeFromInstance == null) throw new ArgumentNullException("getTypeFromInstance");
|
||||
|
||||
return LogManager.GetLogger(getTypeFromInstance.GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Useful if the logger itself is running on another thread
|
||||
/// </summary>
|
||||
/// <param name="generateMessageFormat"></param>
|
||||
/// <returns></returns>
|
||||
private static string PrefixThreadId(string generateMessageFormat)
|
||||
{
|
||||
return "[T" + Thread.CurrentThread.ManagedThreadId + "/D" + AppDomain.CurrentDomain.Id + "] " + generateMessageFormat;
|
||||
}
|
||||
|
||||
#region Error
|
||||
/// <summary>
|
||||
/// Adds an error log
|
||||
@@ -52,14 +23,14 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="exception"></param>
|
||||
public static void Error<T>(string message, Exception exception)
|
||||
{
|
||||
Error(typeof (T), message, exception);
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Error<T>(message, exception);
|
||||
}
|
||||
|
||||
public static void Error(Type callingType, string message, Exception exception)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger != null)
|
||||
logger.Error(PrefixThreadId(message), exception);
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Error(callingType, message, exception);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -68,11 +39,11 @@ namespace Umbraco.Core.Logging
|
||||
|
||||
public static void Warn(Type callingType, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsWarnEnabled) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Warn(callingType, message, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Warn(Type callingType, string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(callingType, "callingType");
|
||||
@@ -81,11 +52,10 @@ namespace Umbraco.Core.Logging
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn(callingType.Name, string.Format(message, formatItems.Select(x => x.Invoke()).ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsWarnEnabled) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Warn(callingType, message, formatItems);
|
||||
|
||||
}
|
||||
|
||||
@@ -94,6 +64,7 @@ namespace Umbraco.Core.Logging
|
||||
WarnWithException(callingType, message, false, e, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void WarnWithException(Type callingType, string message, bool showHttpTrace, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(e, "e");
|
||||
@@ -108,10 +79,8 @@ namespace Umbraco.Core.Logging
|
||||
e);
|
||||
}
|
||||
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsWarnEnabled) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.WarnFormat(PrefixThreadId(message) + ". Exception: " + e, executedParams);
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.WarnWithException(callingType, message, e, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -125,6 +94,7 @@ namespace Umbraco.Core.Logging
|
||||
Warn(typeof(T), message, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Warn<T>(string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
Warn(typeof(T), message, showHttpTrace, formatItems);
|
||||
@@ -134,6 +104,8 @@ namespace Umbraco.Core.Logging
|
||||
{
|
||||
WarnWithException(typeof(T), message, e, formatItems);
|
||||
}
|
||||
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void WarnWithException<T>(string message, bool showHttpTrace, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
WarnWithException(typeof(T), message, showHttpTrace, e, formatItems);
|
||||
@@ -160,9 +132,8 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="generateMessage"></param>
|
||||
public static void Info(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsInfoEnabled) return;
|
||||
logger.Info(PrefixThreadId(generateMessage.Invoke()));
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Info(callingType, generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -173,10 +144,8 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public static void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(type);
|
||||
if (logger == null || !logger.IsInfoEnabled) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.InfoFormat(PrefixThreadId(generateMessageFormat), executedParams);
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Info(type, generateMessageFormat, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -211,9 +180,8 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="generateMessage"></param>
|
||||
public static void Debug(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || !logger.IsDebugEnabled) return;
|
||||
logger.Debug(PrefixThreadId(generateMessage.Invoke()));
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Debug(callingType, generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -224,10 +192,8 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public static void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(type);
|
||||
if (logger == null || !logger.IsDebugEnabled) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.DebugFormat(PrefixThreadId(generateMessageFormat), executedParams);
|
||||
if (LoggerResolver.HasCurrent == false || LoggerResolver.Current.HasValue == false) return;
|
||||
LoggerResolver.Current.Logger.Debug(type, generateMessageFormat, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -250,6 +216,7 @@ namespace Umbraco.Core.Logging
|
||||
/// <param name="generateMessageFormat"></param>
|
||||
/// <param name="showHttpTrace"></param>
|
||||
/// <param name="formatItems"></param>
|
||||
[Obsolete("Warnings with http trace should not be used. This method will be removed in future versions")]
|
||||
public static void Debug<T>(string generateMessageFormat, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using log4net;
|
||||
using log4net.Config;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
///<summary>
|
||||
/// Used for logging
|
||||
///</summary>
|
||||
public class Logger : ILogger
|
||||
{
|
||||
public Logger(FileInfo log4NetConfigFile)
|
||||
{
|
||||
XmlConfigurator.Configure(log4NetConfigFile);
|
||||
}
|
||||
|
||||
private Logger()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a logger with the default log4net configuration discovered (i.e. from the web.config)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Logger CreateWithDefaultLog4NetConfiguration()
|
||||
{
|
||||
return new Logger();
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Returns a logger for the type specified
|
||||
///</summary>
|
||||
///<typeparam name="T"></typeparam>
|
||||
///<returns></returns>
|
||||
internal ILog LoggerFor<T>()
|
||||
{
|
||||
return LogManager.GetLogger(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a logger for the object's type
|
||||
/// </summary>
|
||||
/// <param name="getTypeFromInstance"></param>
|
||||
/// <returns></returns>
|
||||
internal ILog LoggerFor(object getTypeFromInstance)
|
||||
{
|
||||
if (getTypeFromInstance == null) throw new ArgumentNullException("getTypeFromInstance");
|
||||
|
||||
return LogManager.GetLogger(getTypeFromInstance.GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Useful if the logger itself is running on another thread
|
||||
/// </summary>
|
||||
/// <param name="generateMessageFormat"></param>
|
||||
/// <returns></returns>
|
||||
private string PrefixThreadId(string generateMessageFormat)
|
||||
{
|
||||
return "[Thread " + Thread.CurrentThread.ManagedThreadId + "] " + generateMessageFormat;
|
||||
}
|
||||
|
||||
public void Error(Type callingType, string message, Exception exception)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger != null)
|
||||
logger.Error(PrefixThreadId(message), exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Warn(Type callingType, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
}
|
||||
|
||||
public void Warn(Type callingType, string message, bool showHttpTrace, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(callingType, "callingType");
|
||||
Mandate.ParameterNotNullOrEmpty(message, "message");
|
||||
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn(callingType.Name, string.Format(message, formatItems.Select(x => x.Invoke()).ToArray()));
|
||||
}
|
||||
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
logger.WarnFormat(PrefixThreadId(message), formatItems.Select(x => x.Invoke()).ToArray());
|
||||
|
||||
}
|
||||
|
||||
public void WarnWithException(Type callingType, string message, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
Mandate.ParameterNotNull(e, "e");
|
||||
Mandate.ParameterNotNull(callingType, "callingType");
|
||||
Mandate.ParameterNotNullOrEmpty(message, "message");
|
||||
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.WarnFormat(PrefixThreadId(message) + ". Exception: " + e, executedParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="callingType"></param>
|
||||
/// <param name="generateMessage"></param>
|
||||
public void Info(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsInfoEnabled == false) return;
|
||||
logger.Info(PrefixThreadId(generateMessage.Invoke()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="type">The type for the logging namespace.</param>
|
||||
/// <param name="generateMessageFormat">The message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public void Info(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(type);
|
||||
if (logger == null || logger.IsInfoEnabled == false) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.InfoFormat(PrefixThreadId(generateMessageFormat), executedParams);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Debugs if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="callingType"></param>
|
||||
/// <param name="generateMessage"></param>
|
||||
public void Debug(Type callingType, Func<string> generateMessage)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsDebugEnabled == false) return;
|
||||
logger.Debug(PrefixThreadId(generateMessage.Invoke()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs if tracing is enabled.
|
||||
/// </summary>
|
||||
/// <param name="type">The type for the logging namespace.</param>
|
||||
/// <param name="generateMessageFormat">The message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
public void Debug(Type type, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
var logger = LogManager.GetLogger(type);
|
||||
if (logger == null || logger.IsDebugEnabled == false) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.DebugFormat(PrefixThreadId(generateMessageFormat), executedParams);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows for strongly typed log sources
|
||||
/// </summary>
|
||||
public static class LoggerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an error log
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="exception"></param>
|
||||
public static void Error<T>(this ILogger logger, string message, Exception exception)
|
||||
{
|
||||
logger.Error(typeof(T), message, exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a warn log
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="formatItems"></param>
|
||||
public static void Warn<T>(this ILogger logger, string message, params Func<object>[] formatItems)
|
||||
{
|
||||
logger.Warn(typeof(T), message, formatItems);
|
||||
}
|
||||
|
||||
public static void WarnWithException<T>(this ILogger logger, string message, Exception e, params Func<object>[] formatItems)
|
||||
{
|
||||
logger.WarnWithException(typeof(T), message, e, formatItems);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="generateMessageFormat">The generate message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Info<T>(this ILogger logger, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
logger.Info(typeof(T), generateMessageFormat, formatItems);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traces a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="generateMessage">The delegate to generate a message.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Info<T>(this ILogger logger, Func<string> generateMessage)
|
||||
{
|
||||
logger.Info(typeof(T), generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs a message, only generating the message if tracing is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="generateMessage">The delegate to generate a message.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Debug<T>(this ILogger logger, Func<string> generateMessage)
|
||||
{
|
||||
logger.Debug(typeof(T), generateMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugs a message, only generating the message if debug is actually enabled. Use this method to avoid calling any long-running methods such as "ToDebugString" if logging is disabled.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="generateMessageFormat">The generate message format.</param>
|
||||
/// <param name="formatItems">The format items.</param>
|
||||
/// <remarks></remarks>
|
||||
public static void Debug<T>(this ILogger logger, string generateMessageFormat, params Func<object>[] formatItems)
|
||||
{
|
||||
logger.Debug(typeof(T), generateMessageFormat, formatItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
public sealed class LoggerResolver : SingleObjectResolverBase<LoggerResolver, ILogger>
|
||||
{
|
||||
public LoggerResolver(ILogger logger)
|
||||
: base(logger)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method allowing to change the logger during startup
|
||||
/// </summary>
|
||||
/// <param name="profiler"></param>
|
||||
internal void SetLogger(ILogger profiler)
|
||||
{
|
||||
Value = profiler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current logger
|
||||
/// </summary>
|
||||
public ILogger Logger
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
internal class OwinLogger : Microsoft.Owin.Logging.ILogger
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly Lazy<Type> _type;
|
||||
|
||||
public OwinLogger(ILogger logger, Lazy<Type> type)
|
||||
{
|
||||
_logger = logger;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates most logging patterns to a single method. This must be compatible with the Func representation in the OWIN environment.
|
||||
/// To check IsEnabled call WriteCore with only TraceEventType and check the return value, no event will be written.
|
||||
/// </summary>
|
||||
/// <param name="eventType"/><param name="eventId"/><param name="state"/><param name="exception"/><param name="formatter"/>
|
||||
/// <returns/>
|
||||
public bool WriteCore(TraceEventType eventType, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
|
||||
{
|
||||
if (state == null) state = "";
|
||||
switch (eventType)
|
||||
{
|
||||
case TraceEventType.Critical:
|
||||
_logger.Error(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state), exception ?? new Exception("Critical error"));
|
||||
return true;
|
||||
case TraceEventType.Error:
|
||||
_logger.Error(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state), exception ?? new Exception("Error"));
|
||||
return true;
|
||||
case TraceEventType.Warning:
|
||||
_logger.Warn(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Information:
|
||||
_logger.Info(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Verbose:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Start:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Stop:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Suspend:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Resume:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
case TraceEventType.Transfer:
|
||||
_logger.Debug(_type.Value, string.Format("Event Id: {0}, state: {1}", eventId, state));
|
||||
return true;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("eventType");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Owin.Logging;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
internal class OwinLoggerFactory : ILoggerFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new ILogger instance of the given name.
|
||||
/// </summary>
|
||||
/// <param name="name"/>
|
||||
/// <returns/>
|
||||
public Microsoft.Owin.Logging.ILogger Create(string name)
|
||||
{
|
||||
return new OwinLogger(
|
||||
LoggerResolver.HasCurrent ? LoggerResolver.Current.Logger : new DebugDiagnosticsLogger(),
|
||||
new Lazy<Type>(() => Type.GetType(name) ?? typeof (OwinLogger)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Umbraco.Core.Profiling;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to create DisposableTimer instances for debugging or tracing durations
|
||||
/// </summary>
|
||||
public sealed class ProfilingLogger
|
||||
{
|
||||
public ILogger Logger { get; private set; }
|
||||
public IProfiler Profiler { get; private set; }
|
||||
|
||||
public ProfilingLogger(ILogger logger, IProfiler profiler)
|
||||
{
|
||||
Logger = logger;
|
||||
Profiler = profiler;
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (profiler == null) throw new ArgumentNullException("profiler");
|
||||
}
|
||||
|
||||
public DisposableTimer TraceDuration<T>(string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
public DisposableTimer TraceDuration<T>(string startMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, typeof(T), startMessage, "Complete");
|
||||
}
|
||||
|
||||
public DisposableTimer TraceDuration(Type loggerType, string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Info, Profiler, loggerType, startMessage, completeMessage);
|
||||
}
|
||||
|
||||
public DisposableTimer DebugDuration<T>(string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, typeof(T), startMessage, completeMessage);
|
||||
}
|
||||
|
||||
public DisposableTimer DebugDuration<T>(string startMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, typeof(T), startMessage, "Complete");
|
||||
}
|
||||
|
||||
public DisposableTimer DebugDuration(Type loggerType, string startMessage, string completeMessage)
|
||||
{
|
||||
return new DisposableTimer(Logger, DisposableTimer.LogType.Debug, Profiler, loggerType, startMessage, completeMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
@@ -18,13 +19,14 @@ namespace Umbraco.Core.Macros
|
||||
/// </remarks>
|
||||
internal sealed class MacroFieldEditorsResolver : LazyManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="macroEditors"></param>
|
||||
internal MacroFieldEditorsResolver(Func<IEnumerable<Type>> macroEditors)
|
||||
: base(macroEditors, ObjectLifetimeScope.Transient)
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="macroEditors"></param>
|
||||
internal MacroFieldEditorsResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> macroEditors)
|
||||
: base(serviceProvider, logger, macroEditors, ObjectLifetimeScope.Transient)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
@@ -70,10 +72,10 @@ namespace Umbraco.Core.Macros
|
||||
internal Control GetMacroRenderControlByType(PersistableMacroProperty prop, string uniqueId)
|
||||
{
|
||||
var m = MacroControlTypes.FindLast(macroGuiCcontrol => macroGuiCcontrol.ToString() == string.Format("{0}.{1}", prop.AssemblyName, prop.TypeName));
|
||||
var instance = PluginManager.Current.CreateInstance<IMacroGuiRendering>(m);
|
||||
var instance = ServiceProvider.GetService(m) as IMacroGuiRendering;
|
||||
if (instance != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(prop.Value))
|
||||
if (string.IsNullOrEmpty(prop.Value) == false)
|
||||
{
|
||||
instance.Value = HttpUtility.HtmlDecode(prop.Value);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Macros
|
||||
@@ -9,13 +10,14 @@ namespace Umbraco.Core.Macros
|
||||
/// </summary>
|
||||
internal sealed class XsltExtensionsResolver : LazyManyObjectsResolverBase<XsltExtensionsResolver, XsltExtension>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="packageActions"></param>
|
||||
internal XsltExtensionsResolver(Func<IEnumerable<Type>> packageActions)
|
||||
: base(packageActions, ObjectLifetimeScope.Application)
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="packageActions"></param>
|
||||
internal XsltExtensionsResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> packageActions)
|
||||
: base(serviceProvider, logger, packageActions, ObjectLifetimeScope.Application)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
@@ -7,10 +8,17 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
internal class ManifestWatcher : DisposableObject
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly List<FileSystemWatcher> _fws = new List<FileSystemWatcher>();
|
||||
private static volatile bool _isRestarting = false;
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
public ManifestWatcher(ILogger logger)
|
||||
{
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Start(params string[] packageFolders)
|
||||
{
|
||||
foreach (var packageFolder in packageFolders)
|
||||
@@ -43,7 +51,7 @@ namespace Umbraco.Core.Manifest
|
||||
{
|
||||
_isRestarting = true;
|
||||
|
||||
LogHelper.Info<ManifestWatcher>("manifest has changed, app pool is restarting (" + e.FullPath + ")");
|
||||
_logger.Info<ManifestWatcher>("manifest has changed, app pool is restarting (" + e.FullPath + ")");
|
||||
HttpRuntime.UnloadAppDomain();
|
||||
Dispose();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public sealed class AuditItem : Entity, IAggregateRoot
|
||||
{
|
||||
public AuditItem(int objectId, string comment, AuditType type, int userId)
|
||||
{
|
||||
Id = objectId;
|
||||
Comment = comment;
|
||||
AuditType = type;
|
||||
UserId = userId;
|
||||
}
|
||||
|
||||
public string Comment { get; private set; }
|
||||
public AuditType AuditType { get; private set; }
|
||||
public int UserId { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Enums for vailable types of auditing
|
||||
/// </summary>
|
||||
public enum AuditType
|
||||
{
|
||||
/// <summary>
|
||||
/// Used when new nodes are added
|
||||
/// </summary>
|
||||
New,
|
||||
/// <summary>
|
||||
/// Used when nodes are saved
|
||||
/// </summary>
|
||||
Save,
|
||||
/// <summary>
|
||||
/// Used when nodes are opened
|
||||
/// </summary>
|
||||
Open,
|
||||
/// <summary>
|
||||
/// Used when nodes are deleted
|
||||
/// </summary>
|
||||
Delete,
|
||||
/// <summary>
|
||||
/// Used when nodes are published
|
||||
/// </summary>
|
||||
Publish,
|
||||
/// <summary>
|
||||
/// Used when nodes are send to publishing
|
||||
/// </summary>
|
||||
SendToPublish,
|
||||
/// <summary>
|
||||
/// Used when nodes are unpublished
|
||||
/// </summary>
|
||||
UnPublish,
|
||||
/// <summary>
|
||||
/// Used when nodes are moved
|
||||
/// </summary>
|
||||
Move,
|
||||
/// <summary>
|
||||
/// Used when nodes are copied
|
||||
/// </summary>
|
||||
Copy,
|
||||
/// <summary>
|
||||
/// Used when nodes are assígned a domain
|
||||
/// </summary>
|
||||
AssignDomain,
|
||||
/// <summary>
|
||||
/// Used when public access are changed for a node
|
||||
/// </summary>
|
||||
PublicAccess,
|
||||
/// <summary>
|
||||
/// Used when nodes are sorted
|
||||
/// </summary>
|
||||
Sort,
|
||||
/// <summary>
|
||||
/// Used when a notification are send to a user
|
||||
/// </summary>
|
||||
Notify,
|
||||
/// <summary>
|
||||
/// General system notification
|
||||
/// </summary>
|
||||
System,
|
||||
/// <summary>
|
||||
/// Used when a node's content is rolled back to a previous version
|
||||
/// </summary>
|
||||
RollBack,
|
||||
/// <summary>
|
||||
/// Used when a package is installed
|
||||
/// </summary>
|
||||
PackagerInstall,
|
||||
/// <summary>
|
||||
/// Used when a package is uninstalled
|
||||
/// </summary>
|
||||
PackagerUninstall,
|
||||
/// <summary>
|
||||
/// Used when a node is send to translation
|
||||
/// </summary>
|
||||
SendToTranslate,
|
||||
/// <summary>
|
||||
/// Use this log action for custom log messages that should be shown in the audit trail
|
||||
/// </summary>
|
||||
Custom
|
||||
}
|
||||
}
|
||||
@@ -160,10 +160,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Language of the data contained within this Content object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Left internal until multilingual support is implemented.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
[Obsolete("This is not used and will be removed from the codebase in future versions")]
|
||||
public string Language
|
||||
{
|
||||
get { return _language; }
|
||||
@@ -321,6 +318,17 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
internal PublishedState PublishedState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unique identifier of the published version, if any.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public Guid PublishedVersionGuid { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content has a published version.
|
||||
/// </summary>
|
||||
public bool HasPublishedVersion { get { return PublishedVersionGuid != default(Guid); } }
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Trashed state of the content object
|
||||
/// </summary>
|
||||
|
||||
@@ -657,12 +657,10 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns>True if the content has any published versiom otherwise False</returns>
|
||||
[Obsolete("Use the HasPublishedVersion property.", false)]
|
||||
public static bool HasPublishedVersion(this IContent content)
|
||||
{
|
||||
if (content.HasIdentity == false)
|
||||
return false;
|
||||
|
||||
return ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
return content.HasPublishedVersion;
|
||||
}
|
||||
|
||||
#region Tag methods
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal static class CssCompactor
|
||||
{
|
||||
#region CssCompactor.Options
|
||||
|
||||
[Flags]
|
||||
public enum Options
|
||||
{
|
||||
None = 0x00,
|
||||
PrettyPrint = 0x01,
|
||||
Overwrite = 0x02
|
||||
}
|
||||
|
||||
#endregion CssCompactor.Options
|
||||
|
||||
#region Public Methods
|
||||
|
||||
internal static List<ParseException> Compact(string inputFile, string outputFile, string copyright, string timeStamp, CssCompactor.Options options)
|
||||
{
|
||||
if (!System.IO.File.Exists(inputFile))
|
||||
{
|
||||
throw new FileNotFoundException(String.Format("File (\"{0}\") not found.", inputFile), inputFile);
|
||||
}
|
||||
|
||||
if ((options & CssCompactor.Options.Overwrite) == 0x0 && System.IO.File.Exists(outputFile))
|
||||
{
|
||||
throw new AccessViolationException(String.Format("File (\"{0}\") already exists.", outputFile));
|
||||
}
|
||||
|
||||
if (inputFile.Equals(outputFile, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new ApplicationException("Input and output file are set to the same path.");
|
||||
}
|
||||
|
||||
FileUtility.PrepSavePath(outputFile);
|
||||
using (TextWriter output = System.IO.File.CreateText(outputFile))
|
||||
{
|
||||
return CssCompactor.Compact(inputFile, null, output, copyright, timeStamp, options);
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<ParseException> Compact(string inputFile, string inputSource, TextWriter output, string copyright, string timeStamp, CssCompactor.Options options)
|
||||
{
|
||||
if (output == null)
|
||||
{
|
||||
throw new NullReferenceException("Output TextWriter was null.");
|
||||
}
|
||||
|
||||
// write out header with copyright and timestamp
|
||||
CssCompactor.WriteHeader(output, copyright, timeStamp);
|
||||
|
||||
// verify, compact and write out results
|
||||
CssParser parser = new CssParser(inputFile, inputSource);
|
||||
parser.Write(output, options);
|
||||
|
||||
// return any errors
|
||||
return parser.Errors;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private static void WriteHeader(TextWriter writer, string copyright, string timeStamp)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(copyright) || !String.IsNullOrEmpty(timeStamp))
|
||||
{
|
||||
int width = 6;
|
||||
if (!String.IsNullOrEmpty(copyright))
|
||||
{
|
||||
copyright = copyright.Replace("*/", "");// make sure not to nest commments
|
||||
width = Math.Max(copyright.Length + 6, width);
|
||||
}
|
||||
if (!String.IsNullOrEmpty(timeStamp))
|
||||
{
|
||||
timeStamp = DateTime.Now.ToString(timeStamp).Replace("*/", "");// make sure not to nest commments
|
||||
width = Math.Max(timeStamp.Length + 6, width);
|
||||
}
|
||||
|
||||
writer.WriteLine("/*".PadRight(width, '-') + "*\\");
|
||||
|
||||
if (!String.IsNullOrEmpty(copyright))
|
||||
{
|
||||
writer.WriteLine("\t" + copyright);
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(timeStamp))
|
||||
{
|
||||
writer.WriteLine("\t" + timeStamp);
|
||||
}
|
||||
|
||||
writer.WriteLine("\\*".PadRight(width, '-') + "*/");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,653 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal class CssParser
|
||||
{
|
||||
#region Constants
|
||||
|
||||
// this defines comments for CSS
|
||||
private static readonly ReadFilter[] ReadFilters = new ReadFilter[] { new ReadFilter("/*", "*/") };
|
||||
private readonly object SyncLock = new object();
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Fields
|
||||
|
||||
private readonly List<ParseException> errors = new List<ParseException>();
|
||||
private LineReader reader;
|
||||
private CssStyleSheet styleSheet;
|
||||
private string fileContent;
|
||||
private string source;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="fileContent">path to source</param>
|
||||
public CssParser(string fileContent)
|
||||
: this(fileContent, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="fileContent">path to source</param>
|
||||
/// <param name="source">actual source</param>
|
||||
public CssParser(string fileContent, string source)
|
||||
{
|
||||
this.fileContent = fileContent;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<ParseException> Errors
|
||||
{
|
||||
get { return this.errors; }
|
||||
}
|
||||
|
||||
public CssStyleSheet StyleSheet
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.styleSheet == null)
|
||||
{
|
||||
lock (this.SyncLock)
|
||||
{
|
||||
// check again in case race condition
|
||||
// so we don't parse twice
|
||||
if (this.styleSheet == null)
|
||||
{
|
||||
this.styleSheet = this.ParseStyleSheet();
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.styleSheet;
|
||||
}
|
||||
}
|
||||
|
||||
private int Position
|
||||
{
|
||||
get { return this.reader.Position; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Parse Methods
|
||||
|
||||
#region StyleSheet
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) stylesheet : [ CDO | CDC | S | statement ]*;
|
||||
/// </summary>
|
||||
/// <returns>CSS StyleSheet parse tree</returns>
|
||||
private CssStyleSheet ParseStyleSheet()
|
||||
{
|
||||
CssStyleSheet styleSheet = new CssStyleSheet();
|
||||
using (this.reader = new LineReader(this.fileContent, this.source, CssParser.ReadFilters))
|
||||
{
|
||||
this.reader.NormalizeWhiteSpace = true;
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Stopwatch watch = System.Diagnostics.Stopwatch.StartNew();
|
||||
#endif
|
||||
|
||||
char ch;
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '\uFEFF': // BOM (UTF byte order mark)
|
||||
case '\t': //TAB
|
||||
case '\n': //LF
|
||||
case '\r': //CR
|
||||
case ' ': //Space
|
||||
{
|
||||
// skip whitespace
|
||||
continue;
|
||||
}
|
||||
case '<':
|
||||
{
|
||||
// CDO (Char Data Open?)
|
||||
if (!this.Read(out ch) || ch != '-' ||
|
||||
!this.Read(out ch) || ch != '-')
|
||||
{
|
||||
throw new SyntaxError("Expected \"<!--\"", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case '-':
|
||||
{
|
||||
// CDC (Char Data Close?)
|
||||
if (!this.Read(out ch) || ch != '-' ||
|
||||
!this.Read(out ch) || ch != '>')
|
||||
{
|
||||
throw new SyntaxError("Expected \"-->\"", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
{
|
||||
try
|
||||
{
|
||||
CssStatement statement = this.ParseStatement();
|
||||
styleSheet.Statements.Add(statement);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
this.errors.Add(ex);
|
||||
|
||||
while (this.Read(out ch) && ch != '}')
|
||||
{
|
||||
// restabilize on next statement
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
watch.Stop();
|
||||
Console.WriteLine("CSS parse duration: {0} ms for {1} chars", watch.ElapsedMilliseconds, this.reader.Length);
|
||||
#endif
|
||||
}
|
||||
|
||||
this.reader = null;
|
||||
this.source = null;
|
||||
|
||||
return styleSheet;
|
||||
}
|
||||
|
||||
#endregion StyleSheet
|
||||
|
||||
#region Statement
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) statement : ruleset | at-rule;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssStatement ParseStatement()
|
||||
{
|
||||
if (this.reader.Current == '@')
|
||||
{
|
||||
return this.ParseAtRule();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PutBack();
|
||||
return this.ParseRuleSet();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Statement
|
||||
|
||||
#region At-Rule
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) at-rule : ATKEYWORD S* any* [ block | ';' S* ];
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// NOTE: each at-rule might parse differently according to CSS3
|
||||
/// The @media block for example contains a block of statements
|
||||
/// while other at-rules with a block contain a block of declarations
|
||||
/// </remarks>
|
||||
private CssAtRule ParseAtRule()
|
||||
{
|
||||
CssAtRule atRule = new CssAtRule();
|
||||
int start = this.Position + 1;// start with first char of ident
|
||||
|
||||
char ch;
|
||||
while (this.Read(out ch) && !Char.IsWhiteSpace(ch))
|
||||
{
|
||||
// continue consuming
|
||||
}
|
||||
|
||||
atRule.Ident = this.Copy(start);
|
||||
|
||||
while (this.Read(out ch) && Char.IsWhiteSpace(ch))
|
||||
{
|
||||
// consuming whitespace
|
||||
}
|
||||
|
||||
start = this.Position;// start with current char
|
||||
do
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '{': //Block Begin
|
||||
{
|
||||
atRule.Value = this.Copy(start);
|
||||
|
||||
bool containsRuleSets = String.Equals(atRule.Ident, CssAtRule.MediaIdent, StringComparison.Ordinal);
|
||||
while (true)
|
||||
{
|
||||
while (this.Read(out ch) && Char.IsWhiteSpace(ch))
|
||||
{
|
||||
// consume whitespace
|
||||
}
|
||||
|
||||
if (ch == '}')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (containsRuleSets)
|
||||
{
|
||||
// includes @media
|
||||
CssStatement statement = this.ParseStatement();
|
||||
atRule.Block.Values.Add(statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
// includes @font-face, @page
|
||||
this.PutBack();
|
||||
CssDeclaration declaration = this.ParseDeclaration();
|
||||
atRule.Block.Values.Add(declaration);
|
||||
}
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
this.errors.Add(ex);
|
||||
|
||||
while (this.Read(out ch) && ch != '}')
|
||||
{
|
||||
// restabilize on block end
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return atRule;
|
||||
}
|
||||
case ';': //At-Rule End
|
||||
{
|
||||
atRule.Value = this.Copy(start);
|
||||
return atRule;
|
||||
}
|
||||
}
|
||||
} while (this.Read(out ch));
|
||||
|
||||
throw new UnexpectedEndOfFile("Unclosed At-Rule", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
#endregion At-Rule
|
||||
|
||||
#region RuleSet
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) ruleset : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssRuleSet ParseRuleSet()
|
||||
{
|
||||
char ch;
|
||||
CssRuleSet ruleSet = new CssRuleSet();
|
||||
|
||||
ParseSelectors:
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
CssSelector selector = this.ParseSelector();
|
||||
if (selector == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
ruleSet.Selectors.Add(selector);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
this.errors.Add(ex);
|
||||
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
// restabalize on next rulset
|
||||
switch (ch)
|
||||
{
|
||||
case ',':
|
||||
{
|
||||
// continue parsing rest of Selectors
|
||||
goto ParseSelectors;
|
||||
}
|
||||
case '{':
|
||||
{
|
||||
goto ParseDeclarations;
|
||||
}
|
||||
//case ':':// keep going
|
||||
case ';':
|
||||
case '}':
|
||||
{
|
||||
throw new SyntaxError("Invalid selector list", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParseDeclarations:
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
CssDeclaration declaration = this.ParseDeclaration();
|
||||
if (declaration == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
ruleSet.Declarations.Add(declaration);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
this.errors.Add(ex);
|
||||
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
// restabalize on next declaration
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
{
|
||||
throw new SyntaxError("Invalid ruleset", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
//case ':':// keep going
|
||||
case ';':
|
||||
{
|
||||
// continue parsing rest of delcarations
|
||||
goto ParseDeclarations;
|
||||
}
|
||||
case '}':
|
||||
{
|
||||
// no more declarations
|
||||
return ruleSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ruleSet;
|
||||
}
|
||||
|
||||
#endregion RuleSet
|
||||
|
||||
#region Selector
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) selector: any+;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssSelector ParseSelector()
|
||||
{
|
||||
CssSelector selector = new CssSelector();
|
||||
char ch;
|
||||
|
||||
while (this.Read(out ch) && (Char.IsWhiteSpace(ch) || ch == ','))
|
||||
{
|
||||
// skip whitespace, and empty selectors
|
||||
}
|
||||
|
||||
// consume property name
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
{
|
||||
// no more declarations
|
||||
return null;
|
||||
}
|
||||
//case ':':// pseudoclass
|
||||
case ';':
|
||||
case '}':
|
||||
{
|
||||
throw new SyntaxError("Invalid chars in selector", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
}
|
||||
|
||||
int start = this.Position;// start with current char
|
||||
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
// continue consuming selector
|
||||
switch (ch)
|
||||
{
|
||||
case ',':
|
||||
case '{':
|
||||
{
|
||||
selector.Value = this.Copy(start);
|
||||
if (ch == '{')
|
||||
{
|
||||
this.PutBack();
|
||||
}
|
||||
return selector;
|
||||
}
|
||||
//case ':':// pseudoclass
|
||||
case ';':
|
||||
case '}':
|
||||
{
|
||||
throw new SyntaxError("Invalid selector", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new UnexpectedEndOfFile("Unclosed ruleset", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
#endregion Selector
|
||||
|
||||
#region Declaration
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) declaration : property ':' S* value;
|
||||
/// (BNF) property : IDENT S*;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssDeclaration ParseDeclaration()
|
||||
{
|
||||
CssDeclaration declaration = new CssDeclaration();
|
||||
char ch;
|
||||
|
||||
while (this.Read(out ch) && (Char.IsWhiteSpace(ch) || ch == ';'))
|
||||
{
|
||||
// skip whitespace, and empty declarations
|
||||
}
|
||||
|
||||
// consume property name
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
case ':':
|
||||
//case ';':
|
||||
{
|
||||
throw new SyntaxError("Declaration missing property name", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
case '}':
|
||||
{
|
||||
// no more declarations
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// read property, starting with current char
|
||||
int start = this.Position;
|
||||
while (this.Read(out ch) && !Char.IsWhiteSpace(ch) && ch != ':')
|
||||
{
|
||||
// consume property name
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
//case ':':
|
||||
case ';':
|
||||
{
|
||||
throw new SyntaxError("Invalid CSS property name: " + this.Copy(start), this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
case '}':
|
||||
{
|
||||
this.PutBack();
|
||||
goto case ';';
|
||||
}
|
||||
}
|
||||
}
|
||||
declaration.Property = this.Copy(start);
|
||||
|
||||
if (Char.IsWhiteSpace(ch))
|
||||
{
|
||||
while (this.Read(out ch) && (Char.IsWhiteSpace(ch)))
|
||||
{
|
||||
// skip whitespace
|
||||
}
|
||||
}
|
||||
|
||||
if (ch != ':')
|
||||
{
|
||||
// missing the property delim and value
|
||||
|
||||
if (ch == ';' || ch == '}')
|
||||
{
|
||||
// these are good chars for resyncing
|
||||
// so put them back on the stream to
|
||||
// not create subsequent errors
|
||||
this.PutBack();
|
||||
}
|
||||
throw new SyntaxError("Expected <property> : <value>", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
CssValueList value = this.ParseValue();
|
||||
declaration.Value = value;
|
||||
|
||||
return declaration;
|
||||
}
|
||||
|
||||
#endregion Declaration
|
||||
|
||||
#region Value
|
||||
|
||||
/// <summary>
|
||||
/// (BNF) value : [ any | block | ATKEYWORD S* ]+;
|
||||
/// (BNF) any : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
|
||||
/// | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
|
||||
/// | FUNCTION S* any* ')' | DASHMATCH | '(' S* any* ')'
|
||||
/// | '[' S* any* ']' ] S*;
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private CssValueList ParseValue()
|
||||
{
|
||||
CssValueList value = new CssValueList();
|
||||
char ch;
|
||||
|
||||
while (this.Read(out ch) && Char.IsWhiteSpace(ch))
|
||||
{
|
||||
// skip whitespace, and empty declarations
|
||||
}
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
case ':':
|
||||
case ';':
|
||||
case '}':
|
||||
{
|
||||
throw new SyntaxError("Invalid char in CSS property value: '" + ch + "'", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
}
|
||||
|
||||
// read value, starting with current char
|
||||
int start = this.Position;
|
||||
while (this.Read(out ch))
|
||||
{
|
||||
// consume declaration value
|
||||
|
||||
switch (ch)
|
||||
{
|
||||
case '{':
|
||||
//case ':':// leave in for "filter: progid:DXImageTransform.Microsoft..."
|
||||
{
|
||||
throw new SyntaxError("Invalid CSS property value: " + this.Copy(start), this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
case '}':
|
||||
case ';':
|
||||
{
|
||||
//Should this parse the value further?
|
||||
|
||||
CssString any = new CssString();
|
||||
any.Value = this.Copy(start);
|
||||
value.Values.Add(any);
|
||||
if (ch == '}')
|
||||
{
|
||||
this.PutBack();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new UnexpectedEndOfFile("Unclosed declaration", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
#endregion Value
|
||||
|
||||
#endregion Parse Methods
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
this.StyleSheet.Write(writer, options);
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region Reader Methods
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ch"></param>
|
||||
/// <returns>Success</returns>
|
||||
private bool Read(out char ch)
|
||||
{
|
||||
if (this.reader.EndOfFile)
|
||||
{
|
||||
throw new UnexpectedEndOfFile("Unexpected end of file", this.reader.FilePath, this.reader.Line, this.reader.Column);
|
||||
}
|
||||
|
||||
int c = this.reader.Read();
|
||||
if (c < 0)
|
||||
{
|
||||
ch = '\0';
|
||||
return false;
|
||||
}
|
||||
ch = (char)c;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies chars from start until the position before the current position
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string Copy(int start)
|
||||
{
|
||||
// read block
|
||||
return this.reader.Copy(start, this.reader.Position - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Put one character back
|
||||
/// </summary>
|
||||
private void PutBack()
|
||||
{
|
||||
this.reader.PutBack();
|
||||
}
|
||||
|
||||
#endregion Reader Methods
|
||||
}
|
||||
}
|
||||
@@ -1,429 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
#region Base Types
|
||||
|
||||
/// <summary>
|
||||
/// CSS3 inconsistently specifies more than one grammar:
|
||||
/// http://www.w3.org/TR/css3-syntax/#style
|
||||
/// http://www.w3.org/TR/css3-syntax/#detailed-grammar
|
||||
/// </summary>
|
||||
internal abstract class CssSyntax
|
||||
{
|
||||
#region Methods
|
||||
|
||||
public abstract void Write(TextWriter writer, CssCompactor.Options options);
|
||||
|
||||
protected static bool IsPrettyPrint(CssCompactor.Options options)
|
||||
{
|
||||
return (options & CssCompactor.Options.PrettyPrint) > 0;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region Object Overrides
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var writer = new StringWriter();
|
||||
|
||||
this.Write(writer, CssCompactor.Options.PrettyPrint);
|
||||
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
#endregion Object Overrides
|
||||
}
|
||||
|
||||
internal interface ICssValue
|
||||
{
|
||||
#region Methods
|
||||
|
||||
void Write(TextWriter writer, CssCompactor.Options options);
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssString : CssSyntax
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private string value;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public virtual string Value
|
||||
{
|
||||
get { return this.value; }
|
||||
set { this.value = value; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
writer.Write(this.Value);
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
#endregion Base Types
|
||||
|
||||
#region Grammar
|
||||
|
||||
internal class CssStyleSheet : CssSyntax
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<CssStatement> statements = new List<CssStatement>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<CssStatement> Statements
|
||||
{
|
||||
get { return this.statements; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
|
||||
foreach (CssStatement statement in this.statements)
|
||||
{
|
||||
statement.Write(writer, options);
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal abstract class CssStatement : CssSyntax, ICssValue
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: each at-rule might parse differently according to CSS3
|
||||
/// The @media block for example contains a block of statements
|
||||
/// while other at-rules with a block contain a block of declarations
|
||||
/// </remarks>
|
||||
internal class CssAtRule : CssStatement
|
||||
{
|
||||
#region Constants
|
||||
|
||||
internal const string MediaIdent = "media";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Fields
|
||||
|
||||
private string ident;
|
||||
private string value;
|
||||
|
||||
private CssBlock block;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public string Ident
|
||||
{
|
||||
get { return this.ident; }
|
||||
set { this.ident = value; }
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
get { return this.value; }
|
||||
set { this.value = value; }
|
||||
}
|
||||
|
||||
public CssBlock Block
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.block == null)
|
||||
{
|
||||
this.block = new CssBlock();
|
||||
}
|
||||
return this.block;
|
||||
}
|
||||
set { this.block = value; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
|
||||
writer.Write('@');
|
||||
writer.Write(this.ident);
|
||||
|
||||
if (!String.IsNullOrEmpty(this.value))
|
||||
{
|
||||
writer.Write(' ');
|
||||
writer.Write(this.value);
|
||||
}
|
||||
|
||||
if (this.block != null)
|
||||
{
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
this.block.Write(writer, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(';');
|
||||
}
|
||||
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssBlock : CssSyntax, ICssValue
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<ICssValue> values = new List<ICssValue>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<ICssValue> Values
|
||||
{
|
||||
get { return this.values; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
|
||||
writer.Write('{');
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
foreach (ICssValue value in this.Values)
|
||||
{
|
||||
value.Write(writer, options);
|
||||
}
|
||||
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
writer.Write('}');
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssRuleSet : CssStatement
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<CssSelector> selectors = new List<CssSelector>();
|
||||
private readonly List<CssDeclaration> declarations = new List<CssDeclaration>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<CssSelector> Selectors
|
||||
{
|
||||
get { return this.selectors; }
|
||||
}
|
||||
|
||||
public List<CssDeclaration> Declarations
|
||||
{
|
||||
get { return this.declarations; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
|
||||
bool comma = false;
|
||||
|
||||
foreach (CssString selector in this.Selectors)
|
||||
{
|
||||
if (comma)
|
||||
{
|
||||
writer.Write(",");
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
comma = true;
|
||||
}
|
||||
|
||||
selector.Write(writer, options);
|
||||
}
|
||||
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
writer.Write("{");
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
foreach (CssDeclaration dec in this.Declarations)
|
||||
{
|
||||
dec.Write(writer, options);
|
||||
}
|
||||
|
||||
writer.Write("}");
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssSelector : CssString
|
||||
{
|
||||
}
|
||||
|
||||
internal class CssDeclaration : CssSyntax, ICssValue
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private string property;
|
||||
private CssValueList value;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public string Property
|
||||
{
|
||||
get { return this.property; }
|
||||
set { this.property = value; }
|
||||
}
|
||||
|
||||
public CssValueList Value
|
||||
{
|
||||
get { return this.value; }
|
||||
set { this.value = value; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool prettyPrint = IsPrettyPrint(options);
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.Write('\t');
|
||||
}
|
||||
writer.Write(this.Property);
|
||||
writer.Write(':');
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.Write(" ");
|
||||
}
|
||||
this.Value.Write(writer, options);
|
||||
writer.Write(";");
|
||||
if (prettyPrint)
|
||||
{
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class CssValueList : CssSyntax
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<CssString> values = new List<CssString>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
public List<CssString> Values
|
||||
{
|
||||
get { return this.values; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Write(TextWriter writer, CssCompactor.Options options)
|
||||
{
|
||||
bool space = false;
|
||||
|
||||
foreach (CssString value in this.Values)
|
||||
{
|
||||
if (space)
|
||||
{
|
||||
writer.Write(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
space = true;
|
||||
}
|
||||
|
||||
value.Write(writer, options);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
#endregion Grammar
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal class FileUtility
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private static readonly char[] IllegalChars;
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Init
|
||||
|
||||
static FileUtility()
|
||||
{
|
||||
var chars = new List<char>(Path.GetInvalidPathChars());
|
||||
foreach (char ch in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
if (!chars.Contains(ch) && ch != Path.DirectorySeparatorChar)
|
||||
{
|
||||
chars.Add(ch);
|
||||
}
|
||||
}
|
||||
IllegalChars = chars.ToArray();
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Makes sure directory exists and if file exists is not readonly.
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns>if valid path</returns>
|
||||
internal static bool PrepSavePath(string filename)
|
||||
{
|
||||
if (System.IO.File.Exists(filename))
|
||||
{
|
||||
// make sure not readonly
|
||||
FileAttributes attributes = System.IO.File.GetAttributes(filename);
|
||||
attributes &= ~FileAttributes.ReadOnly;
|
||||
System.IO.File.SetAttributes(filename, attributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
string dir = Path.GetDirectoryName(filename);
|
||||
if (!String.IsNullOrEmpty(dir) && dir.IndexOfAny(IllegalChars) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!String.IsNullOrEmpty(dir) && !Directory.Exists(dir))
|
||||
{
|
||||
// make sure path exists
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
string file = Path.GetFileName(filename);
|
||||
if (!String.IsNullOrEmpty(file) && file.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a character sequence to filter out when reading.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the sequence exists in the read source, it will be read out as if it was never there.
|
||||
/// </remarks>
|
||||
internal struct ReadFilter
|
||||
{
|
||||
#region Fields
|
||||
|
||||
public readonly string StartToken;
|
||||
public readonly string EndToken;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
public ReadFilter(string start, string end)
|
||||
{
|
||||
if (String.IsNullOrEmpty(start))
|
||||
{
|
||||
throw new ArgumentNullException("start");
|
||||
}
|
||||
if (String.IsNullOrEmpty(end))
|
||||
{
|
||||
throw new ArgumentNullException("end");
|
||||
}
|
||||
|
||||
this.StartToken = start;
|
||||
this.EndToken = end;
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Trie out of ReadFilters
|
||||
/// </summary>
|
||||
internal class FilterTrie : TrieNode<char, string>
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const int DefaultTrieWidth = 1;
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Init
|
||||
|
||||
internal FilterTrie(IEnumerable<ReadFilter> filters)
|
||||
: base(DefaultTrieWidth)
|
||||
{
|
||||
// load trie
|
||||
foreach (ReadFilter filter in filters)
|
||||
{
|
||||
TrieNode<char, string> node = this;
|
||||
|
||||
// build out the path for StartToken
|
||||
foreach (char ch in filter.StartToken)
|
||||
{
|
||||
if (!node.Contains(ch))
|
||||
{
|
||||
node[ch] = new TrieNode<char, string>(DefaultTrieWidth);
|
||||
}
|
||||
|
||||
node = (TrieNode<char, string>)node[ch];
|
||||
}
|
||||
|
||||
// at the end of StartToken path is the EndToken
|
||||
node.Value = filter.EndToken;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
}
|
||||
@@ -1,464 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal class LineReader : TextReader
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private int line = 1;
|
||||
private int column = 0;
|
||||
private int position = -1;
|
||||
|
||||
private string filePath;
|
||||
private string source;
|
||||
|
||||
private readonly FilterTrie trie;
|
||||
|
||||
private bool normalizeWhiteSpace = false;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="filters"></param>
|
||||
internal LineReader(string filePath, IEnumerable<ReadFilter> filters) : this(filePath, null, filters) { }
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="filters"></param>
|
||||
internal LineReader(string filePath, string source, IEnumerable<ReadFilter> filters)
|
||||
{
|
||||
this.trie = new FilterTrie(filters);
|
||||
this.source = source;
|
||||
this.filePath = filePath;
|
||||
|
||||
if (this.source == null)
|
||||
{
|
||||
this.source = filePath;//Changed to direct content string instead of file.
|
||||
/*if (System.IO.File.Exists(filePath))
|
||||
{
|
||||
this.source = System.IO.File.ReadAllText(filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileError("File not found", filePath, 0, 0);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="source"></param>
|
||||
internal LineReader(string filePath, string source)
|
||||
: this(filePath, source, new ReadFilter[0])
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the source file
|
||||
/// </summary>
|
||||
public string FilePath
|
||||
{
|
||||
get { return this.filePath; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of source file in chars
|
||||
/// </summary>
|
||||
public int Length
|
||||
{
|
||||
get { return this.source.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current line number
|
||||
/// </summary>
|
||||
public int Line
|
||||
{
|
||||
get { return this.line; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current col number
|
||||
/// </summary>
|
||||
public int Column
|
||||
{
|
||||
get { return this.column; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current char position
|
||||
/// </summary>
|
||||
public int Position
|
||||
{
|
||||
get { return this.position; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets if at end the end of file
|
||||
/// </summary>
|
||||
public bool EndOfFile
|
||||
{
|
||||
get { return this.position >= this.source.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets if whitespace is normalized while reading
|
||||
/// </summary>
|
||||
public bool NormalizeWhiteSpace
|
||||
{
|
||||
get { return this.normalizeWhiteSpace; }
|
||||
set { this.normalizeWhiteSpace = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current char
|
||||
/// </summary>
|
||||
public int Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.EndOfFile)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return this.source[this.position];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region TextReader Members
|
||||
|
||||
/// <summary>
|
||||
/// Unfiltered look ahead
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int Peek()
|
||||
{
|
||||
return this.Peek(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filtered read of the next source char. Counters are incremented.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// NewLine sequences (CR/LF, LF, CR) are normalized to LF.
|
||||
/// </remarks>
|
||||
public override int Read()
|
||||
{
|
||||
return this.Read(true);
|
||||
}
|
||||
|
||||
#endregion TextReader Members
|
||||
|
||||
#region Utility Methods
|
||||
|
||||
/// <summary>
|
||||
/// Backs the current position up one.
|
||||
/// </summary>
|
||||
public void PutBack()
|
||||
{
|
||||
if (this.position < 0)
|
||||
{
|
||||
throw new InvalidOperationException("Already at start of source");
|
||||
}
|
||||
switch (this.source[this.position])
|
||||
{
|
||||
case '\r': //CR
|
||||
{
|
||||
// manipulate CR/LF as one char
|
||||
if ((this.position + 1 < this.Length) && this.source[this.position + 1] == '\n')
|
||||
{
|
||||
this.position--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '\n': //LF
|
||||
case '\f': //FF
|
||||
{
|
||||
this.line--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.column--;
|
||||
this.position--;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies a range from the source
|
||||
/// </summary>
|
||||
/// <param name="start">starting position, inclusive</param>
|
||||
/// <param name="end">ending position, inclusive</param>
|
||||
/// <returns></returns>
|
||||
public string Copy(int start, int end)
|
||||
{
|
||||
if (start < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("start");
|
||||
}
|
||||
if (end < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("end");
|
||||
}
|
||||
if (end < 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// set to just before read, next char is start
|
||||
int copyPosition = start - 1;
|
||||
|
||||
// allocate the full range but may not use due to filtering
|
||||
char[] buffer = new char[end - start + 1];
|
||||
|
||||
int count = 0;
|
||||
while (copyPosition < end)
|
||||
{
|
||||
int ch = this.CopyRead(ref copyPosition);
|
||||
if (ch == -1)
|
||||
{
|
||||
throw new UnexpectedEndOfFile("Read past end of file", this.FilePath, this.Line, this.Column);
|
||||
}
|
||||
buffer[count] = (char)ch;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new String(buffer, 0, count).Trim();
|
||||
}
|
||||
|
||||
#endregion Utility Methods
|
||||
|
||||
#region Filter Methods
|
||||
|
||||
/// <summary>
|
||||
/// Peeks with n chars of lookahead.
|
||||
/// </summary>
|
||||
/// <param name="lookahead"></param>
|
||||
/// <returns>unfiltered read</returns>
|
||||
protected int Peek(int lookahead)
|
||||
{
|
||||
int pos = this.position + lookahead;
|
||||
if (pos >= this.source.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return this.source[pos];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the next char
|
||||
/// </summary>
|
||||
/// <param name="filter">if filtering</param>
|
||||
/// <returns>the next char, or -1 if at EOF</returns>
|
||||
protected int Read(bool filter)
|
||||
{
|
||||
if (this.position + 1 >= this.source.Length)
|
||||
{
|
||||
this.position = this.source.Length;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// increment counters
|
||||
this.position++;
|
||||
this.column++;
|
||||
char ch = this.source[this.position];
|
||||
|
||||
if (Char.IsWhiteSpace(ch))
|
||||
{
|
||||
ch = this.NormalizeSpaces(ch, ref this.position, ref this.line, ref this.column);
|
||||
}
|
||||
|
||||
return filter ? this.Filter(ch) : ch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalized CR/CRLF/LF/FF to LF, or all whitespace to SPACE if NormalizeWhiteSpace is true
|
||||
/// </summary>
|
||||
/// <param name="ch"></param>
|
||||
/// <param name="pos"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="col"></param>
|
||||
/// <returns></returns>
|
||||
private char NormalizeSpaces(char ch, ref int pos, ref int line, ref int col)
|
||||
{
|
||||
int length = this.source.Length;
|
||||
if (this.normalizeWhiteSpace)
|
||||
{
|
||||
// normalize runs of WhiteSpace to ' '
|
||||
while ((pos + 1 < length) && Char.IsWhiteSpace(this.source, pos + 1))
|
||||
{
|
||||
pos++;
|
||||
col++;
|
||||
|
||||
// increment line count
|
||||
switch (this.source[pos])
|
||||
{
|
||||
case '\r': //CR
|
||||
{
|
||||
// manipulate CR/LF as one char
|
||||
if ((pos + 1 < length) && this.source[pos + 1] == '\n')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
goto case '\n';
|
||||
}
|
||||
case '\n': //LF
|
||||
case '\f': //FF
|
||||
{
|
||||
line++;
|
||||
col = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ch = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
// normalize NewLines to '\n', increment line count
|
||||
switch (ch)
|
||||
{
|
||||
case '\r': //CR
|
||||
{
|
||||
// manipulate CR/LF as one char
|
||||
if ((pos + 1 < length) && this.source[pos + 1] == '\n')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
goto case '\n';
|
||||
}
|
||||
case '\n': //LF
|
||||
case '\f': //FF
|
||||
{
|
||||
line++;
|
||||
col = 0;
|
||||
ch = '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read for Copying (doesn't reset line.col counters)
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
protected int CopyRead(ref int copyPosition)
|
||||
{
|
||||
if (copyPosition + 1 >= this.source.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// increment counters
|
||||
copyPosition++;
|
||||
char ch = this.source[copyPosition];
|
||||
|
||||
if (Char.IsWhiteSpace(ch))
|
||||
{
|
||||
int dummyLine = 0, dummyCol = 0;
|
||||
ch = this.NormalizeSpaces(ch, ref copyPosition, ref dummyLine, ref dummyCol);
|
||||
}
|
||||
|
||||
return this.Filter(ch);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters based upon an internal Trie
|
||||
/// </summary>
|
||||
/// <param name="ch"></param>
|
||||
/// <returns></returns>
|
||||
private int Filter(char ch)
|
||||
{
|
||||
int lookAhead = 0;
|
||||
ITrieNode<char, string> node = this.trie[ch];
|
||||
|
||||
while (node != null)
|
||||
{
|
||||
if (node.HasValue)
|
||||
{
|
||||
// found StartToken
|
||||
string endToken = node.Value;
|
||||
int length = endToken.Length;
|
||||
|
||||
// move to end of StartToken
|
||||
this.position += lookAhead;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
int ch2 = this.Read(false);
|
||||
if (ch < 0)
|
||||
{
|
||||
throw new UnexpectedEndOfFile("Expected " + endToken, this.FilePath, this.Line, this.Column);
|
||||
}
|
||||
if (ch2 != endToken[i])
|
||||
{
|
||||
// reset search
|
||||
while (i > 0)
|
||||
{
|
||||
i--;
|
||||
this.PutBack();
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return this.Read(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
lookAhead++;
|
||||
int pk = this.Peek(lookAhead);
|
||||
if (pk < 0)
|
||||
{
|
||||
return ch;
|
||||
}
|
||||
node = node[(char)pk];
|
||||
}
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#endregion Filter Methods
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Free source resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
this.source = null;
|
||||
}
|
||||
|
||||
#endregion IDisposable Members
|
||||
}
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
internal enum ParseExceptionType
|
||||
{
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal abstract class ParseException : ApplicationException
|
||||
{
|
||||
#region Constants
|
||||
|
||||
// this cannot change every char is important or Visual Studio will not list as error/warning
|
||||
// http://blogs.msdn.com/msbuild/archive/2006/11/03/msbuild-visual-studio-aware-error-messages-and-message-formats.aspx
|
||||
private const string MSBuildErrorFormat = "{0}({1},{2}): {3} {4}: {5}";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Fields
|
||||
|
||||
private string file;
|
||||
private int line;
|
||||
private int column;
|
||||
private int code = 0;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
public ParseException(string message, string file, int line, int column)
|
||||
: base(message)
|
||||
{
|
||||
this.file = file;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
public ParseException(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
this.file = file;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public abstract ParseExceptionType Type
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public virtual int Code
|
||||
{
|
||||
get { return this.code; }
|
||||
}
|
||||
|
||||
public string ErrorCode
|
||||
{
|
||||
get
|
||||
{
|
||||
string ext = System.IO.Path.GetExtension(file);
|
||||
if (ext == null || ext.Length < 2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ext.Substring(1).ToUpperInvariant() + this.Code.ToString("####0000");
|
||||
}
|
||||
}
|
||||
|
||||
public string File
|
||||
{
|
||||
get { return this.file; }
|
||||
}
|
||||
|
||||
public int Line
|
||||
{
|
||||
get { return this.line; }
|
||||
}
|
||||
|
||||
public int Column
|
||||
{
|
||||
get { return this.column; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public virtual string GetCompilerMessage()
|
||||
{
|
||||
return this.GetCompilerMessage(this.Type == ParseExceptionType.Warning);
|
||||
}
|
||||
|
||||
public virtual string GetCompilerMessage(bool isWarning)
|
||||
{
|
||||
// format exception as a VS2005 error/warning
|
||||
return String.Format(
|
||||
ParseException.MSBuildErrorFormat,
|
||||
this.File,
|
||||
(this.Line > 0) ? this.Line : 1,
|
||||
(this.Column > 0) ? this.Column : 1,
|
||||
isWarning ? "warning" : "error",
|
||||
this.ErrorCode,
|
||||
this.Message);
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class ParseWarning : ParseException
|
||||
{
|
||||
#region Init
|
||||
|
||||
public ParseWarning(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public ParseWarning(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public override ParseExceptionType Type
|
||||
{
|
||||
get { return ParseExceptionType.Warning; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class ParseError : ParseException
|
||||
{
|
||||
#region Init
|
||||
|
||||
public ParseError(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public ParseError(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public override ParseExceptionType Type
|
||||
{
|
||||
get { return ParseExceptionType.Error; }
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class UnexpectedEndOfFile : ParseError
|
||||
{
|
||||
#region Init
|
||||
|
||||
public UnexpectedEndOfFile(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public UnexpectedEndOfFile(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class FileError : ParseWarning
|
||||
{
|
||||
#region Init
|
||||
|
||||
public FileError(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public FileError(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class SyntaxError : ParseError
|
||||
{
|
||||
#region Init
|
||||
|
||||
public SyntaxError(string message, string file, int line, int column)
|
||||
: base(message, file, line, column)
|
||||
{
|
||||
}
|
||||
|
||||
public SyntaxError(string message, string file, int line, int column, Exception innerException)
|
||||
: base(message, file, line, column, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Css
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic node for building a Trie
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">the Type used for the node path</typeparam>
|
||||
/// <typeparam name="TValue">the Type used for the node value</typeparam>
|
||||
/// <remarks>
|
||||
/// http://en.wikipedia.org/wiki/Trie
|
||||
/// </remarks>
|
||||
internal class TrieNode<TKey, TValue> : ITrieNode<TKey, TValue>
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly IDictionary<TKey, ITrieNode<TKey, TValue>> Children;
|
||||
private TValue value = default(TValue);
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Init
|
||||
|
||||
/// <summary>
|
||||
/// Ctor
|
||||
/// </summary>
|
||||
public TrieNode()
|
||||
: this(-1)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="capacity"></param>
|
||||
public TrieNode(int capacity)
|
||||
{
|
||||
if (capacity < 1)
|
||||
{
|
||||
this.Children = new Dictionary<TKey, ITrieNode<TKey, TValue>>();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Children = new Dictionary<TKey, ITrieNode<TKey, TValue>>(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Init
|
||||
|
||||
#region Properties
|
||||
|
||||
public ITrieNode<TKey, TValue> this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.Children.ContainsKey(key))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return this.Children[key];
|
||||
}
|
||||
|
||||
// added "internal" to get around change in C# 3.0 modifiers
|
||||
// this worked fine in C# 2.0 but they fixed that bug
|
||||
// http://blogs.msdn.com/ericlippert/archive/2008/03/28/why-can-t-i-access-a-protected-member-from-a-derived-class-part-two-why-can-i.aspx
|
||||
protected internal set { this.Children[key] = value; }
|
||||
}
|
||||
|
||||
public TValue Value
|
||||
{
|
||||
get { return this.value; }
|
||||
|
||||
// added "internal" to get around change in C# 3.0 modifiers
|
||||
// this worked fine in C# 2.0 but they fixed that bug
|
||||
// http://blogs.msdn.com/ericlippert/archive/2008/03/28/why-can-t-i-access-a-protected-member-from-a-derived-class-part-two-why-can-i.aspx
|
||||
protected internal set
|
||||
{
|
||||
if (!EqualityComparer<TValue>.Default.Equals(this.value, default(TValue)))
|
||||
{
|
||||
throw new InvalidOperationException("Trie path collision: the value for TrieNode<" + value.GetType().Name + "> has already been assigned.");
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return !EqualityComparer<TValue>.Default.Equals(this.value, default(TValue));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Determines if child exists
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public bool Contains(TKey key)
|
||||
{
|
||||
return this.Children.ContainsKey(key);
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal interface ITrieNode<TKey, TValue>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
ITrieNode<TKey, TValue> this[TKey key]
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
TValue Value
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
bool HasValue
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
|
||||
#region Methods
|
||||
|
||||
bool Contains(TKey key);
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ namespace Umbraco.Core.Models
|
||||
private DataTypeDatabaseType _databaseType;
|
||||
|
||||
[Obsolete("Property editor's are defined by a string alias from version 7 onwards, use the alternative contructor that specifies an alias")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public DataTypeDefinition(int parentId, Guid controlId)
|
||||
{
|
||||
_parentId = parentId;
|
||||
@@ -47,6 +48,9 @@ namespace Umbraco.Core.Models
|
||||
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
[Obsolete("Don't use this, parentId is always -1 for data types")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public DataTypeDefinition(int parentId, string propertyEditorAlias)
|
||||
{
|
||||
_parentId = parentId;
|
||||
@@ -55,6 +59,14 @@ namespace Umbraco.Core.Models
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public DataTypeDefinition(string propertyEditorAlias)
|
||||
{
|
||||
_parentId = -1;
|
||||
_propertyEditorAlias = propertyEditorAlias;
|
||||
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<DataTypeDefinition, string>(x => x.Name);
|
||||
private static readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<DataTypeDefinition, int>(x => x.ParentId);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<DataTypeDefinition, int>(x => x.SortOrder);
|
||||
|
||||
@@ -7,25 +7,6 @@ using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to attribute properties that have a setter and are a reference type
|
||||
/// that should be ignored for cloning when using the DeepCloneHelper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// This attribute must be used:
|
||||
/// * when the property is backed by a field but the result of the property is the un-natural data stored in the field
|
||||
///
|
||||
/// This attribute should not be used:
|
||||
/// * when the property is virtual
|
||||
/// * when the setter performs additional required logic other than just setting the underlying field
|
||||
///
|
||||
/// </remarks>
|
||||
internal class DoNotCloneAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static class DeepCloneHelper
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Models
|
||||
private IEnumerable<IDictionaryTranslation> _translations;
|
||||
|
||||
public DictionaryItem(string itemKey)
|
||||
: this(new Guid("41c7638d-f529-4bff-853e-59a0c2fb1bde"), itemKey)
|
||||
: this(new Guid(Constants.Conventions.Localization.DictionaryItemRootId), itemKey)
|
||||
{}
|
||||
|
||||
public DictionaryItem(Guid parentId, string itemKey)
|
||||
@@ -99,7 +99,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
//If ParentId is not set we should default to the root parent id
|
||||
if(ParentId == Guid.Empty)
|
||||
_parentId = new Guid("41c7638d-f529-4bff-853e-59a0c2fb1bde");
|
||||
_parentId = new Guid(Constants.Conventions.Localization.DictionaryItemRootId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,12 +18,14 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public DictionaryTranslation(ILanguage language, string value)
|
||||
{
|
||||
if (language == null) throw new ArgumentNullException("language");
|
||||
_language = language;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public DictionaryTranslation(ILanguage language, string value, Guid uniqueId)
|
||||
{
|
||||
if (language == null) throw new ArgumentNullException("language");
|
||||
_language = language;
|
||||
_value = value;
|
||||
Key = uniqueId;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to attribute properties that have a setter and are a reference type
|
||||
/// that should be ignored for cloning when using the DeepCloneHelper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// This attribute must be used:
|
||||
/// * when the property is backed by a field but the result of the property is the un-natural data stored in the field
|
||||
///
|
||||
/// This attribute should not be used:
|
||||
/// * when the property is virtual
|
||||
/// * when the setter performs additional required logic other than just setting the underlying field
|
||||
///
|
||||
/// </remarks>
|
||||
internal class DoNotCloneAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,13 @@ namespace Umbraco.Core.Models
|
||||
public abstract class File : Entity, IFile
|
||||
{
|
||||
private string _path;
|
||||
private string _originalPath;
|
||||
private string _content = string.Empty; //initialize to empty string, not null
|
||||
|
||||
protected File(string path)
|
||||
{
|
||||
_path = path;
|
||||
_originalPath = _path;
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo<File, string>(x => x.Content);
|
||||
@@ -32,14 +34,7 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
public virtual string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_name == null)
|
||||
{
|
||||
_name = System.IO.Path.GetFileName(Path);
|
||||
}
|
||||
return _name;
|
||||
}
|
||||
get { return _name ?? (_name = System.IO.Path.GetFileName(Path)); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -82,6 +77,22 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the original path of the file
|
||||
/// </summary>
|
||||
public string OriginalPath
|
||||
{
|
||||
get { return _originalPath; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to re-set the OriginalPath to the Path
|
||||
/// </summary>
|
||||
public void ResetOriginalPath()
|
||||
{
|
||||
_originalPath = _path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Content of a File
|
||||
/// </summary>
|
||||
@@ -104,11 +115,11 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public string VirtualPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the file could be validated
|
||||
/// </summary>
|
||||
/// <returns>True if file is valid, otherwise false</returns>
|
||||
public abstract bool IsValid();
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in future versions")]
|
||||
public virtual bool IsValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
|
||||
@@ -20,12 +20,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
bool Published { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Language of the data contained within this Content object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Left internal until multilingual support is implemented.
|
||||
/// </remarks>
|
||||
[Obsolete("This will be removed in future versions")]
|
||||
string Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -78,5 +73,15 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IContent DeepCloneWithResetIdentities();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content has a published version.
|
||||
/// </summary>
|
||||
bool HasPublishedVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique identifier of the published version, if any.
|
||||
/// </summary>
|
||||
Guid PublishedVersionGuid { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IDomain : IAggregateRoot, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
ILanguage Language { get; set; }
|
||||
string DomainName { get; set; }
|
||||
IContent RootContent { get; set; }
|
||||
bool IsWildcard { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using System;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -23,6 +24,16 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the original path of the file
|
||||
/// </summary>
|
||||
string OriginalPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called to re-set the OriginalPath to the Path
|
||||
/// </summary>
|
||||
void ResetOriginalPath();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Content of a File
|
||||
/// </summary>
|
||||
@@ -33,10 +44,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
string VirtualPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the file could be validated
|
||||
/// </summary>
|
||||
/// <returns>True if file is valid, otherwise false</returns>
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in future versions")]
|
||||
bool IsValid();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -7,10 +9,31 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public interface ITemplate : IFile, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Name of the File including extension
|
||||
/// </summary>
|
||||
new string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Alias of the File, which is the name without the extension
|
||||
/// </summary>
|
||||
new string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the template is used as a layout for other templates (i.e. it has 'children')
|
||||
/// </summary>
|
||||
bool IsMasterTemplate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// returns the master template alias
|
||||
/// </summary>
|
||||
string MasterTemplateAlias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="RenderingEngine"/> that corresponds to the template file
|
||||
/// </summary>
|
||||
/// <returns><see cref="RenderingEngine"/></returns>
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in future versions, use the IFileSystem DetermineRenderingEngine method instead")]
|
||||
RenderingEngine GetTypeOfRenderingEngine();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
public class BackOfficeIdentityUser : IdentityUser<int, IIdentityUserLogin, IdentityUserRole<string>, IdentityUserClaim<int>>
|
||||
{
|
||||
|
||||
public virtual async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager manager)
|
||||
{
|
||||
// NOTE the authenticationType must match the umbraco one
|
||||
// defined in CookieAuthenticationOptions.AuthenticationType
|
||||
var userIdentity = await manager.CreateIdentityAsync(this, Constants.Security.BackOfficeAuthenticationType);
|
||||
return userIdentity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the user's real name
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public int StartContentId { get; set; }
|
||||
public int StartMediaId { get; set; }
|
||||
public string[] AllowedSections { get; set; }
|
||||
public string Culture { get; set; }
|
||||
|
||||
public string UserTypeAlias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Overridden to make the retrieval lazy
|
||||
/// </summary>
|
||||
public override ICollection<IIdentityUserLogin> Logins
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_getLogins != null && _getLogins.IsValueCreated == false)
|
||||
{
|
||||
_logins = new ObservableCollection<IIdentityUserLogin>();
|
||||
foreach (var l in _getLogins.Value)
|
||||
{
|
||||
_logins.Add(l);
|
||||
}
|
||||
//now assign events
|
||||
_logins.CollectionChanged += Logins_CollectionChanged;
|
||||
}
|
||||
return _logins;
|
||||
}
|
||||
}
|
||||
|
||||
public bool LoginsChanged { get; private set; }
|
||||
|
||||
void Logins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
LoginsChanged = true;
|
||||
}
|
||||
|
||||
private ObservableCollection<IIdentityUserLogin> _logins;
|
||||
private Lazy<IEnumerable<IIdentityUserLogin>> _getLogins;
|
||||
|
||||
/// <summary>
|
||||
/// Used to set a lazy call back to populate the user's Login list
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
public void SetLoginsCallback(Lazy<IEnumerable<IIdentityUserLogin>> callback)
|
||||
{
|
||||
if (callback == null) throw new ArgumentNullException("callback");
|
||||
_getLogins = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
public interface IIdentityUserLogin : IAggregateRoot, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// The login provider for the login (i.e. facebook, google)
|
||||
///
|
||||
/// </summary>
|
||||
string LoginProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key representing the login for the provider
|
||||
///
|
||||
/// </summary>
|
||||
string ProviderKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this login
|
||||
///
|
||||
/// </summary>
|
||||
int UserId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
public class IdentityModelMappings : MapperConfiguration
|
||||
{
|
||||
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
|
||||
{
|
||||
config.CreateMap<IUser, BackOfficeIdentityUser>()
|
||||
.ForMember(user => user.Email, expression => expression.MapFrom(user => user.Email))
|
||||
.ForMember(user => user.Id, expression => expression.MapFrom(user => user.Id))
|
||||
.ForMember(user => user.LockoutEnabled, expression => expression.MapFrom(user => user.IsLockedOut))
|
||||
.ForMember(user => user.LockoutEndDateUtc, expression => expression.UseValue(DateTime.MaxValue.ToUniversalTime()))
|
||||
.ForMember(user => user.UserName, expression => expression.MapFrom(user => user.Username))
|
||||
.ForMember(user => user.PasswordHash, expression => expression.MapFrom(user => GetPasswordHash(user.RawPasswordValue)))
|
||||
.ForMember(user => user.Culture, expression => expression.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
|
||||
.ForMember(user => user.Name, expression => expression.MapFrom(user => user.Name))
|
||||
.ForMember(user => user.StartMediaId, expression => expression.MapFrom(user => user.StartMediaId))
|
||||
.ForMember(user => user.StartContentId, expression => expression.MapFrom(user => user.StartContentId))
|
||||
.ForMember(user => user.UserTypeAlias, expression => expression.MapFrom(user => user.UserType.Alias))
|
||||
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()));
|
||||
}
|
||||
|
||||
private string GetPasswordHash(string storedPass)
|
||||
{
|
||||
return storedPass.StartsWith("___UIDEMPTYPWORD__") ? null : storedPass;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Identity;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Default IUser implementation
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"/><typeparam name="TLogin"/><typeparam name="TRole"/><typeparam name="TClaim"/>
|
||||
/// <remarks>
|
||||
/// This class normally exists inside of the EntityFramework library, not sure why MS chose to explicitly put it there but we don't want
|
||||
/// references to that so we will create our own here
|
||||
/// </remarks>
|
||||
public class IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
|
||||
where TLogin : IIdentityUserLogin
|
||||
//NOTE: Making our role id a string
|
||||
where TRole : IdentityUserRole<string>
|
||||
where TClaim : IdentityUserClaim<TKey>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
///
|
||||
/// </summary>
|
||||
public IdentityUser()
|
||||
{
|
||||
this.Claims = new List<TClaim>();
|
||||
this.Roles = new List<TRole>();
|
||||
this.Logins = new List<TLogin>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Email
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the email is confirmed, default is false
|
||||
///
|
||||
/// </summary>
|
||||
public virtual bool EmailConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The salted/hashed form of the user password
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string PasswordHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A random value that should change whenever a users credentials have changed (password changed, login removed)
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string SecurityStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PhoneNumber for the user
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string PhoneNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the phone number is confirmed, default is false
|
||||
///
|
||||
/// </summary>
|
||||
public virtual bool PhoneNumberConfirmed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is two factor enabled for the user
|
||||
///
|
||||
/// </summary>
|
||||
public virtual bool TwoFactorEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// DateTime in UTC when lockout ends, any time in the past is considered not locked out.
|
||||
///
|
||||
/// </summary>
|
||||
public virtual DateTime? LockoutEndDateUtc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is lockout enabled for this user
|
||||
///
|
||||
/// </summary>
|
||||
public virtual bool LockoutEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to record failures for the purposes of lockout
|
||||
///
|
||||
/// </summary>
|
||||
public virtual int AccessFailedCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for user roles
|
||||
///
|
||||
/// </summary>
|
||||
public virtual ICollection<TRole> Roles { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for user claims
|
||||
///
|
||||
/// </summary>
|
||||
public virtual ICollection<TClaim> Claims { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Navigation property for user logins
|
||||
///
|
||||
/// </summary>
|
||||
public virtual ICollection<TLogin> Logins { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// User ID (Primary Key)
|
||||
///
|
||||
/// </summary>
|
||||
public virtual TKey Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User name
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string UserName { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityType that represents one specific user claim
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"/>
|
||||
/// <remarks>
|
||||
/// This class normally exists inside of the EntityFramework library, not sure why MS chose to explicitly put it there but we don't want
|
||||
/// references to that so we will create our own here
|
||||
/// </remarks>
|
||||
public class IdentityUserClaim<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// Primary key
|
||||
///
|
||||
/// </summary>
|
||||
public virtual int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this login
|
||||
///
|
||||
/// </summary>
|
||||
public virtual TKey UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Claim type
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string ClaimType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Claim value
|
||||
///
|
||||
/// </summary>
|
||||
public virtual string ClaimValue { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity type for a user's login (i.e. facebook, google)
|
||||
///
|
||||
/// </summary>
|
||||
public class IdentityUserLogin : Entity, IIdentityUserLogin
|
||||
{
|
||||
public IdentityUserLogin(string loginProvider, string providerKey, int userId)
|
||||
{
|
||||
LoginProvider = loginProvider;
|
||||
ProviderKey = providerKey;
|
||||
UserId = userId;
|
||||
}
|
||||
|
||||
public IdentityUserLogin(int id, string loginProvider, string providerKey, int userId, DateTime createDate)
|
||||
{
|
||||
Id = id;
|
||||
LoginProvider = loginProvider;
|
||||
ProviderKey = providerKey;
|
||||
UserId = userId;
|
||||
CreateDate = createDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The login provider for the login (i.e. facebook, google)
|
||||
///
|
||||
/// </summary>
|
||||
public string LoginProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Key representing the login for the provider
|
||||
///
|
||||
/// </summary>
|
||||
public string ProviderKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User Id for the user who owns this login
|
||||
///
|
||||
/// </summary>
|
||||
public int UserId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
/// <summary>
|
||||
/// EntityType that represents a user belonging to a role
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"/>
|
||||
/// <remarks>
|
||||
/// This class normally exists inside of the EntityFramework library, not sure why MS chose to explicitly put it there but we don't want
|
||||
/// references to that so we will create our own here
|
||||
/// </remarks>
|
||||
public class IdentityUserRole<TKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// UserId for the user that is in the role
|
||||
///
|
||||
/// </summary>
|
||||
public virtual TKey UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RoleId for the role
|
||||
///
|
||||
/// </summary>
|
||||
public virtual TKey RoleId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -12,4 +12,6 @@ namespace Umbraco.Core.Models.Mapping
|
||||
{
|
||||
public abstract void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -38,5 +38,10 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// Exposes the basic profile data
|
||||
/// </summary>
|
||||
IProfile ProfileData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The security stamp used by ASP.Net identity
|
||||
/// </summary>
|
||||
string SecurityStamp { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a backoffice user
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Should be internal until a proper user/membership implementation
|
||||
/// is part of the roadmap.
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class User : Entity, IUser
|
||||
@@ -58,12 +54,14 @@ namespace Umbraco.Core.Models.Membership
|
||||
|
||||
private IUserType _userType;
|
||||
private string _name;
|
||||
private string _securityStamp;
|
||||
private List<string> _addedSections;
|
||||
private List<string> _removedSections;
|
||||
private ObservableCollection<string> _sectionCollection;
|
||||
private int _sessionTimeout;
|
||||
private int _startContentId;
|
||||
private int _startMediaId;
|
||||
private int _failedLoginAttempts;
|
||||
|
||||
private string _username;
|
||||
private string _email;
|
||||
@@ -71,14 +69,23 @@ namespace Umbraco.Core.Models.Membership
|
||||
private bool _isApproved;
|
||||
private bool _isLockedOut;
|
||||
private string _language;
|
||||
private DateTime _lastPasswordChangedDate;
|
||||
private DateTime _lastLoginDate;
|
||||
private DateTime _lastLockoutDate;
|
||||
|
||||
private IEnumerable<string> _defaultPermissions;
|
||||
|
||||
private bool _defaultToLiveEditing;
|
||||
|
||||
private static readonly PropertyInfo FailedPasswordAttemptsSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.FailedPasswordAttempts);
|
||||
private static readonly PropertyInfo LastLockoutDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime>(x => x.LastLockoutDate);
|
||||
private static readonly PropertyInfo LastLoginDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime>(x => x.LastLoginDate);
|
||||
private static readonly PropertyInfo LastPasswordChangeDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime>(x => x.LastPasswordChangeDate);
|
||||
|
||||
private static readonly PropertyInfo SecurityStampSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.SecurityStamp);
|
||||
private static readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.SessionTimeout);
|
||||
private static readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartContentId);
|
||||
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
|
||||
private static readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
|
||||
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.AllowedSections);
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Name);
|
||||
|
||||
@@ -154,9 +161,9 @@ namespace Umbraco.Core.Models.Membership
|
||||
return _isApproved;
|
||||
}, _isApproved, IsApprovedSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
[IgnoreDataMember]
|
||||
public bool IsLockedOut
|
||||
{
|
||||
get { return _isLockedOut; }
|
||||
@@ -170,6 +177,62 @@ namespace Umbraco.Core.Models.Membership
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public DateTime LastLoginDate
|
||||
{
|
||||
get { return _lastLoginDate; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_lastLoginDate = value;
|
||||
return _lastLoginDate;
|
||||
}, _lastLoginDate, LastLoginDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public DateTime LastPasswordChangeDate
|
||||
{
|
||||
get { return _lastPasswordChangedDate; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_lastPasswordChangedDate = value;
|
||||
return _lastPasswordChangedDate;
|
||||
}, _lastPasswordChangedDate, LastPasswordChangeDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public DateTime LastLockoutDate
|
||||
{
|
||||
get { return _lastLockoutDate; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_lastLockoutDate = value;
|
||||
return _lastLockoutDate;
|
||||
}, _lastLockoutDate, LastLockoutDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public int FailedPasswordAttempts
|
||||
{
|
||||
get { return _failedLoginAttempts; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_failedLoginAttempts = value;
|
||||
return _failedLoginAttempts;
|
||||
}, _failedLoginAttempts, FailedPasswordAttemptsSelector);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Figure out how to support all of this! - we cannot have NotImplementedExceptions because these get used by the IMembershipMemberService<IUser> service so
|
||||
// we'll just have them as generic get/set which don't interact with the db.
|
||||
|
||||
@@ -178,15 +241,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
[IgnoreDataMember]
|
||||
public string RawPasswordAnswerValue { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public string Comments { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public DateTime LastLoginDate { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public DateTime LastPasswordChangeDate { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public DateTime LastLockoutDate { get; set; }
|
||||
[IgnoreDataMember]
|
||||
public int FailedPasswordAttempts { get; set; }
|
||||
public string Comments { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -232,6 +287,23 @@ namespace Umbraco.Core.Models.Membership
|
||||
get { return new UserProfile(this); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The security stamp used by ASP.Net identity
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public string SecurityStamp
|
||||
{
|
||||
get { return _securityStamp; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_securityStamp = value;
|
||||
return _securityStamp;
|
||||
}, _securityStamp, SecurityStampSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally to check if we need to add a section in the repository to the db
|
||||
/// </summary>
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Models
|
||||
/// Represents a paged result for a model collection
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[DataContract(Name = "pagedCollection", Namespace = "")]
|
||||
[DataContract(Name = "pagedCollection", Namespace = "")]
|
||||
public class PagedResult<T>
|
||||
{
|
||||
public PagedResult(long totalItems, long pageNumber, long pageSize)
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
if (pageSize > 0)
|
||||
{
|
||||
TotalPages = (long) Math.Ceiling(totalItems/(Decimal) pageSize);
|
||||
TotalPages = (long)Math.Ceiling(totalItems / (Decimal)pageSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -48,16 +48,13 @@ namespace Umbraco.Core.Models
|
||||
/// <remarks>
|
||||
/// Returns 0 if the page number or page size is zero
|
||||
/// </remarks>
|
||||
internal int SkipSize
|
||||
public int GetSkipSize()
|
||||
{
|
||||
get
|
||||
if (PageNumber > 0 && PageSize > 0)
|
||||
{
|
||||
if (PageNumber > 0 && PageSize > 0)
|
||||
{
|
||||
return Convert.ToInt32((PageNumber - 1)*PageSize);
|
||||
}
|
||||
return 0;
|
||||
return Convert.ToInt32((PageNumber - 1) * PageSize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,20 +7,7 @@ using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
//internal class PartialViewMacro : PartialView
|
||||
//{
|
||||
// public PartialViewMacro()
|
||||
// : base(string.Empty)
|
||||
// {
|
||||
// }
|
||||
|
||||
// public PartialViewMacro(string path) : base(path)
|
||||
// {
|
||||
// }
|
||||
|
||||
// public IMacro AssociatedMacro { get; set; }
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Partial View file
|
||||
/// </summary>
|
||||
@@ -28,9 +15,6 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public class PartialView : File, IPartialView
|
||||
{
|
||||
//public PartialView(): base(string.Empty)
|
||||
//{
|
||||
//}
|
||||
|
||||
public PartialView(string path)
|
||||
: base(path)
|
||||
@@ -38,19 +22,5 @@ namespace Umbraco.Core.Models
|
||||
base.Path = path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the file could be validated
|
||||
/// </summary>
|
||||
/// <returns>True if file is valid, otherwise false</returns>
|
||||
public override bool IsValid()
|
||||
{
|
||||
//TODO: Why is this here? Needs to go on the FileService
|
||||
|
||||
var validatePath = IOHelper.ValidateEditPath(Path, new[] { SystemDirectories.MvcViews + "/Partials/", SystemDirectories.MvcViews + "/MacroPartials/" });
|
||||
var verifyFileExtension = IOHelper.VerifyFileExtension(Path, new List<string> { "cshtml" });
|
||||
|
||||
return validatePath && verifyFileExtension;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace Umbraco.Core.Models
|
||||
/// Returns the PropertyType, which this Property is based on
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
internal PropertyType PropertyType { get { return _propertyType; } }
|
||||
public PropertyType PropertyType { get { return _propertyType; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the version id for the Property
|
||||
|
||||
@@ -255,7 +255,7 @@ namespace Umbraco.Core.Models
|
||||
/// Gets of Sets the Help text for the current PropertyType
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
[Obsolete("Not used anywhere in the UI")]
|
||||
[Obsolete("Not used anywhere, will be removed in future versions")]
|
||||
public string HelpText
|
||||
{
|
||||
get { return _helpText; }
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class PublicAccessEntry : Entity, IAggregateRoot
|
||||
{
|
||||
private readonly ObservableCollection<PublicAccessRule> _ruleCollection;
|
||||
private int _protectedNodeId;
|
||||
private int _noAccessNodeId;
|
||||
private int _loginNodeId;
|
||||
private readonly List<Guid> _removedRules = new List<Guid>();
|
||||
|
||||
public PublicAccessEntry(IContent protectedNode, IContent loginNode, IContent noAccessNode, IEnumerable<PublicAccessRule> ruleCollection)
|
||||
{
|
||||
LoginNodeId = loginNode.Id;
|
||||
NoAccessNodeId = noAccessNode.Id;
|
||||
_protectedNodeId = protectedNode.Id;
|
||||
|
||||
_ruleCollection = new ObservableCollection<PublicAccessRule>(ruleCollection);
|
||||
_ruleCollection.CollectionChanged += _ruleCollection_CollectionChanged;
|
||||
}
|
||||
|
||||
public PublicAccessEntry(Guid id, int protectedNodeId, int loginNodeId, int noAccessNodeId, IEnumerable<PublicAccessRule> ruleCollection)
|
||||
{
|
||||
Key = id;
|
||||
Id = Key.GetHashCode();
|
||||
|
||||
LoginNodeId = loginNodeId;
|
||||
NoAccessNodeId = noAccessNodeId;
|
||||
_protectedNodeId = protectedNodeId;
|
||||
|
||||
_ruleCollection = new ObservableCollection<PublicAccessRule>(ruleCollection);
|
||||
_ruleCollection.CollectionChanged += _ruleCollection_CollectionChanged;
|
||||
}
|
||||
|
||||
void _ruleCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(AllowedSectionsSelector);
|
||||
|
||||
//if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
//{
|
||||
// var item = e.NewItems.Cast<PublicAccessRule>().First();
|
||||
|
||||
// if (_addedSections.Contains(item) == false)
|
||||
// {
|
||||
// _addedSections.Add(item);
|
||||
// }
|
||||
//}
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Remove)
|
||||
{
|
||||
var item = e.OldItems.Cast<PublicAccessRule>().First();
|
||||
|
||||
if (_removedRules.Contains(item.Key) == false)
|
||||
{
|
||||
_removedRules.Add(item.Key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo ProtectedNodeIdSelector = ExpressionHelper.GetPropertyInfo<PublicAccessEntry, int>(x => x.ProtectedNodeId);
|
||||
private static readonly PropertyInfo LoginNodeIdSelector = ExpressionHelper.GetPropertyInfo<PublicAccessEntry, int>(x => x.LoginNodeId);
|
||||
private static readonly PropertyInfo NoAccessNodeIdSelector = ExpressionHelper.GetPropertyInfo<PublicAccessEntry, int>(x => x.NoAccessNodeId);
|
||||
private static readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<PublicAccessEntry, IEnumerable<PublicAccessRule>>(x => x.Rules);
|
||||
|
||||
internal IEnumerable<Guid> RemovedRules
|
||||
{
|
||||
get { return _removedRules; }
|
||||
}
|
||||
|
||||
public IEnumerable<PublicAccessRule> Rules
|
||||
{
|
||||
get { return _ruleCollection; }
|
||||
}
|
||||
|
||||
public PublicAccessRule AddRule(string ruleValue, string ruleType)
|
||||
{
|
||||
var rule = new PublicAccessRule
|
||||
{
|
||||
AccessEntryId = Key,
|
||||
RuleValue = ruleValue,
|
||||
RuleType = ruleType
|
||||
};
|
||||
_ruleCollection.Add(rule);
|
||||
return rule;
|
||||
}
|
||||
|
||||
public void RemoveRule(PublicAccessRule rule)
|
||||
{
|
||||
_ruleCollection.Remove(rule);
|
||||
}
|
||||
|
||||
public void ClearRules()
|
||||
{
|
||||
foreach (var rule in _ruleCollection)
|
||||
{
|
||||
RemoveRule(rule);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to call on entity saved when first added
|
||||
/// </summary>
|
||||
internal override void AddingEntity()
|
||||
{
|
||||
if (Key == default(Guid))
|
||||
{
|
||||
Key = Guid.NewGuid();
|
||||
}
|
||||
base.AddingEntity();
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int LoginNodeId
|
||||
{
|
||||
get { return _loginNodeId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_loginNodeId = value;
|
||||
return _loginNodeId;
|
||||
}, _loginNodeId, LoginNodeIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int NoAccessNodeId
|
||||
{
|
||||
get { return _noAccessNodeId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_noAccessNodeId = value;
|
||||
return _noAccessNodeId;
|
||||
}, _noAccessNodeId, NoAccessNodeIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int ProtectedNodeId
|
||||
{
|
||||
get { return _protectedNodeId; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_protectedNodeId = value;
|
||||
return _protectedNodeId;
|
||||
}, _protectedNodeId, ProtectedNodeIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
_removedRules.Clear();
|
||||
base.ResetDirtyProperties(rememberPreviouslyChangedProperties);
|
||||
foreach (var publicAccessRule in _ruleCollection)
|
||||
{
|
||||
publicAccessRule.ResetDirtyProperties(rememberPreviouslyChangedProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user