Compare commits

..

105 Commits

Author SHA1 Message Date
Sebastiaan Janssen fd2fe1939a Adds new installer image 2014-06-11 10:22:13 +02:00
Morten Christensen 81e56bed9e Implementing Document Type Compositions in the Document Type Editor.
Adds changes to the CMSNode and doc type related class which improves the internal usage of the new model based on IUmbracoEntity.
2014-06-11 07:08:38 +02:00
Sebastiaan Janssen 52457fea21 Bump version number 2014-06-10 18:47:02 +02:00
Sebastiaan Janssen 07ec9aa813 Undo formatting of query for now 2014-06-10 18:11:14 +02:00
Sebastiaan Janssen ba89aec34f Merge pull request #415 from rustyswayne/7.1.5-templatequery
Query Builder - Fix Date sort fields and format returned query
2014-06-10 17:48:59 +02:00
Jeavon Leopold 29533820ab Query Builder - Fix Date sort fields and format returned query to be on new lines and tabbed 2014-06-10 16:43:28 +01:00
Sebastiaan Janssen 4366500fad Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.2.0
Conflicts:
	src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js
2014-06-10 17:15:07 +02:00
Sebastiaan Janssen ee6e1a9d8b Disable extra templates tree 2014-06-10 17:13:58 +02:00
antoine 3b95184f04 empty video or media issue 2014-06-10 17:06:13 +02:00
antoine 9da7e108da double )) in embed open windows 2014-06-10 16:52:29 +02:00
antoine cb491d45ab open preview issue fixed 2014-06-10 16:50:03 +02:00
Sebastiaan Janssen 344b880ba7 Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.2.0
Conflicts:
	src/Umbraco.Web.UI.Client/src/views/common/dialogs/content/edit.controller.js
	src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js
	src/Umbraco.Web/Umbraco.Web.csproj
2014-06-10 15:22:31 +02:00
Sebastiaan Janssen c958f12bc1 Merge pull request #413 from rustyswayne/7.1.5-templatequery
Template Query Editor Prototype
2014-06-10 15:11:57 +02:00
Shannon 9a973d0ccc fixes csproj 2014-06-10 15:06:41 +02:00
Jeavon Leopold b170053e87 Support for multiple "and" conditions in the query builder 2014-06-10 14:05:57 +01:00
antoine db4509de2b link picker removed 2014-06-10 14:35:57 +02:00
antoine 5c91b822e3 legacy grid's configs removed 2014-06-10 13:45:52 +02:00
Shannon e6ddf63e56 re-adds old providers 2014-06-10 13:19:52 +02:00
Shannon 84ac029372 re-add segment provider 2014-06-10 13:18:54 +02:00
antoine 5d59741612 iframe resize with the tuning panel 2014-06-10 12:52:33 +02:00
Jeavon Leopold 2ffd0413e8 Adding query builder button to View editor 2014-06-10 11:27:26 +01:00
Jeavon Leopold dc4e6ee01c Adding Visible to template query builder 2014-06-10 08:40:33 +01:00
Jeavon Leopold 1d8e217c6f Template Query builder prototype working! 2014-06-09 23:23:31 +01:00
Rusty Swayne 0b3136cf20 Patched Contains query & implemented SortExpression 2014-06-09 09:14:26 -07:00
Rusty Swayne b0e96b256a Merge branch '7.1.5' into 7.1.5-templatequery 2014-06-09 08:44:19 -07:00
Jeavon Leopold 72a966b0fa Template Query Editor - Angular and hooking up to the API controller 2014-06-09 16:42:57 +01:00
Rusty Swayne bf222f26cd Merge remote-tracking branch 'umbraco/7.1.5' into 7.1.5 2014-06-09 08:41:33 -07:00
Rusty Swayne be9f4b70e2 Added JasonCamelCaseFormatter to the .Web project 2014-06-09 08:40:47 -07:00
Rusty Swayne 0060f0019e Merge branch '7.1.5' into 7.1.5-templatequery 2014-06-09 05:41:16 -07:00
Rusty Swayne 632cd221d9 Attribute for WebApi controllers that camel cases object property names when serialized to Json 2014-06-09 05:39:14 -07:00
Jeavon Leopold 46d5215d9e Merge remote-tracking branch 'upstream/7.1.5' into 7.1.5-templatequery 2014-06-09 13:21:07 +01:00
Jeavon Leopold aa43656cb9 Revisions to QueryModel. Added Sorting and Take functionality. 2014-06-09 13:18:35 +01:00
Jeavon Leopold e4837d1962 Changing DescendantOrSelf to DescendantOrSelf.First as it doesn't work with dynamics 2014-06-09 08:41:29 +01:00
Jeavon Leopold 40868d7cd2 Fixing typo in Descendants for template query controller 2014-06-09 07:08:06 +01:00
Jeavon Leopold 0fde3f7b5d Fixing up the test method for the query builder 2014-06-08 23:26:46 +01:00
Jeavon Leopold 76f0eac5f8 Template Query WIP 2014-06-08 22:39:01 +01:00
Jeavon Leopold 2352d258b9 Fix mock API method and some Stylecop 2014-06-08 19:06:37 +01:00
Rusty Swayne 2dc38a29cf Added QueryModel 2014-06-08 10:20:34 -07:00
Jeavon Leopold 1aa162e255 Add Site() method to DynamicPublishedContent for Template Query Builder 2014-06-08 18:09:29 +01:00
Rusty Swayne 342999a678 TemplateQueryController 2014-06-08 09:51:06 -07:00
antoine 5cb210c7b6 slider input updated real time 2014-06-08 11:08:56 +02:00
antoine b80ab20cb4 device preview background color 2014-06-08 09:42:39 +02:00
antoine bac6e71e7f color picker in real time, general clear code 2014-06-05 14:02:38 +02:00
antoine 9a36d74418 tuning issue 2014-06-04 16:24:02 +02:00
antoine 39eaa4a15e Element select improved, default style more clean 2014-06-03 19:33:31 +02:00
antoine 2fdf040f73 Palette improvement 2014-06-02 10:55:53 +02:00
antoine aec956dd2e grunt js task issue 2014-06-02 10:55:17 +02:00
antoine 65bb1e1e20 gridRow default less 2014-05-30 20:03:34 +02:00
antoine 3dabd73ec2 Merge branch '7.1.2-Usky' into 7.1.2-Usky-Grid
Conflicts:
	src/Umbraco.Web.UI.Client/src/tuning/tuning.controller.js
	src/Umbraco.Web.UI.Client/src/tuning/tuning.global.js
	src/Umbraco.Web.UI/Umbraco/js/tuning.panel.js
	src/Umbraco.Web.UI/Views/Partials/Grid/bootstrap3.cshtml
2014-05-30 19:56:51 +02:00
antoine 90e5440518 bootstrap3 ; issue + hx style issue 2014-05-28 15:33:36 +02:00
antoine 7cfd2d6593 schema's selector improved 2014-05-28 15:06:16 +02:00
antoine 6382515258 Device preview always enable 2014-05-28 11:29:08 +02:00
antoine fd2b9ce67d /umbraco/dialogs/tuning.aspx removed 2014-05-27 12:37:43 +02:00
antoine 1284417a58 /umbraco/dialogs/tuning.aspx removed 2014-05-27 12:36:49 +02:00
antoine b57642003c Grid row unique id 2014-05-25 20:52:23 +02:00
antoine 9ee59e8e38 Merge branch '7.1.2-Usky' into 7.1.2-Usky-Grid
Conflicts:
	src/Umbraco.Web.UI/Views/Partials/Grid/bootstrap3.cshtml
2014-05-25 18:35:18 +02:00
antoine a5f81ae6c2 Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.1.2-Usky
Conflicts:
	src/Umbraco.Web.UI.Client/gruntFile.js
2014-05-23 16:39:39 +02:00
per ploug 08cc608dc8 One last change, enable setting max number of items in a cell 2014-05-23 14:57:16 +02:00
per ploug 71839d53a6 Last round of polish to the grid
adds image captions, textstring markup support in rendering, better
styling and icon previews
2014-05-23 14:37:00 +02:00
antoine 7508613d13 First approach 2014-05-22 22:20:13 +02:00
antoine 9626e91c83 dependency with bootstrap.3.0.1.min.js 2014-05-21 19:51:13 +02:00
per ploug 83b6375f04 Migrated the Editors out of the grid
Added configuration for individual editors, added allowed editors, new
styling refactored css
2014-05-21 15:40:17 +02:00
antoine 52cd44a700 Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.1.2-Usky 2014-05-21 15:37:58 +02:00
antoine 0c8ff187aa grunt update to copy default files 2014-05-21 15:37:20 +02:00
John 3af74bd4fd Load google fonts independently in the content iframe.
Enables live preview on the page's content for google fonts.
2014-05-21 14:57:20 +02:00
John c9e2e1e116 Apply preview of font to page's content. 2014-05-21 14:57:18 +02:00
John c27f73e54a Fix glitch when selecting new font in dropdown.
In the font family picker, selecting a not-yet-loaded font caused the font sample to render as Arial until the font had been downloaded.
2014-05-21 14:57:17 +02:00
John cede13d180 Merge name and description changes from uSky. 2014-05-21 14:57:15 +02:00
antoine 3ffb2772b6 Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.1.2-Usky 2014-05-21 13:54:25 +02:00
antoine e6f0d4e056 @Umbraco.EnableTuning() and Recursive less file 2014-05-21 13:53:00 +02:00
per ploug 23c7eafaf5 merge from upstream 7.1.4 2014-05-20 12:32:47 +02:00
per ploug 90892ce818 adds rootscope access to umb.clientmgr 2014-05-20 12:14:10 +02:00
John e62d1559b1 Fix grunt not copying tuning's index.html to Umbraco/preview.
Also fixes same issue when using grunt --dev.
2014-05-20 10:36:48 +02:00
antoine 81934c47d2 laptop width 2014-05-19 16:06:45 +02:00
antoine 80379e116d umbraco media support 2014-05-19 14:34:09 +02:00
antoine 89081b86af preview grunt issue 2014-05-16 14:42:47 +02:00
antoine 216e2255f2 Save message more friendly 2014-05-16 13:33:41 +02:00
antoine 9db3dbd730 Style improvement
focus schema in front when roll-over in panel
2014-05-16 11:40:39 +02:00
antoine 8a1dd96294 some styles fixed 2014-05-14 19:15:43 +02:00
antoine 67bebd0d2d index.html missing 2014-05-14 18:39:25 +02:00
antoine 4f34fbd2c8 devices preview better look
tested in chrome/firefox/IE
2014-05-14 18:37:44 +02:00
antoine 8cda6e4062 Tuning panel include in preview mode 2014-05-14 14:51:58 +02:00
antoine d8209efefa Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.1.2-Usky 2014-05-13 16:20:20 +02:00
antoine 00180d2120 Web.config with less mime 2014-05-13 16:19:45 +02:00
per ploug 66e768afee Missing bootstrap3 grid view
Missing as gitignore wont allow it, had to manually add it
2014-05-13 13:31:51 +02:00
antoine bba109cb28 tuning.aspx deleted 2014-05-13 13:10:28 +02:00
antoine 39ede8c47a Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.1.2-Usky
Conflicts:
	src/Umbraco.Web/Umbraco.Web.csproj
2014-05-13 13:07:38 +02:00
antoine fec84b8ce3 iframe 100% in firefox 2014-05-13 13:04:39 +02:00
antoine a00e5d54aa rename tuning project without usky 2014-05-13 12:50:48 +02:00
per ploug 331813e370 Adds serverside grid api
Replaces the partial view macro, also enables the grid to be rendered
with different frameworks, should be fairly easy to support a couple
2014-05-13 12:36:38 +02:00
per ploug 6c36f43276 Adds support for loading custom RTE settings into the grid 2014-05-13 12:35:08 +02:00
per ploug e8f4e7663f More visual tweaks to the grid to handle deletes
also rolls back a couple of bower "tweaks" that ended up being horrible
2014-05-13 09:45:09 +02:00
antoine 9f116c00d5 Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.1.2-Usky 2014-05-12 20:00:57 +02:00
antoine 7e61b25746 uskytuning with style suggest and preview device 2014-05-12 19:57:06 +02:00
per ploug 482750ab6a Missing file 2014-05-12 13:22:58 +02:00
per ploug 40d1099fbd grid modifications 2014-05-12 13:22:57 +02:00
antoine 2d050a0c88 original sln 2014-05-10 15:57:59 +02:00
antoine 103f4f33bd Only one less style file 2014-05-10 15:56:36 +02:00
antoine 727f9355a0 dotless dependency 2014-05-10 14:53:59 +02:00
antoine e269a0b9bb Merge branch '7.1.2-Usky' of https://github.com/umbraco/UmbracoCms-Internal into 7.1.2-Usky 2014-05-09 18:22:37 +02:00
antoine 861b1cefe5 uSkyTuning.loader.js deleted 2014-05-09 18:22:02 +02:00
antoine 23301817bf uSkyTuning into Umbraco core, first approach 2014-05-09 18:18:08 +02:00
antoine f5842c82a6 dotless dependency 2014-05-09 18:15:31 +02:00
per ploug 4baf3ed99a Initial commit of the grid 2014-05-09 12:23:59 +02:00
per ploug 3c09cd7674 Initial commit to set upstream
Includes a minor change to force it to commit...
2014-05-07 15:10:14 +02:00
411 changed files with 20712 additions and 10849 deletions
+6
View File
@@ -78,6 +78,12 @@ src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.panel.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.palettes.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.loader.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.front.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.config.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css
+1 -3
View File
@@ -4,7 +4,7 @@ IF NOT EXIST UmbracoVersion.txt (
GOTO :showerror
)
SET /p release=<UmbracoVersion.txt
SET comment=
SET comment=alpha
SET version=%release%
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
@@ -14,14 +14,12 @@ ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %rel
ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice
SET nuGetFolder=%CD%\..\src\packages\
..\src\.nuget\NuGet.exe sources Add -Name MyGetUmbracoCore -Source https://www.myget.org/F/umbracocore/api/v2/
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder%
ECHO Removing the belle build folder to make sure everything is clean as a whistle
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
ECHO Removing existing built files to make sure everything is clean as a whistle
RMDIR /Q /S _BuildOutput
DEL /F /Q UmbracoCms.*.zip
DEL /F /Q UmbracoCms.*.nupkg
DEL /F /Q webpihash.txt
+7 -9
View File
@@ -15,13 +15,11 @@
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.30506.0,5.0.0)" />
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.0,5.0.0)" />
<dependency id="Microsoft.AspNet.WebApi" version="[4.0.30506,5.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.WebHost" version="[4.0.30506, 5.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.Core" version="[4.0.30506, 5.0.0)" />
<dependency id="Microsoft.AspNet.WebApi.Client" version="[4.0.30506, 5.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.Mvc.FixedDisplayModes" version="1.0.0" />
<dependency id="Microsoft.Net.Http" version="[2.0.0, 3.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)" />
@@ -31,10 +29,9 @@
<dependency id="ClientDependency" version="[1.7.1.2, 2.0.0)" />
<dependency id="ClientDependency-Mvc" version="[1.7.0.4, 2.0.0)" />
<dependency id="AutoMapper" version="[3.0.0, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.4, 7.0.0)" />
<dependency id="Examine" version="[0.1.57, 1.0.0)" />
<dependency id="ImageProcessor" version="[1.9.5, 2.0.0)" />
<dependency id="ImageProcessor.Web" version="[3.3.0, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.2, 7.0.0)" />
<dependency id="ImageProcessor" version="[1.9.0, 2.0.0)" />
<dependency id="ImageProcessor.Web" version="[3.2.3, 4.0.0)" />
</dependencies>
</metadata>
<files>
@@ -44,6 +41,7 @@
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\cms.xml" />
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\controls.dll" />
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\controls.xml" />
<file src="..\_BuildOutput\WebApp\bin\Examine.dll" target="lib\Examine.dll" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\interfaces.dll" />
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\interfaces.xml" />
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
+1 -1
View File
@@ -1 +1 @@
7.1.6
7.2.0
Binary file not shown.
-1
View File
@@ -77,7 +77,6 @@
<Compile Include="SqlCEUtility.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
@@ -1,204 +1,218 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
namespace Umbraco.Core.Cache
{
internal abstract class DictionaryCacheProviderBase : ICacheProvider
{
// prefix cache keys so we know which one are ours
protected const string CacheItemPrefix = "umbrtmche";
// an object that represent a value that has not been created yet
protected readonly object ValueNotCreated = new object();
// manupulate the underlying cache entries
// these *must* be called from within the appropriate locks
// and use the full prefixed cache keys
protected abstract IEnumerable<DictionaryEntry> GetDictionaryEntries();
protected abstract void RemoveEntry(string key);
protected abstract object GetEntry(string key);
// read-write lock the underlying cache
protected abstract IDisposable ReadLock { get; }
protected abstract IDisposable WriteLock { get; }
protected string GetCacheKey(string key)
{
return string.Format("{0}-{1}", CacheItemPrefix, key);
}
protected object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
{
try
{
// if onlyIfValueIsCreated, do not trigger value creation
// must return something, though, to differenciate from null values
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
return lazy.Value;
}
catch
{
return null;
}
}
#region Clear
protected static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
protected abstract DictionaryCacheWrapper DictionaryCache { get; }
/// <summary>
/// Clears everything in umbraco's runtime cache
/// </summary>
/// <remarks>
/// Does not clear other stuff the user has put in httpruntime.cache!
/// </remarks>
public virtual void ClearAllCache()
{
using (WriteLock)
using (new WriteLock(Locker))
{
foreach (var entry in GetDictionaryEntries()
.ToArray())
RemoveEntry((string) entry.Key);
var keysToRemove = DictionaryCache.Cast<object>()
.Select(item => new DictionaryItemWrapper(item))
.Where(c => c.Key is string && ((string)c.Key).StartsWith(CacheItemPrefix) && DictionaryCache[c.Key.ToString()] != null)
.Select(c => c.Key)
.ToList();
foreach (var k in keysToRemove)
{
DictionaryCache.Remove(k);
}
}
}
/// <summary>
/// Clears the item in umbraco's runtime cache with the given key
/// </summary>
/// <param name="key">Key</param>
public virtual void ClearCacheItem(string key)
{
var cacheKey = GetCacheKey(key);
using (WriteLock)
using (new WriteLock(Locker))
{
RemoveEntry(cacheKey);
if (DictionaryCache[GetCacheKey(key)] == null) return;
DictionaryCache.Remove(GetCacheKey(key)); ;
}
}
/// <summary>
/// Clears all objects in the System.Web.Cache with the System.Type name as the
/// input parameter. (using [object].GetType())
/// </summary>
/// <param name="typeName">The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument"</param>
public virtual void ClearCacheObjectTypes(string typeName)
{
using (WriteLock)
using (new WriteLock(Locker))
{
foreach (var entry in GetDictionaryEntries()
.Where(x =>
var keysToRemove = DictionaryCache
.Cast<object>()
.Select(item => new DictionaryItemWrapper(item))
.Where(c =>
{
// entry.Value is Lazy<object> and not null, its value may be null
// 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);
var k = c.Key.ToString();
var v = DictionaryCache[k];
return v != null && v.GetType().ToString().InvariantEquals(typeName);
})
.ToArray())
RemoveEntry((string) entry.Key);
.Select(c => c.Key)
.ToList();
foreach (var k in keysToRemove)
DictionaryCache.Remove(k);
}
}
public virtual void ClearCacheObjectTypes<T>()
{
var typeOfT = typeof(T);
using (WriteLock)
using (new WriteLock(Locker))
{
foreach (var entry in GetDictionaryEntries()
.Where(x =>
var typeOfT = typeof(T);
var keysToRemove = DictionaryCache
.Cast<object>()
.Select(item => new DictionaryItemWrapper(item))
.Where(c =>
{
// entry.Value is Lazy<object> and not null, its value may be null
// remove null values as well, does not hurt
// 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;
var k = c.Key.ToString();
var v = DictionaryCache[k];
return v != null && v.GetType() == typeOfT;
})
.ToArray())
RemoveEntry((string) entry.Key);
.Select(c => c.Key)
.ToList();
foreach (var k in keysToRemove)
DictionaryCache.Remove(k);
}
}
public virtual void ClearCacheObjectTypes<T>(Func<string, T, bool> predicate)
{
var typeOfT = typeof(T);
var plen = CacheItemPrefix.Length + 1;
using (WriteLock)
using (new WriteLock(Locker))
{
foreach (var entry in GetDictionaryEntries()
.Where(x =>
var typeOfT = typeof(T);
var keysToRemove = DictionaryCache
.Cast<object>()
.Select(item => new DictionaryItemWrapper(item))
.Where(c =>
{
// entry.Value is Lazy<object> and not null, its value may be null
// remove null values as well, does not hurt
// compare on exact type, don't use "is"
// 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);
}))
RemoveEntry((string) entry.Key);
var k = c.Key.ToString();
var v = DictionaryCache[k];
return v != null && v.GetType() == typeOfT && predicate(k, (T)v);
})
.Select(c => c.Key)
.ToList();
foreach (var k in keysToRemove)
DictionaryCache.Remove(k);
}
}
/// <summary>
/// Clears all cache items that starts with the key passed.
/// </summary>
/// <param name="keyStartsWith">The start of the key</param>
public virtual void ClearCacheByKeySearch(string keyStartsWith)
{
var plen = CacheItemPrefix.Length + 1;
using (WriteLock)
var keysToRemove = DictionaryCache.Cast<object>()
.Select(item => new DictionaryItemWrapper(item))
.Where(c => c.Key is string && ((string)c.Key).InvariantStartsWith(string.Format("{0}-{1}", CacheItemPrefix, keyStartsWith)))
.Select(c => c.Key)
.ToList();
foreach (var k in keysToRemove)
{
foreach (var entry in GetDictionaryEntries()
.Where(x => ((string)x.Key).Substring(plen).InvariantStartsWith(keyStartsWith))
.ToArray())
RemoveEntry((string) entry.Key);
DictionaryCache.Remove(k);
}
}
/// <summary>
/// Clears all cache items that have a key that matches the regular expression
/// </summary>
/// <param name="regexString"></param>
public virtual void ClearCacheByKeyExpression(string regexString)
{
var plen = CacheItemPrefix.Length + 1;
using (WriteLock)
var keysToRemove = new List<object>();
foreach (var item in DictionaryCache)
{
foreach (var entry in GetDictionaryEntries()
.Where(x => Regex.IsMatch(((string)x.Key).Substring(plen), regexString))
.ToArray())
RemoveEntry((string) entry.Key);
var c = new DictionaryItemWrapper(item);
var s = c.Key as string;
if (s != null)
{
var withoutPrefix = s.TrimStart(string.Format("{0}-", CacheItemPrefix));
if (Regex.IsMatch(withoutPrefix, regexString))
{
keysToRemove.Add(c.Key);
}
}
}
foreach (var k in keysToRemove)
{
DictionaryCache.Remove(k);
}
}
#endregion
#region Get
public virtual IEnumerable<object> GetCacheItemsByKeySearch(string keyStartsWith)
{
var plen = CacheItemPrefix.Length + 1;
IEnumerable<DictionaryEntry> entries;
using (ReadLock)
{
entries = GetDictionaryEntries()
.Where(x => ((string)x.Key).Substring(plen).InvariantStartsWith(keyStartsWith))
.ToArray(); // evaluate while locked
}
return entries
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
.Where(x => x != null); // backward compat, don't store null values in the cache
return (from object item in DictionaryCache
select new DictionaryItemWrapper(item)
into c
where c.Key is string && ((string) c.Key).InvariantStartsWith(string.Format("{0}-{1}", CacheItemPrefix, keyStartsWith))
select c.Value).ToList();
}
public virtual IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
{
const string prefix = CacheItemPrefix + "-";
var plen = prefix.Length;
IEnumerable<DictionaryEntry> entries;
using (ReadLock)
var found = new List<object>();
foreach (var item in DictionaryCache)
{
entries = GetDictionaryEntries()
.Where(x => Regex.IsMatch(((string)x.Key).Substring(plen), regexString))
.ToArray(); // evaluate while locked
var c = new DictionaryItemWrapper(item);
var s = c.Key as string;
if (s != null)
{
var withoutPrefix = s.TrimStart(string.Format("{0}-", CacheItemPrefix));
if (Regex.IsMatch(withoutPrefix, regexString))
{
found.Add(c.Value);
}
}
}
return entries
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
.Where(x => x != null); // backward compat, don't store null values in the cache
return found;
}
/// <summary>
/// Returns a cache item by key, does not update the cache if it isn't there.
/// </summary>
/// <param name="cacheKey"></param>
/// <returns></returns>
public virtual object GetCacheItem(string cacheKey)
{
cacheKey = GetCacheKey(cacheKey);
Lazy<object> result;
using (ReadLock)
{
result = GetEntry(cacheKey) as Lazy<object>; // null if key not found
}
return result == null ? null : GetSafeLazyValue(result); // return exceptions as null
var result = DictionaryCache.Get(GetCacheKey(cacheKey));
return result;
}
public abstract object GetCacheItem(string cacheKey, Func<object> getCacheItem);
public abstract object GetCacheItem(string cacheKey, Func<object> getCacheItem);
#endregion
/// <summary>
/// We prefix all cache keys with this so that we know which ones this class has created when
/// using the HttpRuntime cache so that when we clear it we don't clear other entries we didn't create.
/// </summary>
protected const string CacheItemPrefix = "umbrtmche";
protected string GetCacheKey(string key)
{
return string.Format("{0}-{1}", CacheItemPrefix, key);
}
}
}
@@ -0,0 +1,45 @@
using System;
using System.Collections;
namespace Umbraco.Core.Cache
{
internal class DictionaryCacheWrapper : IEnumerable
{
private readonly IEnumerable _inner;
private readonly Func<object, object> _get;
private readonly Action<object> _remove;
public DictionaryCacheWrapper(
IEnumerable inner,
Func<object, object> get,
Action<object> remove)
{
_inner = inner;
_get = get;
_remove = remove;
}
public object this[object key]
{
get
{
return Get(key);
}
}
public object Get(object key)
{
return _get(key);
}
public void Remove(object key)
{
_remove(key);
}
public IEnumerator GetEnumerator()
{
return _inner.GetEnumerator();
}
}
}
@@ -0,0 +1,14 @@
namespace Umbraco.Core.Cache
{
internal class DictionaryItemWrapper
{
public DictionaryItemWrapper(dynamic item)
{
Key = item.Key;
Value = item.Value;
}
public object Key { get; private set; }
public object Value { get; private set; }
}
}
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
namespace Umbraco.Core.Cache
@@ -11,115 +12,36 @@ namespace Umbraco.Core.Cache
/// </summary>
internal class HttpRequestCacheProvider : DictionaryCacheProviderBase
{
// context provider
// the idea is that there is only one, application-wide HttpRequestCacheProvider instance,
// that is initialized with a method that returns the "current" context.
// NOTE
// but then it is initialized with () => new HttpContextWrapper(HttpContent.Current)
// which is higly inefficient because it creates a new wrapper each time we refer to _context()
// so replace it with _context1 and _context2 below + a way to get context.Items.
//private readonly Func<HttpContextBase> _context;
private readonly Func<HttpContextBase> _context;
// NOTE
// and then in almost 100% cases _context2 will be () => HttpContext.Current
// so why not bring that logic in here and fallback on to HttpContext.Current when
// _context1 is null?
//private readonly HttpContextBase _context1;
//private readonly Func<HttpContext> _context2;
private readonly HttpContextBase _context;
private IDictionary ContextItems
public HttpRequestCacheProvider(HttpContext context)
{
//get { return _context1 != null ? _context1.Items : _context2().Items; }
get { return _context != null ? _context.Items : HttpContext.Current.Items; }
_context = () => new HttpContextWrapper(context);
}
// for unit tests
public HttpRequestCacheProvider(HttpContextBase context)
public HttpRequestCacheProvider(Func<HttpContextBase> context)
{
_context = context;
}
// main constructor
// will use HttpContext.Current
public HttpRequestCacheProvider(/*Func<HttpContext> context*/)
protected override DictionaryCacheWrapper DictionaryCache
{
//_context2 = context;
}
protected override IEnumerable<DictionaryEntry> GetDictionaryEntries()
{
const string prefix = CacheItemPrefix + "-";
return ContextItems.Cast<DictionaryEntry>()
.Where(x => x.Key is string && ((string)x.Key).StartsWith(prefix));
}
protected override void RemoveEntry(string key)
{
ContextItems.Remove(key);
}
protected override object GetEntry(string key)
{
return ContextItems[key];
}
#region Lock
protected override IDisposable ReadLock
{
// there's no difference between ReadLock and WriteLock here
get { return WriteLock; }
}
protected override IDisposable WriteLock
{
// NOTE
// could think about just overriding base.Locker to return a different
// object but then we'd create a ReaderWriterLockSlim per request,
// which is less efficient than just using a basic monitor lock.
get
{
return new MonitorLock(ContextItems.SyncRoot);
var ctx = _context();
return new DictionaryCacheWrapper(
ctx.Items,
o => ctx.Items[o],
o => ctx.Items.Remove(o));
}
}
#endregion
#region Get
public override object GetCacheItem(string cacheKey, Func<object> getCacheItem)
{
cacheKey = GetCacheKey(cacheKey);
Lazy<object> result;
using (WriteLock)
{
result = ContextItems[cacheKey] as Lazy<object>; // null if key not found
// cannot create value within the lock, so if result.IsValueCreated is false, just
// do nothing here - means that if creation throws, a race condition could cause
// more than one thread to reach the return statement below and throw - accepted.
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
{
result = new Lazy<object>(getCacheItem);
ContextItems[cacheKey] = result;
}
}
// this may throw if getCacheItem throws, but this is the only place where
// it would throw as everywhere else we use GetLazySaveValue() to hide exceptions
// and pretend exceptions were never inserted into cache to begin with.
return result.Value;
var ctx = _context();
var ck = GetCacheKey(cacheKey);
return ctx.Items[ck] ?? (ctx.Items[ck] = getCacheItem());
}
#endregion
#region Insert
#endregion
}
}
@@ -1,9 +1,10 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Caching;
using Umbraco.Core.Logging;
using CacheItemPriority = System.Web.Caching.CacheItemPriority;
namespace Umbraco.Core.Cache
@@ -13,52 +14,48 @@ namespace Umbraco.Core.Cache
/// </summary>
internal class HttpRuntimeCacheProvider : DictionaryCacheProviderBase, IRuntimeCacheProvider
{
// locker object that supports upgradeable read locking
// does not need to support recursion if we implement the cache correctly and ensure
// that methods cannot be reentrant, ie we do NOT create values while holding a lock.
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
private readonly System.Web.Caching.Cache _cache;
private readonly DictionaryCacheWrapper _wrapper;
public HttpRuntimeCacheProvider(System.Web.Caching.Cache cache)
{
_cache = cache;
_wrapper = new DictionaryCacheWrapper(_cache, s => _cache.Get(s.ToString()), o => _cache.Remove(o.ToString()));
}
protected override IEnumerable<DictionaryEntry> GetDictionaryEntries()
protected override DictionaryCacheWrapper DictionaryCache
{
const string prefix = CacheItemPrefix + "-";
return _cache.Cast<DictionaryEntry>()
.Where(x => x.Key is string && ((string) x.Key).StartsWith(prefix));
get { return _wrapper; }
}
protected override void RemoveEntry(string key)
{
_cache.Remove(key);
}
protected override object GetEntry(string key)
{
return _cache.Get(key);
}
#region Lock
protected override IDisposable ReadLock
{
get { return new ReadLock(_locker); }
}
protected override IDisposable WriteLock
{
get { return new WriteLock(_locker); }
}
#endregion
#region Get
/// <summary>
/// Clears all objects in the System.Web.Cache with the System.Type specified that satisfy the predicate
/// </summary>
public override void ClearCacheObjectTypes<T>(Func<string, T, bool> predicate)
{
try
{
lock (Locker)
{
foreach (DictionaryEntry c in _cache)
{
var key = c.Key.ToString();
if (_cache[key] != null
&& _cache[key] is T
&& predicate(key, (T)_cache[key]))
{
_cache.Remove(c.Key.ToString());
}
}
}
}
catch (Exception e)
{
LogHelper.Error<CacheHelper>("Cache clearing error", e);
}
}
/// <summary>
/// Gets (and adds if necessary) an item from the cache with all of the default parameters
/// </summary>
/// <param name="cacheKey"></param>
@@ -84,64 +81,25 @@ namespace Umbraco.Core.Cache
{
cacheKey = GetCacheKey(cacheKey);
// NOTE - because we don't know what getCacheItem does, how long it will take and whether it will hang,
// getCacheItem should run OUTSIDE of the global application lock else we run into lock contention and
// nasty performance issues.
// So.... we insert a Lazy<object> in the cache while holding the global application lock, and then rely
// on the Lazy lock to ensure that getCacheItem runs once and everybody waits on it, while the global
// application lock has been released.
// NOTE
// The Lazy value creation may produce a null value.
// Must make sure (for backward compatibility) that we pretend they are not in the cache.
// So if we find an entry in the cache that already has its value created and is null,
// pretend it was not there. If value is not already created, wait... and return null, that's
// what prior code did.
// NOTE
// The Lazy value creation may throw.
// So... the null value _will_ be in the cache but never returned
Lazy<object> result;
// Fast!
// Only one thread can enter an UpgradeableReadLock at a time, but it does not prevent other
// threads to enter a ReadLock in the meantime -- only upgrading to WriteLock will prevent all
// reads. We first try with a normal ReadLock for maximum concurrency and take the penalty of
// having to re-lock in case there's no value. Would need to benchmark to figure out whether
// it's worth it, though...
using (new ReadLock(_locker))
using (var lck = new UpgradeableReadLock(Locker))
{
result = _cache.Get(cacheKey) as Lazy<object>; // null if key not found
}
var value = result == null ? null : GetSafeLazyValue(result);
if (value != null) return value;
using (var lck = new UpgradeableReadLock(_locker))
{
result = _cache.Get(cacheKey) as Lazy<object>; // null if key not found
// cannot create value within the lock, so if result.IsValueCreated is false, just
// do nothing here - means that if creation throws, a race condition could cause
// more than one thread to reach the return statement below and throw - accepted.
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
var result = DictionaryCache.Get(cacheKey);
if (result == null)
{
result = new Lazy<object>(getCacheItem);
var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
lck.UpgradeToWriteLock();
_cache.Insert(cacheKey, result, dependency, absolute, sliding, priority, removedCallback);
}
}
// this may throw if getCacheItem throws, but this is the only place where
// it would throw as everywhere else we use GetLazySaveValue() to hide exceptions
// and pretend exceptions were never inserted into cache to begin with.
return result.Value;
result = getCacheItem();
if (result != null)
{
var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
_cache.Insert(cacheKey, result, dependency, absolute, sliding, priority, removedCallback);
}
}
return result;
}
}
public object GetCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
@@ -154,10 +112,6 @@ namespace Umbraco.Core.Cache
return GetCacheItem(cacheKey, getCacheItem, timeout, isSliding, priority, removedCallback, dependency);
}
#endregion
#region Insert
/// <summary>
/// This overload is here for legacy purposes
/// </summary>
@@ -170,22 +124,15 @@ namespace Umbraco.Core.Cache
/// <param name="dependency"></param>
internal void InsertCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, CacheDependency dependency = null)
{
// NOTE - here also we must insert a Lazy<object> but we can evaluate it right now
// and make sure we don't store a null value.
var result = new Lazy<object>(getCacheItem);
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
if (value == null) return; // do not store null values (backward compat)
var result = getCacheItem();
if (result == null) return;
cacheKey = GetCacheKey(cacheKey);
var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
using (new WriteLock(_locker))
{
_cache.Insert(cacheKey, result, dependency, absolute, sliding, priority, removedCallback);
}
_cache.Insert(cacheKey, result, dependency, absolute, sliding, priority, removedCallback);
}
public void InsertCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
@@ -197,7 +144,5 @@ namespace Umbraco.Core.Cache
}
InsertCacheItem(cacheKey, getCacheItem, timeout, isSliding, priority, removedCallback, dependency);
}
#endregion
}
}
@@ -16,37 +16,17 @@ namespace Umbraco.Core.Cache
/// </summary>
internal class ObjectCacheRuntimeCacheProvider : IRuntimeCacheProvider
{
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
internal ObjectCache MemoryCache;
// an object that represent a value that has not been created yet
protected readonly object ValueNotCreated = new object();
public ObjectCacheRuntimeCacheProvider()
{
MemoryCache = new MemoryCache("in-memory");
}
protected object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
{
try
{
// if onlyIfValueIsCreated, do not trigger value creation
// must return something, though, to differenciate from null values
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
return lazy.Value;
}
catch
{
return null;
}
}
#region Clear
public virtual void ClearAllCache()
{
using (new WriteLock(_locker))
using (new WriteLock(Locker))
{
MemoryCache.DisposeIfDisposable();
MemoryCache = new MemoryCache("in-memory");
@@ -55,7 +35,7 @@ namespace Umbraco.Core.Cache
public virtual void ClearCacheItem(string key)
{
using (new WriteLock(_locker))
using (new WriteLock(Locker))
{
if (MemoryCache[key] == null) return;
MemoryCache.Remove(key);
@@ -64,179 +44,131 @@ namespace Umbraco.Core.Cache
public virtual void ClearCacheObjectTypes(string typeName)
{
using (new WriteLock(_locker))
using (new WriteLock(Locker))
{
foreach (var key in MemoryCache
.Where(x =>
{
// x.Value is Lazy<object> and not null, its value may be null
// 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);
})
.Select(x => x.Key)
.ToArray()) // ToArray required to remove
MemoryCache.Remove(key);
var keysToRemove = MemoryCache
.Where(c => c.Value != null && c.Value.GetType().ToString().InvariantEquals(typeName))
.Select(c => c.Key)
.ToArray();
foreach (var k in keysToRemove)
MemoryCache.Remove(k);
}
}
public virtual void ClearCacheObjectTypes<T>()
{
using (new WriteLock(_locker))
using (new WriteLock(Locker))
{
var typeOfT = typeof (T);
foreach (var key in MemoryCache
.Where(x =>
{
// x.Value is Lazy<object> and not null, its value may be null
// 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() == typeOfT;
})
.Select(x => x.Key)
.ToArray()) // ToArray required to remove
MemoryCache.Remove(key);
var keysToRemove = MemoryCache
.Where(c => c.Value != null && c.Value.GetType() == typeOfT)
.Select(c => c.Key)
.ToArray();
foreach (var k in keysToRemove)
MemoryCache.Remove(k);
}
}
public virtual void ClearCacheObjectTypes<T>(Func<string, T, bool> predicate)
{
using (new WriteLock(_locker))
using (new WriteLock(Locker))
{
var typeOfT = typeof(T);
foreach (var key in MemoryCache
.Where(x =>
{
// x.Value is Lazy<object> and not null, its value may be null
// remove null values as well, does not hurt
// 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
&& predicate(x.Key, (T) value);
})
.Select(x => x.Key)
.ToArray()) // ToArray required to remove
MemoryCache.Remove(key);
var keysToRemove = MemoryCache
.Where(c => c.Value != null && c.Value.GetType() == typeOfT && predicate(c.Key, (T)c.Value))
.Select(c => c.Key)
.ToArray();
foreach (var k in keysToRemove)
MemoryCache.Remove(k);
}
}
public virtual void ClearCacheByKeySearch(string keyStartsWith)
{
using (new WriteLock(_locker))
using (new WriteLock(Locker))
{
foreach (var key in MemoryCache
.Where(x => x.Key.InvariantStartsWith(keyStartsWith))
.Select(x => x.Key)
.ToArray()) // ToArray required to remove
MemoryCache.Remove(key);
var keysToRemove = (from c in MemoryCache where c.Key.InvariantStartsWith(keyStartsWith) select c.Key).ToList();
foreach (var k in keysToRemove)
{
MemoryCache.Remove(k);
}
}
}
public virtual void ClearCacheByKeyExpression(string regexString)
{
using (new WriteLock(_locker))
using (new WriteLock(Locker))
{
foreach (var key in MemoryCache
.Where(x => Regex.IsMatch(x.Key, regexString))
.Select(x => x.Key)
.ToArray()) // ToArray required to remove
MemoryCache.Remove(key);
var keysToRemove = (from c in MemoryCache where Regex.IsMatch(c.Key, regexString) select c.Key).ToList();
foreach (var k in keysToRemove)
{
MemoryCache.Remove(k);
}
}
}
#endregion
#region Get
public IEnumerable<object> GetCacheItemsByKeySearch(string keyStartsWith)
public virtual IEnumerable<object> GetCacheItemsByKeySearch(string keyStartsWith)
{
KeyValuePair<string, object>[] entries;
using (new ReadLock(_locker))
{
entries = MemoryCache
.Where(x => x.Key.InvariantStartsWith(keyStartsWith))
.ToArray(); // evaluate while locked
}
return entries
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
.Where(x => x != null) // backward compat, don't store null values in the cache
.ToList();
return (from c in MemoryCache
where c.Key.InvariantStartsWith(keyStartsWith)
select c.Value).ToList();
}
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
{
KeyValuePair<string, object>[] entries;
using (new ReadLock(_locker))
{
entries = MemoryCache
.Where(x => Regex.IsMatch(x.Key, regexString))
.ToArray(); // evaluate while locked
}
return entries
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
.Where(x => x != null) // backward compat, don't store null values in the cache
.ToList();
return (from c in MemoryCache
where Regex.IsMatch(c.Key, regexString)
select c.Value).ToList();
}
public object GetCacheItem(string cacheKey)
public virtual object GetCacheItem(string cacheKey)
{
Lazy<object> result;
using (new ReadLock(_locker))
{
result = MemoryCache.Get(cacheKey) as Lazy<object>; // null if key not found
}
return result == null ? null : GetSafeLazyValue(result); // return exceptions as null
var result = MemoryCache.Get(cacheKey);
return result;
}
public object GetCacheItem(string cacheKey, Func<object> getCacheItem)
public virtual object GetCacheItem(string cacheKey, Func<object> getCacheItem)
{
return GetCacheItem(cacheKey, getCacheItem, null);
}
public object GetCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal,CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
public object GetCacheItem(
string cacheKey,
Func<object> getCacheItem,
TimeSpan? timeout,
bool isSliding = false,
CacheItemPriority priority = CacheItemPriority.Normal,
CacheItemRemovedCallback removedCallback = null,
string[] dependentFiles = null)
{
// see notes in HttpRuntimeCacheProvider
Lazy<object> result;
using (var lck = new UpgradeableReadLock(_locker))
using (var lck = new UpgradeableReadLock(Locker))
{
result = MemoryCache.Get(cacheKey) as Lazy<object>;
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
var result = MemoryCache.Get(cacheKey);
if (result == null)
{
result = new Lazy<object>(getCacheItem);
var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles);
lck.UpgradeToWriteLock();
MemoryCache.Set(cacheKey, result, policy);
result = getCacheItem();
if (result != null)
{
var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles);
MemoryCache.Set(cacheKey, result, policy);
}
}
return result;
}
return result.Value;
}
#endregion
#region Insert
public void InsertCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
// NOTE - here also we must insert a Lazy<object> but we can evaluate it right now
// and make sure we don't store a null value.
var result = new Lazy<object>(getCacheItem);
var value = result.Value; // force evaluation now
if (value == null) return; // do not store null values (backward compat)
var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles);
MemoryCache.Set(cacheKey, result, policy);
object result = getCacheItem();
if (result != null)
{
var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles);
MemoryCache.Set(cacheKey, result, policy);
}
}
#endregion
private static CacheItemPolicy GetPolicy(TimeSpan? timeout = null, bool isSliding = false, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
var absolute = isSliding ? ObjectCache.InfiniteAbsoluteExpiration : (timeout == null ? ObjectCache.InfiniteAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
+2 -2
View File
@@ -44,7 +44,7 @@ namespace Umbraco.Core
: this(
new HttpRuntimeCacheProvider(HttpRuntime.Cache),
new StaticCacheProvider(),
new HttpRequestCacheProvider())
new HttpRequestCacheProvider(() => new HttpContextWrapper(HttpContext.Current)))
{
}
@@ -56,7 +56,7 @@ namespace Umbraco.Core
: this(
new HttpRuntimeCacheProvider(cache),
new StaticCacheProvider(),
new HttpRequestCacheProvider())
new HttpRequestCacheProvider(() => new HttpContextWrapper(HttpContext.Current)))
{
}
@@ -5,8 +5,5 @@
string ForcePortnumber { get; }
string ForceProtocol { get; }
string ServerAddress { get; }
string AppId { get; }
string ServerName { get; }
}
}
@@ -26,24 +26,5 @@
{
get { return Value; }
}
public string AppId
{
get
{
return RawXml.Attribute("appId") == null
? null
: RawXml.Attribute("appId").Value;
}
}
public string ServerName
{
get
{
return RawXml.Attribute("serverName") == null
? null
: RawXml.Attribute("serverName").Value;
}
}
}
}
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.1.6");
private static readonly Version Version = new Version("7.2.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 "alpha"; } }
// 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
@@ -70,6 +70,11 @@
//TODO: Fill in the rest!
/// <summary>
/// alias for the media tree.
/// </summary>
public const string Templates = "template";
}
}
-16
View File
@@ -279,22 +279,6 @@ namespace Umbraco.Core
/// </summary>
public const string AltTemplate = "altTemplate";
}
/// <summary>
/// Defines the alias identifiers for Umbraco relation types.
/// </summary>
public static class RelationTypes
{
/// <summary>
/// ContentType name for default relation type "Relate Document On Copy".
/// </summary>
public const string RelateDocumentOnCopyName = "Relate Document On Copy";
/// <summary>
/// ContentType alias for default relation type "Relate Document On Copy".
/// </summary>
public const string RelateDocumentOnCopyAlias = "relateDocumentOnCopy";
}
}
}
}
+50 -54
View File
@@ -1,55 +1,51 @@
namespace Umbraco.Core
{
public static partial class Constants
{
/// <summary>
/// Defines the constants used for Umbraco packages in the package.config xml
/// </summary>
public static class Packaging
{
public const string UmbPackageNodeName = "umbPackage";
public const string DataTypesNodeName = "DataTypes";
public const string PackageXmlFileName = "package.xml";
public const string UmbracoPackageExtention = ".umb";
public const string DataTypeNodeName = "DataType";
public const string LanguagesNodeName = "Languages";
public const string FilesNodeName = "files";
public const string StylesheetsNodeName = "Stylesheets";
public const string TemplatesNodeName = "Templates";
public const string NameNodeName = "Name";
public const string TemplateNodeName = "Template";
public const string AliasNodeNameSmall = "alias";
public const string AliasNodeNameCapital = "Alias";
public const string DictionaryItemsNodeName = "DictionaryItems";
public const string DictionaryItemNodeName = "DictionaryItem";
public const string MacrosNodeName = "Macros";
public const string DocumentsNodeName = "Documents";
public const string DocumentSetNodeName = "DocumentSet";
public const string DocumentTypesNodeName = "DocumentTypes";
public const string DocumentTypeNodeName = "DocumentType";
public const string FileNodeName = "file";
public const string OrgNameNodeName = "orgName";
public const string OrgPathNodeName = "orgPath";
public const string GuidNodeName = "guid";
public const string StylesheetNodeName = "styleSheet";
public const string MacroNodeName = "macro";
public const string InfoNodeName = "info";
public const string PackageRequirementsMajorXpath = "./package/requirements/major";
public const string PackageRequirementsMinorXpath = "./package/requirements/minor";
public const string PackageRequirementsPatchXpath = "./package/requirements/patch";
public const string PackageNameXpath = "./package/name";
public const string PackageVersionXpath = "./package/version";
public const string PackageUrlXpath = "./package/url";
public const string PackageLicenseXpath = "./package/license";
public const string PackageLicenseXpathUrlAttribute = "url";
public const string AuthorNameXpath = "./author/name";
public const string AuthorWebsiteXpath = "./author/website";
public const string ReadmeXpath = "./readme";
public const string ControlNodeName = "control";
public const string ActionNodeName = "Action";
public const string ActionsNodeName = "Actions";
public const string UndoNodeAttribute = "undo";
public const string RunatNodeAttribute = "runat";
}
}
namespace Umbraco.Core
{
public static partial class Constants
{
/// <summary>
/// Defines the constants used for Umbraco packages in the package.config xml
/// </summary>
public static class Packaging
{
public const string UmbPackageNodeName = "umbPackage";
public const string DataTypesNodeName = "DataTypes";
public const string PackageXmlFileName = "package.xml";
public const string UmbracoPackageExtention = ".umb";
public const string DataTypeNodeName = "DataType";
public const string LanguagesNodeName = "Languages";
public const string FilesNodeName = "Files";
public const string StylesheetsNodeName = "Stylesheets";
public const string TemplatesNodeName = "Templates";
public const string OrgnameNodeName = "orgName";
public const string NameNodeName = "Name";
public const string TemplateNodeName = "Template";
public const string AliasNodeName = "Alias";
public const string DictionaryitemsNodeName = "DictionaryItems";
public const string MacrosNodeName = "macros";
public const string DocumentSetNodeName = "DocumentSet";
public const string DocumentTypesNodeName = "DocumentTypes";
public const string DocumentTypeNodeName = "DocumentType";
public const string FileNodeName = "file";
public const string OrgPathNodeName = "orgPath";
public const string GuidNodeName = "guid";
public const string StylesheetNodeName = "styleSheet";
public const string MacroNodeName = "macro";
public const string InfoNodeName = "info";
public const string PackageRequirementsMajorXpath = "/package/requirements/major";
public const string PackageRequirementsMinorXpath = "/package/requirements/minor";
public const string PackageRequirementsPatchXpath = "/package/requirements/patch";
public const string PackageNameXpath = "/package/name";
public const string PackageVersionXpath = "/package/version";
public const string PackageUrlXpath = "/package/url";
public const string PackageLicenseXpath = "/package/license";
public const string AuthorNameXpath = "/author/name";
public const string AuthorWebsiteXpath = "/author/website";
public const string ReadmeXpath = "/readme";
public const string ControlNodeName = "control";
public const string ActionNodeName = "Action";
public const string ActionsNodeName = "Actions";
public const string UndoNodeAttribute = "undo";
public const string RunatNodeAttribute = "runat";
}
}
}
@@ -130,6 +130,12 @@ namespace Umbraco.Core
/// </summary>
public const string FolderBrowserAlias = "Umbraco.FolderBrowser";
/// <summary>
/// Alias for the grid datatype.
/// </summary>
public const string GridAlias = "Umbraco.Grid";
/// <summary>
/// Guid for the Image Cropper datatype.
/// </summary>
+28 -40
View File
@@ -1,47 +1,35 @@
namespace Umbraco.Core.Events
{
public class CopyEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
{
public CopyEventArgs(TEntity original, TEntity copy, bool canCancel, int parentId)
: base(original, canCancel)
{
Copy = copy;
ParentId = parentId;
}
public class CopyEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
{
public CopyEventArgs(TEntity original, TEntity copy, bool canCancel, int parentId) : base(original, canCancel)
{
Copy = copy;
ParentId = parentId;
}
public CopyEventArgs(TEntity eventObject, TEntity copy, int parentId)
: base(eventObject)
{
Copy = copy;
ParentId = parentId;
}
public CopyEventArgs(TEntity eventObject, TEntity copy, int parentId) : base(eventObject)
{
Copy = copy;
ParentId = parentId;
}
public CopyEventArgs(TEntity eventObject, TEntity copy, bool canCancel, int parentId, bool relateToOriginal)
: base(eventObject, canCancel)
{
Copy = copy;
ParentId = parentId;
RelateToOriginal = relateToOriginal;
}
/// <summary>
/// The copied entity
/// </summary>
public TEntity Copy { get; set; }
/// <summary>
/// The copied entity
/// </summary>
public TEntity Copy { get; set; }
/// <summary>
/// The original entity
/// </summary>
public TEntity Original
{
get { return EventObject; }
}
/// <summary>
/// The original entity
/// </summary>
public TEntity Original
{
get { return EventObject; }
}
/// <summary>
/// Gets or Sets the Id of the objects new parent.
/// </summary>
public int ParentId { get; private set; }
public bool RelateToOriginal { get; set; }
}
/// <summary>
/// Gets or Sets the Id of the objects new parent.
/// </summary>
public int ParentId { get; private set; }
}
}
@@ -1,26 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Packaging.Models;
namespace Umbraco.Core.Events
{
internal class ImportPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
{
private readonly MetaData _packageMetaData;
public ImportPackageEventArgs(TEntity eventObject, bool canCancel)
: base(new[] { eventObject }, canCancel)
{
}
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
: base(new[] { eventObject })
{
_packageMetaData = packageMetaData;
}
public MetaData PackageMetaData
{
get { return _packageMetaData; }
}
}
}
@@ -4,7 +4,7 @@ using Umbraco.Core.Persistence.Migrations;
namespace Umbraco.Core.Events
{
public class MigrationEventArgs : CancellableObjectEventArgs<IList<IMigration>>
public class MigrationEventArgs : CancellableObjectEventArgs<IEnumerable<IMigration>>
{
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Events
/// <param name="targetVersion"></param>
/// <param name="canCancel"></param>
/// <param name="configuredVersion"></param>
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion, bool canCancel)
public MigrationEventArgs(IEnumerable<IMigration> eventObject, Version configuredVersion, Version targetVersion, bool canCancel)
: base(eventObject, canCancel)
{
ConfiguredVersion = configuredVersion;
@@ -28,7 +28,7 @@ namespace Umbraco.Core.Events
/// <param name="targetVersion"></param>
/// <param name="canCancel"></param>
/// <param name="configuredVersion"></param>
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, Version configuredVersion, Version targetVersion, bool canCancel)
internal MigrationEventArgs(IEnumerable<IMigration> eventObject, MigrationContext migrationContext, Version configuredVersion, Version targetVersion, bool canCancel)
: base(eventObject, canCancel)
{
MigrationContext = migrationContext;
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Events
/// <param name="eventObject"></param>
/// <param name="configuredVersion"></param>
/// <param name="targetVersion"></param>
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion)
public MigrationEventArgs(IEnumerable<IMigration> eventObject, Version configuredVersion, Version targetVersion)
: base(eventObject)
{
ConfiguredVersion = configuredVersion;
@@ -52,7 +52,7 @@ namespace Umbraco.Core.Events
/// <summary>
/// Returns all migrations that were used in the migration runner
/// </summary>
public IList<IMigration> Migrations
public IEnumerable<IMigration> Migrations
{
get { return EventObject; }
}
+2 -4
View File
@@ -1,5 +1,6 @@
using System;
using System.IO;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Core.IO
{
@@ -18,10 +19,7 @@ namespace Umbraco.Core.IO
public static void CopyFile(this IFileSystem fs, string path, string newPath)
{
using (var stream = fs.OpenFile(path))
{
fs.AddFile(newPath, stream);
}
fs.AddFile(newPath, fs.OpenFile(path));
}
public static string GetExtension(this IFileSystem fs, string path)
+1
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Core.IO
{
+1
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using Umbraco.Core.CodeAnnotations;
namespace Umbraco.Core.IO
{
+5 -3
View File
@@ -3,7 +3,10 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Core.Logging;
using Umbraco.Core.Publishing;
namespace Umbraco.Core.IO
{
@@ -90,9 +93,8 @@ namespace Umbraco.Core.IO
public void AddFile(string path, Stream stream, bool overrideIfExists)
{
var exists = FileExists(path);
if (exists && overrideIfExists == false) throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
if (FileExists(path) && !overrideIfExists) throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
EnsureDirectory(Path.GetDirectoryName(path));
if (stream.CanSeek)
+12 -11
View File
@@ -154,18 +154,19 @@ namespace Umbraco.Core.IO
EnsureFileSupportsResizing();
using (var fs = _fs.OpenFile(Path))
using (var image = Image.FromStream(fs))
{
var fileWidth = image.Width;
var fileHeight = image.Height;
_size = new Size(fileWidth, fileHeight);
using (var image = Image.FromStream(fs))
{
var fileWidth = image.Width;
var fileHeight = image.Height;
_size = new Size(fileWidth, fileHeight);
}
}
}
else
{
_size = new Size(-1, -1);
}
}
}
return _size.Value;
}
@@ -178,7 +179,7 @@ namespace Umbraco.Core.IO
var fileNameThumb = DoResize(width, height, -1, string.Empty);
return _fs.GetUrl(fileNameThumb);
return _fs.GetUrl(fileNameThumb);
}
return string.Empty;
}
@@ -191,7 +192,7 @@ namespace Umbraco.Core.IO
var fileNameThumb = DoResize(-1, -1, maxWidthHeight, fileNameAddition);
return _fs.GetUrl(fileNameThumb);
return _fs.GetUrl(fileNameThumb);
}
return string.Empty;
}
@@ -205,14 +206,14 @@ namespace Umbraco.Core.IO
var fileNameThumb = string.IsNullOrWhiteSpace(fileNameAddition)
? string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)))
: string.Format("{0}_{1}.jpg", Path.Substring(0, Path.LastIndexOf(".", StringComparison.Ordinal)), fileNameAddition);
var thumbnail = maxWidthHeight == -1
? ImageHelper.GenerateThumbnail(image, width, height, fileNameThumb, Extension, _fs)
: ImageHelper.GenerateThumbnail(image, maxWidthHeight, fileNameThumb, Extension, _fs);
return thumbnail.FileName;
}
}
}
}
private void EnsureFileSupportsResizing()
@@ -221,6 +222,6 @@ namespace Umbraco.Core.IO
throw new InvalidOperationException(string.Format("The file {0} is not an image, so can't get dimensions", Filename));
}
}
}
+3 -17
View File
@@ -8,8 +8,6 @@ namespace Umbraco.Core.Manifest
internal class ManifestWatcher : DisposableObject
{
private readonly List<FileSystemWatcher> _fws = new List<FileSystemWatcher>();
private static volatile bool _isRestarting = false;
private static readonly object Locker = new object();
public void Start(params string[] packageFolders)
{
@@ -34,21 +32,9 @@ namespace Umbraco.Core.Manifest
{
if (e.Name.InvariantContains("package.manifest"))
{
//Ensure the app is not restarted multiple times for multiple saving during the same app domain execution
if (_isRestarting == false)
{
lock (Locker)
{
if (_isRestarting == false)
{
_isRestarting = true;
LogHelper.Info<ManifestWatcher>("manifest has changed, app pool is restarting (" + e.FullPath + ")");
HttpRuntime.UnloadAppDomain();
Dispose();
}
}
}
LogHelper.Info<ManifestWatcher>("manifest has changed, app pool is restarting (" + e.FullPath + ")");
HttpRuntime.UnloadAppDomain();
Dispose();
}
}
-10
View File
@@ -165,16 +165,6 @@ namespace Umbraco.Core.Media
ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L);
// Save the new image using the dimensions of the image
var predictableThumbnailName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", maxWidthHeight.ToString(CultureInfo.InvariantCulture));
using (var ms = new MemoryStream())
{
bp.Save(ms, codec, ep);
ms.Seek(0, 0);
fs.AddFile(predictableThumbnailName, ms);
}
// TODO: Remove this, this is ONLY here for backwards compatibility but it is essentially completely unusable see U4-5385
var newFileName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", string.Format("{0}x{1}", widthTh, heightTh));
using (var ms = new MemoryStream())
{
+4 -28
View File
@@ -240,28 +240,6 @@ namespace Umbraco.Core.Models
return content.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Contains(recycleBinId.ToInvariantString());
}
/// <summary>
/// Removes characters that are not valide XML characters from all entity properties
/// of type string. See: http://stackoverflow.com/a/961504/5018
/// </summary>
/// <returns></returns>
/// <remarks>
/// If this is not done then the xml cache can get corrupt and it will throw YSODs upon reading it.
/// </remarks>
/// <param name="entity"></param>
public static void SanitizeEntityPropertiesForXmlStorage(this IContentBase entity)
{
entity.Name = entity.Name.ToValidXmlString();
foreach (var property in entity.Properties)
{
if (property.Value is string)
{
var value = (string)property.Value;
property.Value = value.ToValidXmlString();
}
}
}
/// <summary>
/// Checks if the IContentBase has children
@@ -612,12 +590,6 @@ namespace Umbraco.Core.Models
{
throw new IndexOutOfRangeException("No property exists with name " + propertyTypeAlias);
}
property.SetTags(storageType, propertyTypeAlias, tags, replaceTags, tagGroup);
}
internal static void SetTags(this Property property, TagCacheStorageType storageType, string propertyTypeAlias, IEnumerable<string> tags, bool replaceTags, string tagGroup = "default")
{
if (property == null) throw new ArgumentNullException("property");
var trimmedTags = tags.Select(x => x.Trim()).ToArray();
@@ -756,6 +728,10 @@ namespace Umbraco.Core.Models
{
return ((PackagingService)(ApplicationContext.Current.Services.PackagingService)).Export(member);
}
#endregion
}
}
@@ -93,8 +93,17 @@ namespace Umbraco.Core.Models
{
if (ContentTypeCompositionExists(alias))
{
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
var contentTypeComposition = ContentTypeComposition.FirstOrDefault(x => x.Alias == alias);
if (contentTypeComposition == null)//You can't remove a composition from another composition
return false;
RemovedContentTypeKeyTracker.Add(contentTypeComposition.Id);
//If the ContentType we are removing has Compositions of its own these needs to be removed as well
var compositionIdsToRemove = contentTypeComposition.CompositionIds().ToList();
if(compositionIdsToRemove.Any())
RemovedContentTypeKeyTracker.AddRange(compositionIdsToRemove);
OnPropertyChanged(ContentTypeCompositionSelector);
return _contentTypeComposition.Remove(contentTypeComposition);
}
+10 -18
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@@ -28,11 +27,6 @@ namespace Umbraco.Core.Models
public static class DeepCloneHelper
{
/// <summary>
/// Used to avoid constant reflection (perf)
/// </summary>
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropCache = new ConcurrentDictionary<Type, PropertyInfo[]>();
/// <summary>
/// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output')
/// </summary>
@@ -49,18 +43,16 @@ namespace Umbraco.Core.Models
throw new InvalidOperationException("Both the input and output types must be the same");
}
var refProperties = PropCache.GetOrAdd(inputType, type =>
inputType.GetProperties()
.Where(x =>
//is not attributed with the ignore clone attribute
x.GetCustomAttribute<DoNotCloneAttribute>() == null
//reference type but not string
&& x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
//settable
&& x.CanWrite
//non-indexed
&& x.GetIndexParameters().Any() == false)
.ToArray());
var refProperties = inputType.GetProperties()
.Where(x =>
//is not attributed with the ignore clone attribute
x.GetCustomAttribute<DoNotCloneAttribute>() == null
//reference type but not string
&& x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
//settable
&& x.CanWrite
//non-indexed
&& x.GetIndexParameters().Any() == false);
foreach (var propertyInfo in refProperties)
{
+6 -3
View File
@@ -1,4 +1,7 @@
using System.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
@@ -20,5 +23,5 @@ namespace Umbraco.Core.Models
var dirty = (IRememberBeingDirty)entity;
return dirty.WasPropertyDirty("Id");
}
}
}
}
}
-5
View File
@@ -3,9 +3,6 @@ using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a Tag, which is composed of a Text, Group and NodeCount property.
/// </summary>
public interface ITag : IAggregateRoot
{
[DataMember]
@@ -14,8 +11,6 @@ namespace Umbraco.Core.Models
[DataMember]
string Group { get; set; }
int NodeCount { get; }
//TODO: enable this at some stage
//int ParentId { get; set; }
}
@@ -1,6 +1,4 @@
using System.Collections;
namespace Umbraco.Core.Models.Membership
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents a user -> entity permission
@@ -1,59 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents an entity -> user & permission key value pair collection
/// </summary>
public class EntityPermissionSet
{
/// <summary>
/// The entity id with permissions assigned
/// </summary>
public int EntityId { get; private set; }
/// <summary>
/// The key/value pairs of user id & single permission
/// </summary>
public IEnumerable<UserPermission> UserPermissionsSet { get; private set; }
public EntityPermissionSet(int entityId, IEnumerable<UserPermission> userPermissionsSet)
{
EntityId = entityId;
UserPermissionsSet = userPermissionsSet;
}
public class UserPermission
{
public UserPermission(int userId, string permission)
{
UserId = userId;
Permission = permission;
}
public int UserId { get; private set; }
public string Permission { get; private set; }
protected bool Equals(UserPermission other)
{
return UserId == other.UserId && string.Equals(Permission, other.Permission);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((UserPermission) obj);
}
public override int GetHashCode()
{
unchecked
{
return (UserId*397) ^ Permission.GetHashCode();
}
}
}
}
}
@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Defines the base contract for <see cref="IMember"/> and <see cref="IUser"/>
/// </summary>
public interface IMembershipUser : IAggregateRoot
{
object ProviderUserKey { get; set; }
+9 -48
View File
@@ -1,55 +1,27 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Models.Membership
{
/// <summary>
/// Represents the Type for a Backoffice User
/// </summary>
/// </summary>
/// <remarks>
/// Should be internal until a proper user/membership implementation
/// is part of the roadmap.
/// </remarks>
[Serializable]
[DataContract(IsReference = true)]
internal class UserType : Entity, IUserType
{
private string _alias;
private string _name;
private IEnumerable<string> _permissions;
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Name);
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Alias);
private static readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo<UserType, IEnumerable<string>>(x => x.Permissions);
[DataMember]
public string Alias { get; set; }
[DataMember]
public string Alias
{
get { return _alias; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
return _alias;
}, _alias, AliasSelector);
}
}
[DataMember]
public string Name
{
get { return _name; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_name = value;
return _name;
}, _name, NameSelector);
}
}
public string Name { get; set; }
/// <summary>
/// The set of default permissions for the user type
@@ -58,17 +30,6 @@ namespace Umbraco.Core.Models.Membership
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
/// </remarks>
[DataMember]
public IEnumerable<string> Permissions
{
get { return _permissions; }
set
{
SetPropertyValueAndDetectChanges(o =>
{
_permissions = value;
return _permissions;
}, _permissions, PermissionsSelector);
}
}
public IEnumerable<string> Permissions { get; set; }
}
}
-74
View File
@@ -1,74 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Umbraco.Core.IO;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a Partial View file
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class PartialView : File
{
private readonly Regex _headerMatch = new Regex("^@inherits\\s+?.*$", RegexOptions.Multiline | RegexOptions.Compiled);
public PartialView(string path)
: base(path)
{
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: Validate using the macro engine
//var engine = MacroEngineFactory.GetEngine(PartialViewMacroEngine.EngineName);
//engine.Validate(...)
var validatePath = IOHelper.ValidateEditPath(IOHelper.MapPath(Path), BasePath);
var verifyFileExtension = IOHelper.VerifyFileExtension(Path, new List<string> { "cshtml" });
return validatePath && verifyFileExtension;
}
public string OldFileName { get; set; }
public string FileName { get; set; }
public string SnippetName { get; set; }
public bool CreateMacro { get; set; }
public string CodeHeader { get; set; }
public string ParentFolderName { get; set; }
public string EditViewFile { get; set; }
public string BasePath { get; set; }
public string ReturnUrl { get; set; }
internal Regex HeaderMatch
{
get { return _headerMatch; }
}
internal Attempt<string> TryGetSnippetPath(string fileName)
{
var partialViewsFileSystem = new PhysicalFileSystem(BasePath);
var snippetPath = IOHelper.MapPath(string.Format("{0}/PartialViewMacros/Templates/{1}", SystemDirectories.Umbraco, fileName));
return partialViewsFileSystem.FileExists(snippetPath)
? Attempt<string>.Succeed(snippetPath)
: Attempt<string>.Fail();
}
}
}
@@ -43,11 +43,6 @@ namespace Umbraco.Core.Models.PublishedContent
internal static IPublishedContentExtended Extend(IPublishedContent content, IEnumerable<IPublishedContent> contentSet)
{
// first unwrap content down to the lowest possible level, ie either the deepest inner
// IPublishedContent or the first extended that has added properties. this is to avoid
// nesting extended objects as much as possible, so we try to re-extend that lowest
// object.
var wrapped = content as PublishedContentExtended;
while (wrapped != null && ((IPublishedContentExtended)wrapped).HasAddedProperties == false)
wrapped = (content = wrapped.Unwrap()) as PublishedContentExtended;
@@ -56,38 +51,14 @@ namespace Umbraco.Core.Models.PublishedContent
// a model, and then that model has to inherit from PublishedContentExtended,
// => implements the internal IPublishedContentExtended.
// here we assume that either the factory just created a model that implements
// IPublishedContentExtended and therefore does not need to be extended again,
// because it can carry the extra property - or that it did *not* create a
// model and therefore returned the original content unchanged.
var model = content.CreateModel();
var extended = model == content // == means the factory did not create a model
? new PublishedContentExtended(content) // so we have to extend
: model; // else we can use what the factory returned
// so extended should always implement IPublishedContentExtended, however if
// by mistake the factory returned a different object that does not implement
// IPublishedContentExtended (which would be an error), throw.
//
// see also PublishedContentExtensionsForModels.CreateModel
// NOTE
// could we lift that constraint and accept that models just be IPublishedContent?
// would then mean that we cannot assume a model is IPublishedContentExtended, so
// either it is, or we need to wrap it. so instead of having
// (Model:IPublishedContentExtended (IPublishedContent))
// we'd have
// (PublishedContentExtended (Model (IPublishedContent)))
// and it is that bad? any other consequences?
//
// would also allow the factory to cache the model (though that should really
// be done by the content cache, not by the factory).
var extended2 = extended as IPublishedContentExtended;
if (extended2 == null)
throw new Exception("Extended does not implement IPublishedContentExtended.");
extended2.SetContentSet(contentSet);
if (extended2 != null) // always true, but keeps Resharper happy
extended2.SetContentSet(contentSet);
return extended2;
}
@@ -1,6 +1,4 @@
using System;
namespace Umbraco.Core.Models.PublishedContent
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Provides strongly typed published content models services.
@@ -14,32 +12,9 @@ namespace Umbraco.Core.Models.PublishedContent
/// <returns>The strongly typed published content model.</returns>
public static IPublishedContent CreateModel(this IPublishedContent content)
{
if (content == null)
return null;
if (PublishedContentModelFactoryResolver.Current.HasValue == false)
return content;
// get model
// if factory returns nothing, throw
// if factory just returns what it got, return
var model = PublishedContentModelFactoryResolver.Current.Factory.CreateModel(content);
if (model == null)
throw new Exception("IPublishedContentFactory returned null.");
if (ReferenceEquals(model, content))
return content;
// at the moment, other parts of our code assume that all models will
// somehow implement IPublishedContentExtended and not just be IPublishedContent,
// so we'd better check this here to fail as soon as we can.
//
// see also PublishedContentExtended.Extend
var extended = model as IPublishedContentExtended;
if (extended == null)
throw new Exception("IPublishedContentFactory created an object that does not implement IPublishedContentModelExtended.");
return model;
return PublishedContentModelFactoryResolver.Current.HasValue
? PublishedContentModelFactoryResolver.Current.Factory.CreateModel(content)
: content;
}
}
}
@@ -31,7 +31,7 @@ namespace Umbraco.Core.Models.PublishedContent
public PublishedContentModelFactory(IEnumerable<Type> types)
{
var ctorArgTypes = new[] { typeof(IPublishedContent) };
var constructors = new Dictionary<string, Func<IPublishedContent, IPublishedContent>>(StringComparer.InvariantCultureIgnoreCase);
var constructors = new Dictionary<string, Func<IPublishedContent, IPublishedContent>>();
foreach (var type in types)
{
@@ -40,6 +40,7 @@ namespace Umbraco.Core.Models.PublishedContent
throw new InvalidOperationException(string.Format("Type {0} is missing a public constructor with one argument of type IPublishedContent.", type.FullName));
var attribute = type.GetCustomAttribute<PublishedContentModelAttribute>(false);
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
typeName = typeName.ToLowerInvariant();
if (constructors.ContainsKey(typeName))
throw new InvalidOperationException(string.Format("More that one type want to be a model for content type {0}.", typeName));
@@ -69,7 +70,7 @@ namespace Umbraco.Core.Models.PublishedContent
return content;
// be case-insensitive
var contentTypeAlias = content.DocumentTypeAlias;
var contentTypeAlias = content.DocumentTypeAlias.ToLowerInvariant();
//ConstructorInfo constructor;
//return _constructors.TryGetValue(contentTypeAlias, out constructor)
@@ -78,23 +78,5 @@ namespace Umbraco.Core.Models.Rdbms
return string.Empty;
}
}
protected bool Equals(PropertyDataDto other)
{
return Id == other.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((PropertyDataDto) obj);
}
public override int GetHashCode()
{
return Id;
}
}
}
-3
View File
@@ -27,8 +27,5 @@ namespace Umbraco.Core.Models.Rdbms
[NullSetting(NullSetting = NullSettings.Null)]
[Length(100)]
public string Group { get; set; }//NOTE Is set to [varchar] (100) in Sql Server script
[ResultColumn("NodeCount")]
public int NodeCount { get; set; }
}
}
+28 -9
View File
@@ -1,11 +1,38 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
public class TaggedEntity
{
public TaggedEntity(int entityId, IEnumerable<TaggedProperty> taggedProperties)
{
EntityId = entityId;
TaggedProperties = taggedProperties;
}
public int EntityId { get; private set; }
public IEnumerable<TaggedProperty> TaggedProperties { get; private set; }
}
public class TaggedProperty
{
public TaggedProperty(int propertyTypeId, string propertyTypeAlias, IEnumerable<Tag> tags)
{
PropertyTypeId = propertyTypeId;
PropertyTypeAlias = propertyTypeAlias;
Tags = tags;
}
public int PropertyTypeId { get; private set; }
public string PropertyTypeAlias { get; private set; }
public IEnumerable<Tag> Tags { get; private set; }
}
[Serializable]
[DataContract(IsReference = true)]
public class Tag : Entity, ITag
@@ -16,15 +43,9 @@ namespace Umbraco.Core.Models
public Tag(int id, string text, string @group)
{
Id = id;
Text = text;
Group = @group;
}
public Tag(int id, string text, string @group, int nodeCount)
: this(id, text, @group)
{
NodeCount = nodeCount;
Id = id;
}
private static readonly PropertyInfo TextSelector = ExpressionHelper.GetPropertyInfo<Tag, string>(x => x.Text);
@@ -58,8 +79,6 @@ namespace Umbraco.Core.Models
}
}
public int NodeCount { get; internal set; }
//TODO: enable this at some stage
//public int ParentId { get; set; }
}
-28
View File
@@ -1,28 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a tagged entity.
/// </summary>
/// <remarks>Note that it is the properties of an entity (like Content, Media, Members, etc.) that is tagged,
/// which is why this class is composed of a list of tagged properties and an Id reference to the actual entity.</remarks>
public class TaggedEntity
{
public TaggedEntity(int entityId, IEnumerable<TaggedProperty> taggedProperties)
{
EntityId = entityId;
TaggedProperties = taggedProperties;
}
/// <summary>
/// Id of the entity, which is tagged
/// </summary>
public int EntityId { get; private set; }
/// <summary>
/// An enumerable list of tagged properties
/// </summary>
public IEnumerable<TaggedProperty> TaggedProperties { get; private set; }
}
}
-32
View File
@@ -1,32 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a tagged property on an entity.
/// </summary>
public class TaggedProperty
{
public TaggedProperty(int propertyTypeId, string propertyTypeAlias, IEnumerable<ITag> tags)
{
PropertyTypeId = propertyTypeId;
PropertyTypeAlias = propertyTypeAlias;
Tags = tags;
}
/// <summary>
/// Id of the PropertyType, which this tagged property is based on
/// </summary>
public int PropertyTypeId { get; private set; }
/// <summary>
/// Alias of the PropertyType, which this tagged property is based on
/// </summary>
public string PropertyTypeAlias { get; private set; }
/// <summary>
/// An enumerable list of Tags for the property
/// </summary>
public IEnumerable<ITag> Tags { get; private set; }
}
}
@@ -87,13 +87,13 @@ namespace Umbraco.Core.Models
{
var type = typeof(UmbracoObjectTypes);
var memInfo = type.GetMember(umbracoObjectType.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(FriendlyNameAttribute),
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
false);
if (attributes.Length == 0)
return string.Empty;
var attribute = ((FriendlyNameAttribute)attributes[0]);
var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
if (attribute == null)
return string.Empty;
-32
View File
@@ -1,32 +0,0 @@
using System;
namespace Umbraco.Core
{
/// <summary>
/// Provides an equivalent to the c# lock statement, to be used in a using block.
/// </summary>
/// <remarks>Ie replace <c>lock (o) {...}</c> by <c>using (new MonitorLock(o)) { ... }</c></remarks>
public class MonitorLock : IDisposable
{
private readonly object _locker;
private readonly bool _entered;
/// <summary>
/// Initializes a new instance of the <see cref="MonitorLock"/> class with an object to lock.
/// </summary>
/// <param name="locker">The object to lock.</param>
/// <remarks>Should always be used within a using block.</remarks>
public MonitorLock(object locker)
{
_locker = locker;
_entered = false;
System.Threading.Monitor.Enter(_locker, ref _entered);
}
void IDisposable.Dispose()
{
if (_entered)
System.Threading.Monitor.Exit(_locker);
}
}
}
@@ -63,11 +63,6 @@ namespace Umbraco.Core.ObjectResolution
}
}
// NOTE - the ugly code below exists only because of umbraco.BusinessLogic.Actions.Action.ReRegisterActionsAndHandlers
// which wants to re-register actions and handlers instead of properly restarting the application. Don't even think
// about using it for anything else. Also, while the backdoor is open, the resolution system is locked so nothing
// can work properly => deadlocks. Therefore, open the backdoor, do resolution changes EXCLUSIVELY, and close the door!
/// <summary>
/// Returns a disposable object that reprents dirty access to temporarily unfrozen resolution configuration.
/// </summary>
@@ -1,92 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
namespace Umbraco.Core.Packaging
{
internal class ConflictingPackageData : IConflictingPackageData
{
private readonly IMacroService _macroService;
private readonly IFileService _fileService;
public ConflictingPackageData(IMacroService macroService,
IFileService fileService)
{
if (fileService != null) _fileService = fileService;
else throw new ArgumentNullException("fileService");
if (macroService != null) _macroService = macroService;
else throw new ArgumentNullException("macroService");
}
public IEnumerable<IFile> FindConflictingStylesheets(XElement stylesheetNotes)
{
if (string.Equals(Constants.Packaging.StylesheetsNodeName, stylesheetNotes.Name.LocalName) == false)
{
throw new ArgumentException("the root element must be \"" + Constants.Packaging.StylesheetsNodeName + "\"", "stylesheetNotes");
}
return stylesheetNotes.Elements(Constants.Packaging.StylesheetNodeName)
.Select(n =>
{
XElement xElement = n.Element(Constants.Packaging.NameNodeName);
if (xElement == null)
{
throw new ArgumentException("Missing \"" + Constants.Packaging.NameNodeName + "\" element",
"stylesheetNotes");
}
return _fileService.GetStylesheetByName(xElement.Value) as IFile;
})
.Where(v => v != null);
}
public IEnumerable<ITemplate> FindConflictingTemplates(XElement templateNotes)
{
if (string.Equals(Constants.Packaging.TemplatesNodeName, templateNotes.Name.LocalName) == false)
{
throw new ArgumentException("Node must be a \"" + Constants.Packaging.TemplatesNodeName + "\" node",
"templateNotes");
}
return templateNotes.Elements(Constants.Packaging.TemplateNodeName)
.Select(n =>
{
XElement xElement = n.Element(Constants.Packaging.AliasNodeNameCapital) ?? n.Element(Constants.Packaging.AliasNodeNameSmall);
if (xElement == null)
{
throw new ArgumentException("missing a \"" + Constants.Packaging.AliasNodeNameCapital + "\" element",
"templateNotes");
}
return _fileService.GetTemplate(xElement.Value);
})
.Where(v => v != null);
}
public IEnumerable<IMacro> FindConflictingMacros(XElement macroNodes)
{
if (string.Equals(Constants.Packaging.MacrosNodeName, macroNodes.Name.LocalName) == false)
{
throw new ArgumentException("Node must be a \"" + Constants.Packaging.MacrosNodeName + "\" node",
"macroNodes");
}
return macroNodes.Elements(Constants.Packaging.MacroNodeName)
.Select(n =>
{
XElement xElement = n.Element(Constants.Packaging.AliasNodeNameSmall) ?? n.Element(Constants.Packaging.AliasNodeNameCapital);
if (xElement == null)
{
throw new ArgumentException(string.Format("missing a \"{0}\" element in {0} element", Constants.Packaging.AliasNodeNameSmall),
"macroNodes");
}
return _macroService.GetByAlias(xElement.Value);
})
.Where(v => v != null);
}
}
}
@@ -1,13 +0,0 @@
using System.Collections.Generic;
using System.Xml.Linq;
using Umbraco.Core.Models;
namespace Umbraco.Core.Packaging
{
internal interface IConflictingPackageData
{
IEnumerable<IFile> FindConflictingStylesheets(XElement stylesheetNotes);
IEnumerable<ITemplate> FindConflictingTemplates(XElement templateNotes);
IEnumerable<IMacro> FindConflictingMacros(XElement macroNodes);
}
}
@@ -1,62 +0,0 @@
using System.Collections.Generic;
namespace Umbraco.Core.Packaging
{
/// <summary>
/// Used to access an umbraco package file
/// Remeber that filenames must be unique
/// use "FindDubletFileNames" for sanitycheck
/// </summary>
internal interface IPackageExtraction
{
/// <summary>
/// Returns the content of the file with the given filename
/// </summary>
/// <param name="packageFilePath">Full path to the umbraco package file</param>
/// <param name="fileToRead">filename of the file for wich to get the text content</param>
/// <param name="directoryInPackage">this is the relative directory for the location of the file in the package
/// I dont know why umbraco packages contains directories in the first place??</param>
/// <returns>text content of the file</returns>
string ReadTextFileFromArchive(string packageFilePath, string fileToRead, out string directoryInPackage);
/// <summary>
/// Copies a file from package to given destination
/// </summary>
/// <param name="packageFilePath">Full path to the ubraco package file</param>
/// <param name="fileInPackageName">filename of the file to copy</param>
/// <param name="destinationfilePath">destination path (including destination filename)</param>
/// <returns>True a file was overwritten</returns>
void CopyFileFromArchive(string packageFilePath, string fileInPackageName, string destinationfilePath);
/// <summary>
/// Copies a file from package to given destination
/// </summary>
/// <param name="packageFilePath">Full path to the ubraco package file</param>
/// <param name="sourceDestination">Key: Source file in package. Value: Destination path inclusive file name</param>
void CopyFilesFromArchive(string packageFilePath, IEnumerable<KeyValuePair<string, string>> sourceDestination);
/// <summary>
/// Check if given list of files can be found in the package
/// </summary>
/// <param name="packageFilePath">Full path to the umbraco package file</param>
/// <param name="expectedFiles">a list of files you would like to find in the package</param>
/// <returns>a subset if any of the files in "expectedFiles" that could not be found in the package</returns>
IEnumerable<string> FindMissingFiles(string packageFilePath, IEnumerable<string> expectedFiles);
/// <summary>
/// Sanitycheck - should return en empty collection if package is valid
/// </summary>
/// <param name="packageFilePath">Full path to the umbraco package file</param>
/// <returns>list of files that are found more than ones (accross directories) in the package</returns>
IEnumerable<string> FindDubletFileNames(string packageFilePath);
/// <summary>
/// Reads the given files from archive and returns them as a collection of byte arrays
/// </summary>
/// <param name="packageFilePath"></param>
/// <param name="filesToGet"></param>
/// <returns></returns>
IEnumerable<byte[]> ReadFilesFromArchive(string packageFilePath, IEnumerable<string> filesToGet);
}
}
@@ -1,13 +0,0 @@
using System.Xml.Linq;
using Umbraco.Core.Packaging.Models;
namespace Umbraco.Core.Packaging
{
internal interface IPackageInstallation
{
InstallationSummary InstallPackage(string packageFilePath, int userId);
MetaData GetMetaData(string packageFilePath);
PreInstallWarnings GetPreInstallWarnings(string packageFilePath);
XElement GetConfigXmlElement(string packageFilePath);
}
}
@@ -0,0 +1,21 @@
using System;
using System.Runtime.Serialization;
using System.Xml;
namespace Umbraco.Core.Packaging.Models
{
[Serializable]
[DataContract(IsReference = true)]
internal class InstallAction
{
public string Alias { get; set; }
public string PackageName { get; set; }
public string RunAt { get; set; }//NOTE Should this default to "install"
public bool Undo { get; set; }
public XmlNode XmlData { get; set; }
}
}
@@ -1,44 +1,24 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Models;
namespace Umbraco.Core.Packaging.Models
{
[Serializable]
[DataContract(IsReference = true)]
internal class InstallationSummary
{
public MetaData MetaData { get; set; }
public IEnumerable<IDataTypeDefinition> DataTypesInstalled { get; set; }
public IEnumerable<ILanguage> LanguagesInstalled { get; set; }
public IEnumerable<IDictionaryItem> DictionaryItemsInstalled { get; set; }
public IEnumerable<IMacro> MacrosInstalled { get; set; }
public IEnumerable<string> FilesInstalled { get; set; }
public IEnumerable<ITemplate> TemplatesInstalled { get; set; }
public IEnumerable<IContentType> ContentTypesInstalled { get; set; }
public IEnumerable<IFile> StylesheetsInstalled { get; set; }
public IEnumerable<IContent> ContentInstalled { get; set; }
public IEnumerable<PackageAction> Actions { get; set; }
public bool PackageInstalled { get; set; }
}
internal static class InstallationSummaryExtentions
{
public static InstallationSummary InitEmpty(this InstallationSummary summary)
{
summary.Actions = new List<PackageAction>();
summary.ContentInstalled = new List<IContent>();
summary.ContentTypesInstalled = new List<IContentType>();
summary.DataTypesInstalled = new List<IDataTypeDefinition>();
summary.DictionaryItemsInstalled = new List<IDictionaryItem>();
summary.FilesInstalled = new List<string>();
summary.LanguagesInstalled = new List<ILanguage>();
summary.MacrosInstalled = new List<IMacro>();
summary.MetaData = new MetaData();
summary.TemplatesInstalled = new List<ITemplate>();
summary.PackageInstalled = false;
return summary;
}
}
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Umbraco.Core.Packaging.Models
{
[Serializable]
[DataContract(IsReference = true)]
internal class InstallationSummary
{
public MetaData MetaData { get; set; }
public IEnumerable<int> DataTypesInstalled { get; set; }
public IEnumerable<int> LanguagesInstalled { get; set; }
public IEnumerable<int> DictionaryItemsInstalled { get; set; }
public IEnumerable<int> MacrosInstalled { get; set; }
public IEnumerable<KeyValuePair<string, bool>> FilesInstalled { get; set;}
public IEnumerable<int> TemplatesInstalled { get; set; }
public IEnumerable<int> DocumentTypesInstalled { get; set; }
public IEnumerable<int> StylesheetsInstalled { get; set; }
public IEnumerable<int> DocumentsInstalled { get; set; }
public IEnumerable<InstallAction> InstallActions { get; set; }
public IEnumerable<UninstallAction> UninstallActions { get; set; }
}
}
@@ -1,38 +0,0 @@
using System;
using System.Runtime.Serialization;
using System.Xml.Linq;
namespace Umbraco.Core.Packaging.Models
{
internal enum ActionRunAt
{
Undefined = 0,
Install,
Uninstall
}
[Serializable]
[DataContract(IsReference = true)]
internal class PackageAction
{
private ActionRunAt _runAt;
private bool? _undo;
public string Alias { get; set; }
public string PackageName { get; set; }
public ActionRunAt RunAt
{
get { return _runAt == ActionRunAt.Undefined ? ActionRunAt.Install : _runAt; }
set { _runAt = value; }
}
public bool Undo //NOTE: Should thid default to "False"? but the documentation says default "True" (http://our.umbraco.org/wiki/reference/packaging/package-actions)
{
get { return _undo ?? true; }
set { _undo = value; }
}
public XElement XmlData { get; set; }
}
}
@@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Models;
namespace Umbraco.Core.Packaging.Models
{
[Serializable]
[DataContract(IsReference = true)]
internal class PreInstallWarnings
{
public KeyValuePair<string, string>[] UnsecureFiles { get; set; }
public KeyValuePair<string, string>[] FilesReplaced { get; set; }
public IEnumerable<IMacro> ConflictingMacroAliases { get; set; }
public IEnumerable<ITemplate> ConflictingTemplateAliases { get; set; }
public IEnumerable<IFile> ConflictingStylesheetNames { get; set; }
public IEnumerable<string> AssembliesWithLegacyPropertyEditors { get; set; }
}
}
@@ -0,0 +1,21 @@
using System;
using System.Runtime.Serialization;
using System.Xml;
namespace Umbraco.Core.Packaging.Models
{
[Serializable]
[DataContract(IsReference = true)]
internal class UninstallAction
{
public string Alias { get; set; }
public string PackageName { get; set; }
public string RunAt { get; set; }//NOTE Should this default to "install"
public bool Undo { get; set; }//NOTE: Should thid default to "False"?
public XmlNode XmlData { get; set; }
}
}
@@ -5,47 +5,15 @@ using System.Linq;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Packaging
{
// Note
// That class uses ReflectionOnlyLoad which does NOT handle policies (bindingRedirect) and
// therefore raised warnings when installing a package, if an exact dependency could not be
// found, though it would be found via policies. So we have to explicitely apply policies
// where appropriate.
internal class PackageBinaryInspector : MarshalByRefObject
{
/// <summary>
/// Entry point to call from your code
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblys"></param>
/// <param name="errorReport"></param>
/// <returns></returns>
/// <remarks>
/// Will perform the assembly scan in a separate app domain
/// </remarks>
public static IEnumerable<string> ScanAssembliesForTypeReference<T>(IEnumerable<byte[]> assemblys, out string[] errorReport)
{
var appDomain = GetTempAppDomain();
var type = typeof(PackageBinaryInspector);
try
{
var value = (PackageBinaryInspector)appDomain.CreateInstanceAndUnwrap(
type.Assembly.FullName,
type.FullName);
// do NOT turn PerformScan into static (even if ReSharper says so)!
var result = value.PerformScan<T>(assemblys.ToArray(), out errorReport);
return result;
}
finally
{
AppDomain.Unload(appDomain);
}
}
/// <summary>
/// Entry point to call from your code
/// </summary>
@@ -65,7 +33,6 @@ namespace Umbraco.Core.Packaging
var value = (PackageBinaryInspector)appDomain.CreateInstanceAndUnwrap(
type.Assembly.FullName,
type.FullName);
// do NOT turn PerformScan into static (even if ReSharper says so)!
var result = value.PerformScan<T>(dllPath, out errorReport);
return result;
}
@@ -75,35 +42,6 @@ namespace Umbraco.Core.Packaging
}
}
/// <summary>
/// Performs the assembly scanning
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="assemblies"></param>
/// <param name="errorReport"></param>
/// <returns></returns>
/// <remarks>
/// This method is executed in a separate app domain
/// </remarks>
private IEnumerable<string> PerformScan<T>(IEnumerable<byte[]> assemblies, out string[] errorReport)
{
//we need this handler to resolve assembly dependencies when loading below
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, e) =>
{
var name = AppDomain.CurrentDomain.ApplyPolicy(e.Name);
var a = Assembly.ReflectionOnlyLoad(name);
if (a == null) throw new TypeLoadException("Could not load assembly " + e.Name);
return a;
};
//First load each dll file into the context
// do NOT apply policy here: we want to scan the dlls that are in the binaries
var loaded = assemblies.Select(Assembly.ReflectionOnlyLoad).ToList();
//scan
return PerformScan<T>(loaded, out errorReport);
}
/// <summary>
/// Performs the assembly scanning
/// </summary>
@@ -114,42 +52,33 @@ namespace Umbraco.Core.Packaging
/// <remarks>
/// This method is executed in a separate app domain
/// </remarks>
private IEnumerable<string> PerformScan<T>(string dllPath, out string[] errorReport)
internal IEnumerable<string> PerformScan<T>(string dllPath, out string[] errorReport)
{
if (Directory.Exists(dllPath) == false)
{
throw new DirectoryNotFoundException("Could not find directory " + dllPath);
}
//we need this handler to resolve assembly dependencies when loading below
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, e) =>
{
var name = AppDomain.CurrentDomain.ApplyPolicy(e.Name);
var a = Assembly.ReflectionOnlyLoad(name);
if (a == null) throw new TypeLoadException("Could not load assembly " + e.Name);
return a;
};
//First load each dll file into the context
// do NOT apply policy here: we want to scan the dlls that are in the path
var files = Directory.GetFiles(dllPath, "*.dll");
var loaded = files.Select(Assembly.ReflectionOnlyLoadFrom).ToList();
//scan
return PerformScan<T>(loaded, out errorReport);
}
private static IEnumerable<string> PerformScan<T>(IList<Assembly> loaded, out string[] errorReport)
{
var dllsWithReference = new List<string>();
var errors = new List<string>();
var assembliesWithErrors = new List<Assembly>();
//we need this handler to resolve assembly dependencies below
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, e) =>
{
var a = Assembly.ReflectionOnlyLoad(e.Name);
if (a == null) throw new TypeLoadException("Could not load assembly " + e.Name);
return a;
};
//First load each dll file into the context
var loaded = files.Select(Assembly.ReflectionOnlyLoadFrom).ToList();
//load each of the LoadFrom assemblies into the Load context too
foreach (var a in loaded)
{
var name = AppDomain.CurrentDomain.ApplyPolicy(a.FullName);
Assembly.ReflectionOnlyLoad(name);
Assembly.ReflectionOnlyLoad(a.FullName);
}
//get the list of assembly names to compare below
@@ -165,8 +94,7 @@ namespace Umbraco.Core.Packaging
{
try
{
var name = AppDomain.CurrentDomain.ApplyPolicy(assemblyName.FullName);
Assembly.ReflectionOnlyLoad(name);
Assembly.ReflectionOnlyLoad(assemblyName.FullName);
}
catch (FileNotFoundException)
{
@@ -239,6 +167,7 @@ namespace Umbraco.Core.Packaging
return dllsWithReference;
}
/// <summary>
/// In order to compare types, the types must be in the same context, this method will return the type that
/// we are checking against but from the Load context.
@@ -247,8 +176,7 @@ namespace Umbraco.Core.Packaging
/// <returns></returns>
private static Type GetLoadFromContractType<T>()
{
var name = AppDomain.CurrentDomain.ApplyPolicy(typeof(T).Assembly.FullName);
var contractAssemblyLoadFrom = Assembly.ReflectionOnlyLoad(name);
var contractAssemblyLoadFrom =Assembly.ReflectionOnlyLoad(typeof (T).Assembly.FullName);
var contractType = contractAssemblyLoadFrom.GetExportedTypes()
.FirstOrDefault(x => x.FullName == typeof(T).FullName && x.Assembly.FullName == typeof(T).Assembly.FullName);
@@ -288,5 +216,13 @@ namespace Umbraco.Core.Packaging
domainSetup,
new PermissionSet(PermissionState.Unrestricted));
}
private static string GetAssemblyPath(Assembly a)
{
var codeBase = a.CodeBase;
var uri = new Uri(codeBase);
return uri.LocalPath;
}
}
}
@@ -8,9 +8,9 @@ namespace Umbraco.Core.Packaging
internal class PackageBuilding : IPackageBuilding
{
private readonly IPackagingService _packagingService;
private readonly PackagingService _packagingService;
public PackageBuilding(IPackagingService packagingService)
public PackageBuilding(PackagingService packagingService)
{
_packagingService = packagingService;
}
+33 -200
View File
@@ -1,201 +1,34 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.SharpZipLib.Zip;
namespace Umbraco.Core.Packaging
{
internal class PackageExtraction : IPackageExtraction
{
public string ReadTextFileFromArchive(string packageFilePath, string fileToRead, out string directoryInPackage)
{
string retVal = null;
bool fileFound = false;
string foundDir = null;
ReadZipfileEntries(packageFilePath, (entry, stream) =>
{
string fileName = Path.GetFileName(entry.Name);
if (string.IsNullOrEmpty(fileName) == false &&
fileName.Equals(fileToRead, StringComparison.CurrentCultureIgnoreCase))
{
foundDir = entry.Name.Substring(0, entry.Name.Length - fileName.Length);
fileFound = true;
using (var reader = new StreamReader(stream))
{
retVal = reader.ReadToEnd();
return false;
}
}
return true;
});
if (fileFound == false)
{
directoryInPackage = null;
throw new FileNotFoundException(string.Format("Could not find file in package {0}", packageFilePath), fileToRead);
}
directoryInPackage = foundDir;
return retVal;
}
private static void CheckPackageExists(string packageFilePath)
{
if (string.IsNullOrEmpty(packageFilePath))
{
throw new ArgumentNullException("packageFilePath");
}
if (File.Exists(packageFilePath) == false)
{
if (File.Exists(packageFilePath) == false)
throw new ArgumentException(string.Format("Package file: {0} could not be found", packageFilePath));
}
string extension = Path.GetExtension(packageFilePath).ToLower();
var alowedExtension = new[] { ".umb", ".zip" };
// Check if the file is a valid package
if (alowedExtension.All(ae => ae.Equals(extension) == false))
{
throw new ArgumentException(
string.Format("Error - file isn't a package. only extentions: \"{0}\" is allowed", string.Join(", ", alowedExtension)));
}
}
public void CopyFileFromArchive(string packageFilePath, string fileInPackageName, string destinationfilePath)
{
CopyFilesFromArchive(packageFilePath, new[]{new KeyValuePair<string, string>(fileInPackageName, destinationfilePath) } );
}
public void CopyFilesFromArchive(string packageFilePath, IEnumerable<KeyValuePair<string, string>> sourceDestination)
{
var d = sourceDestination.ToDictionary(k => k.Key.ToLower(), v => v.Value);
ReadZipfileEntries(packageFilePath, (entry, stream) =>
{
string fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower();
if (fileName == string.Empty) { return true; }
string destination;
if (string.IsNullOrEmpty(fileName) == false && d.TryGetValue(fileName, out destination))
{
using (var streamWriter = File.Open(destination, FileMode.Create))
{
stream.CopyTo(streamWriter);
}
d.Remove(fileName);
return d.Any();
}
return true;
});
if (d.Any())
{
throw new ArgumentException(string.Format("The following source file(s): \"{0}\" could not be found in archive: \"{1}\"", string.Join("\", \"",d.Keys), packageFilePath));
}
}
public IEnumerable<string> FindMissingFiles(string packageFilePath, IEnumerable<string> expectedFiles)
{
var retVal = expectedFiles.ToList();
ReadZipfileEntries(packageFilePath, (zipEntry, stream) =>
{
string fileName = Path.GetFileName(zipEntry.Name);
int index = retVal.FindIndex(f => f.Equals(fileName, StringComparison.InvariantCultureIgnoreCase));
if (index != -1) { retVal.RemoveAt(index); }
return retVal.Any();
});
return retVal;
}
public IEnumerable<string> FindDubletFileNames(string packageFilePath)
{
var dictionary = new Dictionary<string, List<string>>();
ReadZipfileEntries(packageFilePath, (entry, stream) =>
{
string fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower();
List<string> list;
if (dictionary.TryGetValue(fileName, out list) == false)
{
list = new List<string>();
dictionary.Add(fileName, list);
}
list.Add(entry.Name);
return true;
});
return dictionary.Values.Where(v => v.Count > 1).SelectMany(v => v);
}
public IEnumerable<byte[]> ReadFilesFromArchive(string packageFilePath, IEnumerable<string> filesToGet)
{
CheckPackageExists(packageFilePath);
var files = new HashSet<string>(filesToGet.Select(f => f.ToLower()));
using (var fs = File.OpenRead(packageFilePath))
{
using (var zipInputStream = new ZipInputStream(fs))
{
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.GetNextEntry()) != null)
{
if (zipEntry.IsDirectory) continue;
if (files.Contains(zipEntry.Name))
{
using (var memStream = new MemoryStream())
{
zipInputStream.CopyTo(memStream);
yield return memStream.ToArray();
memStream.Close();
}
}
}
zipInputStream.Close();
}
fs.Close();
}
}
private void ReadZipfileEntries(string packageFilePath, Func<ZipEntry, ZipInputStream, bool> entryFunc, bool skipsDirectories = true)
{
CheckPackageExists(packageFilePath);
using (var fs = File.OpenRead(packageFilePath))
{
using (var zipInputStream = new ZipInputStream(fs))
{
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.GetNextEntry()) != null)
{
if (zipEntry.IsDirectory && skipsDirectories) continue;
if (entryFunc(zipEntry, zipInputStream) == false) break;
}
zipInputStream.Close();
}
fs.Close();
}
}
}
using System;
using System.IO;
using Umbraco.Core.IO;
namespace Umbraco.Core.Packaging
{
internal interface IPackageExtraction
{
bool Extract(string packageFilePath, string destinationFolder);
string ExtractToTemporaryFolder(string packageFilePath);
string GetPackageConfigFromArchive(string packageFilePath, string fileToRead = "package.xml");
}
internal class PackageExtraction : IPackageExtraction
{
public bool Extract(string packageFilePath, string destinationFolder)
{
return true;
}
public string ExtractToTemporaryFolder(string packageFilePath)
{
string tempDir = Path.Combine(IOHelper.MapPath(SystemDirectories.Data), Guid.NewGuid().ToString("D"));
Directory.CreateDirectory(tempDir);
Extract(packageFilePath, tempDir);
return tempDir;
}
public string GetPackageConfigFromArchive(string packageFilePath, string fileToRead = "package.xml")
{
return string.Empty;
}
}
}
+34 -604
View File
@@ -1,605 +1,35 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Packaging.Models;
using Umbraco.Core.Services;
using umbraco.interfaces;
using File = System.IO.File;
namespace Umbraco.Core.Packaging
{
internal class PackageInstallation : IPackageInstallation
{
private readonly IFileService _fileService;
private readonly IMacroService _macroService;
private readonly IPackagingService _packagingService;
private IConflictingPackageData _conflictingPackageData;
private readonly IPackageExtraction _packageExtraction;
private string _fullPathToRoot;
public PackageInstallation(IPackagingService packagingService, IMacroService macroService,
IFileService fileService, IPackageExtraction packageExtraction)
: this(packagingService, macroService, fileService, packageExtraction, GlobalSettings.FullpathToRoot)
{}
public PackageInstallation(IPackagingService packagingService, IMacroService macroService,
IFileService fileService, IPackageExtraction packageExtraction, string fullPathToRoot)
{
if (packageExtraction != null) _packageExtraction = packageExtraction;
else throw new ArgumentNullException("packageExtraction");
if (macroService != null) _macroService = macroService;
else throw new ArgumentNullException("macroService");
if (fileService != null) _fileService = fileService;
else throw new ArgumentNullException("fileService");
if (packagingService != null) _packagingService = packagingService;
else throw new ArgumentNullException("packagingService");
_fullPathToRoot = fullPathToRoot;
}
public IConflictingPackageData ConflictingPackageData
{
private get
{
return _conflictingPackageData ??
(_conflictingPackageData = new ConflictingPackageData(_macroService, _fileService));
}
set
{
if (_conflictingPackageData != null)
{
throw new PropertyConstraintException("This property already have a value");
}
_conflictingPackageData = value;
}
}
public string FullPathToRoot
{
private get { return _fullPathToRoot; }
set
{
if (_fullPathToRoot != null)
{
throw new PropertyConstraintException("This property already have a value");
}
_fullPathToRoot = value;
}
}
public MetaData GetMetaData(string packageFilePath)
{
try
{
XElement rootElement = GetConfigXmlElement(packageFilePath);
return GetMetaData(rootElement);
}
catch (Exception e)
{
throw new Exception("Error reading " + packageFilePath, e);
}
}
public PreInstallWarnings GetPreInstallWarnings(string packageFilePath)
{
try
{
XElement rootElement = GetConfigXmlElement(packageFilePath);
return GetPreInstallWarnings(packageFilePath, rootElement);
}
catch (Exception e)
{
throw new Exception("Error reading " + packageFilePath, e);
}
}
public InstallationSummary InstallPackage(string packageFile, int userId)
{
XElement dataTypes;
XElement languages;
XElement dictionaryItems;
XElement macroes;
XElement files;
XElement templates;
XElement documentTypes;
XElement styleSheets;
XElement documentSet;
XElement documents;
XElement actions;
MetaData metaData;
InstallationSummary installationSummary;
try
{
XElement rootElement = GetConfigXmlElement(packageFile);
PackageSupportedCheck(rootElement);
PackageStructureSanetyCheck(packageFile, rootElement);
dataTypes = rootElement.Element(Constants.Packaging.DataTypesNodeName);
languages = rootElement.Element(Constants.Packaging.LanguagesNodeName);
dictionaryItems = rootElement.Element(Constants.Packaging.DictionaryItemsNodeName);
macroes = rootElement.Element(Constants.Packaging.MacrosNodeName);
files = rootElement.Element(Constants.Packaging.FilesNodeName);
templates = rootElement.Element(Constants.Packaging.TemplatesNodeName);
documentTypes = rootElement.Element(Constants.Packaging.DocumentTypesNodeName);
styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName);
documentSet = rootElement.Element(Constants.Packaging.DocumentSetNodeName);
documents = rootElement.Element(Constants.Packaging.DocumentsNodeName);
actions = rootElement.Element(Constants.Packaging.ActionsNodeName);
metaData = GetMetaData(rootElement);
installationSummary = new InstallationSummary {MetaData = metaData};
}
catch (Exception e)
{
throw new Exception("Error reading " + packageFile, e);
}
try
{
var dataTypeDefinitions = EmptyEnumerableIfNull<IDataTypeDefinition>(dataTypes) ?? InstallDataTypes(dataTypes, userId);
installationSummary.DataTypesInstalled = dataTypeDefinitions;
var languagesInstalled = EmptyEnumerableIfNull<ILanguage>(languages) ?? InstallLanguages(languages, userId);
installationSummary.LanguagesInstalled = languagesInstalled;
var dictionaryInstalled = EmptyEnumerableIfNull<IDictionaryItem>(dictionaryItems) ?? InstallDictionaryItems(dictionaryItems);
installationSummary.DictionaryItemsInstalled = dictionaryInstalled;
var macros = EmptyEnumerableIfNull<IMacro>(macroes) ?? InstallMacros(macroes, userId);
installationSummary.MacrosInstalled = macros;
var keyValuePairs = EmptyEnumerableIfNull<string>(packageFile) ?? InstallFiles(packageFile, files);
installationSummary.FilesInstalled = keyValuePairs;
var templatesInstalled = EmptyEnumerableIfNull<ITemplate>(templates) ?? InstallTemplats(templates, userId);
installationSummary.TemplatesInstalled = templatesInstalled;
var documentTypesInstalled = EmptyEnumerableIfNull<IContentType>(documentTypes) ?? InstallDocumentTypes(documentTypes, userId);
installationSummary.ContentTypesInstalled =documentTypesInstalled;
var stylesheetsInstalled = EmptyEnumerableIfNull<IFile>(styleSheets) ?? InstallStylesheets(styleSheets, userId);
installationSummary.StylesheetsInstalled = stylesheetsInstalled;
var documentsInstalled = documents != null ? InstallDocuments(documents, userId)
: EmptyEnumerableIfNull<IContent>(documentSet)
?? InstallDocuments(documentSet, userId);
installationSummary.ContentInstalled = documentsInstalled;
var packageActions = EmptyEnumerableIfNull<PackageAction>(actions) ?? GetPackageActions(actions, metaData.Name);
installationSummary.Actions = packageActions;
installationSummary.PackageInstalled = true;
return installationSummary;
}
catch (Exception e)
{
throw new Exception("Error installing package " + packageFile, e);
}
}
/// <summary>
/// Temperary check to test that we support stylesheets
/// </summary>
/// <param name="rootElement"></param>
private void PackageSupportedCheck(XElement rootElement)
{
XElement styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName);
if (styleSheets != null && styleSheets.Elements().Any())
throw new NotSupportedException("Stylesheets is not suported in this version of umbraco");
}
private static T[] EmptyArrayIfNull<T>(object obj)
{
return obj == null ? new T[0] : null;
}
private static IEnumerable<T> EmptyEnumerableIfNull<T>(object obj)
{
return obj == null ? Enumerable.Empty<T>() : null;
}
private XDocument GetConfigXmlDoc(string packageFilePath)
{
string filePathInPackage;
string configXmlContent = _packageExtraction.ReadTextFileFromArchive(packageFilePath,
Constants.Packaging.PackageXmlFileName, out filePathInPackage);
return XDocument.Parse(configXmlContent);
}
public XElement GetConfigXmlElement(string packageFilePath)
{
XDocument document = GetConfigXmlDoc(packageFilePath);
if (document.Root == null ||
document.Root.Name.LocalName.Equals(Constants.Packaging.UmbPackageNodeName) == false)
{
throw new ArgumentException("xml does not have a root node called \"umbPackage\"", packageFilePath);
}
return document.Root;
}
internal void PackageStructureSanetyCheck(string packageFilePath)
{
XElement rootElement = GetConfigXmlElement(packageFilePath);
PackageStructureSanetyCheck(packageFilePath, rootElement);
}
private void PackageStructureSanetyCheck(string packageFilePath, XElement rootElement)
{
XElement filesElement = rootElement.Element(Constants.Packaging.FilesNodeName);
if (filesElement != null)
{
var sourceDestination = ExtractSourceDestinationFileInformation(filesElement).ToArray();
var missingFiles = _packageExtraction.FindMissingFiles(packageFilePath, sourceDestination.Select(i => i.Key)).ToArray();
if (missingFiles.Any())
{
throw new Exception("The following file(s) are missing in the package: " +
string.Join(", ", missingFiles.Select(
mf =>
{
var sd = sourceDestination.Single(fi => fi.Key == mf);
return string.Format("source: \"{0}\" destination: \"{1}\"",
sd.Key, sd.Value);
})));
}
IEnumerable<string> dubletFileNames = _packageExtraction.FindDubletFileNames(packageFilePath).ToArray();
if (dubletFileNames.Any())
{
throw new Exception("The following filename(s) are found more than one time in the package, since the filename is used ad primary key, this is not allowed: " +
string.Join(", ", dubletFileNames));
}
}
}
private static IEnumerable<PackageAction> GetPackageActions(XElement actionsElement, string packageName)
{
if (actionsElement == null) { return new PackageAction[0]; }
if (string.Equals(Constants.Packaging.ActionsNodeName, actionsElement.Name.LocalName) == false)
{
throw new ArgumentException("Must be \"" + Constants.Packaging.ActionsNodeName + "\" as root",
"actionsElement");
}
return actionsElement.Elements(Constants.Packaging.ActionNodeName)
.Select(elemet =>
{
XAttribute aliasAttr = elemet.Attribute(Constants.Packaging.AliasNodeNameCapital);
if (aliasAttr == null)
throw new ArgumentException(
"missing \"" + Constants.Packaging.AliasNodeNameCapital + "\" atribute in alias element",
"actionsElement");
var packageAction = new PackageAction
{
XmlData = elemet,
Alias = aliasAttr.Value,
PackageName = packageName,
};
XAttribute attr = elemet.Attribute(Constants.Packaging.RunatNodeAttribute);
ActionRunAt runAt;
if (attr != null && Enum.TryParse(attr.Value, true, out runAt)) { packageAction.RunAt = runAt; }
attr = elemet.Attribute(Constants.Packaging.UndoNodeAttribute);
bool undo;
if (attr != null && bool.TryParse(attr.Value, out undo)) { packageAction.Undo = undo; }
return packageAction;
}).ToArray();
}
private IEnumerable<IContent> InstallDocuments(XElement documentsElement, int userId = 0)
{
if ((string.Equals(Constants.Packaging.DocumentSetNodeName, documentsElement.Name.LocalName) == false)
&& (string.Equals(Constants.Packaging.DocumentsNodeName, documentsElement.Name.LocalName) == false))
{
throw new ArgumentException("Must be \"" + Constants.Packaging.DocumentsNodeName + "\" as root",
"documentsElement");
}
if (string.Equals(Constants.Packaging.DocumentSetNodeName, documentsElement.Name.LocalName))
return _packagingService.ImportContent(documentsElement, -1, userId);
return
documentsElement.Elements(Constants.Packaging.DocumentSetNodeName)
.SelectMany(documentSetElement => _packagingService.ImportContent(documentSetElement, -1, userId))
.ToArray();
}
private IEnumerable<IFile> InstallStylesheets(XElement styleSheetsElement, int userId = 0)
{
if (string.Equals(Constants.Packaging.StylesheetsNodeName, styleSheetsElement.Name.LocalName) == false)
{
throw new ArgumentException("Must be \"" + Constants.Packaging.StylesheetsNodeName + "\" as root",
"styleSheetsElement");
}
// TODO: Call _packagingService when import stylesheets import has been implimentet
if (styleSheetsElement.HasElements == false) { return new List<IFile>(); }
throw new NotImplementedException("The packaging service do not yes have a method for importing stylesheets");
}
private IEnumerable<IContentType> InstallDocumentTypes(XElement documentTypes, int userId = 0)
{
if (string.Equals(Constants.Packaging.DocumentTypesNodeName, documentTypes.Name.LocalName) == false)
{
if (string.Equals(Constants.Packaging.DocumentTypeNodeName, documentTypes.Name.LocalName) == false)
throw new ArgumentException(
"Must be \"" + Constants.Packaging.DocumentTypesNodeName + "\" as root", "documentTypes");
documentTypes = new XElement(Constants.Packaging.DocumentTypesNodeName, documentTypes);
}
return _packagingService.ImportContentTypes(documentTypes, userId);
}
private IEnumerable<ITemplate> InstallTemplats(XElement templateElement, int userId = 0)
{
if (string.Equals(Constants.Packaging.TemplatesNodeName, templateElement.Name.LocalName) == false)
{
throw new ArgumentException("Must be \"" + Constants.Packaging.TemplatesNodeName + "\" as root",
"templateElement");
}
return _packagingService.ImportTemplates(templateElement, userId);
}
private IEnumerable<string> InstallFiles(string packageFilePath, XElement filesElement)
{
var sourceDestination = ExtractSourceDestinationFileInformation(filesElement);
sourceDestination = AppendRootToDestination(FullPathToRoot, sourceDestination);
_packageExtraction.CopyFilesFromArchive(packageFilePath, sourceDestination);
return sourceDestination.Select(sd => sd.Value).ToArray();
}
private KeyValuePair<string, string>[] AppendRootToDestination(string fullpathToRoot, IEnumerable<KeyValuePair<string, string>> sourceDestination)
{
return
sourceDestination.Select(
sd => new KeyValuePair<string, string>(sd.Key, Path.Combine(fullpathToRoot, sd.Value))).ToArray();
}
private IEnumerable<IMacro> InstallMacros(XElement macroElements, int userId = 0)
{
if (string.Equals(Constants.Packaging.MacrosNodeName, macroElements.Name.LocalName) == false)
{
throw new ArgumentException("Must be \"" + Constants.Packaging.MacrosNodeName + "\" as root",
"macroElements");
}
return _packagingService.ImportMacros(macroElements, userId);
}
private IEnumerable<IDictionaryItem> InstallDictionaryItems(XElement dictionaryItemsElement)
{
if (string.Equals(Constants.Packaging.DictionaryItemsNodeName, dictionaryItemsElement.Name.LocalName) ==
false)
{
throw new ArgumentException("Must be \"" + Constants.Packaging.DictionaryItemsNodeName + "\" as root",
"dictionaryItemsElement");
}
return _packagingService.ImportDictionaryItems(dictionaryItemsElement);
}
private IEnumerable<ILanguage> InstallLanguages(XElement languageElement, int userId = 0)
{
if (string.Equals(Constants.Packaging.LanguagesNodeName, languageElement.Name.LocalName) == false)
{
throw new ArgumentException("Must be \"" + Constants.Packaging.LanguagesNodeName + "\" as root", "languageElement");
}
return _packagingService.ImportLanguages(languageElement, userId);
}
private IEnumerable<IDataTypeDefinition> InstallDataTypes(XElement dataTypeElements, int userId = 0)
{
if (string.Equals(Constants.Packaging.DataTypesNodeName, dataTypeElements.Name.LocalName) == false)
{
if (string.Equals(Constants.Packaging.DataTypeNodeName, dataTypeElements.Name.LocalName) == false)
{
throw new ArgumentException("Must be \"" + Constants.Packaging.DataTypeNodeName + "\" as root", "dataTypeElements");
}
}
return _packagingService.ImportDataTypeDefinitions(dataTypeElements, userId);
}
private PreInstallWarnings GetPreInstallWarnings(string packagePath, XElement rootElement)
{
XElement files = rootElement.Element(Constants.Packaging.FilesNodeName);
XElement styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName);
XElement templates = rootElement.Element(Constants.Packaging.TemplatesNodeName);
XElement alias = rootElement.Element(Constants.Packaging.MacrosNodeName);
var sourceDestination = EmptyArrayIfNull<KeyValuePair<string, string>>(files) ?? ExtractSourceDestinationFileInformation(files);
var installWarnings = new PreInstallWarnings();
var macroAliases = EmptyEnumerableIfNull<IMacro>(alias) ?? ConflictingPackageData.FindConflictingMacros(alias);
installWarnings.ConflictingMacroAliases = macroAliases;
var templateAliases = EmptyEnumerableIfNull<ITemplate>(templates) ?? ConflictingPackageData.FindConflictingTemplates(templates);
installWarnings.ConflictingTemplateAliases = templateAliases;
var stylesheetNames = EmptyEnumerableIfNull<IFile>(styleSheets) ?? ConflictingPackageData.FindConflictingStylesheets(styleSheets);
installWarnings.ConflictingStylesheetNames = stylesheetNames;
installWarnings.UnsecureFiles = FindUnsecureFiles(sourceDestination);
installWarnings.FilesReplaced = FindFilesToBeReplaced(sourceDestination);
installWarnings.AssembliesWithLegacyPropertyEditors = FindLegacyPropertyEditors(packagePath, sourceDestination);
return installWarnings;
}
private KeyValuePair<string, string>[] FindFilesToBeReplaced(IEnumerable<KeyValuePair<string, string>> sourceDestination)
{
return sourceDestination.Where(sd => File.Exists(Path.Combine(FullPathToRoot, sd.Value))).ToArray();
}
private IEnumerable<string> FindLegacyPropertyEditors(string packagePath, IEnumerable<KeyValuePair<string, string>> sourceDestinationPair)
{
var dlls = sourceDestinationPair.Where(
sd => (Path.GetExtension(sd.Value) ?? string.Empty).Equals(".dll", StringComparison.InvariantCultureIgnoreCase)).Select(sd => sd.Key).ToArray();
if (dlls.Any() == false) { return new List<string>(); }
// Now we want to see if the DLLs contain any legacy data types since we want to warn people about that
string[] assemblyErrors;
IEnumerable<byte[]> assemblyesToScan =_packageExtraction.ReadFilesFromArchive(packagePath, dlls);
return PackageBinaryInspector.ScanAssembliesForTypeReference<IDataType>(assemblyesToScan, out assemblyErrors).ToArray();
}
private KeyValuePair<string, string>[] FindUnsecureFiles(IEnumerable<KeyValuePair<string, string>> sourceDestinationPair)
{
return sourceDestinationPair.Where(sd => IsFileDestinationUnsecure(sd.Value)).ToArray();
}
private bool IsFileDestinationUnsecure(string destination)
{
var unsecureDirNames = new[] {"bin", "app_code"};
if(unsecureDirNames.Any(ud => destination.StartsWith(ud, StringComparison.InvariantCultureIgnoreCase)))
return true;
string extension = Path.GetExtension(destination);
return extension != null && extension.Equals(".dll", StringComparison.InvariantCultureIgnoreCase);
}
private KeyValuePair<string, string>[] ExtractSourceDestinationFileInformation(XElement filesElement)
{
if (string.Equals(Constants.Packaging.FilesNodeName, filesElement.Name.LocalName) == false)
{
throw new ArgumentException("the root element must be \"Files\"", "filesElement");
}
return filesElement.Elements(Constants.Packaging.FileNodeName)
.Select(e =>
{
XElement guidElement = e.Element(Constants.Packaging.GuidNodeName);
if (guidElement == null)
{
throw new ArgumentException("Missing element \"" + Constants.Packaging.GuidNodeName + "\"",
"filesElement");
}
XElement orgPathElement = e.Element(Constants.Packaging.OrgPathNodeName);
if (orgPathElement == null)
{
throw new ArgumentException("Missing element \"" + Constants.Packaging.OrgPathNodeName + "\"",
"filesElement");
}
XElement orgNameElement = e.Element(Constants.Packaging.OrgNameNodeName);
if (orgNameElement == null)
{
throw new ArgumentException("Missing element \"" + Constants.Packaging.OrgNameNodeName + "\"",
"filesElement");
}
var fileName = PrepareAsFilePathElement(orgNameElement.Value);
var relativeDir = UpdatePathPlaceholders(PrepareAsFilePathElement(orgPathElement.Value));
var relativePath = Path.Combine(relativeDir, fileName);
return new KeyValuePair<string, string>(guidElement.Value, relativePath);
}).ToArray();
}
private static string PrepareAsFilePathElement(string pathElement)
{
return pathElement.TrimStart(new[] {'\\', '/', '~'}).Replace("/", "\\");
}
private MetaData GetMetaData(XElement xRootElement)
{
XElement infoElement = xRootElement.Element(Constants.Packaging.InfoNodeName);
if (infoElement == null)
{
throw new ArgumentException("Did not hold a \"" + Constants.Packaging.InfoNodeName + "\" element",
"xRootElement");
}
var majorElement = infoElement.XPathSelectElement(Constants.Packaging.PackageRequirementsMajorXpath);
var minorElement = infoElement.XPathSelectElement(Constants.Packaging.PackageRequirementsMinorXpath);
var patchElement = infoElement.XPathSelectElement(Constants.Packaging.PackageRequirementsPatchXpath);
var nameElement = infoElement.XPathSelectElement(Constants.Packaging.PackageNameXpath);
var versionElement = infoElement.XPathSelectElement(Constants.Packaging.PackageVersionXpath);
var urlElement = infoElement.XPathSelectElement(Constants.Packaging.PackageUrlXpath);
var licenseElement = infoElement.XPathSelectElement(Constants.Packaging.PackageLicenseXpath);
var authorNameElement = infoElement.XPathSelectElement(Constants.Packaging.AuthorNameXpath);
var authorUrlElement = infoElement.XPathSelectElement(Constants.Packaging.AuthorWebsiteXpath);
var readmeElement = infoElement.XPathSelectElement(Constants.Packaging.ReadmeXpath);
XElement controlElement = xRootElement.Element(Constants.Packaging.ControlNodeName);
return new MetaData
{
Name = StringValue(nameElement),
Version = StringValue(versionElement),
Url = StringValue(urlElement),
License = StringValue(licenseElement),
LicenseUrl = StringAttribute(licenseElement, Constants.Packaging.PackageLicenseXpathUrlAttribute),
AuthorName = StringValue(authorNameElement),
AuthorUrl = StringValue(authorUrlElement),
Readme = StringValue(readmeElement),
Control = StringValue(controlElement),
ReqMajor = IntValue(majorElement),
ReqMinor = IntValue(minorElement),
ReqPatch = IntValue(patchElement)
};
}
private static string StringValue(XElement xElement, string defaultValue = "")
{
return xElement == null ? defaultValue : xElement.Value;
}
private static string StringAttribute(XElement xElement, string attribute, string defaultValue = "")
{
return xElement == null
? defaultValue
: xElement.HasAttributes ? xElement.AttributeValue<string>(attribute) : defaultValue;
}
private static int IntValue(XElement xElement, int defaultValue = 0)
{
int val;
return xElement == null ? defaultValue : int.TryParse(xElement.Value, out val) ? val : defaultValue;
}
private static string UpdatePathPlaceholders(string path)
{
if (path.Contains("[$"))
{
//this is experimental and undocumented...
path = path.Replace("[$UMBRACO]", SystemDirectories.Umbraco);
path = path.Replace("[$UMBRACOCLIENT]", SystemDirectories.UmbracoClient);
path = path.Replace("[$CONFIG]", SystemDirectories.Config);
path = path.Replace("[$DATA]", SystemDirectories.Data);
}
return path;
}
}
using Umbraco.Core.Packaging.Models;
using Umbraco.Core.Services;
namespace Umbraco.Core.Packaging
{
internal interface IPackageInstallation
{
InstallationSummary InstallPackage(string packageFilePath, int userId = 0);
MetaData GetPackageMetaData(string packageFilePath);
}
internal class PackageInstallation : IPackageInstallation
{
private readonly PackagingService _packagingService;
private readonly PackageExtraction _packageExtraction;
public PackageInstallation(PackagingService packagingService, PackageExtraction packageExtraction)
{
_packagingService = packagingService;
_packageExtraction = packageExtraction;
}
public InstallationSummary InstallPackage(string packageFilePath, int userId = 0)
{
var summary = new InstallationSummary();
return summary;
}
public MetaData GetPackageMetaData(string packageFilePath)
{
var metaData = new MetaData();
return metaData;
}
}
}
@@ -41,8 +41,7 @@ namespace Umbraco.Core.Persistence.Caching
public static RuntimeCacheProvider Current { get { return lazy.Value; } }
//internal for testing! - though I'm not a huge fan of these being singletons!
internal RuntimeCacheProvider()
private RuntimeCacheProvider()
{
if (HttpContext.Current == null)
{
@@ -247,7 +246,7 @@ namespace Umbraco.Core.Persistence.Caching
private string GetCompositeId(Type type, Guid id)
{
return string.Format("{0}{1}-{2}", CacheItemPrefix, type.Name, id);
return string.Format("{0}{1}-{2}", CacheItemPrefix, type.Name, id.ToString());
}
private string GetCompositeId(Type type, int id)
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Persistence.Factories
};
if (entity.HasIdentity)
dto.Id = int.Parse(entity.Id.ToString(CultureInfo.InvariantCulture));
dto.Id = short.Parse(entity.Id.ToString(CultureInfo.InvariantCulture));
return dto;
}
@@ -69,4 +69,4 @@ namespace Umbraco.Core.Persistence.Factories
return list;
}
}
}
}
@@ -28,7 +28,7 @@ namespace Umbraco.Core.Persistence.Factories
ComputerName = entity.ComputerName
};
if (entity.HasIdentity)
dto.Id = int.Parse(entity.Id.ToString(CultureInfo.InvariantCulture));
dto.Id = short.Parse(entity.Id.ToString(CultureInfo.InvariantCulture));
return dto;
}
@@ -7,7 +7,7 @@ namespace Umbraco.Core.Persistence.Factories
{
public ITag BuildEntity(TagDto dto)
{
var model = new Tag(dto.Id, dto.Tag, dto.Group, dto.NodeCount);
var model = new Tag(dto.Id, dto.Tag, dto.Group);
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
model.ResetDirtyProperties(false);
@@ -20,8 +20,7 @@ namespace Umbraco.Core.Persistence.Factories
{
Id = entity.Id,
Group = entity.Group,
Tag = entity.Text,
NodeCount = entity.NodeCount,
Tag = entity.Text
};
}
}
@@ -132,10 +132,10 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
private void CreateCmsContentTypeData()
{
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = "icon-folder", Thumbnail = "icon-folder", IsContainer = false, AllowAtRoot = true });
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = "icon-picture", Thumbnail = "icon-picture" });
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = "icon-document", Thumbnail = "icon-document" });
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 531, NodeId = 1044, Alias = Constants.Conventions.MemberTypes.DefaultAlias, Icon = "icon-user", Thumbnail = "icon-user" });
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 532, NodeId = 1031, Alias = Constants.Conventions.MediaTypes.Folder, Icon = "icon-folder", Thumbnail = "folder.png", IsContainer = false, AllowAtRoot = true });
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 533, NodeId = 1032, Alias = Constants.Conventions.MediaTypes.Image, Icon = "icon-picture", Thumbnail = "mediaPhoto.png" });
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 534, NodeId = 1033, Alias = Constants.Conventions.MediaTypes.File, Icon = "icon-document", Thumbnail = "mediaFile.png" });
_database.Insert("cmsContentType", "pk", false, new ContentTypeDto { PrimaryKey = 531, NodeId = 1044, Alias = Constants.Conventions.MemberTypes.DefaultAlias, Icon = "icon-user", Thumbnail = "folder.png" });
}
private void CreateUmbracoUserData()
@@ -255,7 +255,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
private void CreateUmbracoRelationTypeData()
{
_database.Insert("umbracoRelationType", "id", false, new RelationTypeDto { Id = 1, Alias = Constants.Conventions.RelationTypes.RelateDocumentOnCopyAlias, ChildObjectType = new Guid(Constants.ObjectTypes.Document), ParentObjectType = new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"), Dual = true, Name = Constants.Conventions.RelationTypes.RelateDocumentOnCopyName });
_database.Insert("umbracoRelationType", "id", false, new RelationTypeDto { Id = 1, Alias = "relateDocumentOnCopy", ChildObjectType = new Guid(Constants.ObjectTypes.Document), ParentObjectType = new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"), Dual = true, Name = "Relate Document On Copy" });
}
private void CreateCmsTaskTypeData()
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Migrations
/// <param name="database">The PetaPoco Database, which the migrations will be run against</param>
/// <param name="isUpgrade">Boolean indicating whether this is an upgrade or downgrade</param>
/// <returns><c>True</c> if migrations were applied, otherwise <c>False</c></returns>
public virtual bool Execute(Database database, bool isUpgrade = true)
public bool Execute(Database database, bool isUpgrade = true)
{
return Execute(database, database.GetDatabaseProvider(), isUpgrade);
}
@@ -42,11 +42,11 @@ namespace Umbraco.Core.Persistence.Migrations
/// <param name="databaseProvider"></param>
/// <param name="isUpgrade">Boolean indicating whether this is an upgrade or downgrade</param>
/// <returns><c>True</c> if migrations were applied, otherwise <c>False</c></returns>
public virtual bool Execute(Database database, DatabaseProviders databaseProvider, bool isUpgrade = true)
public bool Execute(Database database, DatabaseProviders databaseProvider, bool isUpgrade = true)
{
LogHelper.Info<MigrationRunner>("Initializing database migrations");
var foundMigrations = FindMigrations();
var foundMigrations = MigrationResolver.Current.Migrations.ToArray();
//filter all non-schema migrations
var migrations = isUpgrade
@@ -54,7 +54,6 @@ namespace Umbraco.Core.Persistence.Migrations
: OrderedDowngradeMigrations(foundMigrations).ToList();
//SD: Why do we want this?
//MCH: Because extensibility ... Mostly relevant to package developers who needs to utilize this type of event to add or remove migrations from the list
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _currentVersion, _targetVersion, true), this))
return false;
@@ -70,6 +69,7 @@ namespace Umbraco.Core.Persistence.Migrations
//if this fails then the transaction will be rolled back, BUT if we are using MySql this is not the case,
//since it does not support schema changes in a transaction, see: http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
//so in that case we have to downgrade
if (databaseProvider == DatabaseProviders.MySql)
{
throw new DataLossException(
@@ -86,57 +86,28 @@ namespace Umbraco.Core.Persistence.Migrations
return true;
}
/// <summary>
/// Filters and orders migrations based on the migrations listed and the currently configured version and the target installation version
/// </summary>
/// <param name="foundMigrations"></param>
/// <returns></returns>
public IEnumerable<IMigration> OrderedUpgradeMigrations(IEnumerable<IMigration> foundMigrations)
private void ExecuteMigrations(IMigrationContext context, Database database)
{
var migrations = (from migration in foundMigrations
let migrationAttributes = migration.GetType().GetCustomAttributes<MigrationAttribute>(false)
from migrationAttribute in migrationAttributes
where migrationAttribute != null
where migrationAttribute.TargetVersion > _currentVersion &&
migrationAttribute.TargetVersion <= _targetVersion &&
migrationAttribute.ProductName == _productName &&
//filter if the migration specifies a minimum current version for which to execute
(migrationAttribute.MinimumCurrentVersion == null || _currentVersion >= migrationAttribute.MinimumCurrentVersion)
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder ascending
select migration).Distinct();
return migrations;
}
//Transactional execution of the sql that was generated from the found migrations
using (var transaction = database.GetTransaction())
{
int i = 1;
foreach (var expression in context.Expressions)
{
var sql = expression.Process(database);
if (string.IsNullOrEmpty(sql))
{
i++;
continue;
}
/// <summary>
/// Filters and orders migrations based on the migrations listed and the currently configured version and the target installation version
/// </summary>
/// <param name="foundMigrations"></param>
/// <returns></returns>
public IEnumerable<IMigration> OrderedDowngradeMigrations(IEnumerable<IMigration> foundMigrations)
{
var migrations = (from migration in foundMigrations
let migrationAttributes = migration.GetType().GetCustomAttributes<MigrationAttribute>(false)
from migrationAttribute in migrationAttributes
where migrationAttribute != null
where
migrationAttribute.TargetVersion > _currentVersion &&
migrationAttribute.TargetVersion <= _targetVersion &&
migrationAttribute.ProductName == _productName &&
//filter if the migration specifies a minimum current version for which to execute
(migrationAttribute.MinimumCurrentVersion == null || _currentVersion >= migrationAttribute.MinimumCurrentVersion)
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder descending
select migration).Distinct();
return migrations;
}
LogHelper.Info<MigrationRunner>("Executing sql statement " + i + ": " + sql);
database.Execute(sql);
i++;
}
/// <summary>
/// Find all migrations that are available through the <see cref="MigrationResolver"/>
/// </summary>
/// <returns>An array of <see cref="IMigration"/></returns>
protected virtual IMigration[] FindMigrations()
{
//MCH NOTE: Consider adding the ProductName filter to the Resolver so we don't get a bunch of irrelevant migrations
return MigrationResolver.Current.Migrations.ToArray();
transaction.Complete();
}
}
internal MigrationContext InitializeMigrations(List<IMigration> migrations, Database database, DatabaseProviders databaseProvider, bool isUpgrade = true)
@@ -179,28 +150,48 @@ namespace Umbraco.Core.Persistence.Migrations
return context;
}
private void ExecuteMigrations(IMigrationContext context, Database database)
/// <summary>
/// Filters and orders migrations based on the migrations listed and the currently configured version and the target installation version
/// </summary>
/// <param name="foundMigrations"></param>
/// <returns></returns>
internal IEnumerable<IMigration> OrderedUpgradeMigrations(IEnumerable<IMigration> foundMigrations)
{
//Transactional execution of the sql that was generated from the found migrations
using (var transaction = database.GetTransaction())
{
int i = 1;
foreach (var expression in context.Expressions)
{
var sql = expression.Process(database);
if (string.IsNullOrEmpty(sql))
{
i++;
continue;
}
var migrations = (from migration in foundMigrations
let migrationAttributes = migration.GetType().GetCustomAttributes<MigrationAttribute>(false)
from migrationAttribute in migrationAttributes
where migrationAttribute != null
where
migrationAttribute.TargetVersion > _currentVersion &&
migrationAttribute.TargetVersion <= _targetVersion &&
migrationAttribute.ProductName == _productName &&
//filter if the migration specifies a minimum current version for which to execute
(migrationAttribute.MinimumCurrentVersion == null || _currentVersion >= migrationAttribute.MinimumCurrentVersion)
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder ascending
select migration).Distinct();
return migrations;
}
LogHelper.Info<MigrationRunner>("Executing sql statement " + i + ": " + sql);
database.Execute(sql);
i++;
}
transaction.Complete();
}
/// <summary>
/// Filters and orders migrations based on the migrations listed and the currently configured version and the target installation version
/// </summary>
/// <param name="foundMigrations"></param>
/// <returns></returns>
public IEnumerable<IMigration> OrderedDowngradeMigrations(IEnumerable<IMigration> foundMigrations)
{
var migrations = (from migration in foundMigrations
let migrationAttributes = migration.GetType().GetCustomAttributes<MigrationAttribute>(false)
from migrationAttribute in migrationAttributes
where migrationAttribute != null
where
migrationAttribute.TargetVersion > _currentVersion &&
migrationAttribute.TargetVersion <= _targetVersion &&
migrationAttribute.ProductName == _productName &&
//filter if the migration specifies a minimum current version for which to execute
(migrationAttribute.MinimumCurrentVersion == null || _currentVersion >= migrationAttribute.MinimumCurrentVersion)
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder descending
select migration).Distinct();
return migrations;
}
/// <summary>
@@ -221,7 +221,6 @@ namespace Umbraco.Core.Persistence
if (overwrite && tableExist)
{
db.DropTable(tableName);
tableExist = false;
}
if (tableExist == false)
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Umbraco.Core.Persistence.Querying;
@@ -126,10 +125,5 @@ namespace Umbraco.Core.Persistence
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(rightColumnName));
return sql.On(onClause);
}
public static Sql OrderByDescending(this Sql sql, params object[] columns)
{
return sql.Append(new Sql("ORDER BY " + String.Join(", ", (from x in columns select x.ToString() + " DESC").ToArray())));
}
}
}
@@ -3,10 +3,8 @@ using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dynamics;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
@@ -257,9 +255,6 @@ namespace Umbraco.Core.Persistence.Repositories
//Ensure unique name on the same level
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name);
//Ensure that strings don't contain characters that are invalid in XML
entity.SanitizeEntityPropertiesForXmlStorage();
var factory = new ContentFactory(NodeObjectTypeId, entity.Id);
var dto = factory.BuildDto(entity);
@@ -301,9 +296,9 @@ namespace Umbraco.Core.Persistence.Repositories
var userPermissions = (
from perm in parentPermissions
from p in perm.AssignedPermissions
select new EntityPermissionSet.UserPermission(perm.UserId, p)).ToList();
permissionsRepo.ReplaceEntityPermissions(new EntityPermissionSet(entity.Id, userPermissions));
select new Tuple<int, string>(perm.UserId, p)).ToList();
permissionsRepo.ReplaceEntityPermissions(entity, userPermissions);
//flag the entity's permissions changed flag so we can track those changes.
//Currently only used for the cache refreshers to detect if we should refresh all user permissions cache.
((Content) entity).PermissionsChanged = true;
@@ -371,9 +366,6 @@ namespace Umbraco.Core.Persistence.Repositories
//Ensure unique name on the same level
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name, entity.Id);
//Ensure that strings don't contain characters that are invalid in XML
entity.SanitizeEntityPropertiesForXmlStorage();
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
if (((ICanBeDirty)entity).IsPropertyDirty("ParentId"))
{
@@ -410,7 +402,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
//a flag that we'll use later to create the tags in the tag db table
var publishedStateChanged = false;
var isNewPublishedVersion = false;
//If Published state has changed then previous versions should have their publish state reset.
//If state has been changed to unpublished the previous versions publish state should also be reset.
@@ -426,7 +418,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
//this is a newly published version so we'll update the tags table too (end of this method)
publishedStateChanged = true;
isNewPublishedVersion = true;
}
//Look up (newest) entries by id in cmsDocument table to set newest = false
@@ -489,15 +481,10 @@ namespace Umbraco.Core.Persistence.Repositories
}
//lastly, check if we are a newly published version and then update the tags table
if (publishedStateChanged && entity.Published)
if (isNewPublishedVersion)
{
UpdatePropertyTags(entity, _tagRepository);
}
else if (publishedStateChanged && (entity.Trashed || entity.Published == false))
{
//it's in the trash or not published remove all entity tags
ClearEntityTags(entity, _tagRepository);
}
((ICanBeDirty)entity).ResetDirtyProperties();
}
@@ -511,7 +498,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (property.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias && property.Value != null &&
string.IsNullOrEmpty(property.Value.ToString()) == false
&& fs.FileExists(fs.GetRelativePath(property.Value.ToString())))
&& fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
{
var relativeFilePath = fs.GetRelativePath(property.Value.ToString());
var parentDirectory = System.IO.Path.GetDirectoryName(relativeFilePath);
@@ -571,12 +558,6 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
public void ReplaceContentPermissions(EntityPermissionSet permissionSet)
{
var repo = new PermissionRepository<IContent>(UnitOfWork, _cacheHelper);
repo.ReplaceEntityPermissions(permissionSet);
}
public IContent GetByLanguage(int id, string language)
{
var sql = GetBaseQuery(false);
@@ -644,117 +625,7 @@ namespace Umbraco.Core.Persistence.Repositories
_contentPreviewRepository.AddOrUpdate(new ContentPreviewEntity<IContent>(previewExists, content, xml));
}
/// <summary>
/// Gets paged content results
/// </summary>
/// <param name="query">Query to excute</param>
/// <param name="pageNumber">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetPagedResultsByQuery(IQuery<IContent> query, int pageNumber, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "")
{
// Get base query
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IContent>(sqlClause, query);
var sql = translator.Translate()
.Where<DocumentDto>(x => x.Newest);
// Apply filter
if (!string.IsNullOrEmpty(filter))
{
sql = sql.Where("cmsDocument.text LIKE @0", "%" + filter + "%");
}
// Apply order according to parameters
if (!string.IsNullOrEmpty(orderBy))
{
var orderByParams = new[] { GetDatabaseFieldNameForOrderBy(orderBy) };
if (orderDirection == Direction.Ascending)
{
sql = sql.OrderBy(orderByParams);
}
else
{
sql = sql.OrderByDescending(orderByParams);
}
}
// Note we can't do multi-page for several DTOs like we can multi-fetch and are doing in PerformGetByQuery,
// but actually given we are doing a Get on each one (again as in PerformGetByQuery), we only need the node Id.
// So we'll modify the SQL.
var modifiedSQL = sql.SQL.Replace("SELECT *", "SELECT cmsDocument.nodeId");
// Get page of results and total count
IEnumerable<IContent> result;
var pagedResult = Database.Page<DocumentDto>(pageNumber, pageSize, modifiedSQL, sql.Arguments);
totalRecords = Convert.ToInt32(pagedResult.TotalItems);
if (totalRecords > 0)
{
// Parse out node Ids and load content (we need the cast here in order to be able to call the IQueryable extension
// methods OrderBy or OrderByDescending)
var content = GetAll(pagedResult.Items
.DistinctBy(x => x.NodeId)
.Select(x => x.NodeId).ToArray())
.Cast<Content>()
.AsQueryable();
// Now we need to ensure this result is also ordered by the same order by clause
var orderByProperty = GetIContentPropertyNameForOrderBy(orderBy);
if (orderDirection == Direction.Ascending)
{
result = content.OrderBy(orderByProperty);
}
else
{
result = content.OrderByDescending(orderByProperty);
}
}
else
{
result = Enumerable.Empty<IContent>();
}
return result;
}
private string GetDatabaseFieldNameForOrderBy(string orderBy)
{
// Translate the passed order by field (which were originally defined for in-memory object sorting
// of ContentItemBasic instances) to the database field names.
switch (orderBy)
{
case "Name":
return "cmsDocument.text";
case "Owner":
return "umbracoNode.nodeUser";
case "Updator":
return "cmsDocument.documentUser";
default:
return orderBy;
}
}
private string GetIContentPropertyNameForOrderBy(string orderBy)
{
// Translate the passed order by field (which were originally defined for in-memory object sorting
// of ContentItemBasic instances) to the IContent property names.
switch (orderBy)
{
case "Owner":
return "CreatorId";
case "Updator":
return "WriterId";
default:
return orderBy;
}
}
#endregion
/// <summary>
@@ -240,7 +240,7 @@ AND umbracoNode.id <> @id",
{
var nodeId = contentDto.NodeId;
var propertyTypeId = propertyType.Id;
var propertySql = new Sql().Select("*")
var propertySql = new Sql().Select("cmsPropertyData.id")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(
@@ -249,7 +249,7 @@ AND umbracoNode.id <> @id",
.Where<PropertyTypeDto>(x => x.Id == propertyTypeId);
//Finally delete the properties that match our criteria for removing a ContentType from the composition
Database.Delete<PropertyDataDto>(propertySql);
Database.Delete<PropertyDataDto>(new Sql("WHERE id IN (" + propertySql.SQL + ")", propertySql.Arguments));
}
}
}
@@ -285,7 +285,8 @@ AND umbracoNode.id <> @id",
}
}
if (((ICanBeDirty) entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") ||
entity.PropertyGroups.Any(x => x.IsDirty()))
{
//Delete Tabs/Groups by excepting entries from db with entries from collections
var dbPropertyGroups =
@@ -346,6 +347,25 @@ AND umbracoNode.id <> @id",
if (propertyType.HasIdentity == false)
propertyType.Id = typePrimaryKey; //Set Id on new PropertyType
}
//If a Composition is removed we need to update/reset references to the PropertyGroups on that ContentType
if (((ICanBeDirty)entity).IsPropertyDirty("ContentTypeComposition") &&
compositionBase != null &&
compositionBase.RemovedContentTypeKeyTracker != null &&
compositionBase.RemovedContentTypeKeyTracker.Any())
{
foreach (var compositionId in compositionBase.RemovedContentTypeKeyTracker)
{
var dbPropertyGroups =
Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new { Id = compositionId })
.Select(x => x.Id);
foreach (var propertyGroup in dbPropertyGroups)
{
Database.Update<PropertyTypeGroupDto>("SET parentGroupId = NULL WHERE parentGroupId = @TabId AND contenttypeNodeId = @ContentTypeNodeId",
new { TabId = propertyGroup, ContentTypeNodeId = entity.Id });
}
}
}
}
protected IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
@@ -426,7 +426,7 @@ AND umbracoNode.id <> @id",
{
//go get the data
var dtos = Database.Fetch<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new { Id = dataTypeId });
var list = dtos.Select(x => new Tuple<PreValue, string, int>(new PreValue(x.Id, x.Value, x.SortOrder), x.Alias, x.SortOrder)).ToList();
var list = dtos.Select(x => new Tuple<PreValue, string, int>(new PreValue(x.Id, x.Value), x.Alias, x.SortOrder)).ToList();
var collection = PreValueConverter.ConvertToPreValuesCollection(list);
//now create the cache key, this needs to include all pre-value ids so that we can use this cached item in the GetPreValuesAsString method
@@ -146,9 +146,6 @@ namespace Umbraco.Core.Persistence.Repositories
{
((DictionaryItem)entity).AddingEntity();
foreach (var translation in entity.Translations)
translation.Value = translation.Value.ToValidXmlString();
var factory = new DictionaryItemFactory();
var dto = factory.BuildDto(entity);
@@ -170,9 +167,6 @@ namespace Umbraco.Core.Persistence.Repositories
{
((Entity)entity).UpdatingEntity();
foreach (var translation in entity.Translations)
translation.Value = translation.Value.ToValidXmlString();
var factory = new DictionaryItemFactory();
var dto = factory.BuildDto(entity);
@@ -1,23 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Xml.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Persistence.Repositories
{
public interface IContentRepository : IRepositoryVersionable<int, IContent>
{
/// <summary>
/// Used to bulk update the permissions set for a content item. This will replace all permissions
/// assigned to an entity with a list of user id & permission pairs.
/// </summary>
/// <param name="permissionSet"></param>
void ReplaceContentPermissions(EntityPermissionSet permissionSet);
/// <summary>
/// Gets a specific language version of an <see cref="IContent"/>
/// </summary>
@@ -68,18 +59,5 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="xml"></param>
void AddOrUpdatePreviewXml(IContent content, Func<IContent, XElement> xml);
/// <summary>
/// Gets paged content results
/// </summary>
/// <param name="query">Query to excute</param>
/// <param name="pageNumber">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetPagedResultsByQuery(IQuery<IContent> query, int pageNumber, int pageSize, out int totalRecords,
string orderBy, Direction orderDirection, string filter = "");
}
}
@@ -12,17 +12,6 @@ namespace Umbraco.Core.Persistence.Repositories
public interface IRepositoryVersionable<TId, TEntity> : IRepositoryQueryable<TId, TEntity>
where TEntity : IAggregateRoot
{
/// <summary>
/// Get the total count of entities
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <returns></returns>
int Count(string contentTypeAlias = null);
int CountChildren(int parentId, string contentTypeAlias = null);
int CountDescendants(int parentId, string contentTypeAlias = null);
/// <summary>
/// Gets a list of all versions for an <see cref="TEntity"/>.
/// </summary>
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Returns all tags for an entity type (content/media/member)
/// </summary>
/// <param name="objectType">Entity type</param>
/// <param name="objectType"></param>
/// <param name="group">Optional group</param>
/// <returns></returns>
IEnumerable<ITag> GetTagsForEntityType(TaggableObjectTypes objectType, string group = null);
@@ -57,18 +57,5 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="propertyTypeId"></param>
/// <param name="tags">The tags to remove from the property</param>
void RemoveTagsFromProperty(int contentId, int propertyTypeId, IEnumerable<ITag> tags);
/// <summary>
/// Removes all tag associations from the property
/// </summary>
/// <param name="contentId"></param>
/// <param name="propertyTypeId"></param>
void ClearTagsFromProperty(int contentId, int propertyTypeId);
/// <summary>
/// Removes all tag associations from the entity
/// </summary>
/// <param name="contentId"></param>
void ClearTagsFromEntity(int contentId);
}
}
@@ -188,22 +188,10 @@ namespace Umbraco.Core.Persistence.Repositories
}
else
{
//This will only work if the Alias hasn't been changed
if (macro.Properties.ContainsKey(propDto.Alias))
//only update if it's dirty
if (macro.Properties[propDto.Alias].IsDirty())
{
//only update if it's dirty
if (macro.Properties[propDto.Alias].IsDirty())
{
Database.Update(propDto);
}
}
else
{
var property = macro.Properties.FirstOrDefault(x => x.Id == propDto.Id);
if (property != null && property.IsDirty())
{
Database.Update(propDto);
}
Database.Update(propDto);
}
}
}
@@ -220,9 +220,6 @@ namespace Umbraco.Core.Persistence.Repositories
//Ensure unique name on the same level
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name);
//Ensure that strings don't contain characters that are invalid in XML
entity.SanitizeEntityPropertiesForXmlStorage();
var factory = new MediaFactory(NodeObjectTypeId, entity.Id);
var dto = factory.BuildDto(entity);
@@ -292,9 +289,6 @@ namespace Umbraco.Core.Persistence.Repositories
//Ensure unique name on the same level
entity.Name = EnsureUniqueNodeName(entity.ParentId, entity.Name, entity.Id);
//Ensure that strings don't contain characters that are invalid in XML
entity.SanitizeEntityPropertiesForXmlStorage();
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
if (((ICanBeDirty)entity).IsPropertyDirty("ParentId"))
{
@@ -375,7 +369,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (property.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias &&
string.IsNullOrEmpty(property.Value.ToString()) == false
&& fs.FileExists(fs.GetRelativePath(property.Value.ToString())))
&& fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
{
var relativeFilePath = fs.GetRelativePath(property.Value.ToString());
var parentDirectory = System.IO.Path.GetDirectoryName(relativeFilePath);
@@ -209,9 +209,6 @@ namespace Umbraco.Core.Persistence.Repositories
{
((Member)entity).AddingEntity();
//Ensure that strings don't contain characters that are invalid in XML
entity.SanitizeEntityPropertiesForXmlStorage();
var factory = new MemberFactory(NodeObjectTypeId, entity.Id);
var dto = factory.BuildDto(entity);
@@ -287,9 +284,6 @@ namespace Umbraco.Core.Persistence.Repositories
//Updates Modified date
((Member)entity).UpdatingEntity();
//Ensure that strings don't contain characters that are invalid in XML
entity.SanitizeEntityPropertiesForXmlStorage();
var dirtyEntity = (ICanBeDirty) entity;
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
@@ -404,7 +398,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (property.PropertyType.PropertyEditorAlias == uploadFieldAlias &&
string.IsNullOrEmpty(property.Value.ToString()) == false
&& fs.FileExists(fs.GetRelativePath(property.Value.ToString())))
&& fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
{
var relativeFilePath = fs.GetRelativePath(property.Value.ToString());
var parentDirectory = System.IO.Path.GetDirectoryName(relativeFilePath);
@@ -191,23 +191,25 @@ namespace Umbraco.Core.Persistence.Repositories
/// <summary>
/// Assigns permissions to an entity for multiple users/permission entries
/// </summary>
/// <param name="permissionSet">
/// <param name="entity"></param>
/// <param name="userPermissions">
/// A key/value pair list containing a userId and a permission to assign
/// </param>
/// <remarks>
/// This will first clear the permissions for this entity then re-create them
/// </remarks>
public void ReplaceEntityPermissions(EntityPermissionSet permissionSet)
public void ReplaceEntityPermissions(TEntity entity, IEnumerable<Tuple<int, string>> userPermissions)
{
var db = _unitOfWork.Database;
using (var trans = db.GetTransaction())
{
db.Execute("DELETE FROM umbracoUser2NodePermission WHERE nodeId=@nodeId", new { nodeId = permissionSet.EntityId });
db.Execute("DELETE FROM umbracoUser2NodePermission WHERE nodeId=@nodeId", new { nodeId = entity.Id });
var actions = permissionSet.UserPermissionsSet.Select(p => new User2NodePermissionDto
var actions = userPermissions.Select(p => new User2NodePermissionDto
{
NodeId = permissionSet.EntityId,
Permission = p.Permission,
UserId = p.UserId
NodeId = entity.Id,
Permission = p.Item2,
UserId = p.Item1
}).ToArray();
_unitOfWork.Database.BulkInsertRecords(actions, trans);
@@ -133,9 +133,6 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns></returns>
public IEnumerable<TEntity> GetAll(params TId[] ids)
{
//ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries
ids = ids.Distinct().ToArray();
if (ids.Any())
{
var entities = _cache.GetByIds(
@@ -64,9 +64,6 @@ namespace Umbraco.Core.Persistence.Repositories
public override IEnumerable<Script> GetAll(params string[] ids)
{
//ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries
ids = ids.Distinct().ToArray();
if (ids.Any())
{
foreach (var id in ids)
@@ -106,9 +106,6 @@ namespace Umbraco.Core.Persistence.Repositories
public override IEnumerable<Stylesheet> GetAll(params string[] ids)
{
//ensure they are de-duplicated, easy win if people don't do this as this can cause many excess queries
ids = ids.Distinct().ToArray();
if (ids.Any())
{
foreach (var id in ids)
@@ -230,96 +230,63 @@ namespace Umbraco.Core.Persistence.Repositories
{
var nodeObjectType = GetNodeObjectType(objectType);
var sql = GetTagsQuerySelect(true);
sql = ApplyRelationshipJoinToTagsQuery(sql);
sql = sql
var sql = new Sql()
.Select("DISTINCT cmsTags.*")
.From<TagDto>()
.InnerJoin<TagRelationshipDto>()
.On<TagRelationshipDto, TagDto>(left => left.TagId, right => right.Id)
.InnerJoin<ContentDto>()
.On<ContentDto, TagRelationshipDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>()
.On<NodeDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(dto => dto.NodeObjectType == nodeObjectType);
sql = ApplyGroupFilterToTagsQuery(sql, group);
if (group.IsNullOrWhiteSpace() == false)
{
sql = sql.Where<TagDto>(dto => dto.Group == group);
}
sql = ApplyGroupByToTagsQuery(sql);
var factory = new TagFactory();
return ExecuteTagsQuery(sql);
return Database.Fetch<TagDto>(sql).Select(factory.BuildEntity);
}
public IEnumerable<ITag> GetTagsForEntity(int contentId, string group = null)
{
var sql = GetTagsQuerySelect();
sql = ApplyRelationshipJoinToTagsQuery(sql);
sql = sql
var sql = new Sql()
.Select("DISTINCT cmsTags.*")
.From<TagDto>()
.InnerJoin<TagRelationshipDto>()
.On<TagRelationshipDto, TagDto>(left => left.TagId, right => right.Id)
.Where<TagRelationshipDto>(dto => dto.NodeId == contentId);
sql = ApplyGroupFilterToTagsQuery(sql, group);
if (group.IsNullOrWhiteSpace() == false)
{
sql = sql.Where<TagDto>(dto => dto.Group == group);
}
return ExecuteTagsQuery(sql);
var factory = new TagFactory();
return Database.Fetch<TagDto>(sql).Select(factory.BuildEntity);
}
public IEnumerable<ITag> GetTagsForProperty(int contentId, string propertyTypeAlias, string group = null)
{
var sql = GetTagsQuerySelect();
sql = ApplyRelationshipJoinToTagsQuery(sql);
sql = sql
var sql = new Sql()
.Select("DISTINCT cmsTags.*")
.From<TagDto>()
.InnerJoin<TagRelationshipDto>()
.On<TagRelationshipDto, TagDto>(left => left.TagId, right => right.Id)
.InnerJoin<PropertyTypeDto>()
.On<PropertyTypeDto, TagRelationshipDto>(left => left.Id, right => right.PropertyTypeId)
.Where<TagRelationshipDto>(dto => dto.NodeId == contentId)
.Where<PropertyTypeDto>(dto => dto.Alias == propertyTypeAlias);
sql = ApplyGroupFilterToTagsQuery(sql, group);
return ExecuteTagsQuery(sql);
}
private Sql GetTagsQuerySelect(bool withGrouping = false)
{
var sql = new Sql();
if (withGrouping)
{
sql = sql.Select("cmsTags.Id, cmsTags.Tag, cmsTags.[Group], Count(*) NodeCount");
}
else
{
sql = sql.Select("DISTINCT cmsTags.*");
}
return sql;
}
private Sql ApplyRelationshipJoinToTagsQuery(Sql sql)
{
return sql
.From<TagDto>()
.InnerJoin<TagRelationshipDto>()
.On<TagRelationshipDto, TagDto>(left => left.TagId, right => right.Id);
}
private Sql ApplyGroupFilterToTagsQuery(Sql sql, string group)
{
if (!group.IsNullOrWhiteSpace())
if (group.IsNullOrWhiteSpace() == false)
{
sql = sql.Where<TagDto>(dto => dto.Group == group);
}
return sql;
}
private Sql ApplyGroupByToTagsQuery(Sql sql)
{
return sql.GroupBy(new string[] { "cmsTags.Id", "cmsTags.Tag", "cmsTags.[Group]" });
}
private IEnumerable<ITag> ExecuteTagsQuery(Sql sql)
{
var factory = new TagFactory();
return Database.Fetch<TagDto>(sql).Select(factory.BuildEntity);
@@ -443,18 +410,6 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Execute(deleteSql);
}
public void ClearTagsFromProperty(int contentId, int propertyTypeId)
{
Database.Execute("DELETE FROM cmsTagRelationship WHERE nodeId = @nodeId AND propertyTypeId = @propertyTypeId",
new { nodeId = contentId, propertyTypeId = propertyTypeId });
}
public void ClearTagsFromEntity(int contentId)
{
Database.Execute("DELETE FROM cmsTagRelationship WHERE nodeId = @nodeId",
new { nodeId = contentId });
}
private Guid GetNodeObjectType(TaggableObjectTypes type)
{
switch (type)
@@ -371,7 +371,6 @@ namespace Umbraco.Core.Persistence.Repositories
//template.CreateDate = _viewsFileSystem.GetCreated(path).UtcDateTime;
//template.Key = new FileInfo(path).Name.EncodeAsGuid();
template.Path = path;
template.Content = content;
}
@@ -2,14 +2,11 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Editors;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -96,100 +93,6 @@ namespace Umbraco.Core.Persistence.Repositories
#endregion
public int CountDescendants(int parentId, string contentTypeAlias = null)
{
var pathMatch = parentId == -1
? "-1,"
: "," + parentId + ",";
var sql = new Sql();
if (contentTypeAlias.IsNullOrWhiteSpace())
{
sql.Select("COUNT(*)")
.From<NodeDto>()
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<NodeDto>(x => x.Path.Contains(pathMatch));
}
else
{
sql.Select("COUNT(*)")
.From<NodeDto>()
.InnerJoin<ContentDto>()
.On<NodeDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentTypeDto>()
.On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<NodeDto>(x => x.Path.Contains(pathMatch))
.Where<ContentTypeDto>(x => x.Alias == contentTypeAlias);
}
return Database.ExecuteScalar<int>(sql);
}
public int CountChildren(int parentId, string contentTypeAlias = null)
{
var sql = new Sql();
if (contentTypeAlias.IsNullOrWhiteSpace())
{
sql.Select("COUNT(*)")
.From<NodeDto>()
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<NodeDto>(x => x.ParentId == parentId);
}
else
{
sql.Select("COUNT(*)")
.From<NodeDto>()
.InnerJoin<ContentDto>()
.On<NodeDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentTypeDto>()
.On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<NodeDto>(x => x.ParentId == parentId)
.Where<ContentTypeDto>(x => x.Alias == contentTypeAlias);
}
return Database.ExecuteScalar<int>(sql);
}
/// <summary>
/// Get the total count of entities
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <returns></returns>
public int Count(string contentTypeAlias = null)
{
var sql = new Sql();
if (contentTypeAlias.IsNullOrWhiteSpace())
{
sql.Select("COUNT(*)")
.From<NodeDto>()
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
}
else
{
sql.Select("COUNT(*)")
.From<NodeDto>()
.InnerJoin<ContentDto>()
.On<NodeDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentTypeDto>()
.On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<ContentTypeDto>(x => x.Alias == contentTypeAlias);
}
return Database.ExecuteScalar<int>(sql);
}
/// <summary>
/// This removes associated tags from the entity - used generally when an entity is recycled
/// </summary>
/// <param name="entity"></param>
/// <param name="tagRepo"></param>
protected void ClearEntityTags(IContentBase entity, ITagsRepository tagRepo)
{
tagRepo.ClearTagsFromEntity(entity.Id);
}
/// <summary>
/// Updates the tag repository with any tag enabled properties and their values
/// </summary>
@@ -232,33 +135,14 @@ namespace Umbraco.Core.Persistence.Repositories
protected PropertyCollection GetPropertyCollection(int id, Guid versionId, IContentTypeComposition contentType, DateTime createDate, DateTime updateDate)
{
var sql = new Sql();
sql.Select("cmsPropertyData.*, cmsDataTypePreValues.id as preValId, cmsDataTypePreValues.value, cmsDataTypePreValues.sortorder, cmsDataTypePreValues.alias, cmsDataTypePreValues.datatypeNodeId")
sql.Select("*")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
.LeftOuterJoin<DataTypePreValueDto>()
.On<PropertyTypeDto, DataTypePreValueDto>(left => left.DataTypeId, right => right.DataTypeNodeId)
.Where<PropertyDataDto>(x => x.NodeId == id)
.Where<PropertyDataDto>(x => x.VersionId == versionId);
var allData = Database.Fetch<dynamic>(sql);
var propertyDataDtos = allData.Select(x => new PropertyDataDto
{
Date = x.dataDate,
Id = x.id,
Integer = x.dataInt,
NodeId = x.contentNodeId,
Text = x.dataNtext,
VarChar = x.dataNvarchar,
VersionId = x.versionId,
PropertyTypeId = x.propertytypeid,
//NOTE: This get's used for nothing so we don't need to map it
//PropertyTypeDto = new PropertyTypeDto()
}).Distinct();
var propertyDataDtos = Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql);
var propertyFactory = new PropertyFactory(contentType, versionId, id, createDate, updateDate);
var properties = propertyFactory.BuildEntity(propertyDataDtos).ToArray();
@@ -272,39 +156,6 @@ namespace Umbraco.Core.Persistence.Repositories
property.Id = primaryKey;
}
foreach (var property in properties)
{
var editor = PropertyEditorResolver.Current.GetByAlias(property.PropertyType.PropertyEditorAlias);
//TODO: Should this be cached somehow? Might need to benchmark this
var tagSupport = TagExtractor.GetAttribute(editor);
if (tagSupport != null)
{
//this property has tags, so we need to extract them and for that we need the prevals which we've already looked up
var preValData = allData.Where(x => x.propertytypeid == property.PropertyTypeId && x.preValId != null)
.Select(x => new DataTypePreValueDto
{
Alias = x.alias,
DataTypeNodeId = x.datatypeNodeId,
Id = x.preValId,
SortOrder = x.sortorder,
Value = x.value
})
.ToDictionary(x => x.Alias, x => new PreValue(x.Id, x.Value, x.SortOrder));
var preVals = new PreValueCollection(preValData);
var d = new ContentPropertyData(property.Value,
preVals,
new Dictionary<string, object>());
TagExtractor.SetPropertyTags(property, d, property.Value, tagSupport);
}
}
return new PropertyCollection(properties);
}
}
@@ -114,7 +114,7 @@ namespace Umbraco.Core.PropertyEditors
throw new NotImplementedException("This method must be implemented if a view is not explicitly set");
}
editor.View = _attribute.EditorView.StartsWith("~/") ? IOHelper.ResolveUrl(_attribute.EditorView) : _attribute.EditorView;
editor.View = _attribute.EditorView;
editor.ValueType = _attribute.ValueType;
editor.HideLabel = _attribute.HideLabel;
return editor;
@@ -223,12 +223,6 @@ namespace Umbraco.Core.PropertyEditors
/// </remarks>
public virtual object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
{
//if it's json but it's empty json, then return null
if (ValueType.InvariantEquals("JSON") && editorValue.Value != null && editorValue.Value.ToString().DetectIsEmptyJson())
{
return null;
}
var result = TryConvertValueToCrlType(editorValue.Value);
if (result.Success == false)
{
@@ -1,18 +0,0 @@
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
public class ColorPickerValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ColorPickerAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
// make sure it's a string
return source.ToString();
}
}
}
@@ -16,34 +16,12 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
{
// in xml a boolean is: string
// in the database a boolean is: string "1" or "0" or empty
// typically the converter does not need to handle anything else ("true"...)
// however there are cases where the value passed to the converter could be a non-string object, e.g. int, bool
if (source is string)
{
var str = (string)source;
if (str == null || str.Length == 0 || str == "0")
return false;
if (str == "1")
return true;
bool result;
if (bool.TryParse(str, out result))
return result;
return false;
}
if (source is int)
return (int)source == 1;
if (source is bool)
return (bool)source;
// the converter does not need to handle anything else ("true"...)
// default value is: false
return false;
var sourceString = source as string;
if (sourceString == null) return false;
return sourceString == "1";
}
// default ConvertSourceToObject just returns source ie a boolean value
@@ -51,7 +29,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
{
// source should come from ConvertSource and be a boolean already
return (bool)source ? "1" : "0";
return (bool) source ? "1" : "0";
}
}
}
@@ -1,61 +0,0 @@
using System;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
namespace Umbraco.Core.Publishing
{
/// <summary>
/// Used to perform scheduled publishing/unpublishing
/// </summary>
internal class ScheduledPublisher
{
private readonly IContentService _contentService;
public ScheduledPublisher(IContentService contentService)
{
_contentService = contentService;
}
public void CheckPendingAndProcess()
{
foreach (var d in _contentService.GetContentForRelease())
{
try
{
d.ReleaseDate = null;
var result = _contentService.SaveAndPublishWithStatus(d, (int)d.GetWriterProfile().Id);
if (result.Success == false)
{
if (result.Exception != null)
{
LogHelper.Error<ScheduledPublisher>("Could not published the document (" + d.Id + ") based on it's scheduled release, status result: " + result.Result.StatusType, result.Exception);
}
else
{
LogHelper.Warn<ScheduledPublisher>("Could not published the document (" + d.Id + ") based on it's scheduled release. Status result: " + result.Result.StatusType);
}
}
}
catch (Exception ee)
{
LogHelper.Error<ScheduledPublisher>(string.Format("Error publishing node {0}", d.Id), ee);
throw;
}
}
foreach (var d in _contentService.GetContentForExpiration())
{
try
{
d.ExpireDate = null;
_contentService.UnPublish(d, (int)d.GetWriterProfile().Id);
}
catch (Exception ee)
{
LogHelper.Error<ScheduledPublisher>(string.Format("Error unpublishing node {0}", d.Id), ee);
throw;
}
}
}
}
}
@@ -211,7 +211,7 @@ namespace Umbraco.Core.Security
_enablePasswordReset = config.GetValue("enablePasswordReset", false);
_requiresQuestionAndAnswer = config.GetValue("requiresQuestionAndAnswer", false);
_requiresUniqueEmail = config.GetValue("requiresUniqueEmail", true);
_maxInvalidPasswordAttempts = GetIntValue(config, "maxInvalidPasswordAttempts", 20, false, 0);
_maxInvalidPasswordAttempts = GetIntValue(config, "maxInvalidPasswordAttempts", 5, false, 0);
_passwordAttemptWindow = GetIntValue(config, "passwordAttemptWindow", 10, false, 0);
_minRequiredPasswordLength = GetIntValue(config, "minRequiredPasswordLength", DefaultMinPasswordLength, true, 0x80);
_minRequiredNonAlphanumericCharacters = GetIntValue(config, "minRequiredNonalphanumericCharacters", DefaultMinNonAlphanumericChars, true, 0x80);
@@ -62,30 +62,12 @@ namespace Umbraco.Core.Security
return Membership.Providers[UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider];
}
/// <summary>
/// Returns the currently logged in MembershipUser and flags them as being online - use sparingly (i.e. login)
/// </summary>
/// <param name="membershipProvider"></param>
/// <returns></returns>
public static MembershipUser GetCurrentUserOnline(this MembershipProvider membershipProvider)
{
var username = membershipProvider.GetCurrentUserName();
return username.IsNullOrWhiteSpace()
? null
: membershipProvider.GetUser(username, true);
}
/// <summary>
/// Returns the currently logged in MembershipUser
/// </summary>
/// <param name="membershipProvider"></param>
/// <returns></returns>
public static MembershipUser GetCurrentUser(this MembershipProvider membershipProvider)
{
var username = membershipProvider.GetCurrentUserName();
return username.IsNullOrWhiteSpace()
? null
: membershipProvider.GetUser(username, false);
: membershipProvider.GetUser(username, true);
}
/// <summary>
+59 -103
View File
@@ -6,14 +6,15 @@ using System.Threading;
using System.Xml.Linq;
using Umbraco.Core.Auditing;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Publishing;
@@ -73,47 +74,6 @@ namespace Umbraco.Core.Services
_dataTypeService = dataTypeService;
}
public int Count(string contentTypeAlias = null)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
return repository.Count(contentTypeAlias);
}
}
public int CountChildren(int parentId, string contentTypeAlias = null)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
return repository.CountChildren(parentId, contentTypeAlias);
}
}
public int CountDescendants(int parentId, string contentTypeAlias = null)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
return repository.CountDescendants(parentId, contentTypeAlias);
}
}
/// <summary>
/// Used to bulk update the permissions set for a content item. This will replace all permissions
/// assigned to an entity with a list of user id & permission pairs.
/// </summary>
/// <param name="permissionSet"></param>
public void ReplaceContentPermissions(EntityPermissionSet permissionSet)
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
repository.ReplaceContentPermissions(permissionSet);
}
}
/// <summary>
/// Assigns a single permission to the current content item for the specified user ids
/// </summary>
@@ -472,29 +432,6 @@ namespace Umbraco.Core.Services
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageNumber">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirections">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetPagedChildren(int id, int pageNumber, int pageSize, out int totalChildren,
string orderBy, Direction orderDirection, string filter = "")
{
using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IContent>.Builder.Where(x => x.ParentId == id);
var contents = repository.GetPagedResultsByQuery(query, pageNumber, pageSize, out totalChildren, orderBy, orderDirection, filter);
return contents;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by its name or partial name
/// </summary>
@@ -752,7 +689,7 @@ namespace Umbraco.Core.Services
{
var result = SaveAndPublishDo(content, userId);
LogHelper.Info<ContentService>("Call was made to ContentService.Publish, use PublishWithStatus instead since that method will provide more detailed information on the outcome");
return result.Success;
return result.Success;
}
/// <summary>
@@ -782,7 +719,7 @@ namespace Umbraco.Core.Services
if (!result.Any(x => x.Result.ContentItem.Id == content.Id))
return false;
return result.Single(x => x.Result.ContentItem.Id == content.Id).Success;
return result.Single(x => x.Result.ContentItem.Id == content.Id).Success;
}
/// <summary>
@@ -819,7 +756,7 @@ namespace Umbraco.Core.Services
public bool SaveAndPublish(IContent content, int userId = 0, bool raiseEvents = true)
{
var result = SaveAndPublishDo(content, userId, raiseEvents);
return result.Success;
return result.Success;
}
/// <summary>
@@ -883,7 +820,7 @@ namespace Umbraco.Core.Services
repository.AddOrUpdate(content);
//add or update preview
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
}
}
else
@@ -894,7 +831,7 @@ namespace Umbraco.Core.Services
repository.AddOrUpdate(content);
//add or update preview
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
}
}
}
uow.Commit();
@@ -1135,7 +1072,7 @@ namespace Umbraco.Core.Services
MoveToRecycleBin(content, userId);
return;
}
if (Moving.IsRaisedEventCancelled(
new MoveEventArgs<IContent>(
new MoveEventInfo<IContent>(content, content.Path, parentId)), this))
@@ -1222,21 +1159,37 @@ namespace Umbraco.Core.Services
repository.AddOrUpdatePreviewXml(copy, c => _entitySerializer.Serialize(this, _dataTypeService, c));
uow.Commit();
//Special case for the associated tags
//TODO: Move this to the repository layer in a single transaction!
//don't copy tags data in tags table if the item is in the recycle bin
if (parentId != Constants.System.RecycleBinContent)
//Special case for the associated tags
var tags = uow.Database.Fetch<TagRelationshipDto>("WHERE nodeId = @Id", new { Id = content.Id });
foreach (var tag in tags)
{
var tags = uow.Database.Fetch<TagRelationshipDto>("WHERE nodeId = @Id", new { Id = content.Id });
foreach (var tag in tags)
{
uow.Database.Insert(new TagRelationshipDto { NodeId = copy.Id, TagId = tag.TagId, PropertyTypeId = tag.PropertyTypeId });
}
uow.Database.Insert(new TagRelationshipDto { NodeId = copy.Id, TagId = tag.TagId, PropertyTypeId = tag.PropertyTypeId });
}
}
//NOTE This 'Relation' part should eventually be delegated to a RelationService
//TODO: This should be part of a single commit
if (relateToOriginal)
{
IRelationType relationType = null;
using (var relationTypeRepository = _repositoryFactory.CreateRelationTypeRepository(uow))
{
relationType = relationTypeRepository.Get(1);
}
using (var relationRepository = _repositoryFactory.CreateRelationRepository(uow))
{
var relation = new Relation(content.Id, copy.Id, relationType);
relationRepository.AddOrUpdate(relation);
uow.Commit();
}
Audit.Add(AuditTypes.Copy,
string.Format("Copied content with Id: '{0}' related to original content with Id: '{1}'",
copy.Id, content.Id), copy.WriterId, copy.Id);
}
//Look for children and copy those as well
var children = GetChildren(content.Id);
foreach (var child in children)
@@ -1246,10 +1199,10 @@ namespace Umbraco.Core.Services
Copy(child, copy.Id, relateToOriginal, userId);
}
Copied.RaiseEvent(new CopyEventArgs<IContent>(content, copy, false, parentId, relateToOriginal), this);
Copied.RaiseEvent(new CopyEventArgs<IContent>(content, copy, false, parentId), this);
Audit.Add(AuditTypes.Copy, "Copy Content performed by user", content.WriterId, content.Id);
//TODO: Don't think we need this here because cache should be cleared by the event listeners
// and the correct ICacheRefreshers!?
RuntimeCacheProvider.Current.Clear();
@@ -1378,9 +1331,9 @@ namespace Umbraco.Core.Services
//add or update a preview
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
}
foreach (var content in shouldBePublished)
{
{
//Create and Save ContentXml DTO
repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
}
@@ -1571,7 +1524,7 @@ namespace Umbraco.Core.Services
//bulk insert it into the database
uow.Database.BulkInsertRecords(xmlItems, tr);
tr.Complete();
tr.Complete();
}
Audit.Add(AuditTypes.Publish, "RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
@@ -1676,26 +1629,29 @@ namespace Umbraco.Core.Services
/// <returns>True if unpublishing succeeded, otherwise False</returns>
private bool UnPublishDo(IContent content, bool omitCacheRefresh = false, int userId = 0)
{
var unpublished = _publishingStrategy.UnPublish(content, userId);
if (unpublished)
using (new WriteLock(Locker))
{
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
var unpublished = _publishingStrategy.UnPublish(content, userId);
if (unpublished)
{
content.WriterId = userId;
repository.AddOrUpdate(content);
repository.DeleteContentXml(content);
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateContentRepository(uow))
{
content.WriterId = userId;
repository.AddOrUpdate(content);
repository.DeleteContentXml(content);
uow.Commit();
uow.Commit();
}
//Delete xml from db? and call following method to fire event through PublishingStrategy to update cache
if (omitCacheRefresh == false)
_publishingStrategy.UnPublishingFinalized(content);
Audit.Add(AuditTypes.UnPublish, "UnPublish performed by user", userId, content.Id);
}
//Delete xml from db? and call following method to fire event through PublishingStrategy to update cache
if (omitCacheRefresh == false)
_publishingStrategy.UnPublishingFinalized(content);
Audit.Add(AuditTypes.UnPublish, "UnPublish performed by user", userId, content.Id);
return unpublished;
}
return unpublished;
}
/// <summary>
@@ -1758,7 +1714,7 @@ namespace Umbraco.Core.Services
//Generate a new preview
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, c));
if (published)
{
//Content Xml
@@ -1898,7 +1854,7 @@ namespace Umbraco.Core.Services
}
return PublishStatusType.Success;
}
}
private IContentType FindContentTypeByAlias(string contentTypeAlias)
{
@@ -127,244 +127,6 @@ namespace Umbraco.Core.Services
return xElement;
}
/// <summary>
/// Exports an <see cref="IDataTypeDefinition"/> item to xml as an <see cref="XElement"/>
/// </summary>
/// <param name="dataTypeService"></param>
/// <param name="dataTypeDefinition">IDataTypeDefinition type to export</param>
/// <returns><see cref="XElement"/> containing the xml representation of the IDataTypeDefinition object</returns>
public XElement Serialize(IDataTypeService dataTypeService, IDataTypeDefinition dataTypeDefinition)
{
var prevalues = new XElement("PreValues");
var prevalueList = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeDefinition.Id)
.FormatAsDictionary();
var sort = 0;
foreach (var pv in prevalueList)
{
var prevalue = new XElement("PreValue");
prevalue.Add(new XAttribute("Id", pv.Value.Id));
prevalue.Add(new XAttribute("Value", pv.Value.Value ?? ""));
prevalue.Add(new XAttribute("Alias", pv.Key));
prevalue.Add(new XAttribute("SortOrder", sort));
prevalues.Add(prevalue);
sort++;
}
var xml = new XElement("DataType", prevalues);
xml.Add(new XAttribute("Name", dataTypeDefinition.Name));
//The 'ID' when exporting is actually the property editor alias (in pre v7 it was the IDataType GUID id)
xml.Add(new XAttribute("Id", dataTypeDefinition.PropertyEditorAlias));
xml.Add(new XAttribute("Definition", dataTypeDefinition.Key));
xml.Add(new XAttribute("DatabaseType", dataTypeDefinition.DatabaseType.ToString()));
return xml;
}
public XElement Serialize(IDictionaryItem dictionaryItem)
{
var xml = new XElement("DictionaryItem", new XAttribute("Key", dictionaryItem.ItemKey));
foreach (var translation in dictionaryItem.Translations)
{
xml.Add(new XElement("Value",
new XAttribute("LanguageId", translation.Language.Id),
new XAttribute("LanguageCultureAlias", translation.Language.IsoCode),
new XCData(translation.Value)));
}
return xml;
}
public XElement Serialize(ILanguage language)
{
var xml = new XElement("Language",
new XAttribute("Id", language.Id),
new XAttribute("CultureAlias", language.IsoCode),
new XAttribute("FriendlyName", language.CultureName));
return xml;
}
public XElement Serialize(ITemplate template)
{
var xml = new XElement("Template");
xml.Add(new XElement("Name", template.Name));
xml.Add(new XElement("Alias", template.Alias));
xml.Add(new XElement("Design", new XCData(template.Content)));
var concreteTemplate = template as Template;
if (concreteTemplate != null && concreteTemplate.MasterTemplateId != null)
{
if (concreteTemplate.MasterTemplateId.IsValueCreated &&
concreteTemplate.MasterTemplateId.Value != default(int))
{
xml.Add(new XElement("Master", concreteTemplate.MasterTemplateId.ToString()));
xml.Add(new XElement("MasterAlias", concreteTemplate.MasterTemplateAlias));
}
}
return xml;
}
public XElement Serialize(IDataTypeService dataTypeService, IMediaType mediaType)
{
var info = new XElement("Info",
new XElement("Name", mediaType.Name),
new XElement("Alias", mediaType.Alias),
new XElement("Icon", mediaType.Icon),
new XElement("Thumbnail", mediaType.Thumbnail),
new XElement("Description", mediaType.Description),
new XElement("AllowAtRoot", mediaType.AllowedAsRoot.ToString()));
var masterContentType = mediaType.CompositionAliases().FirstOrDefault();
if (masterContentType != null)
info.Add(new XElement("Master", masterContentType));
var structure = new XElement("Structure");
foreach (var allowedType in mediaType.AllowedContentTypes)
{
structure.Add(new XElement("MediaType", allowedType.Alias));
}
var genericProperties = new XElement("GenericProperties");
foreach (var propertyType in mediaType.PropertyTypes)
{
var definition = dataTypeService.GetDataTypeDefinitionById(propertyType.DataTypeDefinitionId);
var propertyGroup = mediaType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
var genericProperty = new XElement("GenericProperty",
new XElement("Name", propertyType.Name),
new XElement("Alias", propertyType.Alias),
new XElement("Type", propertyType.PropertyEditorAlias),
new XElement("Definition", definition.Key),
new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name),
new XElement("Mandatory", propertyType.Mandatory.ToString()),
new XElement("Validation", propertyType.ValidationRegExp),
new XElement("Description", new XCData(propertyType.Description)));
genericProperties.Add(genericProperty);
}
var tabs = new XElement("Tabs");
foreach (var propertyGroup in mediaType.PropertyGroups)
{
var tab = new XElement("Tab",
new XElement("Id", propertyGroup.Id.ToString(CultureInfo.InvariantCulture)),
new XElement("Caption", propertyGroup.Name));
tabs.Add(tab);
}
var xml = new XElement("MediaType",
info,
structure,
genericProperties,
tabs);
return xml;
}
public XElement Serialize(IMacro macro)
{
var xml = new XElement("macro");
xml.Add(new XElement("name", macro.Name));
xml.Add(new XElement("alias", macro.Alias));
xml.Add(new XElement("scriptType", macro.ControlType));
xml.Add(new XElement("scriptAssembly", macro.ControlAssembly));
xml.Add(new XElement("scriptingFile", macro.ScriptPath));
xml.Add(new XElement("xslt", macro.XsltPath));
xml.Add(new XElement("useInEditor", macro.UseInEditor.ToString()));
xml.Add(new XElement("dontRender", macro.DontRender.ToString()));
xml.Add(new XElement("refreshRate", macro.CacheDuration.ToString(CultureInfo.InvariantCulture)));
xml.Add(new XElement("cacheByMember", macro.CacheByMember.ToString()));
xml.Add(new XElement("cacheByPage", macro.CacheByPage.ToString()));
var properties = new XElement("properties");
foreach (var property in macro.Properties)
{
properties.Add(new XElement("property",
new XAttribute("name", property.Name),
new XAttribute("alias", property.Alias),
new XAttribute("sortOrder", property.SortOrder),
new XAttribute("propertyType", property.EditorAlias)));
}
xml.Add(properties);
return xml;
}
/// <summary>
/// Exports an <see cref="IContentType"/> item to xml as an <see cref="XElement"/>
/// </summary>
/// <param name="dataTypeService"></param>
/// <param name="contentType">Content type to export</param>
/// <returns><see cref="XElement"/> containing the xml representation of the IContentType object</returns>
public XElement Serialize(IDataTypeService dataTypeService, IContentType contentType)
{
var info = new XElement("Info",
new XElement("Name", contentType.Name),
new XElement("Alias", contentType.Alias),
new XElement("Icon", contentType.Icon),
new XElement("Thumbnail", contentType.Thumbnail),
new XElement("Description", contentType.Description),
new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString()),
new XElement("IsListView", contentType.IsContainer.ToString()));
var masterContentType = contentType.CompositionAliases().FirstOrDefault();
if (masterContentType != null)
info.Add(new XElement("Master", masterContentType));
var allowedTemplates = new XElement("AllowedTemplates");
foreach (var template in contentType.AllowedTemplates)
{
allowedTemplates.Add(new XElement("Template", template.Alias));
}
info.Add(allowedTemplates);
if (contentType.DefaultTemplate != null && contentType.DefaultTemplate.Id != 0)
info.Add(new XElement("DefaultTemplate", contentType.DefaultTemplate.Alias));
else
info.Add(new XElement("DefaultTemplate", ""));
var structure = new XElement("Structure");
foreach (var allowedType in contentType.AllowedContentTypes)
{
structure.Add(new XElement("DocumentType", allowedType.Alias));
}
var genericProperties = new XElement("GenericProperties");
foreach (var propertyType in contentType.PropertyTypes)
{
var definition = dataTypeService.GetDataTypeDefinitionById(propertyType.DataTypeDefinitionId);
var propertyGroup = propertyType.PropertyGroupId == null
? null
: contentType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
var genericProperty = new XElement("GenericProperty",
new XElement("Name", propertyType.Name),
new XElement("Alias", propertyType.Alias),
new XElement("Type", propertyType.PropertyEditorAlias),
new XElement("Definition", definition.Key),
new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name),
new XElement("Mandatory", propertyType.Mandatory.ToString()),
new XElement("Validation", propertyType.ValidationRegExp),
new XElement("Description", new XCData(propertyType.Description)));
genericProperties.Add(genericProperty);
}
var tabs = new XElement("Tabs");
foreach (var propertyGroup in contentType.PropertyGroups)
{
var tab = new XElement("Tab",
new XElement("Id", propertyGroup.Id.ToString(CultureInfo.InvariantCulture)),
new XElement("Caption", propertyGroup.Name));
tabs.Add(tab);
}
return new XElement("DocumentType",
info,
structure,
genericProperties,
tabs);
}
/// <summary>
/// Used by Media Export to recursively add children
/// </summary>
+2 -173
View File
@@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Web;
using Umbraco.Core.Auditing;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Repositories;
@@ -23,21 +17,19 @@ namespace Umbraco.Core.Services
private readonly RepositoryFactory _repositoryFactory;
private readonly IUnitOfWorkProvider _fileUowProvider;
private readonly IDatabaseUnitOfWorkProvider _dataUowProvider;
private readonly IMacroService _macroService;
public FileService()
: this(new RepositoryFactory())
{ }
public FileService(RepositoryFactory repositoryFactory)
: this(new FileUnitOfWorkProvider(), new PetaPocoUnitOfWorkProvider(), repositoryFactory, new MacroService())
: this(new FileUnitOfWorkProvider(), new PetaPocoUnitOfWorkProvider(), repositoryFactory)
{
}
public FileService(IUnitOfWorkProvider fileProvider, IDatabaseUnitOfWorkProvider dataProvider, RepositoryFactory repositoryFactory, IMacroService macroService)
public FileService(IUnitOfWorkProvider fileProvider, IDatabaseUnitOfWorkProvider dataProvider, RepositoryFactory repositoryFactory)
{
_repositoryFactory = repositoryFactory;
_macroService = macroService;
_fileUowProvider = fileProvider;
_dataUowProvider = dataProvider;
}
@@ -370,138 +362,6 @@ namespace Umbraco.Core.Services
return template.IsValid();
}
// TODO: Before making this public: How to get feedback in the UI when cancelled
internal Attempt<PartialView> CreatePartialView(PartialView partialView)
{
var partialViewsFileSystem = new PhysicalFileSystem(partialView.BasePath);
var relativeFilePath = partialView.ParentFolderName.EnsureEndsWith('/') + partialViewsFileSystem.GetRelativePath(partialView.FileName);
partialView.ReturnUrl = string.Format(partialView.EditViewFile + "?file={0}", HttpUtility.UrlEncode(relativeFilePath));
//return the link to edit the file if it already exists
if (partialViewsFileSystem.FileExists(partialView.Path))
return Attempt<PartialView>.Succeed(partialView);
if (CreatingPartialView.IsRaisedEventCancelled(new NewEventArgs<PartialView>(partialView, true, partialView.Alias, -1), this))
{
// We have nowhere to return to, clear ReturnUrl
partialView.ReturnUrl = string.Empty;
var failureMessage = string.Format("Creating Partial View {0} was cancelled by an event handler.", partialViewsFileSystem.GetFullPath(partialView.FileName));
LogHelper.Info<FileService>(failureMessage);
return Attempt<PartialView>.Fail(partialView, new ArgumentException(failureMessage));
}
//create the file
var snippetPathAttempt = partialView.TryGetSnippetPath(partialView.SnippetName);
if (snippetPathAttempt.Success == false)
{
throw new InvalidOperationException("Could not load template with name " + partialView.SnippetName);
}
using (var snippetFile = new StreamReader(partialViewsFileSystem.OpenFile(snippetPathAttempt.Result)))
{
var snippetContent = snippetFile.ReadToEnd().Trim();
//strip the @inherits if it's there
snippetContent = partialView.HeaderMatch.Replace(snippetContent, string.Empty);
var content = string.Format("{0}{1}{2}", partialView.CodeHeader, Environment.NewLine, snippetContent);
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
{
partialViewsFileSystem.AddFile(partialView.Path, stream);
}
}
if (partialView.CreateMacro)
CreatePartialViewMacro(partialView);
CreatedPartialView.RaiseEvent(new NewEventArgs<PartialView>(partialView, false, partialView.Alias, -1), this);
return Attempt<PartialView>.Succeed(partialView);
}
internal void CreatePartialViewMacro(PartialView partialView)
{
var name = partialView.FileName.Substring(0, (partialView.FileName.LastIndexOf('.') + 1))
.Trim('.')
.SplitPascalCasing()
.ToFirstUpperInvariant();
var macro = new Macro(name, name) { ScriptPath = partialView.BasePath + partialView.FileName };
_macroService.Save(macro);
}
// TODO: Before making this public: How to get feedback in the UI when cancelled
internal bool DeletePartialView(PartialView partialView, int userId = 0)
{
var partialViewsFileSystem = new PhysicalFileSystem(partialView.BasePath);
if (DeletingPartialView.IsRaisedEventCancelled(new DeleteEventArgs<PartialView>(partialView), this))
{
LogHelper.Info<FileService>(string.Format("Deleting Partial View {0} was cancelled by an event handler.", partialViewsFileSystem.GetFullPath(partialView.FileName)));
return false;
}
if (partialViewsFileSystem.FileExists(partialView.FileName))
{
partialViewsFileSystem.DeleteFile(partialView.FileName);
LogHelper.Info<FileService>(string.Format("Partial View file {0} deleted by user {1}", partialViewsFileSystem.GetFullPath(partialView.FileName), userId));
}
// TODO: does this ever even happen? I don't think folders show up in the tree currently.
// Leaving this here as it was in the original PartialViewTasks code - SJ
else if (partialViewsFileSystem.DirectoryExists(partialView.FileName))
{
partialViewsFileSystem.DeleteDirectory(partialView.FileName, true);
LogHelper.Info<FileService>(string.Format("Partial View directory {0} deleted by user {1}", partialViewsFileSystem.GetFullPath(partialView.FileName), userId));
}
DeletedPartialView.RaiseEvent(new DeleteEventArgs<PartialView>(partialView, false), this);
return true;
}
internal Attempt<PartialView> SavePartialView(PartialView partialView, int userId = 0)
{
if (SavingPartialView.IsRaisedEventCancelled(new SaveEventArgs<PartialView>(partialView, true), this))
{
return Attempt<PartialView>.Fail(new ArgumentException("Save was cancelled by an event handler " + partialView.FileName));
}
//Directory check.. only allow files in script dir and below to be edited
if (partialView.IsValid() == false)
{
return Attempt<PartialView>.Fail(
new ArgumentException(string.Format("Illegal path: {0} or illegal file extension {1}",
partialView.Path,
partialView.FileName.Substring(partialView.FileName.LastIndexOf(".", StringComparison.Ordinal)))));
}
//NOTE: I've left the below here just for informational purposes. If we save a file this way, then the UTF8
// BOM mucks everything up, strangely, if we use WriteAllText everything is ok!
// http://issues.umbraco.org/issue/U4-2118
//using (var sw = System.IO.File.CreateText(savePath))
//{
// sw.Write(val);
//}
System.IO.File.WriteAllText(partialView.Path, partialView.Content, Encoding.UTF8);
//deletes the old file
if (partialView.FileName != partialView.OldFileName)
{
// Create a new PartialView class so that we can set the FileName of the file that needs deleting
var deletePartial = partialView;
deletePartial.FileName = partialView.OldFileName;
DeletePartialView(deletePartial, userId);
}
SavedPartialView.RaiseEvent(new SaveEventArgs<PartialView>(partialView), this);
return Attempt.Succeed(partialView);
}
//TODO Method to change name and/or alias of view/masterpage template
#region Event Handlers
@@ -565,37 +425,6 @@ namespace Umbraco.Core.Services
/// </summary>
public static event TypedEventHandler<IFileService, SaveEventArgs<Stylesheet>> SavedStylesheet;
/// <summary>
/// Occurs before Save
/// </summary>
internal static event TypedEventHandler<IFileService, SaveEventArgs<PartialView>> SavingPartialView;
/// <summary>
/// Occurs after Save
/// </summary>
internal static event TypedEventHandler<IFileService, SaveEventArgs<PartialView>> SavedPartialView;
/// <summary>
/// Occurs before Create
/// </summary>
internal static event TypedEventHandler<IFileService, NewEventArgs<PartialView>> CreatingPartialView;
/// <summary>
/// Occurs after Create
/// </summary>
internal static event TypedEventHandler<IFileService, NewEventArgs<PartialView>> CreatedPartialView;
/// <summary>
/// Occurs before Delete
/// </summary>
internal static event TypedEventHandler<IFileService, DeleteEventArgs<PartialView>> DeletingPartialView;
/// <summary>
/// Occurs after Delete
/// </summary>
internal static event TypedEventHandler<IFileService, DeleteEventArgs<PartialView>> DeletedPartialView;
#endregion
}
}
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Publishing;
namespace Umbraco.Core.Services
@@ -12,17 +11,6 @@ namespace Umbraco.Core.Services
/// </summary>
public interface IContentService : IService
{
int Count(string contentTypeAlias = null);
int CountChildren(int parentId, string contentTypeAlias = null);
int CountDescendants(int parentId, string contentTypeAlias = null);
/// <summary>
/// Used to bulk update the permissions set for a content item. This will replace all permissions
/// assigned to an entity with a list of user id & permission pairs.
/// </summary>
/// <param name="permissionSet"></param>
void ReplaceContentPermissions(EntityPermissionSet permissionSet);
/// <summary>
/// Assigns a single permission to the current content item for the specified user ids
/// </summary>
@@ -109,20 +97,6 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetChildren(int id);
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageNumber">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records query would return without paging</param>
/// <param name="orderBy">Field to order by</param>
/// <param name="orderDirections">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetPagedChildren(int id, int pageNumber, int pageSize, out int totalChildren,
string orderBy, Direction orderDirection, string filter = "");
/// <summary>
/// Gets a collection of an <see cref="IContent"/> objects versions by its Id
/// </summary>

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