Compare commits

...

84 Commits

Author SHA1 Message Date
Warren Buckley 30f63eefb3 Merge branch 'dev-v7.6' of https://github.com/umbraco/Umbraco-CMS into dev-v7.6 2017-03-14 10:18:00 +00:00
Warren Buckley 6114193fd5 Bump version to alpha 75 2017-03-14 10:17:43 +00:00
Warren Buckley 82420605ef Allow Forms Assemblies to access internals in Umbraco.Core - Required to use AppContext.ScopeProvider for Scope Events for Deploy 2017-03-14 10:01:23 +00:00
Sebastiaan Janssen 3bddceb17b Put the rewrite section in system.webServer where it belongs 2017-03-14 11:00:41 +01:00
Sebastiaan Janssen 27fab61646 Merge pull request #1792 from umbraco/temp-U4-9497
U4-9497 Update Related Links Property Editor to support UDIs
2017-03-14 10:14:45 +01:00
Shannon 05f8870424 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6 2017-03-14 17:25:40 +11:00
Shannon 4a829154db Adds documentation link to IIS Rewrite rules 2017-03-14 17:10:39 +11:00
Shannon f8073f429f adds debug transforms to ensure that any urlrewriting stuff is removed when the sln is built 2017-03-14 16:36:15 +11:00
Shannon Deminick 04d37c590b Merge pull request #1786 from umbraco/temp-U4-9004
U4-9004 Remove URLRewriting.net dependency
2017-03-14 16:25:41 +11:00
Warren Buckley 7753993987 Adds in more checks for the UDI or int to be stored - as there is a similar call to open the dialog to pick content from another function name - unknown why
Same for persisting data
2017-03-13 13:48:13 +00:00
Shannon 8f48da8bb0 Gets the related links editor working with the old property value converter too, udpates the install script so that works and updates tests to reference the correct one, adds GUID overloads to the UrlProvider 2017-03-13 16:58:41 +11:00
Shannon aba325e109 Creates UDI Related Links Property Editor and deprecates the old one 2017-03-13 16:14:30 +11:00
Shannon 2dd31f0f05 reverts the change for the showing an error if the node doesn't exist - it was for a start node (i.e. based on a user), not for an existing picked node 2017-03-13 16:00:56 +11:00
Shannon d42d96e166 Fixes issue with new picker logic when a picked node no longer exist, this would result in a 404 error which would actually show the red error and the dialog would die, instead we handle the error and initialize the tree when were ready 2017-03-13 15:04:35 +11:00
Shannon 3571c238b4 Renames the new UDI pickers to still be suffixed with "PropertyEditor" to make things more consistent 2017-03-13 12:59:36 +11:00
Shannon 2087332b69 removes committed Deploy dashboard config 2017-03-13 12:58:44 +11:00
Shannon dc71f9cd5e Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2017-03-13 12:39:27 +11:00
Shannon 99ed4d6cb9 Makes umbraco.GlobalSettings.UmbracoMvcArea available since we haven't been able to get the GlobalSettings into the right public classes yet. 2017-03-13 12:38:08 +11:00
Shannon Deminick 3646cfb47e Merge pull request #1791 from soreng/patch-3
Removed weird comment
2017-03-12 21:37:44 +01:00
Søren Gregersen 1b7ce8bcde Removed weird comment
removed "this" as remark for NewPassword
2017-03-12 21:20:24 +01:00
Shannon 1c7b374c42 Fixes new property value converters to shadow their old ones correctly 2017-03-10 12:27:29 +01:00
Shannon 7100a00ef1 fix merges 2017-03-10 12:22:44 +01:00
Shannon df04100ff6 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6
# Conflicts:
#	build/UmbracoVersion.txt
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
#	src/Umbraco.Core/Persistence/Querying/ExpressionVisitorBase.cs
#	src/Umbraco.Core/Persistence/Querying/SqlExpressionExtensions.cs
#	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/MediaService.cs
#	src/Umbraco.Core/Umbraco.Core.csproj
#	src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
#	src/Umbraco.Tests/Umbraco.Tests.csproj
#	src/Umbraco.Web.UI.Client/src/less/tree.less
#	src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
2017-03-10 10:40:28 +01:00
Stephan b893df035b Files were committed by mistake 2017-03-10 08:48:26 +01:00
Sebastiaan Janssen 67c6146f96 Merge pull request #1787 from umbraco/temp-u4-9595
U4-9595 - improve log error msg on thread aborts on timeouts
2017-03-09 15:59:47 +01:00
Sebastiaan Janssen 13aa615745 U4-9004 Remove URLRewriting.net dependency 2017-03-09 11:41:36 +01:00
Stephan b8c0d4c4ea U4-9595 - improve log error msg on thread aborts on timeouts 2017-03-09 11:35:06 +01:00
Sebastiaan Janssen 6c624ca08a Merge pull request #1785 from CreunaAB/fix/add-missing-sv-translation
Adds missing swedish translation for document type without template
2017-03-08 15:21:55 +01:00
nengberg 8a133938e6 Adds missing swedish translation for document type without template 2017-03-08 09:57:32 +01:00
hartvig c1b3f1977d Merge pull request #1768 from danieland/dev-v7
U4-9571: Legacy icons look weird
2017-03-07 18:58:13 +01:00
hartvig f086156d48 Merge pull request #1781 from majken92/dev-v7
Updating sv.xml with correct translation
2017-03-07 18:53:43 +01:00
hartvig 7080013dd6 Merge pull request #1777 from jamescoxhead/U4-9373
U4-9373 Fix for duplicate dashboards after upgrading
2017-03-07 18:45:50 +01:00
Michael Razmgah b080825bb2 Updating sv.xml with correct translation 2017-03-06 21:31:42 +01:00
Stephan 8bb696bf9a Merge pull request #1776 from umbraco/temp-U4-9587
U4-9587 RebuildXmlStructures doesn't clear out stale data so there is…
2017-03-06 14:51:50 +01:00
Shannon 55e8451513 changes to in groups of 2000 2017-03-06 14:44:41 +01:00
Shannon 7e4e2a1d5d Fixes query when rebuilding xml structures for a content type 2017-03-06 14:42:02 +01:00
Stephan 79d4956b75 Merge branch 'dev-v7' into temp-U4-9587 2017-03-03 13:26:43 +01:00
James Coxhead 9acfd8f5d2 Updated dashboard config transform
Fix for dupicate dashboards after upgrading
2017-03-02 21:02:25 +00:00
Shannon 0b530ce181 Fixes rebuilding xml structures when a content type is specified, we need to filter on that when looking for orphaned items. 2017-03-02 19:17:39 +01:00
Shannon 402835d72d Merge branch 'Colletz-U4-9573' into dev-v7 2017-03-02 18:45:06 +01:00
Shannon 08d579ec87 Fixes a bunch of id assignments in PublicAccessRepository along with clearing out old entries that are flagged for removal, adds a lot more assertions for retrieving items and their rules. 2017-03-02 18:44:42 +01:00
Shannon 8b92755487 Merge branch 'U4-9573' of https://github.com/Colletz/Umbraco-CMS into Colletz-U4-9573 2017-03-02 17:55:16 +01:00
Shannon 01b48107f3 ensures that the content type is not used in the query when it is null. 2017-03-02 17:45:21 +01:00
Shannon a546803970 Need to also update the health check check not just the old endpoint for non trashed media. 2017-03-02 17:40:39 +01:00
Shannon 96c28c2611 U4-9587 RebuildXmlStructures doesn't clear out stale data so there is unpublished or trashed items remaining in the xml table, xml data integrity check is misleading due to the media lookup 2017-03-02 17:28:34 +01:00
Shannon 65a22417f7 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2017-03-02 16:54:37 +01:00
Shannon 6c271e7af9 Fixes issue with U4-9456 when we use the withCache flag we do not add that to the defs collection so an error would occur if one was resolved from cache. 2017-03-02 16:54:25 +01:00
Stephan a85cafe7ab Merge pull request #1772 from umbraco/temp-U4-9577
U4-9577 Ability to store the xml content file in diff storage locatio…
2017-03-02 11:42:44 +01:00
Stephan 41d91ae791 Merge pull request #1758 from umbraco/temp-U4-9536
Updates Content/Entity repos to deal with cases where there is corrupt newest/published flags
2017-03-02 11:17:56 +01:00
Shannon Deminick dca5a26fe4 Merge pull request #1774 from umbraco/temp-9586-async-content-xml-save
Removes async from filestream instance
2017-03-02 10:49:31 +01:00
Shannon 7e8f6d391f Just to be sure, moves the text replacement outside of the using - though that wouldn't make any diff 2017-03-02 10:48:11 +01:00
Shannon 7aa00ee6e0 Removes unused method that also uses the async flag for file stream - which we know in some cases causes fcn issues, fixes streams not being closed property if there are exceptions 2017-03-02 10:37:04 +01:00
Niels Hartvig 2e027e6195 Removes async from filestream instance 2017-03-02 10:33:00 +01:00
Shannon 337ba4ef34 U4-9577 Ability to store the xml content file in diff storage locations: Default, Environment Temp or ASP.NET temp location 2017-02-28 23:53:12 +01:00
Colletz 0f32c2d680 PublicAccess - Ensure correct ordering on join
Ensured the correct order on JOIN for the subsequent mapping on AccessDto and AccessRuleDto.
2017-02-28 12:43:49 +01:00
Shannon 96a18ec8e9 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into temp-U4-9536
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
2017-02-27 15:24:55 +01:00
Shannon 65c39a3117 Fixes issue with returning multiple versions and mapping their property values, adds more assertions 2017-02-27 15:19:59 +01:00
Claus 15150f9a16 Merge pull request #1763 from umbraco/temp-U4-9545
U4-9545 EntityRepository performs poorly for Media due to unnecessary outer joins
2017-02-27 12:00:06 +01:00
Claus 259879c964 just cleaning some using statements and fixing a few typos. 2017-02-27 11:59:19 +01:00
Daniel Sune Andreasen ed87789abe collides with .legacy-custom-file 2017-02-27 11:14:37 +01:00
Shannon 09492fa779 Ensures that the published data retrieved uses the latest content version PK instead of by date in case dates are exactly the same. 2017-02-24 14:14:28 +11:00
Shannon 8122c0b352 Simplifies the includeAllVersions check 2017-02-24 14:00:38 +11:00
Shannon 28f0ab1001 Fixes U4-9456, ensures that property sets are mapped to a content version instead of an Id, adds more unit tests, ensures that if this warning ever occurs in a test that the test will fail. 2017-02-24 13:51:14 +11:00
Shannon 266f82b6c5 Fixes issue with returning all versions, adds more tests/assertions, updates content and media repository to double check that the versions match before returning from cache. 2017-02-24 13:23:27 +11:00
Shannon 813a8956d3 Gets EntityRepository to deal with corrupted newest/published flags, adds tests and lots of assertions for each method 2017-02-24 12:27:36 +11:00
Shannon Deminick 0a8fa2be4d Merge pull request #1761 from abjerner/patch-16
Added support for ignoring HTTP errors directly from the Angular $http options
2017-02-23 15:50:22 +11:00
Anders Bjerner 6e347dd32c Added some extra validation 2017-02-22 17:28:40 +01:00
Sebastiaan Janssen 33c9e2b58d Merge pull request #1767 from umbraco/temp-u4-9560
U4-9560 - fix db issue
2017-02-22 16:27:20 +01:00
Stephan 16f8f6036c U4-9560 - fix db issue 2017-02-22 15:52:02 +01:00
Sebastiaan Janssen 76b696e3bf U4-9559 Security: files of type xhtml should not be allowed to be uploaded to the media section 2017-02-22 11:12:24 +01:00
Shannon 7cadbb6398 Backports some required EntityRepository changes, starts adding the custom collection to remove duplicate (throw err currently) 2017-02-22 21:09:25 +11:00
Emil Wangaa bf22399aba Fixup linendings for EntityRepository 2017-02-22 10:34:46 +01:00
Sebastiaan Janssen 0b9a3ef68a Bump version 2017-02-22 10:26:37 +01:00
Shannon f8d6c7e7d0 Fixes expression tree changes 2017-02-22 18:34:55 +11:00
Shannon 90ba9a1a3a Adds new overload to IMediaService.GetPagedChildren to filter on media type ids which turns out to be much easier than filtering on media type aliases, however i did all of the work to make that happen including unit tests and then it turned out to not be required but we now have the code if necessary, i've left comments about it. I've backported some updates from 7.6 for the SqlIn stuff for the ExpressionVisitor which we still use in the media type id filtering. I updated the JS to query for the folders which all works now. 2017-02-22 17:22:22 +11:00
Shannon 6815731da1 adds failing test that i'll need to fix 2017-02-22 13:31:04 +11:00
Sebastiaan Janssen 52dce66598 Bump version 2017-02-21 08:49:34 +01:00
Shannon 255fec84bd Merge branch 'refs/heads/dev-v7' into temp-U4-9536 2017-02-21 17:56:39 +11:00
Shannon 9142314d39 U4-9522 Media recycle bin does not show folders 2017-02-21 14:18:49 +11:00
Shannon 27164093ea FIxes: U4-9547, Fixes: U4-9546 even though GetChildFolders isn't used anymore i made it work slightly faster 2017-02-20 18:08:55 +11:00
Shannon 67312d03d0 Fixes media query in EntityRepository, it doesn't require outer joins to get the published version, this also enhances the content query to do an inner join on cmsDocument to get the newest instead of an outer join. 2017-02-20 17:24:10 +11:00
Anders Bjerner ad9ae867c0 Added support for ignoring HTTP errors directly from the Angular $http options 2017-02-16 19:22:26 +01:00
Shannon af287c387e Adds test to show that the content repo can deal with corrupted data, this fix actually simplifies a bunch of logic too and should consume slightly less memory, have added some TODOs in the code and need to then write more tests and code to deal with this in the EntityRepository. 2017-02-16 18:54:44 +11:00
Sebastiaan Janssen acf10eeef0 U4-9532 logic in ContentRepository.ClearPublished is inefficient - cherry picked from 7.6.0 2017-02-16 08:11:35 +01:00
103 changed files with 2401 additions and 1124 deletions
-1
View File
@@ -37,7 +37,6 @@
<dependency id="ImageProcessor" version="[2.5.2, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.8.2, 5.0.0)" />
<dependency id="semver" version="[2.0.4, 3.0.0)" />
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.6.0, 5.0.0)" />
@@ -41,16 +41,6 @@
views/dashboard/developer/examinemanagement.html
</control>
</tab>
<tab caption="Health Check" xdt:Transform="InsertIfMissing" xdt:Locator="Match(caption)">
<control>
views/dashboard/developer/healthcheck.html
</control>
</tab>
<tab caption="Redirect URL Management" xdt:Transform="InsertIfMissing" xdt:Locator="Match(caption)">
<control>
views/dashboard/developer/redirecturls.html
</control>
</tab>
</section>
<section alias="StartupMediaDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
@@ -80,4 +70,26 @@
<tab caption="Change Password" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
<tab caption="Last Edits" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
</section>
<section alias="RedirectUrlManagement" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<areas>
<area>content</area>
</areas>
<tab caption="Redirect URL Management">
<control>
views/dashboard/developer/redirecturls.html
</control>
</tab>
</section>
<section alias="UmbracoHealthCheck" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing">
<areas>
<area>developer</area>
</areas>
<tab caption="Health Check">
<control>
views/dashboard/developer/healthcheck.html
</control>
</tab>
</section>
</dashBoard>
-1
View File
@@ -53,7 +53,6 @@ if ($project) {
if(Test-Path $umbracoBinFolder\umbraco.providers.dll) { Remove-Item $umbracoBinFolder\umbraco.providers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\UmbracoExamine.dll) { Remove-Item $umbracoBinFolder\UmbracoExamine.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll) { Remove-Item $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll -Force -Confirm:$false }
# Delete files Umbraco depends upon
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
+1 -1
View File
@@ -1,3 +1,3 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.6.0
alpha074
alpha075
+1 -1
View File
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.6.0")]
[assembly: AssemblyInformationalVersion("7.6.0-alpha074")]
[assembly: AssemblyInformationalVersion("7.6.0-alpha075")]
@@ -0,0 +1,9 @@
namespace Umbraco.Core.Configuration
{
internal enum ContentXmlStorage
{
Default,
AspNetTemp,
EnvironmentTemp
}
}
@@ -517,12 +517,25 @@ namespace Umbraco.Core.Configuration
}
internal static bool ContentCacheXmlStoredInCodeGen
{
get { return ContentCacheXmlStorageLocation == ContentXmlStorage.AspNetTemp; }
}
internal static ContentXmlStorage ContentCacheXmlStorageLocation
{
get
{
//defaults to false
return ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLUseLocalTemp")
&& bool.Parse(ConfigurationManager.AppSettings["umbracoContentXMLUseLocalTemp"]); //default to false
if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLStorage"))
{
return Enum<ContentXmlStorage>.Parse(ConfigurationManager.AppSettings["umbracoContentXMLStorage"]);
}
if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLUseLocalTemp"))
{
return bool.Parse(ConfigurationManager.AppSettings["umbracoContentXMLUseLocalTemp"])
? ContentXmlStorage.AspNetTemp
: ContentXmlStorage.Default;
}
return ContentXmlStorage.Default;
}
}
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return "alpha074"; } }
public static string CurrentComment { get { return "alpha075"; } }
// 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
@@ -289,11 +289,14 @@ namespace Umbraco.Core
/// </summary>
[Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")]
public const string RelatedLinks = "71B8AD1A-8DC2-425C-B6B8-FAA158075E63";
[Obsolete("This is an obsoleted picker, use RelatedLinks2Alias instead")]
public const string RelatedLinksAlias = "Umbraco.RelatedLinks";
/// <summary>
/// Alias for the Related Links datatype.
/// Alias for the Related Links property editor.
/// </summary>
public const string RelatedLinksAlias = "Umbraco.RelatedLinks";
public const string RelatedLinks2Alias = "Umbraco.RelatedLinks2";
/// <summary>
/// Guid for the Slider datatype.
+2
View File
@@ -1,10 +1,12 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
{
/// <summary>
/// Represents a guid-based entity identifier.
/// </summary>
[TypeConverter(typeof(UdiTypeConverter))]
public class GuidUdi : Udi
{
/// <summary>
+18 -4
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.IO;
using System.Linq;
@@ -72,15 +73,28 @@ namespace Umbraco.Core.IO
{
get
{
if (GlobalSettings.ContentCacheXmlStoredInCodeGen && SystemUtilities.GetCurrentTrustLevel() == AspNetHostingPermissionLevel.Unrestricted)
{
return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config");
switch (GlobalSettings.ContentCacheXmlStorageLocation)
{
case ContentXmlStorage.AspNetTemp:
return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config");
case ContentXmlStorage.EnvironmentTemp:
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoXml",
//include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path
appDomainHash);
return Path.Combine(cachePath, "umbraco.config");
case ContentXmlStorage.Default:
return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config");
default:
throw new ArgumentOutOfRangeException();
}
return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config");
}
}
[Obsolete("Use GlobalSettings.ContentCacheXmlStoredInCodeGen instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
internal static bool ContentCacheXmlStoredInCodeGen
{
get { return GlobalSettings.ContentCacheXmlStoredInCodeGen; }
+27 -4
View File
@@ -2,6 +2,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Web;
using log4net;
@@ -62,12 +63,34 @@ namespace Umbraco.Core.Logging
public void Error(Type callingType, string message, Exception exception)
{
var logger = LogManager.GetLogger(callingType);
if (logger != null)
logger.Error((message), exception);
var logger = LogManager.GetLogger(callingType);
if (logger == null) return;
if (IsTimeoutThreadAbortException(exception))
{
message += "\r\nThe thread has been aborted, because the request has timed out.";
}
logger.Error(message, exception);
}
public void Warn(Type callingType, string message, params Func<object>[] formatItems)
private static bool IsTimeoutThreadAbortException(Exception exception)
{
var abort = exception as ThreadAbortException;
if (abort == null) return false;
if (abort.ExceptionState == null) return false;
var stateType = abort.ExceptionState.GetType();
if (stateType.FullName != "System.Web.HttpApplication+CancelModuleException") return false;
var timeoutField = stateType.GetField("_timeout", BindingFlags.Instance | BindingFlags.NonPublic);
if (timeoutField == null) return false;
return (bool) timeoutField.GetValue(abort.ExceptionState);
}
public void Warn(Type callingType, string message, params Func<object>[] formatItems)
{
var logger = LogManager.GetLogger(callingType);
if (logger == null || logger.IsWarnEnabled == false) return;
@@ -69,6 +69,7 @@ namespace Umbraco.Core.Models
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
//TODO: Instead of 'new' this should explicitly implement one of the collection interfaces members
internal new void Add(PropertyType item)
{
using (new WriteLock(_addLocker))
@@ -110,6 +110,12 @@ namespace Umbraco.Core.Models
_ruleCollection.Clear();
}
internal void ClearRemovedRules()
{
_removedRules.Clear();
}
[DataMember]
public int LoginNodeId
{
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Models.Rdbms
internal class DataTypeDto
{
[Column("pk")]
[PrimaryKeyColumn(IdentitySeed = 30)]
[PrimaryKeyColumn(IdentitySeed = 40)]
public int PrimaryKey { get; set; }
[Column("nodeId")]
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Models.Rdbms
[ExplicitColumns]
internal class NodeDto
{
public const int NodeIdSeed = 1050;
public const int NodeIdSeed = 1060;
[Column("id")]
[PrimaryKeyColumn(Name = "PK_structure", IdentitySeed = NodeIdSeed)]
@@ -28,17 +28,17 @@ namespace Umbraco.Core.Persistence.Factories
#region Implementation of IEntityFactory<IMedia,ContentVersionDto>
public IMember BuildEntity(MemberDto dto)
public static IMember BuildEntity(MemberDto dto, IMemberType contentType)
{
var member = new Member(
dto.ContentVersionDto.ContentDto.NodeDto.Text,
dto.Email, dto.LoginName, dto.Password, _contentType);
dto.Email, dto.LoginName, dto.Password, contentType);
try
{
member.DisableChangeTracking();
member.Id = _id;
member.Id = dto.NodeId;
member.Key = dto.ContentVersionDto.ContentDto.NodeDto.UniqueId;
member.Path = dto.ContentVersionDto.ContentDto.NodeDto.Path;
member.CreatorId = dto.ContentVersionDto.ContentDto.NodeDto.UserId.Value;
@@ -62,6 +62,12 @@ namespace Umbraco.Core.Persistence.Factories
}
}
[Obsolete("Use the static BuildEntity instead so we don't have to allocate one of these objects everytime we want to map values")]
public IMember BuildEntity(MemberDto dto)
{
return BuildEntity(dto, _contentType);
}
public MemberDto BuildDto(IMember entity)
{
var dto = new MemberDto
@@ -6,6 +6,7 @@ using System.Reflection;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Persistence.Factories
{
@@ -17,7 +18,7 @@ namespace Umbraco.Core.Persistence.Factories
//figure out what extra properties we have that are not on the IUmbracoEntity and add them to additional data
foreach (var k in originalEntityProperties.Keys
.Select(x => new { orig = x, title = x.ConvertCase(StringAliasCaseType.PascalCase) })
.Select(x => new { orig = x, title = x.ToCleanString(CleanStringType.PascalCase | CleanStringType.Ascii | CleanStringType.ConvertCase) })
.Where(x => entityProps.InvariantContains(x.title) == false))
{
entity.AdditionalData[k.title] = originalEntityProperties[k.orig];
@@ -75,65 +76,6 @@ namespace Umbraco.Core.Persistence.Factories
entity.EnableChangeTracking();
}
}
public UmbracoEntity BuildEntity(EntityRepository.UmbracoEntityDto dto)
{
var entity = new UmbracoEntity(dto.Trashed)
{
CreateDate = dto.CreateDate,
CreatorId = dto.UserId.Value,
Id = dto.NodeId,
Key = dto.UniqueId,
Level = dto.Level,
Name = dto.Text,
NodeObjectTypeId = dto.NodeObjectType.Value,
ParentId = dto.ParentId,
Path = dto.Path,
SortOrder = dto.SortOrder,
HasChildren = dto.Children > 0,
ContentTypeAlias = dto.Alias ?? string.Empty,
ContentTypeIcon = dto.Icon ?? string.Empty,
ContentTypeThumbnail = dto.Thumbnail ?? string.Empty,
};
entity.IsPublished = dto.PublishedVersion != default(Guid) || (dto.NewestVersion != default(Guid) && dto.PublishedVersion == dto.NewestVersion);
entity.IsDraft = dto.NewestVersion != default(Guid) && (dto.PublishedVersion == default(Guid) || dto.PublishedVersion != dto.NewestVersion);
entity.HasPendingChanges = (dto.PublishedVersion != default(Guid) && dto.NewestVersion != default(Guid)) && dto.PublishedVersion != dto.NewestVersion;
if (dto.UmbracoPropertyDtos != null)
{
foreach (var propertyDto in dto.UmbracoPropertyDtos)
{
entity.AdditionalData[propertyDto.PropertyAlias] = new UmbracoEntity.EntityProperty
{
PropertyEditorAlias = propertyDto.PropertyEditorAlias,
Value = propertyDto.NTextValue.IsNullOrWhiteSpace()
? propertyDto.NVarcharValue
: propertyDto.NTextValue.ConvertToJsonIfPossible()
};
}
}
return entity;
}
public EntityRepository.UmbracoEntityDto BuildDto(UmbracoEntity entity)
{
var node = new EntityRepository.UmbracoEntityDto
{
CreateDate = entity.CreateDate,
Level = short.Parse(entity.Level.ToString(CultureInfo.InvariantCulture)),
NodeId = entity.Id,
NodeObjectType = entity.NodeObjectTypeId,
ParentId = entity.ParentId,
Path = entity.Path,
SortOrder = entity.SortOrder,
Text = entity.Name,
Trashed = entity.Trashed,
UniqueId = entity.Key,
UserId = entity.CreatorId
};
return node;
}
}
}
@@ -31,7 +31,7 @@ namespace Umbraco.Core.Persistence.Mappers
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
internal BaseMapper ResolveMapperByType(Type type)
public virtual BaseMapper ResolveMapperByType(Type type)
{
return _mapperCache.GetOrAdd(type, type1 =>
{
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Persistence.Mappers
return Attempt<BaseMapper>.Succeed(mapper);
}
internal string GetMapping(Type type, string propertyName)
public virtual string GetMapping(Type type, string propertyName)
{
var mapper = ResolveMapperByType(type);
var result = mapper.Map(propertyName);
@@ -130,8 +130,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultMembersListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-97", SortOrder = 2, UniqueId = new Guid("AA2C52A0-CE87-4E65-A47C-7DF09358585D"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Members", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1031, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1031", SortOrder = 2, UniqueId = new Guid("f38bd2d7-65d0-48e6-95dc-87ce06ec2d3d"), Text = Constants.Conventions.MediaTypes.Folder, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1032, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1032", SortOrder = 2, UniqueId = new Guid("cc07b313-0843-4aa8-bbda-871c8da728c8"), Text = Constants.Conventions.MediaTypes.Image, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1040, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1040", SortOrder = 2, UniqueId = new Guid("21e798da-e06e-4eda-a511-ed257f78d4fa"), Text = "Related Links", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1033, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1033", SortOrder = 2, UniqueId = new Guid("4c52d8ab-54e6-40cd-999c-7a5f24903e4d"), Text = Constants.Conventions.MediaTypes.File, NodeObjectType = new Guid(Constants.ObjectTypes.MediaType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1041, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1041", SortOrder = 2, UniqueId = new Guid("b6b73142-b9c1-4bf8-a16d-e1c23320b549"), Text = "Tags", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1043, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1043", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = new Guid(Constants.ObjectTypes.MemberType), CreateDate = DateTime.Now });
@@ -141,6 +140,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Related Links", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
//TODO: We're not creating these for 7.0
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1039, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1039", SortOrder = 2, UniqueId = new Guid("06f349a9-c949-4b6a-8660-59c10451af42"), Text = "Ultimate Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
@@ -246,8 +246,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 12, DataTypeId = -40, PropertyEditorAlias = Constants.PropertyEditors.RadioButtonListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 13, DataTypeId = -41, PropertyEditorAlias = Constants.PropertyEditors.DateAlias, DbType = "Date" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 14, DataTypeId = -42, PropertyEditorAlias = Constants.PropertyEditors.DropDownListAlias, DbType = "Integer" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 21, DataTypeId = 1040, PropertyEditorAlias = Constants.PropertyEditors.RelatedLinksAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 22, DataTypeId = 1041, PropertyEditorAlias = Constants.PropertyEditors.TagsAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 24, DataTypeId = 1043, PropertyEditorAlias = Constants.PropertyEditors.ImageCropperAlias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -26, DataTypeId = Constants.System.DefaultContentListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
@@ -259,6 +258,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 27, DataTypeId = 1047, PropertyEditorAlias = Constants.PropertyEditors.MemberPicker2Alias, DbType = "Nvarchar" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 28, DataTypeId = 1048, PropertyEditorAlias = Constants.PropertyEditors.MediaPicker2Alias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 29, DataTypeId = 1049, PropertyEditorAlias = Constants.PropertyEditors.MediaPicker2Alias, DbType = "Ntext" });
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 30, DataTypeId = 1050, PropertyEditorAlias = Constants.PropertyEditors.RelatedLinks2Alias, DbType = "Ntext" });
//TODO: We're not creating these for 7.0
//_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 19, DataTypeId = 1038, PropertyEditorAlias = Constants.PropertyEditors.MarkdownEditorAlias, DbType = "Ntext" });
@@ -546,7 +546,7 @@ namespace Umbraco.Core.Persistence.Querying
&& methodArgs.Length == 1
&& methodArgs[0].NodeType == ExpressionType.MemberAccess
&& TypeHelper.IsTypeAssignableFrom<IEnumerable>(m.Arguments[0].Type))
{
{
goto case "SqlIn";
}
@@ -1,5 +1,6 @@
using System;
using System.Linq.Expressions;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.SqlSyntax;
@@ -12,17 +13,19 @@ namespace Umbraco.Core.Persistence.Querying
/// <remarks>This object is stateful and cannot be re-used to parse an expression.</remarks>
internal class ModelToSqlExpressionVisitor<T> : ExpressionVisitorBase
{
private readonly MappingResolver _mappingResolver;
private readonly BaseMapper _mapper;
public ModelToSqlExpressionVisitor(ISqlSyntaxProvider sqlSyntax, BaseMapper mapper)
public ModelToSqlExpressionVisitor(ISqlSyntaxProvider sqlSyntax, MappingResolver mappingResolver)
: base(sqlSyntax)
{
_mapper = mapper;
_mapper = mappingResolver.ResolveMapperByType(typeof(T));
_mappingResolver = mappingResolver;
}
[Obsolete("Use the overload the specifies a SqlSyntaxProvider")]
public ModelToSqlExpressionVisitor()
: this(SqlSyntaxContext.SqlSyntaxProvider, MappingResolver.Current.ResolveMapperByType(typeof(T)))
: this(SqlSyntaxContext.SqlSyntaxProvider, MappingResolver.Current)
{ }
protected override string VisitMemberAccess(MemberExpression m)
@@ -36,7 +39,7 @@ namespace Umbraco.Core.Persistence.Querying
{
var field = _mapper.Map(m.Member.Name, true);
if (field.IsNullOrWhiteSpace())
throw new InvalidOperationException("The mapper returned an empty field for the member name: " + m.Member.Name);
throw new InvalidOperationException(string.Format("The mapper returned an empty field for the member name: {0} for type: {1}", m.Member.Name, m.Expression.Type));
return field;
}
//already compiled, return
@@ -50,13 +53,42 @@ namespace Umbraco.Core.Persistence.Querying
{
var field = _mapper.Map(m.Member.Name, true);
if (field.IsNullOrWhiteSpace())
throw new InvalidOperationException("The mapper returned an empty field for the member name: " + m.Member.Name);
throw new InvalidOperationException(string.Format("The mapper returned an empty field for the member name: {0} for type: {1}", m.Member.Name, m.Expression.Type));
return field;
}
//already compiled, return
return string.Empty;
}
if (m.Expression != null
&& m.Expression.Type != typeof(T)
&& TypeHelper.IsTypeAssignableFrom<IUmbracoEntity>(m.Expression.Type)
&& EndsWithConstant(m) == false)
{
//if this is the case, it means we have a sub expression / nested property access, such as: x.ContentType.Alias == "Test";
//and since the sub type (x.ContentType) is not the same as x, we need to resolve a mapper for x.ContentType to get it's mapped SQL column
//don't execute if compiled
if (Visited == false)
{
var subMapper = _mappingResolver.ResolveMapperByType(m.Expression.Type);
if (subMapper == null)
throw new NullReferenceException("No mapper found for type " + m.Expression.Type);
var field = subMapper.Map(m.Member.Name, true);
if (field.IsNullOrWhiteSpace())
throw new InvalidOperationException(string.Format("The mapper returned an empty field for the member name: {0} for type: {1}", m.Member.Name, m.Expression.Type));
return field;
}
//already compiled, return
return string.Empty;
}
//TODO: When m.Expression.NodeType == ExpressionType.Constant and it's an expression like: content => aliases.Contains(content.ContentType.Alias);
// then an SQL parameter will be added for aliases as an array, however in SqlIn on the subclass it will manually add these SqlParameters anyways,
// however the query will still execute because the SQL that is written will only contain the correct indexes of SQL parameters, this would be ignored,
// I'm just unsure right now due to time constraints how to make it correct. It won't matter right now and has been working already with this bug but I've
// only just discovered what it is actually doing.
var member = Expression.Convert(m, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();
@@ -71,5 +103,24 @@ namespace Umbraco.Core.Persistence.Querying
return string.Empty;
}
/// <summary>
/// Determines if the MemberExpression ends in a Constant value
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
private bool EndsWithConstant(MemberExpression m)
{
Expression expr = m;
while (expr is MemberExpression)
{
var memberExpr = expr as MemberExpression;
expr = memberExpr.Expression;
}
var constExpr = expr as ConstantExpression;
return constExpr != null;
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
@@ -64,7 +64,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateContentFromDto(dto, dto.ContentVersionDto.VersionId, sql);
var content = CreateContentFromDto(dto, sql);
return content;
}
@@ -134,6 +134,9 @@ namespace Umbraco.Core.Persistence.Repositories
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
//TODO: IF we want to enable querying on content type information this will need to be joined
//.InnerJoin<ContentTypeDto>(SqlSyntax)
//.On<ContentDto, ContentTypeDto>(SqlSyntax, left => left.ContentTypeId, right => right.NodeId, SqlSyntax);
if (queryType == BaseQueryType.FullSingle)
{
@@ -260,6 +263,39 @@ namespace Umbraco.Core.Persistence.Repositories
}
baseId = xmlItems[xmlItems.Count - 1].NodeId;
}
//now delete the items that shouldn't be there
var sqlAllIds = translate(0, GetBaseQuery(BaseQueryType.Ids));
var allContentIds = Database.Fetch<int>(sqlAllIds);
var docObjectType = Guid.Parse(Constants.ObjectTypes.Document);
var xmlIdsQuery = new Sql()
.Select("DISTINCT cmsContentXml.nodeId")
.From<ContentXmlDto>(SqlSyntax)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentXmlDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
if (contentTypeIdsA.Length > 0)
{
xmlIdsQuery.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentTypeDto>(SqlSyntax)
.On<ContentTypeDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.ContentTypeId)
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
}
xmlIdsQuery.Where<NodeDto>(dto => dto.NodeObjectType == docObjectType, SqlSyntax);
var allXmlIds = Database.Fetch<int>(xmlIdsQuery);
var toRemove = allXmlIds.Except(allContentIds).ToArray();
if (toRemove.Length > 0)
{
foreach (var idGroup in toRemove.InGroupsOf(2000))
{
Database.Execute("DELETE FROM cmsContentXml WHERE nodeId IN (@ids)", new { ids = idGroup });
}
}
}
public override IEnumerable<IContent> GetAllVersions(int id)
@@ -273,12 +309,13 @@ namespace Umbraco.Core.Persistence.Repositories
var sqlFull = translate(GetBaseQuery(BaseQueryType.FullMultiple));
var sqlIds = translate(GetBaseQuery(BaseQueryType.Ids));
return ProcessQuery(sqlFull, new PagingSqlQuery(sqlIds), true);
return ProcessQuery(sqlFull, new PagingSqlQuery(sqlIds), true, includeAllVersions:true);
}
public override IContent GetByVersion(Guid versionId)
{
var sql = GetBaseQuery(BaseQueryType.FullSingle);
//TODO: cmsContentVersion.VersionId has a Unique Index constraint applied, seems silly then to also add OrderByDescending since it would be impossible to return more than one.
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
@@ -287,7 +324,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateContentFromDto(dto, versionId, sql);
var content = CreateContentFromDto(dto, sql);
return content;
}
@@ -297,7 +334,8 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = new Sql()
.Select("*")
.From<DocumentDto>(SqlSyntax)
.InnerJoin<ContentVersionDto>(SqlSyntax).On<ContentVersionDto, DocumentDto>(SqlSyntax, left => left.VersionId, right => right.VersionId)
.InnerJoin<ContentVersionDto>(SqlSyntax)
.On<ContentVersionDto, DocumentDto>(SqlSyntax, left => left.VersionId, right => right.VersionId)
.Where<ContentVersionDto>(x => x.VersionId == versionId, SqlSyntax)
.Where<DocumentDto>(x => x.Newest != true, SqlSyntax);
var dto = Database.Fetch<DocumentDto, ContentVersionDto>(sql).FirstOrDefault();
@@ -317,7 +355,8 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = new Sql()
.Select("*")
.From<DocumentDto>()
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, DocumentDto>(left => left.VersionId, right => right.VersionId)
.InnerJoin<ContentVersionDto>()
.On<ContentVersionDto, DocumentDto>(left => left.VersionId, right => right.VersionId)
.Where<ContentVersionDto>(x => x.NodeId == id)
.Where<ContentVersionDto>(x => x.VersionDate < versionDate)
.Where<DocumentDto>(x => x.Newest != true);
@@ -558,6 +597,7 @@ namespace Umbraco.Core.Persistence.Repositories
//if (((ICanBeDirty)entity).IsPropertyDirty("Published") && (entity.Published || publishedState == PublishedState.Unpublished))
if (entity.ShouldClearPublishedFlagForPreviousVersions(publishedState, shouldCreateNewVersion))
{
//TODO: This perf can be improved, it could easily be UPDATE WHERE.... (one SQL call instead of many)
var publishedDocs = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND published = @IsPublished", new { Id = entity.Id, IsPublished = true });
foreach (var doc in publishedDocs)
{
@@ -571,6 +611,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
//Look up (newest) entries by id in cmsDocument table to set newest = false
//TODO: This perf can be improved, it could easily be UPDATE WHERE.... (one SQL call instead of many)
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true });
foreach (var documentDto in documentDtos)
{
@@ -898,7 +939,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
return base.GetDatabaseFieldNameForOrderBy(orderBy);
}
/// <summary>
/// This is the underlying method that processes most queries for this repository
/// </summary>
@@ -909,8 +950,12 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
/// The Id SQL without the outer join to just return all document ids - used to process the properties for the content item
/// </param>
/// <param name="withCache"></param>
/// <param name="includeAllVersions">
/// Generally when querying for content we only want to return the most recent version of the content item, however in some cases like when
/// we want to return all versions of a content item, we can't simply return the latest
/// </param>
/// <returns></returns>
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false)
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, PagingSqlQuery pagingSqlQuery, bool withCache = false, bool includeAllVersions = false)
{
// fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sqlFull);
@@ -929,13 +974,12 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.LastIndexOf("ORDER BY ", StringComparison.Ordinal));
}
var publishedSql = new Sql(@"SELECT *
FROM cmsDocument AS doc2
INNER JOIN
(" + parsedOriginalSql + @") as docData
ON doc2.nodeId = docData.nodeId
WHERE doc2.published = 1
ORDER BY doc2.nodeId
//order by update date DESC, if there is corrupted published flags we only want the latest!
var publishedSql = new Sql(@"SELECT cmsDocument.nodeId, cmsDocument.published, cmsDocument.versionId, cmsDocument.newest
FROM cmsDocument INNER JOIN cmsContentVersion ON cmsContentVersion.VersionId = cmsDocument.versionId
WHERE cmsDocument.published = 1 AND cmsDocument.nodeId IN
(" + parsedOriginalSql + @")
ORDER BY cmsContentVersion.id DESC
", sqlFull.Arguments);
//go and get the published version data, we do a Query here and not a Fetch so we are
@@ -950,9 +994,9 @@ ORDER BY doc2.nodeId
publishedDataCollection.Add(publishedDto);
}
var content = new IContent[dtos.Count];
var defs = new List<DocumentDefinition>();
//This is a tuple list identifying if the content item came from the cache or not
var content = new List<Tuple<IContent, bool>>();
var defs = new DocumentDefinitionCollection(includeAllVersions);
var templateIds = new List<int>();
//track the looked up content types, even though the content types are cached
@@ -960,9 +1004,8 @@ ORDER BY doc2.nodeId
// the overhead of deep cloning them on every item in this loop
var contentTypes = new Dictionary<int, IContentType>();
for (var i = 0; i < dtos.Count; i++)
foreach (var dto in dtos)
{
var dto = dtos[i];
DocumentPublishedReadOnlyDto publishedDto;
publishedDataCollection.TryGetValue(dto.NodeId, out publishedDto);
@@ -970,10 +1013,10 @@ ORDER BY doc2.nodeId
if (withCache)
{
var cached = IsolatedCache.GetCacheItem<IContent>(GetCacheIdKey<IContent>(dto.NodeId));
//only use this cached version if the dto returned is also the publish version, they must match
if (cached != null && cached.Published && dto.Published)
//only use this cached version if the dto returned is also the publish version, they must match and be teh same version
if (cached != null && cached.Version == dto.VersionId && cached.Published && dto.Published)
{
content[i] = cached;
content.Add(new Tuple<IContent, bool>(cached, true));
continue;
}
}
@@ -991,21 +1034,16 @@ ORDER BY doc2.nodeId
contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
contentTypes[dto.ContentVersionDto.ContentDto.ContentTypeId] = contentType;
}
content[i] = ContentFactory.BuildEntity(dto, contentType, publishedDto);
// need template
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
templateIds.Add(dto.TemplateId.Value);
// track the definition and if it's successfully added or updated then processed
if (defs.AddOrUpdate(new DocumentDefinition(dto, contentType)))
{
// assign template
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
templateIds.Add(dto.TemplateId.Value);
// need properties
defs.Add(new DocumentDefinition(
dto.NodeId,
dto.VersionId,
dto.ContentVersionDto.VersionDate,
dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
contentType
));
content.Add(new Tuple<IContent, bool>(ContentFactory.BuildEntity(dto, contentType, publishedDto), false));
}
}
// load all required templates in 1 query
@@ -1015,38 +1053,38 @@ ORDER BY doc2.nodeId
// load all properties for all documents from database in 1 query
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
// assign
var dtoIndex = 0;
foreach (var def in defs)
// assign template and property data
foreach (var contentItem in content)
{
// move to corresponding item (which has to exist)
while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
var cc = contentItem.Item1;
var fromCache = contentItem.Item2;
//if this has come from cache, we do not need to build up it's structure
if (fromCache) continue;
var def = defs[includeAllVersions ? (ValueType)cc.Version : cc.Id];
// complete the item
var cc = content[dtoIndex];
var dto = dtos[dtoIndex];
ITemplate template = null;
if (dto.TemplateId.HasValue)
templates.TryGetValue(dto.TemplateId.Value, out template); // else null
if (def.DocumentDto.TemplateId.HasValue)
templates.TryGetValue(def.DocumentDto.TemplateId.Value, out template); // else null
cc.Template = template;
cc.Properties = propertyData[cc.Id];
cc.Properties = propertyData[cc.Version];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
cc.ResetDirtyProperties(false);
}
return content;
return content.Select(x => x.Item1).ToArray();
}
/// <summary>
/// Private method to create a content object from a DocumentDto, which is used by Get and GetByVersion.
/// </summary>
/// <param name="dto"></param>
/// <param name="versionId"></param>
/// <param name="docSql"></param>
/// <returns></returns>
private IContent CreateContentFromDto(DocumentDto dto, Guid versionId, Sql docSql)
private IContent CreateContentFromDto(DocumentDto dto, Sql docSql)
{
var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
@@ -1058,11 +1096,11 @@ ORDER BY doc2.nodeId
content.Template = _templateRepository.Get(dto.TemplateId.Value);
}
var docDef = new DocumentDefinition(dto.NodeId, versionId, content.UpdateDate, content.CreateDate, contentType);
var docDef = new DocumentDefinition(dto, contentType);
var properties = GetPropertyCollection(docSql, new[] { docDef });
content.Properties = properties[dto.NodeId];
content.Properties = properties[dto.VersionId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
@@ -104,7 +104,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (objectTypes.Any())
{
sql = sql.Where("umbracoNode.nodeObjectType IN (@objectTypes)", objectTypes);
sql = sql.Where("umbracoNode.nodeObjectType IN (@objectTypes)", new {objectTypes = objectTypes});
}
return Database.Fetch<string>(sql);
@@ -1,19 +1,14 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using Umbraco.Core.Models;
using Umbraco.Core;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Strings;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -187,10 +182,12 @@ namespace Umbraco.Core.Persistence.Repositories
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
var sql = GetFullSqlForEntityType(key, isContent, isMedia, objectTypeId);
var factory = new UmbracoEntityFactory();
if (isMedia)
{
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
//for now treat media differently and include all property data too
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
@@ -198,14 +195,16 @@ namespace Umbraco.Core.Persistence.Repositories
}
else
{
var nodeDto = _work.Database.FirstOrDefault<dynamic>(sql);
if (nodeDto == null)
return null;
var factory = new UmbracoEntityFactory();
var entity = factory.BuildEntityFromDynamic(nodeDto);
return entity;
//query = read forward data reader, do not load everything into mem
var dtos = _work.Database.Query<dynamic>(sql);
var collection = new EntityDefinitionCollection();
foreach (var dto in dtos)
{
collection.AddOrUpdate(new EntityDefinition(factory, dto, isContent, false));
}
var found = collection.FirstOrDefault();
return found != null ? found.BuildFromDynamic() : null;
}
@@ -230,28 +229,29 @@ namespace Umbraco.Core.Persistence.Repositories
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
var sql = GetFullSqlForEntityType(id, isContent, isMedia, objectTypeId);
var factory = new UmbracoEntityFactory();
if (isMedia)
{
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
//for now treat media differently and include all property data too
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
return entities.FirstOrDefault();
}
else
{
var nodeDto = _work.Database.FirstOrDefault<dynamic>(sql);
if (nodeDto == null)
return null;
var factory = new UmbracoEntityFactory();
var entity = factory.BuildEntityFromDynamic(nodeDto);
return entity;
{
//query = read forward data reader, do not load everything into mem
var dtos = _work.Database.Query<dynamic>(sql);
var collection = new EntityDefinitionCollection();
foreach (var dto in dtos)
{
collection.AddOrUpdate(new EntityDefinition(factory, dto, isContent, false));
}
var found = collection.FirstOrDefault();
return found != null ? found.BuildFromDynamic() : null;
}
}
public virtual IEnumerable<IUmbracoEntity> GetAll(Guid objectTypeId, params int[] ids)
@@ -288,21 +288,21 @@ namespace Umbraco.Core.Persistence.Repositories
if (isMedia)
{
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
//for now treat media differently and include all property data too
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, sql);
foreach (var entity in entities)
{
yield return entity;
}
return entities;
}
else
{
var dtos = _work.Database.Fetch<dynamic>(sql);
foreach (var entity in dtos.Select(dto => factory.BuildEntityFromDynamic(dto)))
//query = read forward data reader, do not load everything into mem
var dtos = _work.Database.Query<dynamic>(sql);
var collection = new EntityDefinitionCollection();
foreach (var dto in dtos)
{
yield return entity;
collection.AddOrUpdate(new EntityDefinition(factory, dto, isContent, false));
}
return collection.Select(x => x.BuildFromDynamic()).ToList();
}
}
@@ -347,7 +347,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
});
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
//for now treat media differently and include all property data too
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
new UmbracoEntityRelator().Map, mediaSql);
return entities;
@@ -356,8 +356,15 @@ namespace Umbraco.Core.Persistence.Repositories
{
//use dynamic so that we can get ALL properties from the SQL so we can chuck that data into our AdditionalData
var finalSql = entitySql.Append(GetGroupBy(isContent, false));
var dtos = _work.Database.Fetch<dynamic>(finalSql);
return dtos.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
//query = read forward data reader, do not load everything into mem
var dtos = _work.Database.Query<dynamic>(finalSql);
var collection = new EntityDefinitionCollection();
foreach (var dto in dtos)
{
collection.AddOrUpdate(new EntityDefinition(factory, dto, isContent, false));
}
return collection.Select(x => x.BuildFromDynamic()).ToList();
}
}
@@ -468,9 +475,10 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (isContent)
{
//only content has this info
//only content has/needs this info
columns.Add("published.versionId as publishedVersion");
columns.Add("document.versionId as newestVersion");
columns.Add("contentversion.id as versionId");
}
columns.Add("contenttype.alias");
@@ -485,21 +493,22 @@ namespace Umbraco.Core.Persistence.Repositories
var entitySql = new Sql()
.Select(columns.ToArray())
.From("umbracoNode umbracoNode");
if (isContent || isMedia)
{
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id");
if (isContent)
{
//only content has this info
entitySql
//only content has/needs this info
entitySql
.InnerJoin("cmsDocument document").On("document.nodeId = umbracoNode.id")
.InnerJoin("cmsContentVersion contentversion").On("contentversion.VersionId = document.versionId")
.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1) as published")
.On("umbracoNode.id = published.nodeId");
}
entitySql.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType");
entitySql.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType");
}
if (isCount == false)
@@ -546,7 +555,7 @@ namespace Umbraco.Core.Persistence.Repositories
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, Guid key)
{
var sql = baseQuery(isContent, isMedia, null)
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key });
.Where("umbracoNode.uniqueID = @UniqueID", new {UniqueID = key});
if (isContent)
{
@@ -609,13 +618,14 @@ namespace Umbraco.Core.Persistence.Repositories
{
columns.Add("published.versionId");
columns.Add("document.versionId");
columns.Add("contentversion.id");
}
columns.Add("contenttype.alias");
columns.Add("contenttype.icon");
columns.Add("contenttype.thumbnail");
columns.Add("contenttype.isContainer");
columns.Add("contenttype.isContainer");
}
var sql = new Sql()
.GroupBy(columns.ToArray());
@@ -626,7 +636,7 @@ namespace Umbraco.Core.Persistence.Repositories
return sql;
}
#endregion
/// <summary>
@@ -652,33 +662,7 @@ namespace Umbraco.Core.Persistence.Repositories
return _work.Database.ExecuteScalar<int>(sql) > 0;
}
#region umbracoNode POCO - Extends NodeDto
[TableName("umbracoNode")]
[PrimaryKey("id")]
[ExplicitColumns]
internal class UmbracoEntityDto : NodeDto
{
[Column("children")]
public int Children { get; set; }
[Column("publishedVersion")]
public Guid PublishedVersion { get; set; }
[Column("newestVersion")]
public Guid NewestVersion { get; set; }
[Column("alias")]
public string Alias { get; set; }
[Column("icon")]
public string Icon { get; set; }
[Column("thumbnail")]
public string Thumbnail { get; set; }
[ResultColumn]
public List<UmbracoPropertyDto> UmbracoPropertyDtos { get; set; }
}
#region private classes
[ExplicitColumns]
internal class UmbracoPropertyDto
@@ -762,6 +746,99 @@ namespace Umbraco.Core.Persistence.Repositories
return prev;
}
}
private class EntityDefinitionCollection : KeyedCollection<int, EntityDefinition>
{
protected override int GetKeyForItem(EntityDefinition item)
{
return item.Id;
}
/// <summary>
/// if this key already exists if it does then we need to check
/// if the existing item is 'older' than the new item and if that is the case we'll replace the older one
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool AddOrUpdate(EntityDefinition item)
{
if (Dictionary == null)
{
base.Add(item);
return true;
}
var key = GetKeyForItem(item);
EntityDefinition found;
if (TryGetValue(key, out found))
{
//it already exists and it's older so we need to replace it
if (item.VersionId > found.VersionId)
{
var currIndex = Items.IndexOf(found);
if (currIndex == -1)
throw new IndexOutOfRangeException("Could not find the item in the list: " + found.Id);
//replace the current one with the newer one
SetItem(currIndex, item);
return true;
}
//could not add or update
return false;
}
base.Add(item);
return true;
}
private bool TryGetValue(int key, out EntityDefinition val)
{
if (Dictionary == null)
{
val = null;
return false;
}
return Dictionary.TryGetValue(key, out val);
}
}
private class EntityDefinition
{
private readonly UmbracoEntityFactory _factory;
private readonly dynamic _entity;
private readonly bool _isContent;
private readonly bool _isMedia;
public EntityDefinition(UmbracoEntityFactory factory, dynamic entity, bool isContent, bool isMedia)
{
_factory = factory;
_entity = entity;
_isContent = isContent;
_isMedia = isMedia;
}
public IUmbracoEntity BuildFromDynamic()
{
return _factory.BuildEntityFromDynamic(_entity);
}
public int Id
{
get { return _entity.id; }
}
public int VersionId
{
get
{
if (_isContent || _isMedia)
{
return _entity.versionId;
}
return _entity.id;
}
}
}
#endregion
}
}
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="serializer">The serializer to convert TEntity to Xml</param>
/// <param name="groupSize">Structures will be rebuilt in chunks of this size</param>
/// <param name="contentTypeIds"></param>
void RebuildXmlStructures(Func<TEntity, XElement> serializer, int groupSize = 5000, IEnumerable<int> contentTypeIds = null);
void RebuildXmlStructures(Func<TEntity, XElement> serializer, int groupSize = 200, IEnumerable<int> contentTypeIds = null);
/// <summary>
/// Get the total count of entities
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateMediaFromDto(dto, dto.VersionId, sql);
var content = CreateMediaFromDto(dto, sql);
return content;
}
@@ -94,6 +94,9 @@ namespace Umbraco.Core.Persistence.Repositories
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId, SqlSyntax)
//TODO: IF we want to enable querying on content type information this will need to be joined
//.InnerJoin<ContentTypeDto>(SqlSyntax)
//.On<ContentDto, ContentTypeDto>(SqlSyntax, left => left.ContentTypeId, right => right.NodeId, SqlSyntax);
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
return sql;
}
@@ -161,25 +164,27 @@ namespace Umbraco.Core.Persistence.Repositories
{
// fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sqlFull);
var content = new IMedia[dtos.Count];
var defs = new List<DocumentDefinition>();
//This is a tuple list identifying if the content item came from the cache or not
var content = new List<Tuple<IMedia, bool>>();
var defs = new DocumentDefinitionCollection();
//track the looked up content types, even though the content types are cached
// they still need to be deep cloned out of the cache and we don't want to add
// the overhead of deep cloning them on every item in this loop
var contentTypes = new Dictionary<int, IMediaType>();
for (var i = 0; i < dtos.Count; i++)
foreach (var dto in dtos)
{
var dto = dtos[i];
// if the cache contains the item, use it
if (withCache)
{
var cached = IsolatedCache.GetCacheItem<IMedia>(GetCacheIdKey<IMedia>(dto.NodeId));
if (cached != null)
//only use this cached version if the dto returned is the same version - this is just a safety check, media doesn't
//store different versions, but just in case someone corrupts some data we'll double check to be sure.
if (cached != null && cached.Version == dto.VersionId)
{
content[i] = cached;
content.Add(new Tuple<IMedia, bool>(cached, true));
continue;
}
}
@@ -197,39 +202,34 @@ namespace Umbraco.Core.Persistence.Repositories
contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
contentTypes[dto.ContentDto.ContentTypeId] = contentType;
}
content[i] = MediaFactory.BuildEntity(dto, contentType);
// need properties
defs.Add(new DocumentDefinition(
dto.NodeId,
dto.VersionId,
dto.VersionDate,
dto.ContentDto.NodeDto.CreateDate,
contentType
));
// track the definition and if it's successfully added or updated then processed
if (defs.AddOrUpdate(new DocumentDefinition(dto, contentType)))
{
content.Add(new Tuple<IMedia, bool>(MediaFactory.BuildEntity(dto, contentType), false));
}
}
// load all properties for all documents from database in 1 query
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
// assign
var dtoIndex = 0;
foreach (var def in defs)
// assign property data
foreach (var contentItem in content)
{
// move to corresponding item (which has to exist)
while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
var cc = contentItem.Item1;
var fromCache = contentItem.Item2;
// complete the item
var cc = content[dtoIndex];
cc.Properties = propertyData[cc.Id];
//if this has come from cache, we do not need to build up it's structure
if (fromCache) continue;
cc.Properties = propertyData[cc.Version];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
cc.ResetDirtyProperties(false);
}
return content;
return content.Select(x => x.Item1).ToArray();
}
public override IMedia GetByVersion(Guid versionId)
@@ -243,7 +243,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateMediaFromDto(dto, versionId, sql);
var content = CreateMediaFromDto(dto, sql);
return content;
}
@@ -263,10 +263,12 @@ namespace Umbraco.Core.Persistence.Repositories
// get the next group of nodes
var query = GetBaseQuery(false);
if (contentTypeIdsA.Length > 0)
query = query
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
{
query = query.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
}
query = query
.Where<NodeDto>(x => x.NodeId > baseId, SqlSyntax)
.Where<NodeDto>(x => x.Trashed == false, SqlSyntax)
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
var sql = SqlSyntax.SelectTop(query, groupSize);
var xmlItems = ProcessQuery(sql, new PagingSqlQuery(sql))
@@ -290,7 +292,38 @@ namespace Umbraco.Core.Persistence.Repositories
Logger.Error<MediaRepository>("Could not rebuild XML for nodeId=" + xmlItem.NodeId, e);
}
}
baseId = xmlItems.Last().NodeId;
baseId = xmlItems[xmlItems.Count - 1].NodeId;
}
//now delete the items that shouldn't be there
var allMediaIds = Database.Fetch<int>(GetBaseQuery(BaseQueryType.Ids).Where<NodeDto>(x => x.Trashed == false, SqlSyntax));
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
var xmlIdsQuery = new Sql()
.Select("DISTINCT cmsContentXml.nodeId")
.From<ContentXmlDto>(SqlSyntax)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentXmlDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
if (contentTypeIdsA.Length > 0)
{
xmlIdsQuery.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentTypeDto>(SqlSyntax)
.On<ContentTypeDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.ContentTypeId)
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
}
xmlIdsQuery.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType, SqlSyntax);
var allXmlIds = Database.Fetch<int>(xmlIdsQuery);
var toRemove = allXmlIds.Except(allMediaIds).ToArray();
if (toRemove.Length > 0)
{
foreach (var idGroup in toRemove.InGroupsOf(2000))
{
Database.Execute("DELETE FROM cmsContentXml WHERE nodeId IN (@ids)", new { ids = idGroup });
}
}
}
@@ -526,20 +559,19 @@ namespace Umbraco.Core.Persistence.Repositories
/// Private method to create a media object from a ContentDto
/// </summary>
/// <param name="dto"></param>
/// <param name="versionId"></param>
/// <param name="docSql"></param>
/// <returns></returns>
private IMedia CreateMediaFromDto(ContentVersionDto dto, Guid versionId, Sql docSql)
private IMedia CreateMediaFromDto(ContentVersionDto dto, Sql docSql)
{
var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
var media = MediaFactory.BuildEntity(dto, contentType);
var docDef = new DocumentDefinition(dto.NodeId, versionId, media.UpdateDate, media.CreateDate, contentType);
var docDef = new DocumentDefinition(dto, contentType);
var properties = GetPropertyCollection(new PagingSqlQuery(docSql), new[] { docDef });
media.Properties = properties[dto.NodeId];
media.Properties = properties[dto.VersionId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
@@ -54,7 +54,7 @@ namespace Umbraco.Core.Persistence.Repositories
if (dto == null)
return null;
var content = CreateMemberFromDto(dto, dto.ContentVersionDto.VersionId, sql);
var content = CreateMemberFromDto(dto, sql);
return content;
@@ -448,16 +448,16 @@ namespace Umbraco.Core.Persistence.Repositories
var memberType = _memberTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
var factory = new MemberFactory(memberType, NodeObjectTypeId, dto.NodeId);
var media = factory.BuildEntity(dto);
var member = factory.BuildEntity(dto);
var properties = GetPropertyCollection(new PagingSqlQuery(sql), new[] { new DocumentDefinition(dto.NodeId, dto.ContentVersionDto.VersionId, media.UpdateDate, media.CreateDate, memberType) });
var properties = GetPropertyCollection(new PagingSqlQuery(sql), new[] { new DocumentDefinition(dto.ContentVersionDto, memberType) });
media.Properties = properties[dto.NodeId];
member.Properties = properties[dto.ContentVersionDto.VersionId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
((Entity)media).ResetDirtyProperties(false);
return media;
((Entity)member).ResetDirtyProperties(false);
return member;
}
@@ -658,20 +658,21 @@ namespace Umbraco.Core.Persistence.Repositories
// fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch<MemberDto, ContentVersionDto, ContentDto, NodeDto>(sqlFull);
var content = new IMember[dtos.Count];
var defs = new List<DocumentDefinition>();
//This is a tuple list identifying if the content item came from the cache or not
var content = new List<Tuple<IMember, bool>>();
var defs = new DocumentDefinitionCollection();
for (var i = 0; i < dtos.Count; i++)
foreach (var dto in dtos)
{
var dto = dtos[i];
// if the cache contains the item, use it
if (withCache)
{
var cached = IsolatedCache.GetCacheItem<IMember>(GetCacheIdKey<IMember>(dto.NodeId));
if (cached != null)
//only use this cached version if the dto returned is the same version - this is just a safety check, members dont
//store different versions, but just in case someone corrupts some data we'll double check to be sure.
if (cached != null && cached.Version == dto.ContentVersionDto.VersionId)
{
content[i] = cached;
content.Add(new Tuple<IMember, bool>(cached, true));
continue;
}
}
@@ -679,60 +680,54 @@ namespace Umbraco.Core.Persistence.Repositories
// else, need to fetch from the database
// content type repository is full-cache so OK to get each one independently
var contentType = _memberTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
var factory = new MemberFactory(contentType, NodeObjectTypeId, dto.NodeId);
content[i] = factory.BuildEntity(dto);
// need properties
defs.Add(new DocumentDefinition(
dto.NodeId,
dto.ContentVersionDto.VersionId,
dto.ContentVersionDto.VersionDate,
dto.ContentVersionDto.ContentDto.NodeDto.CreateDate,
contentType
));
if (defs.AddOrUpdate(new DocumentDefinition(dto.ContentVersionDto, contentType)))
{
content.Add(new Tuple<IMember, bool>(MemberFactory.BuildEntity(dto, contentType), false));
}
}
// load all properties for all documents from database in 1 query
var propertyData = GetPropertyCollection(pagingSqlQuery, defs);
// assign
var dtoIndex = 0;
foreach (var def in defs)
// assign property data
foreach (var contentItem in content)
{
// move to corresponding item (which has to exist)
while (dtos[dtoIndex].NodeId != def.Id) dtoIndex++;
var cc = contentItem.Item1;
var fromCache = contentItem.Item2;
// complete the item
var cc = content[dtoIndex];
cc.Properties = propertyData[cc.Id];
//if this has come from cache, we do not need to build up it's structure
if (fromCache) continue;
cc.Properties = propertyData[cc.Version];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
((Entity)cc).ResetDirtyProperties(false);
cc.ResetDirtyProperties(false);
}
return content;
return content.Select(x => x.Item1).ToArray();
}
/// <summary>
/// Private method to create a member object from a MemberDto
/// </summary>
/// <param name="dto"></param>
/// <param name="versionId"></param>
/// <param name="docSql"></param>
/// <returns></returns>
private IMember CreateMemberFromDto(MemberDto dto, Guid versionId, Sql docSql)
private IMember CreateMemberFromDto(MemberDto dto, Sql docSql)
{
var memberType = _memberTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
var factory = new MemberFactory(memberType, NodeObjectTypeId, dto.ContentVersionDto.NodeId);
var member = factory.BuildEntity(dto);
var docDef = new DocumentDefinition(dto.ContentVersionDto.NodeId, versionId, member.UpdateDate, member.CreateDate, memberType);
var docDef = new DocumentDefinition(dto.ContentVersionDto, memberType);
var properties = GetPropertyCollection(docSql, new[] { docDef });
member.Properties = properties[dto.ContentVersionDto.NodeId];
member.Properties = properties[dto.ContentVersionDto.VersionId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
@@ -38,10 +38,9 @@ namespace Umbraco.Core.Persistence.Repositories
{
sql.Where("umbracoAccess.id IN (@ids)", new { ids = ids });
}
sql.OrderBy<AccessDto>(x => x.NodeId, SqlSyntax);
var factory = new PublicAccessEntryFactory();
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
var dtos = Database.Fetch<AccessDto, AccessRuleDto, AccessDto>(new AccessRulesRelator().Map, sql);
return dtos.Select(factory.BuildEntity);
}
@@ -53,6 +52,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sql = translator.Translate();
var factory = new PublicAccessEntryFactory();
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
var dtos = Database.Fetch<AccessDto, AccessRuleDto, AccessDto>(new AccessRulesRelator().Map, sql);
return dtos.Select(factory.BuildEntity);
}
@@ -63,7 +63,9 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Select("*")
.From<AccessDto>(SqlSyntax)
.LeftJoin<AccessRuleDto>(SqlSyntax)
.On<AccessDto, AccessRuleDto>(SqlSyntax, left => left.Id, right => right.AccessId);
.On<AccessDto, AccessRuleDto>(SqlSyntax, left => left.Id, right => right.AccessId)
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
.OrderBy<AccessDto>(dto => dto.Id, SqlSyntax);
return sql;
}
@@ -104,6 +106,11 @@ namespace Umbraco.Core.Persistence.Repositories
{
rule.AccessId = entity.Key;
Database.Insert(rule);
//update the id so HasEntity is correct
var entityRule = entity.Rules.First(x => x.Key == rule.Id);
entityRule.Id = entityRule.Key.GetHashCode();
//double make sure that this is set since it is possible to add rules via ctor without AddRule
entityRule.AccessEntryId = entity.Key;
}
entity.ResetDirtyProperties();
@@ -124,7 +131,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (rule.HasIdentity)
{
var count = Database.Update(dto.Rules.Single(x => x.Id == rule.Key));
var count = Database.Update(dto.Rules.First(x => x.Id == rule.Key));
if (count == 0)
{
throw new InvalidOperationException("No rows were updated for the access rule");
@@ -150,6 +157,8 @@ namespace Umbraco.Core.Persistence.Repositories
Database.Delete<AccessRuleDto>("WHERE id=@Id", new {Id = removedRule});
}
entity.ClearRemovedRules();
entity.ResetDirtyProperties();
}
@@ -158,4 +167,4 @@ namespace Umbraco.Core.Persistence.Repositories
return entity.Key;
}
}
}
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Linq;
using System.Text;
@@ -33,6 +34,11 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly IContentSection _contentSection;
/// <summary>
/// This is used for unit tests ONLY
/// </summary>
internal static bool ThrowOnWarning = false;
protected VersionableRepositoryBase(IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, IContentSection contentSection)
: base(work, cache, logger, sqlSyntax)
{
@@ -503,7 +509,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="sql"></param>
/// <param name="documentDefs"></param>
/// <returns></returns>
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
protected IDictionary<Guid, PropertyCollection> GetPropertyCollection(
Sql sql,
IReadOnlyCollection<DocumentDefinition> documentDefs)
{
@@ -516,11 +522,11 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="pagingSqlQuery"></param>
/// <param name="documentDefs"></param>
/// <returns></returns>
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
protected IDictionary<Guid, PropertyCollection> GetPropertyCollection(
PagingSqlQuery pagingSqlQuery,
IReadOnlyCollection<DocumentDefinition> documentDefs)
{
if (documentDefs.Count == 0) return new Dictionary<int, PropertyCollection>();
if (documentDefs.Count == 0) return new Dictionary<Guid, PropertyCollection>();
//initialize to the query passed in
var docSql = pagingSqlQuery.PrePagedSql;
@@ -576,16 +582,16 @@ ON cmsPropertyData.propertytypeid = cmsPropertyType.id
INNER JOIN
(" + string.Format(parsedOriginalSql, "cmsContent.nodeId, cmsContentVersion.VersionId") + @") as docData
ON cmsPropertyData.versionId = docData.VersionId AND cmsPropertyData.contentNodeId = docData.nodeId
ORDER BY contentNodeId, propertytypeid
ORDER BY contentNodeId, versionId, propertytypeid
", docSql.Arguments);
//This does NOT fetch all data into memory in a list, this will read
// over the records as a data reader, this is much better for performance and memory,
// but it means that during the reading of this data set, nothing else can be read
// from SQL server otherwise we'll get an exception.
var allPropertyData = Database.Query<PropertyDataDto>(propSql);
var result = new Dictionary<int, PropertyCollection>();
var result = new Dictionary<Guid, PropertyCollection>();
var propertiesWithTagSupport = new Dictionary<string, SupportTagsAttribute>();
//used to track the resolved composition property types per content type so we don't have to re-resolve (ToArray) the list every time
var resolvedCompositionProperties = new Dictionary<int, PropertyType[]>();
@@ -594,11 +600,13 @@ ORDER BY contentNodeId, propertytypeid
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
var hasCurrent = false; // initially there is no enumerator.Current
var comparer = new DocumentDefinitionComparer(SqlSyntax);
try
{
//This must be sorted by node id because this is how we are sorting the query to lookup property types above,
// which allows us to more efficiently iterate over the large data set of property values
foreach (var def in documentDefs.OrderBy(x => x.Id))
foreach (var def in documentDefs.OrderBy(x => x.Id).ThenBy(x => x.Version, comparer))
{
// get the resolved properties from our local cache, or resolve them and put them in cache
PropertyType[] compositionProperties;
@@ -617,15 +625,17 @@ ORDER BY contentNodeId, propertytypeid
var propertyDataDtos = new List<PropertyDataDto>();
while (hasCurrent || propertyDataSetEnumerator.MoveNext())
{
if (propertyDataSetEnumerator.Current.NodeId == def.Id)
//Not checking null on VersionId because it can never be null - no idea why it's set to nullable
// ReSharper disable once PossibleInvalidOperationException
if (propertyDataSetEnumerator.Current.VersionId.Value == def.Version)
{
hasCurrent = false; // enumerator.Current is not available
propertyDataDtos.Add(propertyDataSetEnumerator.Current);
}
else
{
hasCurrent = true; // enumerator.Current is available for another def
break; // no more propertyDataDto for this def
hasCurrent = true; // enumerator.Current is available for another def
break; // no more propertyDataDto for this def
}
}
@@ -660,11 +670,19 @@ ORDER BY contentNodeId, propertytypeid
}
}
if (result.ContainsKey(def.Id))
if (result.ContainsKey(def.Version))
{
Logger.Warn<VersionableRepositoryBase<TId, TEntity>>("The query returned multiple property sets for document definition " + def.Id + ", " + def.Composition.Name);
var msg = string.Format("The query returned multiple property sets for document definition {0}, {1}, {2}", def.Id, def.Version, def.Composition.Name);
if (ThrowOnWarning)
{
throw new InvalidOperationException(msg);
}
else
{
Logger.Warn<VersionableRepositoryBase<TId, TEntity>>(msg);
}
}
result[def.Id] = new PropertyCollection(properties);
result[def.Version] = new PropertyCollection(properties);
}
}
finally
@@ -687,8 +705,8 @@ ORDER BY contentNodeId, propertytypeid
case "NAME":
return "umbracoNode.text";
case "PUBLISHED":
return "cmsDocument.published";
case "OWNER":
return "cmsDocument.published";
//TODO: This isn't going to work very nicely because it's going to order by ID, not by letter
return "umbracoNode.nodeUser";
// Members only
@@ -772,25 +790,159 @@ ORDER BY contentNodeId, propertytypeid
/// <returns></returns>
protected abstract Sql GetBaseQuery(BaseQueryType queryType);
internal class DocumentDefinitionCollection : KeyedCollection<ValueType, DocumentDefinition>
{
private readonly bool _includeAllVersions;
/// <summary>
/// Constructor specifying if all versions should be allowed, in that case the key for the collection becomes the versionId (GUID)
/// </summary>
/// <param name="includeAllVersions"></param>
public DocumentDefinitionCollection(bool includeAllVersions = false)
{
_includeAllVersions = includeAllVersions;
}
protected override ValueType GetKeyForItem(DocumentDefinition item)
{
return _includeAllVersions ? (ValueType)item.Version : item.Id;
}
/// <summary>
/// if this key already exists if it does then we need to check
/// if the existing item is 'older' than the new item and if that is the case we'll replace the older one
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool AddOrUpdate(DocumentDefinition item)
{
//if we are including all versions then just add, we aren't checking for latest
if (_includeAllVersions)
{
base.Add(item);
return true;
}
if (Dictionary == null)
{
base.Add(item);
return true;
}
var key = GetKeyForItem(item);
DocumentDefinition found;
if (TryGetValue(key, out found))
{
//it already exists and it's older so we need to replace it
if (item.VersionId > found.VersionId)
{
var currIndex = Items.IndexOf(found);
if (currIndex == -1)
throw new IndexOutOfRangeException("Could not find the item in the list: " + found.Version);
//replace the current one with the newer one
SetItem(currIndex, item);
return true;
}
//could not add or update
return false;
}
base.Add(item);
return true;
}
public bool TryGetValue(ValueType key, out DocumentDefinition val)
{
if (Dictionary == null)
{
val = null;
return false;
}
return Dictionary.TryGetValue(key, out val);
}
}
/// <summary>
/// A custom comparer required for sorting entities by GUIDs to match how the sorting of GUIDs works on SQL server
/// </summary>
/// <remarks>
/// MySql sorts GUIDs as a string, MSSQL sorts based on byte sections, this comparer will allow sorting GUIDs to be the same as how SQL server does
/// </remarks>
private class DocumentDefinitionComparer : IComparer<Guid>
{
private readonly ISqlSyntaxProvider _sqlSyntax;
public DocumentDefinitionComparer(ISqlSyntaxProvider sqlSyntax)
{
_sqlSyntax = sqlSyntax;
}
public int Compare(Guid x, Guid y)
{
//MySql sorts on GUIDs as strings (i.e. normal)
if (_sqlSyntax is MySqlSyntaxProvider)
{
return x.CompareTo(y);
}
//MSSQL doesn't it sorts them on byte sections!
return new SqlGuid(x).CompareTo(new SqlGuid(y));
}
}
internal class DocumentDefinition
{
/// <summary>
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
/// </summary>
public DocumentDefinition(int id, Guid version, DateTime versionDate, DateTime createDate, IContentTypeComposition composition)
public DocumentDefinition(DocumentDto dto, IContentTypeComposition composition)
{
Id = id;
Version = version;
VersionDate = versionDate;
CreateDate = createDate;
DocumentDto = dto;
ContentVersionDto = dto.ContentVersionDto;
Composition = composition;
}
public int Id { get; set; }
public Guid Version { get; set; }
public DateTime VersionDate { get; set; }
public DateTime CreateDate { get; set; }
public IContentTypeComposition Composition { get; set; }
public DocumentDefinition(ContentVersionDto dto, IContentTypeComposition composition)
{
ContentVersionDto = dto;
Composition = composition;
}
public DocumentDto DocumentDto { get; private set; }
public ContentVersionDto ContentVersionDto { get; private set; }
public int Id
{
get { return ContentVersionDto.NodeId; }
}
public Guid Version
{
get { return DocumentDto != null ? DocumentDto.VersionId : ContentVersionDto.VersionId; }
}
/// <summary>
/// This is used to determien which version is the most recent
/// </summary>
public int VersionId
{
get { return ContentVersionDto.Id; }
}
public DateTime VersionDate
{
get { return ContentVersionDto.VersionDate; }
}
public DateTime CreateDate
{
get { return ContentVersionDto.ContentDto.NodeDto.CreateDate; }
}
public IContentTypeComposition Composition { get; set; }
}
/// <summary>
@@ -47,5 +47,9 @@ using System.Security.Permissions;
[assembly: InternalsVisibleTo("Umbraco.Deploy.UI")]
[assembly: InternalsVisibleTo("Umbraco.Deploy.Cloud")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Core")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Core.Providers")]
[assembly: InternalsVisibleTo("Umbraco.Forms.Web")]
//allow this to be mocked in our unit tests
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
@@ -2243,6 +2243,7 @@ namespace Umbraco.Core.Services
//We need to check if children and their publish state to ensure that we 'republish' content that was previously published
if (published && previouslyPublished == false && HasChildren(content.Id))
{
//TODO: Horrible for performance if there are lots of descendents! We should page if anything but this is crazy
var descendants = GetPublishedDescendants(content);
_publishingStrategy.PublishingFinalized(uow, descendants, false);
@@ -81,6 +81,7 @@ namespace Umbraco.Core.Services
/// </param>
void RebuildXmlStructures(params int[] contentTypeIds);
int CountNotTrashed(string contentTypeAlias = null);
int Count(string contentTypeAlias = null);
int CountChildren(int parentId, string contentTypeAlias = null);
int CountDescendants(int parentId, string contentTypeAlias = null);
@@ -167,6 +168,22 @@ namespace Umbraco.Core.Services
IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter);
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">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="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <param name="filter">Search text filter</param>
/// <param name="contentTypeFilter">A list of content type Ids to filter the list by</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter);
[Obsolete("Use the overload with 'long' parameter types instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords,
+47
View File
@@ -261,6 +261,29 @@ namespace Umbraco.Core.Services
}
}
public int CountNotTrashed(string contentTypeAlias = null)
{
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
using (var mediaTypeRepository = RepositoryFactory.CreateMediaTypeRepository(uow))
{
var mediaTypeId = 0;
if (contentTypeAlias.IsNullOrWhiteSpace() == false)
{
var mediaType = mediaTypeRepository.Get(contentTypeAlias);
if (mediaType == null) return 0;
mediaTypeId = mediaType.Id;
}
var query = Query<IMedia>.Builder.Where(media => media.Trashed == false);
if (mediaTypeId > 0)
{
query.Where(media => media.ContentTypeId == mediaTypeId);
}
return repository.Count(query);
}
}
public int Count(string contentTypeAlias = null)
{
using (var uow = UowProvider.GetUnitOfWork(commit: true))
@@ -448,6 +471,25 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter)
{
return GetPagedChildren(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filter, null);
}
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
/// </summary>
/// <param name="id">Id of the Parent to retrieve Children from</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalChildren">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="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <param name="filter">Search text filter</param>
/// <param name="contentTypeFilter">A list of content type Ids to filter the list by</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IMedia> GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter, int[] contentTypeFilter)
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
@@ -460,6 +502,11 @@ namespace Umbraco.Core.Services
// always check for a parent - else it will also get decendants (and then you should use the GetPagedDescendants method)
query.Where(x => x.ParentId == id);
if (contentTypeFilter != null && contentTypeFilter.Length > 0)
{
query.Where(x => contentTypeFilter.Contains(x.ContentTypeId));
}
IQuery<IMedia> filterQuery = null;
if (filter.IsNullOrWhiteSpace() == false)
{
+2
View File
@@ -1,10 +1,12 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
{
/// <summary>
/// Represents a string-based entity identifier.
/// </summary>
[TypeConverter(typeof(UdiTypeConverter))]
public class StringUdi : Udi
{
/// <summary>
+1
View File
@@ -198,6 +198,7 @@
<Compile Include="Configuration\BaseRest\ExtensionElement.cs" />
<Compile Include="Configuration\BaseRest\ExtensionElementCollection.cs" />
<Compile Include="Configuration\BaseRest\MethodElement.cs" />
<Compile Include="Configuration\ContentXmlStorage.cs" />
<Compile Include="Configuration\Dashboard\AccessElement.cs" />
<Compile Include="Configuration\Dashboard\AccessItem.cs" />
<Compile Include="Configuration\Dashboard\AccessType.cs" />
-26
View File
@@ -16,32 +16,6 @@ namespace Umbraco.Core
/// </summary>
internal static class XmlExtensions
{
/// <summary>
/// Saves the xml document async
/// </summary>
/// <param name="xdoc"></param>
/// <param name="filename"></param>
/// <returns></returns>
public static async Task SaveAsync(this XmlDocument xdoc, string filename)
{
if (xdoc.DocumentElement == null)
throw new XmlException("Cannot save xml document, there is no root element");
using (var fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true))
using (var xmlWriter = XmlWriter.Create(fs, new XmlWriterSettings
{
Async = true,
Encoding = Encoding.UTF8,
Indent = true
}))
{
//NOTE: There are no nice methods to write it async, only flushing it async. We
// could implement this ourselves but it'd be a very manual process.
xdoc.WriteTo(xmlWriter);
await xmlWriter.FlushAsync().ConfigureAwait(false);
}
}
public static bool HasAttribute(this XmlAttributeCollection attributes, string attributeName)
{
return attributes.Cast<XmlAttribute>().Any(x => x.Name == attributeName);
@@ -16,6 +16,7 @@ using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Validators;
using Moq;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -43,15 +44,18 @@ namespace Umbraco.Tests.Benchmarks
public ModelToSqlExpressionHelperBenchmarks()
{
_contentMapper = new ContentMapper(_syntaxProvider);
_contentMapper.BuildMap();
var contentMapper = new ContentMapper(_syntaxProvider);
contentMapper.BuildMap();
_cachedExpression = new CachedExpression();
var mappingResolver = new Mock<MappingResolver>();
mappingResolver.Setup(resolver => resolver.ResolveMapperByType(It.IsAny<Type>())).Returns(contentMapper);
_mappingResolver = mappingResolver.Object;
}
private readonly ISqlSyntaxProvider _syntaxProvider = new SqlCeSyntaxProvider();
private readonly BaseMapper _contentMapper;
private readonly CachedExpression _cachedExpression;
private readonly MappingResolver _mappingResolver;
[Benchmark(Baseline = true)]
public void WithNonCached()
{
@@ -62,7 +66,7 @@ namespace Umbraco.Tests.Benchmarks
Expression<Func<IContent, bool>> predicate = content =>
content.Path.StartsWith("-1") && content.Published && (content.ContentTypeId == a || content.ContentTypeId == b);
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>(_syntaxProvider, _contentMapper);
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>(_syntaxProvider, _mappingResolver);
var result = modelToSqlExpressionHelper.Visit(predicate);
}
@@ -80,7 +84,7 @@ namespace Umbraco.Tests.Benchmarks
Expression<Func<IContent, bool>> predicate = content =>
content.Path.StartsWith("-1") && content.Published && (content.ContentTypeId == a || content.ContentTypeId == b);
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>(_syntaxProvider, _contentMapper);
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>(_syntaxProvider, _mappingResolver);
//wrap it!
_cachedExpression.Wrap(predicate);
@@ -54,6 +54,9 @@
<HintPath>..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.9.9\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CodeAnalysis, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
<Private>True</Private>
@@ -66,6 +69,9 @@
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Moq, Version=4.7.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\packages\Moq.4.7.0\lib\net45\Moq.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
@@ -4,11 +4,13 @@
<package id="BenchmarkDotNet.Core" version="0.9.9" targetFramework="net45" />
<package id="BenchmarkDotNet.Diagnostics.Windows" version="0.9.9" targetFramework="net45" />
<package id="BenchmarkDotNet.Toolchains.Roslyn" version="0.9.9" targetFramework="net45" />
<package id="Castle.Core" version="4.0.0" targetFramework="net45" />
<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net45" />
<package id="Microsoft.CodeAnalysis.Common" version="1.3.2" targetFramework="net45" />
<package id="Microsoft.CodeAnalysis.CSharp" version="1.3.2" targetFramework="net45" />
<package id="Microsoft.Diagnostics.Tracing.TraceEvent" version="1.0.41" targetFramework="net45" />
<package id="Microsoft.SqlServer.Compact" version="4.0.8854.1" targetFramework="net45" />
<package id="Moq" version="4.7.0" targetFramework="net45" />
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
<package id="System.Collections" version="4.0.11" targetFramework="net45" />
<package id="System.Collections.Concurrent" version="4.0.12" targetFramework="net45" />
+92
View File
@@ -0,0 +1,92 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Issues
{
[TestFixture]
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
public class U9560 : BaseDatabaseFactoryTest
{
[Test]
public void Test()
{
// create a content type and some properties
var contentType = new ContentType(-1);
contentType.Alias = "test";
contentType.Name = "test";
var propertyType = new PropertyType("test", DataTypeDatabaseType.Ntext, "prop") { Name = "Prop", Description = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 };
contentType.PropertyTypeCollection.Add(propertyType);
ServiceContext.ContentTypeService.Save(contentType);
var aliasName = string.Empty;
// read fields, same as what we do with PetaPoco Fetch<dynamic>
var db = DatabaseContext.Database;
db.OpenSharedConnection();
try
{
var conn = db.Connection;
var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT mandatory, dataTypeId, propertyTypeGroupId, contentTypeId, sortOrder, alias, name, validationRegExp, description from cmsPropertyType where id=" + propertyType.Id;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
for (var i = 0; i < reader.FieldCount; i++)
Console.WriteLine(reader.GetName(i));
aliasName = reader.GetName(5);
}
}
}
finally
{
db.CloseSharedConnection();
}
// note that although the query is for 'alias' the field is named 'Alias'
Assert.AreEqual("Alias", aliasName);
// try differently
db.OpenSharedConnection();
try
{
var conn = db.Connection;
var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT mandatory, dataTypeId, propertyTypeGroupId, contentTypeId, sortOrder, alias as alias, name, validationRegExp, description from cmsPropertyType where id=" + propertyType.Id;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
for (var i = 0; i < reader.FieldCount; i++)
Console.WriteLine(reader.GetName(i));
aliasName = reader.GetName(5);
}
}
}
finally
{
db.CloseSharedConnection();
}
// and now it is OK
Assert.AreEqual("alias", aliasName);
// get the legacy content type
var legacyContentType = new umbraco.cms.businesslogic.ContentType(contentType.Id);
Assert.AreEqual("test", legacyContentType.Alias);
// get the legacy properties
var legacyProperties = legacyContentType.PropertyTypes;
// without the fix, due to some (swallowed) inner exception, we have no properties
//Assert.IsNull(legacyProperties);
// thanks to the fix, it works
Assert.IsNotNull(legacyProperties);
Assert.AreEqual(1, legacyProperties.Count);
Assert.AreEqual("prop", legacyProperties[0].Alias);
}
}
}
@@ -48,6 +48,13 @@ namespace Umbraco.Tests.Persistence
ApplicationContext.Current = null;
}
[Test]
public void Database_Connection()
{
var db = _dbContext.Database;
Assert.IsNull(db.Connection);
}
[Test]
public void Can_Verify_Single_Database_Instance()
{
@@ -17,19 +17,52 @@ namespace Umbraco.Tests.Persistence.Querying
[TestFixture]
public class ExpressionTests : BaseUsingSqlCeSyntax
{
// [Test]
// public void Can_Query_With_Content_Type_Alias()
// {
// //Arrange
// Expression<Func<IMedia, bool>> predicate = content => content.ContentType.Alias == "Test";
// var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>();
// var result = modelToSqlExpressionHelper.Visit(predicate);
[Test]
public void Equals_Claus_With_Two_Entity_Values()
{
var dataType = new DataTypeDefinition(-1, "Test")
{
Id = 12345
};
Expression<Func<PropertyType, bool>> predicate = p => p.DataTypeDefinitionId == dataType.Id;
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<PropertyType>();
var result = modelToSqlExpressionHelper.Visit(predicate);
// Debug.Print("Model to Sql ExpressionHelper: \n" + result);
Debug.Print("Model to Sql ExpressionHelper: \n" + result);
// Assert.AreEqual("[cmsContentType].[alias] = @0", result);
// Assert.AreEqual("Test", modelToSqlExpressionHelper.GetSqlParameters()[0]);
// }
Assert.AreEqual("([cmsPropertyType].[dataTypeId] = @0)", result);
Assert.AreEqual(12345, modelToSqlExpressionHelper.GetSqlParameters()[0]);
}
[Test]
public void Can_Query_With_Content_Type_Alias()
{
//Arrange
Expression<Func<IMedia, bool>> predicate = content => content.ContentType.Alias == "Test";
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>();
var result = modelToSqlExpressionHelper.Visit(predicate);
Debug.Print("Model to Sql ExpressionHelper: \n" + result);
Assert.AreEqual("([cmsContentType].[alias] = @0)", result);
Assert.AreEqual("Test", modelToSqlExpressionHelper.GetSqlParameters()[0]);
}
[Test]
public void Can_Query_With_Content_Type_Aliases()
{
//Arrange
var aliases = new[] {"Test1", "Test2"};
Expression<Func<IMedia, bool>> predicate = content => aliases.Contains(content.ContentType.Alias);
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>();
var result = modelToSqlExpressionHelper.Visit(predicate);
Debug.Print("Model to Sql ExpressionHelper: \n" + result);
Assert.AreEqual("[cmsContentType].[alias] IN (@1,@2)", result);
Assert.AreEqual("Test1", modelToSqlExpressionHelper.GetSqlParameters()[1]);
Assert.AreEqual("Test2", modelToSqlExpressionHelper.GetSqlParameters()[2]);
}
[Test]
public void CachedExpression_Can_Verify_Path_StartsWith_Predicate_In_Same_Result()
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
@@ -21,7 +22,6 @@ using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
using umbraco.editorControls.tinyMCE3;
using umbraco.interfaces;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Tests.Persistence.Repositories
@@ -36,11 +36,15 @@ namespace Umbraco.Tests.Persistence.Repositories
base.Initialize();
CreateTestData();
VersionableRepositoryBase<int, IContent>.ThrowOnWarning = true;
}
[TearDown]
public override void TearDown()
{
VersionableRepositoryBase<int, IContent>.ThrowOnWarning = false;
base.TearDown();
}
@@ -67,6 +71,131 @@ namespace Umbraco.Tests.Persistence.Repositories
return repository;
}
[Test]
public void Get_Always_Returns_Latest_Version()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentTypeRepository contentTypeRepository;
IContent content1;
var versions = new List<Guid>();
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
//save version
contentTypeRepository.AddOrUpdate(hasPropertiesContentType);
repository.AddOrUpdate(content1);
unitOfWork.Commit();
versions.Add(content1.Version);
//publish version
content1.ChangePublishedState(PublishedState.Published);
repository.AddOrUpdate(content1);
unitOfWork.Commit();
versions.Add(content1.Version);
//change something and make a pending version
content1.Name = "new name";
content1.ChangePublishedState(PublishedState.Saved);
repository.AddOrUpdate(content1);
unitOfWork.Commit();
versions.Add(content1.Version);
}
// Assert
Assert.AreEqual(3, versions.Distinct().Count());
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
var content = repository.GetByQuery(new Query<IContent>().Where(c => c.Id == content1.Id)).ToArray()[0];
Assert.AreEqual(versions[2], content.Version);
content = repository.Get(content1.Id);
Assert.AreEqual(versions[2], content.Version);
foreach (var version in versions)
{
content = repository.GetByVersion(version);
Assert.IsNotNull(content);
Assert.AreEqual(version, content.Version);
}
}
}
[Test]
public void Deal_With_Corrupt_Duplicate_Newest_Published_Flags()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentTypeRepository contentTypeRepository;
IContent content1;
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
contentTypeRepository.AddOrUpdate(hasPropertiesContentType);
repository.AddOrUpdate(content1);
unitOfWork.Commit();
}
var versionDtos = new List<ContentVersionDto>();
//Now manually corrupt the data
var versions = new[] { Guid.NewGuid(), Guid.NewGuid() };
for (var index = 0; index < versions.Length; index++)
{
var version = versions[index];
var versionDate = DateTime.Now.AddMinutes(index);
var versionDto = new ContentVersionDto
{
NodeId = content1.Id,
VersionDate = versionDate,
VersionId = version
};
this.DatabaseContext.Database.Insert(versionDto);
versionDtos.Add(versionDto);
this.DatabaseContext.Database.Insert(new DocumentDto
{
Newest = true,
NodeId = content1.Id,
Published = true,
Text = content1.Name,
VersionId = version,
WriterUserId = 0,
UpdateDate = versionDate,
TemplateId = content1.Template == null || content1.Template.Id <= 0 ? null : (int?) content1.Template.Id
});
}
// Assert
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
var content = repository.GetByQuery(new Query<IContent>().Where(c => c.Id == content1.Id)).ToArray();
Assert.AreEqual(1, content.Length);
Assert.AreEqual(content[0].Version, versionDtos.Single(x => x.Id == versionDtos.Max(y => y.Id)).VersionId);
Assert.AreEqual(content[0].UpdateDate.ToString(CultureInfo.InvariantCulture), versionDtos.Single(x => x.Id == versionDtos.Max(y => y.Id)).VersionDate.ToString(CultureInfo.InvariantCulture));
var contentItem = repository.GetByVersion(content1.Version);
Assert.IsNotNull(contentItem);
contentItem = repository.Get(content1.Id);
Assert.IsNotNull(contentItem);
Assert.AreEqual(contentItem.UpdateDate.ToString(CultureInfo.InvariantCulture), versionDtos.Single(x => x.Id == versionDtos.Max(y => y.Id)).VersionDate.ToString(CultureInfo.InvariantCulture));
Assert.AreEqual(contentItem.Version, versionDtos.Single(x => x.Id == versionDtos.Max(y => y.Id)).VersionId);
var allVersions = repository.GetAllVersions(content[0].Id);
var allKnownVersions = versionDtos.Select(x => x.VersionId).Union(new[]{ content1.Version }).ToArray();
Assert.IsTrue(allKnownVersions.ContainsAll(allVersions.Select(x => x.Version)));
Assert.IsTrue(allVersions.Select(x => x.Version).ContainsAll(allKnownVersions));
}
}
/// <summary>
/// This tests the regression issue of U4-9438
/// </summary>
@@ -226,6 +355,62 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
[Test]
public void Rebuild_All_Xml_Structures_Ensure_Orphaned_Are_Removed()
{
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentTypeRepository contentTypeRepository;
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
//delete all xml
unitOfWork.Database.Execute("DELETE FROM cmsContentXml");
var contentType1 = MockedContentTypes.CreateSimpleContentType("Textpage1", "Textpage1");
contentTypeRepository.AddOrUpdate(contentType1);
var allCreated = new List<IContent>();
for (var i = 0; i < 100; i++)
{
//These will be non-published so shouldn't show up
var c1 = MockedContent.CreateSimpleContent(contentType1);
repository.AddOrUpdate(c1);
allCreated.Add(c1);
}
for (var i = 0; i < 100; i++)
{
var c1 = MockedContent.CreateSimpleContent(contentType1);
c1.ChangePublishedState(PublishedState.Published);
repository.AddOrUpdate(c1);
allCreated.Add(c1);
}
unitOfWork.Commit();
//now create some versions of this content - this shouldn't affect the xml structures saved
for (int i = 0; i < allCreated.Count; i++)
{
allCreated[i].Name = "blah" + i;
repository.AddOrUpdate(allCreated[i]);
}
unitOfWork.Commit();
//Add some extra orphaned rows that shouldn't be there
var notPublished = MockedContent.CreateSimpleContent(contentType1);
repository.AddOrUpdate(notPublished);
unitOfWork.Commit();
//Force add it
unitOfWork.Database.Insert(new ContentXmlDto
{
NodeId = notPublished.Id,
Xml = "<test></test>"
});
repository.RebuildXmlStructures(media => new XElement("test"), 10);
Assert.AreEqual(100, unitOfWork.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM cmsContentXml"));
}
}
[Test]
public void Rebuild_All_Xml_Structures_For_Content_Type()
{
@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Persistence.Repositories
{
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
[TestFixture]
public class EntityRepositoryTest : BaseDatabaseFactoryTest
{
[SetUp]
public override void Initialize()
{
base.Initialize();
}
[TearDown]
public override void TearDown()
{
base.TearDown();
}
private ContentRepository CreateContentRepository(IScopeUnitOfWork unitOfWork, out ContentTypeRepository contentTypeRepository)
{
TemplateRepository tr;
return CreateContentRepository(unitOfWork, out contentTypeRepository, out tr);
}
private ContentRepository CreateContentRepository(IScopeUnitOfWork unitOfWork, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository)
{
templateRepository = new TemplateRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
var tagRepository = new TagRepository(unitOfWork, CacheHelper, Logger, SqlSyntax);
contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, templateRepository);
var repository = new ContentRepository(unitOfWork, CacheHelper, Logger, SqlSyntax, contentTypeRepository, templateRepository, tagRepository, Mock.Of<IContentSection>());
return repository;
}
[Test]
public void Deal_With_Corrupt_Duplicate_Newest_Published_Flags_Full_Model()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentTypeRepository contentTypeRepository;
IContent content1;
using (var repository = CreateContentRepository(unitOfWork, out contentTypeRepository))
{
var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
contentTypeRepository.AddOrUpdate(hasPropertiesContentType);
repository.AddOrUpdate(content1);
unitOfWork.Commit();
}
var versionDtos = new List<ContentVersionDto>();
//Now manually corrupt the data
var versions = new[] {Guid.NewGuid(), Guid.NewGuid()};
for (var index = 0; index < versions.Length; index++)
{
var version = versions[index];
var versionDate = DateTime.Now.AddMinutes(index);
var versionDto = new ContentVersionDto
{
NodeId = content1.Id,
VersionDate = versionDate,
VersionId = version
};
this.DatabaseContext.Database.Insert(versionDto);
versionDtos.Add(versionDto);
this.DatabaseContext.Database.Insert(new DocumentDto
{
Newest = true,
NodeId = content1.Id,
Published = true,
Text = content1.Name,
VersionId = version,
WriterUserId = 0,
UpdateDate = versionDate,
TemplateId = content1.Template == null || content1.Template.Id <= 0 ? null : (int?)content1.Template.Id
});
}
// Assert
using (var repository = new EntityRepository(unitOfWork))
{
var content = repository.GetByQuery(new Query<IUmbracoEntity>().Where(c => c.Id == content1.Id), Constants.ObjectTypes.DocumentGuid).ToArray();
Assert.AreEqual(1, content.Length);
Assert.AreEqual(versionDtos.Max(x => x.Id), content[0].AdditionalData["VersionId"]);
content = repository.GetAll(Constants.ObjectTypes.DocumentGuid, content[0].Key).ToArray();
Assert.AreEqual(1, content.Length);
Assert.AreEqual(versionDtos.Max(x => x.Id), content[0].AdditionalData["VersionId"]);
content = repository.GetAll(Constants.ObjectTypes.DocumentGuid, content[0].Id).ToArray();
Assert.AreEqual(1, content.Length);
Assert.AreEqual(versionDtos.Max(x => x.Id), content[0].AdditionalData["VersionId"]);
var contentItem = repository.Get(content[0].Id, Constants.ObjectTypes.DocumentGuid);
Assert.AreEqual(versionDtos.Max(x => x.Id), contentItem.AdditionalData["VersionId"]);
contentItem = repository.GetByKey(content[0].Key, Constants.ObjectTypes.DocumentGuid);
Assert.AreEqual(versionDtos.Max(x => x.Id), contentItem.AdditionalData["VersionId"]);
}
}
/// <summary>
/// The Slim model will test the EntityRepository when it doesn't know the object type so it will
/// make the simplest (slim) query
/// </summary>
[Test]
public void Deal_With_Corrupt_Duplicate_Newest_Published_Flags_Slim_Model()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentTypeRepository contentTypeRepository;
IContent content1;
using (var repository = CreateContentRepository(unitOfWork, out contentTypeRepository))
{
var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
contentTypeRepository.AddOrUpdate(hasPropertiesContentType);
repository.AddOrUpdate(content1);
unitOfWork.Commit();
}
//Now manually corrupt the data
var versions = new[] { Guid.NewGuid(), Guid.NewGuid() };
for (var index = 0; index < versions.Length; index++)
{
var version = versions[index];
var versionDate = DateTime.Now.AddMinutes(index);
var versionDto = new ContentVersionDto
{
NodeId = content1.Id,
VersionDate = versionDate,
VersionId = version
};
this.DatabaseContext.Database.Insert(versionDto);
this.DatabaseContext.Database.Insert(new DocumentDto
{
Newest = true,
NodeId = content1.Id,
Published = true,
Text = content1.Name,
VersionId = version,
WriterUserId = 0,
UpdateDate = versionDate,
TemplateId = content1.Template == null || content1.Template.Id <= 0 ? null : (int?)content1.Template.Id
});
}
// Assert
using (var repository = new EntityRepository(unitOfWork))
{
var content = repository.GetByQuery(new Query<IUmbracoEntity>().Where(c => c.Id == content1.Id)).ToArray();
Assert.AreEqual(1, content.Length);
var contentItem = repository.Get(content[0].Id);
Assert.IsNotNull(contentItem);
contentItem = repository.GetByKey(content[0].Key);
Assert.IsNotNull(contentItem);
}
}
}
}
@@ -4,6 +4,7 @@ using System.Linq;
using System.Xml.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -70,6 +71,44 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
[Test]
public void Rebuild_All_Xml_Structures_Ensure_Orphaned_Are_Removed()
{
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
MediaTypeRepository mediaTypeRepository;
using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
{
//delete all xml
unitOfWork.Database.Execute("DELETE FROM cmsContentXml");
var mediaType = mediaTypeRepository.Get(1032);
for (var i = 0; i < 100; i++)
{
var image = MockedMedia.CreateMediaImage(mediaType, -1);
repository.AddOrUpdate(image);
}
unitOfWork.Commit();
//Add some extra orphaned rows that shouldn't be there
var trashed = MockedMedia.CreateMediaImage(mediaType, -1);
trashed.ChangeTrashedState(true, Constants.System.RecycleBinMedia);
repository.AddOrUpdate(trashed);
unitOfWork.Commit();
//Force add it
unitOfWork.Database.Insert(new ContentXmlDto
{
NodeId = trashed.Id,
Xml = "<test></test>"
});
repository.RebuildXmlStructures(media => new XElement("test"), 10);
Assert.AreEqual(103, unitOfWork.Database.ExecuteScalar<int>("SELECT COUNT(*) FROM cmsContentXml"));
}
}
[Test]
public void Rebuild_Some_Xml_Structures()
{
@@ -345,6 +384,61 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
[Test]
public void Can_Perform_GetByQuery_On_MediaRepository_With_ContentType_Id_Filter()
{
// Arrange
var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031);
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
MediaTypeRepository mediaTypeRepository;
using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
{
// Act
for (int i = 0; i < 10; i++)
{
var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1);
repository.AddOrUpdate(folder);
}
unitOfWork.Commit();
var types = new[] { 1031 };
var query = Query<IMedia>.Builder.Where(x => types.Contains(x.ContentTypeId));
var result = repository.GetByQuery(query);
// Assert
Assert.That(result.Count(), Is.GreaterThanOrEqualTo(11));
}
}
[Ignore("We could allow this to work but it requires an extra join on the query used which currently we don't absolutely need so leaving this out for now")]
[Test]
public void Can_Perform_GetByQuery_On_MediaRepository_With_ContentType_Alias_Filter()
{
// Arrange
var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031);
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
MediaTypeRepository mediaTypeRepository;
using (var repository = CreateRepository(unitOfWork, out mediaTypeRepository))
{
// Act
for (int i = 0; i < 10; i++)
{
var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1);
repository.AddOrUpdate(folder);
}
unitOfWork.Commit();
var types = new[] { "Folder" };
var query = Query<IMedia>.Builder.Where(x => types.Contains(x.ContentType.Alias));
var result = repository.GetByQuery(query);
// Assert
Assert.That(result.Count(), Is.GreaterThanOrEqualTo(11));
}
}
[Test]
public void Can_Perform_GetPagedResultsByQuery_ForFirstPage_On_MediaRepository()
{
@@ -472,7 +566,7 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.That(result.First().Name, Is.EqualTo("Test File"));
}
}
[Test]
public void Can_Perform_GetPagedResultsByQuery_WithFilterMatchingAll_On_MediaRepository()
{
@@ -154,36 +154,61 @@ namespace Umbraco.Tests.Persistence.Repositories
[Test]
public void Get_All()
{
var content = CreateTestData(3).ToArray();
var content = CreateTestData(30).ToArray();
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
using (var repo = new PublicAccessRepository(unitOfWork, CacheHelper, Logger, SqlSyntax))
{
var entry1 = new PublicAccessEntry(content[0], content[1], content[2], new[]
{
var allEntries = new List<PublicAccessEntry>();
for (int i = 0; i < 10; i++)
{
new PublicAccessRule
var rules = new List<PublicAccessRule>();
for (int j = 0; j < 50; j++)
{
RuleValue = "test",
RuleType = "RoleName"
},
});
repo.AddOrUpdate(entry1);
rules.Add(new PublicAccessRule
{
RuleValue = "test" + j,
RuleType = "RoleName" + j
});
}
var entry1 = new PublicAccessEntry(content[i], content[i+1], content[i+2], rules);
repo.AddOrUpdate(entry1);
unitOfWork.Commit();
allEntries.Add(entry1);
}
var entry2 = new PublicAccessEntry(content[1], content[0], content[2], new[]
//now remove a few rules from a few of the items and then add some more, this will put things 'out of order' which
//we need to verify our sort order is working for the relator
for (int i = 0; i < allEntries.Count; i++)
{
new PublicAccessRule
//all the even ones
if (i % 2 == 0)
{
RuleValue = "test",
RuleType = "RoleName"
},
});
repo.AddOrUpdate(entry2);
unitOfWork.Commit();
var rules = allEntries[i].Rules.ToArray();
for (int j = 0; j < rules.Length; j++)
{
//all the even ones
if (j % 2 == 0)
{
allEntries[i].RemoveRule(rules[j]);
}
}
allEntries[i].AddRule("newrule" + i, "newrule" + i);
repo.AddOrUpdate(allEntries[i]);
unitOfWork.Commit();
}
}
var found = repo.GetAll().ToArray();
Assert.AreEqual(2, found.Count());
Assert.AreEqual(10, found.Length);
foreach (var publicAccessEntry in found)
{
var matched = allEntries.First(x => x.Key == publicAccessEntry.Key);
Assert.AreEqual(matched.Rules.Count(), publicAccessEntry.Rules.Count());
}
}
}
@@ -36,11 +36,15 @@ namespace Umbraco.Tests.Services
public override void Initialize()
{
base.Initialize();
VersionableRepositoryBase<int, IContent>.ThrowOnWarning = true;
}
[TearDown]
public override void TearDown()
{
VersionableRepositoryBase<int, IContent>.ThrowOnWarning = false;
base.TearDown();
}
@@ -762,16 +766,26 @@ namespace Umbraco.Tests.Services
var parent = ServiceContext.ContentService.GetById(NodeDto.NodeIdSeed + 1);
ServiceContext.ContentService.Publish(parent);//Publishing root, so Text Page 2 can be updated.
var subpage2 = contentService.GetById(NodeDto.NodeIdSeed + 3);
subpage2.Name = "Text Page 2 Updated";
subpage2.SetValue("author", "Jane Doe");
contentService.SaveAndPublishWithStatus(subpage2, 0);//NOTE New versions are only added between publish-state-changed, so publishing to ensure addition version.
subpage2.Name = "Text Page 2 Updated again";
subpage2.SetValue("author", "Bob Hope");
contentService.SaveAndPublishWithStatus(subpage2, 0);//NOTE New versions are only added between publish-state-changed, so publishing to ensure addition version.
// Act
var versions = contentService.GetVersions(NodeDto.NodeIdSeed + 3).ToList();
// Assert
Assert.That(versions.Any(), Is.True);
Assert.That(versions.Count(), Is.GreaterThanOrEqualTo(2));
//ensure each version contains the correct property values
Assert.AreEqual("John Doe", versions[2].GetValue("author"));
Assert.AreEqual("Jane Doe", versions[1].GetValue("author"));
Assert.AreEqual("Bob Hope", versions[0].GetValue("author"));
}
[Test]
@@ -7,6 +7,7 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Tests.TestHelpers;
@@ -30,6 +31,33 @@ namespace Umbraco.Tests.Services
base.TearDown();
}
[Test]
public void Get_Paged_Children_With_Media_Type_Filter()
{
var mediaService = ServiceContext.MediaService;
var mediaType1 = MockedContentTypes.CreateImageMediaType("Image2");
ServiceContext.ContentTypeService.Save(mediaType1);
var mediaType2 = MockedContentTypes.CreateImageMediaType("Image3");
ServiceContext.ContentTypeService.Save(mediaType2);
for (int i = 0; i < 10; i++)
{
var m1 = MockedMedia.CreateMediaImage(mediaType1, -1);
mediaService.Save(m1);
var m2 = MockedMedia.CreateMediaImage(mediaType2, -1);
mediaService.Save(m2);
}
long total;
var result = ServiceContext.MediaService.GetPagedChildren(-1, 0, 11, out total, "SortOrder", Direction.Ascending, true, null, new[] {mediaType1.Id, mediaType2.Id});
Assert.AreEqual(11, result.Count());
Assert.AreEqual(20, total);
result = ServiceContext.MediaService.GetPagedChildren(-1, 1, 11, out total, "SortOrder", Direction.Ascending, true, null, new[] { mediaType1.Id, mediaType2.Id });
Assert.AreEqual(9, result.Count());
Assert.AreEqual(20, total);
}
[Test]
public void Can_Move_Media()
{
@@ -361,7 +361,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
contentCollection.Add(new PropertyType(Constants.PropertyEditors.ContentPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeDefinitionId = 1046 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.MediaPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeDefinitionId = 1048 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.MemberPicker2Alias, DataTypeDatabaseType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeDefinitionId = 1047 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.RelatedLinksAlias, DataTypeDatabaseType.Ntext) { Alias = "relatedLinks", Name = "Related Links", Mandatory = false, SortOrder = 21, DataTypeDefinitionId = 1040 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.RelatedLinks2Alias, DataTypeDatabaseType.Ntext) { Alias = "relatedLinks", Name = "Related Links", Mandatory = false, SortOrder = 21, DataTypeDefinitionId = 1050 });
contentCollection.Add(new PropertyType(Constants.PropertyEditors.TagsAlias, DataTypeDatabaseType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeDefinitionId = 1041 });
//contentCollection.Add(new PropertyType(Constants.PropertyEditors.UltraSimpleEditorAlias, DataTypeDatabaseType.Ntext) { Alias = "simpleEditor", Name = "Ultra Simple Editor", Mandatory = false, SortOrder = 19, DataTypeDefinitionId = 1038 });
+2
View File
@@ -159,6 +159,7 @@
<Compile Include="Cache\CacheRefresherEventHandlerTests.cs" />
<Compile Include="Dependencies\NuGet.cs" />
<Compile Include="CallContextTests.cs" />
<Compile Include="Issues\U9560.cs" />
<Compile Include="Collections\OrderedHashSetTests.cs" />
<Compile Include="IO\ShadowFileSystemTests.cs" />
<Compile Include="Logging\ConsoleLogger.cs" />
@@ -170,6 +171,7 @@
<Compile Include="Persistence\PetaPocoCachesTest.cs" />
<Compile Include="Persistence\PetaPocoExpressionsTests.cs" />
<Compile Include="Persistence\Repositories\LockedRepositoryTests.cs" />
<Compile Include="Persistence\Repositories\EntityRepositoryTest.cs" />
<Compile Include="Persistence\Repositories\RedirectUrlRepositoryTests.cs" />
<Compile Include="Scheduling\BackgroundTaskRunnerTests2.cs" />
<Compile Include="Routing\NiceUrlRoutesTests.cs" />
@@ -152,12 +152,12 @@ function entityResource($q, $http, umbRequestHelper) {
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetById",
[{ id: id}, {type: type }])),
'Failed to retrieve entity data for id ' + id);
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetById",
[{ id: id }, { type: type }])),
'Failed to retrieve entity data for id ' + id);
},
/**
@@ -427,7 +427,9 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
* Retrieves all media children with types used as folders.
* Uses the convention of looking for media items with mediaTypes ending in
* *Folder so will match "Folder", "bannerFolder", "secureFolder" etc,
*
*
* NOTE: This will return a max of 500 folders, if more is required it needs to be paged
*
* ##usage
* <pre>
* mediaResource.getChildFolders(1234)
@@ -445,14 +447,15 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
parentId = -1;
}
//NOTE: This will return a max of 500 folders, if more is required it needs to be paged
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaApiBaseUrl",
"GetChildFolders",
[
{ id: parentId }
])),
{
id: parentId
})),
'Failed to retrieve child folders for media item ' + parentId);
},
@@ -19,15 +19,20 @@ angular.module('umbraco.security.interceptor')
return promise;
}, function(originalResponse) {
// Intercept failed requests
// Make sure we have the configuration of the request (don't we always?)
var config = originalResponse.config ? originalResponse.config : {};
// Make sure we have an object for the headers of the request
var headers = config.headers ? config.headers : {};
//Here we'll check if we should ignore the error, this will be based on an original header set
var headers = originalResponse.config ? originalResponse.config.headers : {};
if (headers["x-umb-ignore-error"] === "ignore") {
//Here we'll check if we should ignore the error (either based on the original header set or the request configuration)
if (headers["x-umb-ignore-error"] === "ignore" || config.umbIgnoreErrors === true || (angular.isArray(config.umbIgnoreStatus) && config.umbIgnoreStatus.indexOf(originalResponse.status) !== -1)) {
//exit/ignore
return promise;
}
var filtered = _.find(requestInterceptorFilter(), function(val) {
return originalResponse.config.url.indexOf(val) > 0;
return config.url.indexOf(val) > 0;
});
if (filtered) {
return promise;
@@ -99,4 +104,4 @@ angular.module('umbraco.security.interceptor')
// We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block.
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.responseInterceptors.push('securityInterceptor');
}]);
}]);
@@ -7,6 +7,19 @@ function mediaTypeHelper(mediaTypeResource, $q) {
var mediaTypeHelperService = {
isFolderType: function(mediaEntity) {
if (!mediaEntity) {
throw "mediaEntity is null";
}
if (!mediaEntity.contentTypeAlias) {
throw "mediaEntity.contentTypeAlias is null";
}
//if you create a media type, which has an alias that ends with ...Folder then its a folder: ex: "secureFolder", "bannerFolder", "Folder"
//this is the exact same logic that is performed in MediaController.GetChildFolders
return mediaEntity.contentTypeAlias.endsWith("Folder");
},
getAllowedImagetypes: function (mediaId){
// Get All allowedTypes
@@ -1,14 +1,15 @@
//used for the media picker dialog
angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
function ($scope, $q, entityResource, eventsService, $log, searchService, angularHelper, $timeout, localizationService, treeService, contentResource, mediaResource, memberResource) {
function ($scope, $q, entityResource, eventsService, $log, searchService, angularHelper, $timeout, localizationService, treeService, contentResource, mediaResource, memberResource) {
var tree = null;
var dialogOptions = $scope.model;
$scope.dialogTreeEventHandler = $({});
$scope.section = dialogOptions.section;
$scope.treeAlias = dialogOptions.treeAlias;
$scope.multiPicker = dialogOptions.multiPicker;
$scope.hideHeader = true;
var tree = null;
var dialogOptions = $scope.model;
$scope.treeReady = false;
$scope.dialogTreeEventHandler = $({});
$scope.section = dialogOptions.section;
$scope.treeAlias = dialogOptions.treeAlias;
$scope.multiPicker = dialogOptions.multiPicker;
$scope.hideHeader = true;
$scope.searchInfo = {
searchFromId: dialogOptions.startNodeId,
searchFromName: null,
@@ -17,80 +18,81 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
selectedSearchResults: []
}
$scope.model.selection = [];
$scope.model.selection = [];
$scope.init = function(contentType) {
//TODO: I don't think this is used or called anywhere!!
$scope.init = function (contentType) {
if(contentType === "content") {
$scope.entityType = "Document";
if(!$scope.model.title) {
$scope.model.title = localizationService.localize("defaultdialogs_selectContent");
}
} else if(contentType === "member") {
$scope.entityType = "Member";
if(!$scope.model.title) {
$scope.model.title = localizationService.localize("defaultdialogs_selectMember");
}
} else if(contentType === "media") {
$scope.entityType = "Media";
if(!$scope.model.title) {
$scope.model.title = localizationService.localize("defaultdialogs_selectMedia");
}
}
}
if (contentType === "content") {
$scope.entityType = "Document";
if (!$scope.model.title) {
$scope.model.title = localizationService.localize("defaultdialogs_selectContent");
}
} else if (contentType === "member") {
$scope.entityType = "Member";
if (!$scope.model.title) {
$scope.model.title = localizationService.localize("defaultdialogs_selectMember");
}
} else if (contentType === "media") {
$scope.entityType = "Media";
if (!$scope.model.title) {
$scope.model.title = localizationService.localize("defaultdialogs_selectMedia");
}
}
}
//create the custom query string param for this tree
$scope.customTreeParams = dialogOptions.startNodeId ? "startNodeId=" + dialogOptions.startNodeId : "";
$scope.customTreeParams += dialogOptions.customTreeParams ? "&" + dialogOptions.customTreeParams : "";
var searchText = "Search...";
localizationService.localize("general_search").then(function (value) {
searchText = value + "...";
});
var searchText = "Search...";
localizationService.localize("general_search").then(function (value) {
searchText = value + "...";
});
// Allow the entity type to be passed in but defaults to Document for backwards compatibility.
$scope.entityType = dialogOptions.entityType ? dialogOptions.entityType : "Document";
$scope.entityType = dialogOptions.entityType ? dialogOptions.entityType : "Document";
//min / max values
if (dialogOptions.minNumber) {
dialogOptions.minNumber = parseInt(dialogOptions.minNumber, 10);
}
if (dialogOptions.maxNumber) {
dialogOptions.maxNumber = parseInt(dialogOptions.maxNumber, 10);
}
//min / max values
if (dialogOptions.minNumber) {
dialogOptions.minNumber = parseInt(dialogOptions.minNumber, 10);
}
if (dialogOptions.maxNumber) {
dialogOptions.maxNumber = parseInt(dialogOptions.maxNumber, 10);
}
if (dialogOptions.section === "member") {
$scope.entityType = "Member";
}
else if (dialogOptions.section === "media") {
$scope.entityType = "Media";
}
if (dialogOptions.section === "member") {
$scope.entityType = "Member";
}
else if (dialogOptions.section === "media") {
$scope.entityType = "Media";
}
// Search and listviews is only working for content, media and member section so we will remove it from everything else
if ($scope.section === "content" || $scope.section === "media" || $scope.section === "member") {
$scope.enableSearh = true;
// Search and listviews is only working for content, media and member section
var searchableSections = ["content", "media", "member"];
//if a alternative startnode is used, we need to check if it is a container
if (dialogOptions.startNodeId && dialogOptions.startNodeId !== -1 && dialogOptions.startNodeId !== "-1") {
entityResource.getById(dialogOptions.startNodeId, $scope.entityType).then(function (node) {
if (node.metaData.IsContainer) {
openMiniListView(node);
}
});
}
}
$scope.enableSearh = searchableSections.indexOf($scope.section) !== -1;
//Configures filtering
if (dialogOptions.filter) {
//if a alternative startnode is used, we need to check if it is a container
if ($scope.enableSearh && dialogOptions.startNodeId && dialogOptions.startNodeId !== -1 && dialogOptions.startNodeId !== "-1") {
entityResource.getById(dialogOptions.startNodeId, $scope.entityType).then(function(node) {
if (node.metaData.IsContainer) {
openMiniListView(node);
}
initTree();
});
}
else {
initTree();
}
dialogOptions.filterExclude = false;
dialogOptions.filterAdvanced = false;
//Configures filtering
if (dialogOptions.filter) {
//used advanced filtering
if (angular.isFunction(dialogOptions.filter)) {
dialogOptions.filterAdvanced = true;
}
dialogOptions.filterExclude = false;
dialogOptions.filterAdvanced = false;
//used advanced filtering
if (angular.isFunction(dialogOptions.filter)) {
dialogOptions.filterAdvanced = true;
}
else if (angular.isObject(dialogOptions.filter)) {
dialogOptions.filterAdvanced = true;
}
@@ -107,44 +109,51 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
dialogOptions.filter = angular.fromJson(dialogOptions.filter);
}
}
}
}
function nodeExpandedHandler(ev, args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
openMiniListView(args.node);
}
if (angular.isArray(args.children)) {
function initTree() {
//create the custom query string param for this tree
$scope.customTreeParams = dialogOptions.startNodeId ? "startNodeId=" + dialogOptions.startNodeId : "";
$scope.customTreeParams += dialogOptions.customTreeParams ? "&" + dialogOptions.customTreeParams : "";
$scope.treeReady = true;
}
function nodeExpandedHandler(ev, args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
openMiniListView(args.node);
}
if (angular.isArray(args.children)) {
//iterate children
_.each(args.children, function (child) {
_.each(args.children, function (child) {
//now we need to look in the already selected search results and
// toggle the check boxes for those ones that are listed
var exists = _.find($scope.searchInfo.selectedSearchResults, function (selected) {
return child.id == selected.id;
});
if (exists) {
child.selected = true;
}
});
//now we need to look in the already selected search results and
// toggle the check boxes for those ones that are listed
var exists = _.find($scope.searchInfo.selectedSearchResults, function (selected) {
return child.id == selected.id;
});
if (exists) {
child.selected = true;
}
});
//check filter
performFiltering(args.children);
}
}
//check filter
performFiltering(args.children);
}
}
//gets the tree object when it loads
function treeLoadedHandler(ev, args) {
tree = args.tree;
}
function treeLoadedHandler(ev, args) {
tree = args.tree;
}
//wires up selection
function nodeSelectHandler(ev, args) {
args.event.preventDefault();
args.event.stopPropagation();
//wires up selection
function nodeSelectHandler(ev, args) {
args.event.preventDefault();
args.event.stopPropagation();
if (args.node.metaData.isSearchResult) {
//check if the item selected was a search result from a list view
@@ -154,15 +163,15 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
//remove it from the list view children
var listView = args.node.parent();
listView.children = _.reject(listView.children, function(child) {
return child.id == args.node.id;
});
listView.children = _.reject(listView.children, function (child) {
return child.id == args.node.id;
});
//remove it from the custom tracked search result list
$scope.searchInfo.selectedSearchResults = _.reject($scope.searchInfo.selectedSearchResults, function (i) {
return i.id == args.node.id;
});
}
$scope.searchInfo.selectedSearchResults = _.reject($scope.searchInfo.selectedSearchResults, function (i) {
return i.id == args.node.id;
});
}
else {
eventsService.emit("dialogs.treePickerController.select", args);
@@ -172,194 +181,194 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
//This is a tree node, so we don't have an entity to pass in, it will need to be looked up
//from the server in this method.
if($scope.model.select){
$scope.model.select(args.node)
}else{
select(args.node.name, args.node.id);
//toggle checked state
args.node.selected = args.node.selected === true ? false : true;
}
if ($scope.model.select) {
$scope.model.select(args.node)
} else {
select(args.node.name, args.node.id);
//toggle checked state
args.node.selected = args.node.selected === true ? false : true;
}
}
}
}
/** Method used for selecting a node */
function select(text, id, entity) {
//if we get the root, we just return a constructed entity, no need for server data
if (id < 0) {
if ($scope.multiPicker) {
/** Method used for selecting a node */
function select(text, id, entity) {
//if we get the root, we just return a constructed entity, no need for server data
if (id < 0) {
if ($scope.multiPicker) {
if (entity) {
multiSelectItem(entity);
} else {
//otherwise we have to get it from the server
entityResource.getById(id, $scope.entityType).then(function (ent) {
multiSelectItem(ent);
});
}
if (entity) {
multiSelectItem(entity);
} else {
//otherwise we have to get it from the server
entityResource.getById(id, $scope.entityType).then(function (ent) {
multiSelectItem(ent);
});
}
}
else {
var node = {
alias: null,
icon: "icon-folder",
id: id,
name: text
};
$scope.model.selection.push(node);
$scope.model.submit($scope.model);
}
}
else {
}
else {
var node = {
alias: null,
icon: "icon-folder",
id: id,
name: text
};
$scope.model.selection.push(node);
$scope.model.submit($scope.model);
}
}
else {
if ($scope.multiPicker) {
if ($scope.multiPicker) {
if (entity) {
multiSelectItem(entity);
} else {
//otherwise we have to get it from the server
entityResource.getById(id, $scope.entityType).then(function (ent) {
multiSelectItem(ent);
});
}
if (entity) {
multiSelectItem(entity);
} else {
//otherwise we have to get it from the server
entityResource.getById(id, $scope.entityType).then(function (ent) {
multiSelectItem(ent);
});
}
}
}
else {
else {
$scope.hideSearch();
$scope.hideSearch();
//if an entity has been passed in, use it
if (entity) {
$scope.model.selection.push(entity);
$scope.model.submit($scope.model);
} else {
//otherwise we have to get it from the server
entityResource.getById(id, $scope.entityType).then(function (ent) {
$scope.model.selection.push(ent);
$scope.model.submit($scope.model);
});
}
}
}
}
//if an entity has been passed in, use it
if (entity) {
$scope.model.selection.push(entity);
$scope.model.submit($scope.model);
} else {
//otherwise we have to get it from the server
entityResource.getById(id, $scope.entityType).then(function (ent) {
$scope.model.selection.push(ent);
$scope.model.submit($scope.model);
});
}
}
}
}
function multiSelectItem(item) {
function multiSelectItem(item) {
var found = false;
var foundIndex = 0;
var found = false;
var foundIndex = 0;
if($scope.model.selection.length > 0) {
for(i = 0; $scope.model.selection.length > i; i++) {
var selectedItem = $scope.model.selection[i];
if(selectedItem.id === item.id) {
found = true;
foundIndex = i;
}
}
}
if ($scope.model.selection.length > 0) {
for (i = 0; $scope.model.selection.length > i; i++) {
var selectedItem = $scope.model.selection[i];
if (selectedItem.id === item.id) {
found = true;
foundIndex = i;
}
}
}
if(found) {
$scope.model.selection.splice(foundIndex, 1);
} else {
$scope.model.selection.push(item);
}
if (found) {
$scope.model.selection.splice(foundIndex, 1);
} else {
$scope.model.selection.push(item);
}
}
}
function performFiltering(nodes) {
function performFiltering(nodes) {
if (!dialogOptions.filter) {
return;
}
if (!dialogOptions.filter) {
return;
}
//remove any list view search nodes from being filtered since these are special nodes that always must
// be allowed to be clicked on
nodes = _.filter(nodes, function(n) {
return !angular.isObject(n.metaData.listViewNode);
});
//remove any list view search nodes from being filtered since these are special nodes that always must
// be allowed to be clicked on
nodes = _.filter(nodes, function (n) {
return !angular.isObject(n.metaData.listViewNode);
});
if (dialogOptions.filterAdvanced) {
if (dialogOptions.filterAdvanced) {
//filter either based on a method or an object
var filtered = angular.isFunction(dialogOptions.filter)
? _.filter(nodes, dialogOptions.filter)
: _.where(nodes, dialogOptions.filter);
var filtered = angular.isFunction(dialogOptions.filter)
? _.filter(nodes, dialogOptions.filter)
: _.where(nodes, dialogOptions.filter);
angular.forEach(filtered, function (value, key) {
value.filtered = true;
if (dialogOptions.filterCssClass) {
angular.forEach(filtered, function (value, key) {
value.filtered = true;
if (dialogOptions.filterCssClass) {
if (!value.cssClasses) {
value.cssClasses = [];
}
value.cssClasses.push(dialogOptions.filterCssClass);
}
});
} else {
var a = dialogOptions.filter.toLowerCase().replace(/\s/g, '').split(',');
angular.forEach(nodes, function (value, key) {
value.cssClasses.push(dialogOptions.filterCssClass);
}
});
} else {
var a = dialogOptions.filter.toLowerCase().replace(/\s/g, '').split(',');
angular.forEach(nodes, function (value, key) {
var found = a.indexOf(value.metaData.contentType.toLowerCase()) >= 0;
var found = a.indexOf(value.metaData.contentType.toLowerCase()) >= 0;
if (!dialogOptions.filterExclude && !found || dialogOptions.filterExclude && found) {
value.filtered = true;
if (!dialogOptions.filterExclude && !found || dialogOptions.filterExclude && found) {
value.filtered = true;
if (dialogOptions.filterCssClass) {
if (!value.cssClasses) {
value.cssClasses = [];
}
value.cssClasses.push(dialogOptions.filterCssClass);
}
}
});
}
}
if (dialogOptions.filterCssClass) {
if (!value.cssClasses) {
value.cssClasses = [];
}
value.cssClasses.push(dialogOptions.filterCssClass);
}
}
});
}
}
$scope.multiSubmit = function (result) {
entityResource.getByIds(result, $scope.entityType).then(function (ents) {
$scope.submit(ents);
});
};
$scope.multiSubmit = function (result) {
entityResource.getByIds(result, $scope.entityType).then(function (ents) {
$scope.submit(ents);
});
};
/** method to select a search result */
$scope.selectResult = function (evt, result) {
/** method to select a search result */
$scope.selectResult = function (evt, result) {
if (result.filtered) {
return;
}
result.selected = result.selected === true ? false : true;
result.selected = result.selected === true ? false : true;
//since result = an entity, we'll pass it in so we don't have to go back to the server
select(result.name, result.id, result);
//since result = an entity, we'll pass it in so we don't have to go back to the server
select(result.name, result.id, result);
//add/remove to our custom tracked list of selected search results
//add/remove to our custom tracked list of selected search results
if (result.selected) {
$scope.searchInfo.selectedSearchResults.push(result);
}
else {
$scope.searchInfo.selectedSearchResults = _.reject($scope.searchInfo.selectedSearchResults, function(i) {
$scope.searchInfo.selectedSearchResults = _.reject($scope.searchInfo.selectedSearchResults, function (i) {
return i.id == result.id;
});
}
//ensure the tree node in the tree is checked/unchecked if it already exists there
if (tree) {
var found = treeService.getDescendantNode(tree.root, result.id);
//ensure the tree node in the tree is checked/unchecked if it already exists there
if (tree) {
var found = treeService.getDescendantNode(tree.root, result.id);
if (found) {
found.selected = result.selected;
}
}
}
};
};
$scope.hideSearch = function () {
$scope.hideSearch = function () {
//Traverse the entire displayed tree and update each node to sync with the selected search results
if (tree) {
if (tree) {
//we need to ensure that any currently displayed nodes that get selected
// from the search get updated to have a check box!
//we need to ensure that any currently displayed nodes that get selected
// from the search get updated to have a check box!
function checkChildren(children) {
_.each(children, function (child) {
//check if the id is in the selection, if so ensure it's flagged as selected
@@ -376,7 +385,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
// to the tree dynamically under the list view that was searched, so we actually want to remove
// it all together from the tree
var listView = child.parent();
listView.children = _.reject(listView.children, function(c) {
listView.children = _.reject(listView.children, function (c) {
return c.id == child.id;
});
}
@@ -385,7 +394,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
// that need to be added as child nodes to it based on search results selected
if (child.metaData.isContainer) {
child.cssClasses = _.reject(child.cssClasses, function(c) {
child.cssClasses = _.reject(child.cssClasses, function (c) {
return c === 'tree-node-slide-up-hide-active';
});
@@ -393,7 +402,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
return i.parentId == child.id;
});
_.each(listViewResults, function (item) {
var childExists = _.find(child.children, function(c) {
var childExists = _.find(child.children, function (c) {
return c.id == item.id;
});
if (!childExists) {
@@ -422,7 +431,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
});
}
checkChildren(tree.root.children);
}
}
$scope.searchInfo.showSearch = false;
@@ -431,53 +440,53 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
$scope.searchInfo.results = [];
}
$scope.onSearchResults = function(results) {
$scope.onSearchResults = function (results) {
//filter all items - this will mark an item as filtered
performFiltering(results);
performFiltering(results);
//now actually remove all filtered items so they are not even displayed
results = _.filter(results, function(item) {
return !item.filtered;
});
//now actually remove all filtered items so they are not even displayed
results = _.filter(results, function (item) {
return !item.filtered;
});
$scope.searchInfo.results = results;
$scope.searchInfo.results = results;
//sync with the curr selected results
_.each($scope.searchInfo.results, function (result) {
var exists = _.find($scope.model.selection, function (selectedId) {
return result.id == selectedId;
});
if (exists) {
result.selected = true;
}
});
_.each($scope.searchInfo.results, function (result) {
var exists = _.find($scope.model.selection, function (selectedId) {
return result.id == selectedId;
});
if (exists) {
result.selected = true;
}
});
$scope.searchInfo.showSearch = true;
};
$scope.searchInfo.showSearch = true;
};
$scope.dialogTreeEventHandler.bind("treeLoaded", treeLoadedHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.bind("treeLoaded", treeLoadedHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeLoaded", treeLoadedHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeLoaded", treeLoadedHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
$scope.selectListViewNode = function(node) {
select(node.name, node.id);
$scope.selectListViewNode = function (node) {
select(node.name, node.id);
//toggle checked state
node.selected = node.selected === true ? false : true;
};
};
$scope.closeMiniListView = function() {
$scope.miniListView = undefined;
};
$scope.closeMiniListView = function () {
$scope.miniListView = undefined;
};
function openMiniListView(node) {
$scope.miniListView = node;
}
function openMiniListView(node) {
$scope.miniListView = node;
}
});
});
@@ -20,7 +20,7 @@
select-result-callback="selectResult">
</umb-tree-search-results>
<div ng-hide="searchInfo.showSearch" ng-animate="'tree-fade-out'">
<div ng-if="treeReady" ng-hide="searchInfo.showSearch" ng-animate="'tree-fade-out'">
<umb-tree
section="{{section}}"
treealias="{{treeAlias}}"
@@ -51,7 +51,7 @@
</umb-file-dropzone>
<umb-folder-grid
ng-if="folders.length > 0 && !vm.isRecycleBin"
ng-if="folders.length > 0"
folders="folders"
on-click="vm.selectFolder"
on-click-name="vm.goToItem">
@@ -37,7 +37,8 @@
function activate() {
vm.itemsWithoutFolders = filterOutFolders($scope.items);
if($scope.entityType === 'media') {
//no need to make another REST/DB call if this data is not used when we are browsing the bin
if ($scope.entityType === 'media' && !vm.isRecycleBin) {
mediaTypeHelper.getAllowedImagetypes(vm.nodeId).then(function (types) {
vm.acceptedMediatypes = types;
});
@@ -53,7 +53,9 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
$scope.isNew = false;
$scope.actionInProgress = false;
$scope.selection = [];
$scope.folders = [];
$scope.folders = [];
//tracks if we've already loaded the folders for the current node
var foldersLoaded = false;
$scope.listViewResultSet = {
totalPages: 0,
items: []
@@ -268,12 +270,13 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
});
}
if ($scope.entityType === 'media') {
if (!foldersLoaded && $scope.entityType === 'media') {
//The folders aren't loaded - we only need to do this once since we're never changing node ids
mediaResource.getChildFolders($scope.contentId)
.then(function (folders) {
$scope.folders = folders;
$scope.viewLoaded = true;
foldersLoaded = true;
});
} else {
@@ -19,13 +19,13 @@
$scope.hasError = false;
$scope.internal = function($event) {
$scope.currentEditLink = null;
$scope.contentPickerOverlay = {};
$scope.contentPickerOverlay.view = "contentpicker";
$scope.contentPickerOverlay.multiPicker = false;
$scope.contentPickerOverlay.show = true;
$scope.contentPickerOverlay.idType = $scope.model.config.idType ? $scope.model.config.idType : "int";
$scope.contentPickerOverlay.submit = function(model) {
@@ -43,14 +43,14 @@
$event.preventDefault();
};
$scope.selectInternal = function($event, link) {
$scope.selectInternal = function ($event, link) {
$scope.currentEditLink = link;
$scope.contentPickerOverlay = {};
$scope.contentPickerOverlay.view = "contentpicker";
$scope.contentPickerOverlay.multiPicker = false;
$scope.contentPickerOverlay.show = true;
$scope.contentPickerOverlay.idType = $scope.model.config.idType ? $scope.model.config.idType : "int";
$scope.contentPickerOverlay.submit = function(model) {
@@ -223,12 +223,12 @@
function select(data) {
if ($scope.currentEditLink != null) {
$scope.currentEditLink.internal = data.id;
$scope.currentEditLink.internal = $scope.model.config.idType === "udi" ? data.udi : data.id;
$scope.currentEditLink.internalName = data.name;
$scope.currentEditLink.internalIcon = iconHelper.convertFromLegacyIcon(data.icon);
$scope.currentEditLink.link = data.id;
$scope.currentEditLink.link = $scope.model.config.idType === "udi" ? data.udi : data.id;
} else {
$scope.newInternal = data.id;
$scope.newInternal = $scope.model.config.idType === "udi" ? data.udi : data.id;
$scope.newInternalName = data.name;
$scope.newInternalIcon = iconHelper.convertFromLegacyIcon(data.icon);
}
-8
View File
@@ -352,10 +352,6 @@
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.5\lib\Umbraco.ModelsBuilder.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="UrlRewritingNet.UrlRewriter, Version=2.0.7.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\UrlRewritingNet.UrlRewriter.2.0.7\lib\UrlRewritingNet.UrlRewriter.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SolutionInfo.cs">
@@ -659,9 +655,6 @@
<None Include="Config\EmbeddedMedia.Release.config">
<DependentUpon>EmbeddedMedia.config</DependentUpon>
</None>
<None Include="Config\UrlRewriting.Release.config">
<DependentUpon>UrlRewriting.config</DependentUpon>
</None>
<None Include="Config\umbracoSettings.Release.config">
<DependentUpon>umbracoSettings.config</DependentUpon>
<SubType>Designer</SubType>
@@ -2375,7 +2368,6 @@
<Content Include="Config\umbracoSettings.config">
<SubType>Designer</SubType>
</Content>
<Content Include="Config\UrlRewriting.config" />
<Content Include="Config\log4net.config" />
<Content Include="Config\FileSystemProviders.config" />
<Content Include="Config\EmbeddedMedia.config" />
+20 -20
View File
@@ -10,6 +10,16 @@
</control>
</tab>
</section>
<section alias="StartupFormsDashboardSection">
<areas>
<area>forms</area>
</areas>
<tab caption="Install Umbraco Forms">
<control showOnce="true" addPanel="true" panelCaption="">
views/dashboard/forms/formsdashboardintro.html
</control>
</tab>
</section>
<section alias="StartupDeveloperDashboardSection">
<areas>
<area>developer</area>
@@ -35,6 +45,16 @@
</control>
</tab>
</section>
<section alias="StartupFormsDashboardSection">
<areas>
<area>forms</area>
</areas>
<tab caption="Install Umbraco Forms">
<control showOnce="true" addPanel="true" panelCaption="">
views/dashboard/forms/formsdashboardintro.html
</control>
</tab>
</section>
<section alias="StartupDashboardSection">
<access>
<deny>translator</deny>
@@ -99,24 +119,4 @@
</control>
</tab>
</section>
<section alias="Deploy">
<areas>
<area>content</area>
</areas>
<tab caption="Deploy">
<control>
/App_Plugins/Deploy/views/dashboards/dashboard.html
</control>
</tab>
</section>
<section alias="StartupFormsDashboardSection">
<areas>
<area>forms</area>
</areas>
<tab caption="Dashboard">
<control>/app_plugins/umbracoforms/backoffice/dashboards/licensing.html</control>
<control>/app_plugins/umbracoforms/backoffice/dashboards/yourforms.html</control>
<control>/app_plugins/umbracoforms/backoffice/dashboards/activity.html</control>
</tab>
</section>
</dashBoard>
@@ -8,11 +8,4 @@
</Parameters>
</Provider>
<!--
<Provider alias="forms" type="Umbraco.Core.IO.PhysicalFileSystem, Umbraco.Core">
<Parameters>
<add key="virtualRoot" value="~/App_Data/ZbForms" />
</Parameters>
</Provider>
-->
</FileSystemProviders>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<urlrewritingnet xmlns="http://www.urlrewriting.net/schemas/config/2006/07">
<rewrites>
<!--
URLRewriting.net is obsolete and will be removed from Umbraco in the future.
If you want to do rewrites, make sure to use IIS URL rewrite: https://www.iis.net/downloads/microsoft/url-rewrite
The advantage of using IIS rewrite is that it is much faster, much less CPU intensive and much less memory intensive.
-->
</rewrites>
</urlrewritingnet>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<urlrewritingnet xmlns="http://www.urlrewriting.net/schemas/config/2006/07">
<rewrites>
<!--
URLRewriting.net is obsolete and will be removed from Umbraco in the future.
If you want to do rewrites, make sure to use IIS URL rewrite: https://www.iis.net/downloads/microsoft/url-rewrite
The advantage of using IIS rewrite is that it is much faster, much less CPU intensive and much less memory intensive.
-->
</rewrites>
</urlrewritingnet>
@@ -51,7 +51,7 @@
<MacroErrors>throw</MacroErrors>
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>
@@ -100,7 +100,7 @@
<MacroErrors>throw</MacroErrors>
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>
-1
View File
@@ -38,5 +38,4 @@
<package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
<package id="System.Reflection.Metadata" version="1.0.21" targetFramework="net45" />
<package id="Umbraco.ModelsBuilder" version="3.0.5" targetFramework="net45" />
<package id="UrlRewritingNet.UrlRewriter" version="2.0.7" targetFramework="net45" />
</packages>
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<language alias="en" intName="English (UK)" localName="English (UK)" lcid="" culture="en-GB">
<creator>
<name>The Umbraco community</name>
@@ -40,7 +40,7 @@
<key alias="translate">Translate</key>
<key alias="update">Update</key>
<key alias="defaultValue">Default value</key>
<key alias="exportContourForm">Export form</key><key alias="importContourForm">Import form</key><key alias="archiveContourForm">Archive form</key><key alias="unarchiveContourForm">Unarchive form</key><key alias="defaultValue">Default value</key><key alias="exportContourForm">Export form</key><key alias="importContourForm">Import form</key><key alias="archiveContourForm">Archive form</key><key alias="unarchiveContourForm">Unarchive form</key><key alias="defaultValue">Default value</key></area>
</area>
<area alias="assignDomain">
<key alias="permissionDenied">Permission denied.</key>
<key alias="addNew">Add new Domain</key>
@@ -934,7 +934,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="help" version="7.0">Help</key>
<key alias="forms">Forms</key>
<key alias="analytics">Analytics</key>
<key alias="forms">Forms</key><key alias="forms">Forms</key></area>
</area>
<area alias="help">
<key alias="goTo">go to</key>
<key alias="helpTopicsFor">Help topics for</key>
@@ -1117,7 +1117,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="iWant">I want</key>
<key alias="allContent">all content</key>
<key alias="contentOfType">content of type "%0%"</key>
<key alias="contentOfType">content of type &quot;%0%&quot;</key>
<key alias="from">from</key>
<key alias="websiteRoot">my website</key>
<key alias="where">where</key>
@@ -87,7 +87,7 @@
<key alias="selectCurrentFolder">Välj aktuell mapp</key>
<key alias="showPage">Förhandsgranska</key>
<key alias="showPageDisabled">Förhandsgranskning är avstängt på grund av att det inte finns någon mall tilldelad</key>
<key alias="somethingElse">Ångra</key>
<key alias="somethingElse">Annat</key>
<key alias="styleChoose">Välj stil</key>
<key alias="styleShow">Visa stil</key>
<key alias="tableInsert">Infoga tabell</key>
@@ -171,6 +171,7 @@
<key alias="noDocumentTypes"><![CDATA[Det finns inga giltiga dokumenttyper tillgängliga. Du måste aktivera dessa under sektionen inställningar och under <strong>"dokumenttyper"</strong>.]]></key>
<key alias="noMediaTypes"><![CDATA[Det finns inga giltiga mediatyper tillgängliga. Du måste aktivera dessa under sektionen inställningar och under <strong>"mediatyper"</strong>.]]></key>
<key alias="updateData">Välj typ och rubrik</key>
<key alias="documentTypeWithoutTemplate">Dokumenttyp utan sidmall</key>
</area>
<area alias="dashboard">
<key alias="browser">Surfa på din webbplats</key>
@@ -936,4 +937,4 @@
<key alias="translator">Översättare</key>
<key alias="yourProfile">Din profil</key>
</area>
</language>
</language>
@@ -17,6 +17,8 @@
<configSections>
<section name="urlrewritingnet" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<section name="Examine" xdt:Locator="Match(name)" xdt:Transform="SetAttributes(type)" />
<section name="ExamineLuceneIndexSets" xdt:Locator="Match(name)" xdt:Transform="SetAttributes(type)" />
@@ -35,6 +37,8 @@
</configSections>
<urlrewritingnet xdt:Transform="Remove" />
<BaseRestExtensions xdt:Transform="Remove" />
<FileSystemProviders xdt:Transform="Remove" />
<umbracoConfiguration xdt:Transform="Remove" />
@@ -101,6 +105,9 @@
</assemblies>
</compilation>
<httpModules>
<add name="UrlRewriteModule" xdt:Transform="Remove" xdt:Locator="Match(name)" />
</httpModules>
<httpHandlers>
<add path="GoogleSpellChecker.ashx" xdt:Transform="Remove" xdt:Locator="Match(path)" />
</httpHandlers>
@@ -310,6 +317,10 @@
<system.codedom xdt:Transform="Remove" />
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="UrlRewriteModule" xdt:Transform="Remove" xdt:Locator="Match(name)" />
<add name="UrlRewriteModule" xdt:Transform="Remove" xdt:Locator="Match(name)" />
</modules>
<handlers>
<remove name="SpellChecker" xdt:Transform="Remove" xdt:Locator="Match(name)" />
<add name="SpellChecker" xdt:Transform="Remove" xdt:Locator="Match(name)" />
+12 -7
View File
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="urlrewritingnet" restartOnExternalChanges="true" requirePermission="false" type="UrlRewritingNet.Configuration.UrlRewriteSection, UrlRewritingNet.UrlRewriter" />
<section name="microsoft.scripting" type="Microsoft.Scripting.Hosting.Configuration.Section, Microsoft.Scripting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" />
<section name="clientDependency" type="ClientDependency.Core.Config.ClientDependencySection, ClientDependency.Core" requirePermission="false" />
<section name="Examine" type="Examine.Config.ExamineSettings, Examine" requirePermission="false" />
@@ -29,7 +28,6 @@
<dashBoard configSource="config\Dashboard.config" />
</umbracoConfiguration>
<urlrewritingnet configSource="config\UrlRewriting.config" />
<microsoft.scripting configSource="config\scripting.config" />
<clientDependency configSource="config\ClientDependency.config" />
<Examine configSource="config\ExamineSettings.config" />
@@ -109,7 +107,6 @@
</controls>
</pages>
<httpModules>
<add name="UrlRewriteModule" type="UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter" />
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,umbraco" />
<add name="ClientDependencyModule" type="ClientDependency.Core.Module.ClientDependencyModule, ClientDependency.Core" />
@@ -274,9 +271,6 @@
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule" />
<remove name="UrlRewriteModule" />
<add name="UrlRewriteModule" type="UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter" />
<remove name="UmbracoModule" />
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,umbraco" />
@@ -346,7 +340,17 @@
<requestLimits maxAllowedContentLength="52428800" />
</requestFiltering>
</security>
<!--
If you wish to use IIS rewrite rules, see the documentation here:
https://our.umbraco.org/documentation/Reference/Routing/IISRewriteRules
-->
<!--
<rewrite>
<rules></rules>
</rewrite>
-->
</system.webServer>
<runtime>
@@ -448,4 +452,5 @@
<caching configSource="config\imageprocessor\cache.config" />
<processing configSource="config\imageprocessor\processing.config" />
</imageProcessor>
</configuration>
@@ -5,30 +5,17 @@ using System.Globalization;
using System.Net;
using System.Text;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using AutoMapper;
using ClientDependency.Core;
using Examine.LuceneEngine;
using Examine.LuceneEngine.Providers;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using System.Linq;
using System.Net.Http;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models;
using Umbraco.Web.WebApi.Filters;
using umbraco.cms.businesslogic.packager;
using Constants = Umbraco.Core.Constants;
using Examine;
using Examine.LuceneEngine.SearchCriteria;
using Examine.SearchCriteria;
using Umbraco.Web.Dynamics;
using umbraco;
using System.Text.RegularExpressions;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using System.Web.Http.Controllers;
+33 -13
View File
@@ -6,39 +6,30 @@ using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Dynamics;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Editors;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Services;
using Umbraco.Web.Models;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Models.Mapping;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using System.Linq;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using System.Web.Http.Controllers;
using Examine;
using Umbraco.Web.WebApi.Binders;
using Umbraco.Web.WebApi.Filters;
using umbraco;
using umbraco.BusinessLogic.Actions;
using Constants = Umbraco.Core.Constants;
using Umbraco.Core.Configuration;
using Umbraco.Core.Persistence.FaultHandling;
using Umbraco.Web.UI;
using Notification = Umbraco.Web.Models.ContentEditing.Notification;
using Umbraco.Core.Persistence;
@@ -163,19 +154,48 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Returns media items known to be a container of other media items
/// Returns media items known to be of a "Folder" type
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[Obsolete("This is no longer used and shouldn't be because it performs poorly when there are a lot of media items")]
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>>))]
public IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildFolders(int id = -1)
{
//we are only allowing a max of 500 to be returned here, if more is required it needs to be paged
var result = GetChildFolders(id, 1, 500);
return result.Items;
}
/// <summary>
/// Returns a paged result of media items known to be of a "Folder" type
/// </summary>
/// <param name="id"></param>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildFolders(int id, int pageNumber, int pageSize)
{
//Suggested convention for folder mediatypes - we can make this more or less complicated as long as we document it...
//if you create a media type, which has an alias that ends with ...Folder then its a folder: ex: "secureFolder", "bannerFolder", "Folder"
var folderTypes = Services.ContentTypeService.GetAllMediaTypes().ToArray().Where(x => x.Alias.EndsWith("Folder")).Select(x => x.Id);
var folderTypes = Services.ContentTypeService
.GetAllMediaTypes()
.Where(x => x.Alias.EndsWith("Folder"))
.Select(x => x.Id)
.ToArray();
var children = (id < 0) ? Services.MediaService.GetRootMedia() : Services.MediaService.GetById(id).Children();
return children.Where(x => folderTypes.Contains(x.ContentTypeId)).Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic, IMedia>>);
if (folderTypes.Length == 0)
{
return new PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>>(0, pageNumber, pageSize);
}
long total;
var children = Services.MediaService.GetPagedChildren(id, pageNumber - 1, pageSize, out total, "Name", Direction.Ascending, true, null, folderTypes.ToArray());
return new PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>>(total, pageNumber, pageSize)
{
Items = children.Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic, IMedia>>)
};
}
/// <summary>
@@ -103,7 +103,7 @@ namespace Umbraco.Web.HealthCheck.Checks.DataIntegrity
/// </remarks>
private HealthCheckStatus CheckMedia()
{
var total = _services.MediaService.Count();
var total = _services.MediaService.CountNotTrashed();
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
//count entries
@@ -10,9 +10,6 @@ namespace Umbraco.Web.Models
/// <summary>
/// The password value
/// </summary>
/// <remarks>
/// This
/// </remarks>
[DataMember(Name = "newPassword")]
public string NewPassword { get; set; }
@@ -40,4 +37,4 @@ namespace Umbraco.Web.Models
[DataMember(Name = "generatedPassword")]
public string GeneratedPassword { get; set; }
}
}
}
@@ -0,0 +1,63 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// Content property editor that stores UDI
/// </summary>
[PropertyEditor(Constants.PropertyEditors.ContentPicker2Alias, "Content Picker", PropertyEditorValueTypes.String, "contentpicker", IsParameterEditor = true, Group = "Pickers")]
public class ContentPicker2PropertyEditor : PropertyEditor
{
public ContentPicker2PropertyEditor()
{
InternalPreValues = new Dictionary<string, object>
{
{"startNodeId", "-1"},
{"showOpenButton", "0"},
{"showEditButton", "0"},
{"showPathOnHover", "0"},
{"idType", "udi"}
};
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
protected override PreValueEditor CreatePreValueEditor()
{
return new ContentPickerPreValueEditor();
}
internal class ContentPickerPreValueEditor : PreValueEditor
{
public ContentPickerPreValueEditor()
{
//create the fields
Fields.Add(new PreValueField()
{
Key = "showOpenButton",
View = "boolean",
Name = "Show open button (this feature is in preview!)",
Description = "Opens the node in a dialog"
});
Fields.Add(new PreValueField()
{
Key = "startNodeId",
View = "treepicker",
Name = "Start node",
Config = new Dictionary<string, object>
{
{"idType", "udi"}
}
});
}
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
@@ -12,7 +11,7 @@ namespace Umbraco.Web.PropertyEditors
/// </summary>
[Obsolete("This editor is obsolete, use ContentPickerPropertyEditor2 instead which stores UDI")]
[PropertyEditor(Constants.PropertyEditors.ContentPickerAlias, "(Obsolete) Content Picker", PropertyEditorValueTypes.Integer, "contentpicker", IsParameterEditor = true, Group = "Pickers", IsDeprecated = true)]
public class ContentPickerPropertyEditor : ContentPickerPropertyEditor2
public class ContentPickerPropertyEditor : ContentPicker2PropertyEditor
{
public ContentPickerPropertyEditor()
{
@@ -30,61 +29,4 @@ namespace Umbraco.Web.PropertyEditors
return preValEditor;
}
}
/// <summary>
/// Content property editor that stores UDI
/// </summary>
[PropertyEditor(Constants.PropertyEditors.ContentPicker2Alias, "Content Picker", PropertyEditorValueTypes.String, "contentpicker", IsParameterEditor = true, Group = "Pickers")]
public class ContentPickerPropertyEditor2 : PropertyEditor
{
public ContentPickerPropertyEditor2()
{
InternalPreValues = new Dictionary<string, object>
{
{"startNodeId", "-1"},
{"showOpenButton", "0"},
{"showEditButton", "0"},
{"showPathOnHover", "0"},
{"idType", "udi"}
};
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
protected override PreValueEditor CreatePreValueEditor()
{
return new ContentPickerPreValueEditor();
}
internal class ContentPickerPreValueEditor : PreValueEditor
{
public ContentPickerPreValueEditor()
{
//create the fields
Fields.Add(new PreValueField()
{
Key = "showOpenButton",
View = "boolean",
Name = "Show open button (this feature is in preview!)",
Description = "Opens the node in a dialog"
});
Fields.Add(new PreValueField()
{
Key = "startNodeId",
View = "treepicker",
Name = "Start node",
Config = new Dictionary<string, object>
{
{"idType", "udi"}
}
});
}
}
}
}
@@ -0,0 +1,72 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
/// <summary>
/// Media picker property editors that stores UDI
/// </summary>
[PropertyEditor(Constants.PropertyEditors.MediaPicker2Alias, "Media Picker", PropertyEditorValueTypes.Text, "mediapicker", Group = "media", Icon = "icon-picture")]
public class MediaPicker2PropertyEditor : PropertyEditor
{
public MediaPicker2PropertyEditor()
{
InternalPreValues = new Dictionary<string, object>
{
{"idType", "udi"}
};
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
protected override PreValueEditor CreatePreValueEditor()
{
return new MediaPickerPreValueEditor();
}
internal class MediaPickerPreValueEditor : PreValueEditor
{
public MediaPickerPreValueEditor()
{
//create the fields
Fields.Add(new PreValueField()
{
Key = "multiPicker",
View = "boolean",
Name = "Pick multiple items"
});
Fields.Add(new PreValueField()
{
Key = "onlyImages",
View = "boolean",
Name = "Pick only images",
Description = "Only let the editor choose images from media."
});
Fields.Add(new PreValueField()
{
Key = "disableFolderSelect",
View = "boolean",
Name = "Disable folder select",
Description = "Do not allow folders to be picked."
});
Fields.Add(new PreValueField()
{
Key = "startNodeId",
View = "mediapicker",
Name = "Start node",
Config = new Dictionary<string, object>
{
{"idType", "udi"}
}
});
}
}
}
}
@@ -12,9 +12,9 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Legacy media property editor that stores Integer Ids
/// </summary>
[Obsolete("This editor is obsolete, use ContentPickerPropertyEditor2 instead which stores UDI")]
[Obsolete("This editor is obsolete, use ContentPicker2PropertyEditor instead which stores UDI")]
[PropertyEditor(Constants.PropertyEditors.MediaPickerAlias, "(Obsolete) Media Picker", PropertyEditorValueTypes.Integer, "mediapicker", Group = "media", Icon = "icon-picture", IsDeprecated = true)]
public class MediaPickerPropertyEditor : MediaPickerPropertyEditor2
public class MediaPickerPropertyEditor : MediaPicker2PropertyEditor
{
public MediaPickerPropertyEditor()
{
@@ -37,70 +37,4 @@ namespace Umbraco.Web.PropertyEditors
public int StartNodeId { get; set; }
}
}
/// <summary>
/// Media picker property editors that stores UDI
/// </summary>
[PropertyEditor(Constants.PropertyEditors.MediaPicker2Alias, "Media Picker", PropertyEditorValueTypes.Text, "mediapicker", Group = "media", Icon = "icon-picture")]
public class MediaPickerPropertyEditor2 : PropertyEditor
{
public MediaPickerPropertyEditor2()
{
InternalPreValues = new Dictionary<string, object>
{
{"idType", "udi"}
};
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
protected override PreValueEditor CreatePreValueEditor()
{
return new MediaPickerPreValueEditor();
}
internal class MediaPickerPreValueEditor : PreValueEditor
{
public MediaPickerPreValueEditor()
{
//create the fields
Fields.Add(new PreValueField()
{
Key = "multiPicker",
View = "boolean",
Name = "Pick multiple items"
});
Fields.Add(new PreValueField()
{
Key = "onlyImages",
View = "boolean",
Name = "Pick only images",
Description = "Only let the editor choose images from media."
});
Fields.Add(new PreValueField()
{
Key = "disableFolderSelect",
View = "boolean",
Name = "Disable folder select",
Description = "Do not allow folders to be picked."
});
Fields.Add(new PreValueField()
{
Key = "startNodeId",
View = "mediapicker",
Name = "Start node",
Config = new Dictionary<string, object>
{
{"idType", "udi"}
}
});
}
}
}
}
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[PropertyEditor(Constants.PropertyEditors.MemberPicker2Alias, "Member Picker", PropertyEditorValueTypes.String, "memberpicker", Group = "People", Icon = "icon-user")]
public class MemberPicker2PropertyEditor : PropertyEditor
{
public MemberPicker2PropertyEditor()
{
InternalPreValues = new Dictionary<string, object>
{
{"idType", "udi"}
};
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -11,30 +10,11 @@ namespace Umbraco.Web.PropertyEditors
[Obsolete("This editor is obsolete, use MemberPickerPropertyEditor2 instead which stores UDI")]
[PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "(Obsolete) Member Picker", PropertyEditorValueTypes.Integer, "memberpicker", Group = "People", Icon = "icon-user", IsDeprecated = true)]
public class MemberPickerPropertyEditor : MemberPickerPropertyEditor2
public class MemberPickerPropertyEditor : MemberPicker2PropertyEditor
{
public MemberPickerPropertyEditor()
{
InternalPreValues["idType"] = "int";
}
}
[PropertyEditor(Constants.PropertyEditors.MemberPicker2Alias, "Member Picker", PropertyEditorValueTypes.String, "memberpicker", Group = "People", Icon = "icon-user")]
public class MemberPickerPropertyEditor2 : PropertyEditor
{
public MemberPickerPropertyEditor2()
{
InternalPreValues = new Dictionary<string, object>
{
{"idType", "udi"}
};
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
}
}
@@ -0,0 +1,121 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[PropertyEditor(Constants.PropertyEditors.MultiNodeTreePicker2Alias, "Multinode Treepicker", PropertyEditorValueTypes.Text, "contentpicker", Group="pickers", Icon="icon-page-add")]
public class MultiNodeTreePicker2PropertyEditor : PropertyEditor
{
public MultiNodeTreePicker2PropertyEditor()
{
InternalPreValues = new Dictionary<string, object>
{
{"multiPicker", "1"},
{"showOpenButton", "0"},
{"showEditButton", "0"},
{"showPathOnHover", "0"},
{"idType", "udi"}
};
}
protected override PreValueEditor CreatePreValueEditor()
{
return new MultiNodePickerPreValueEditor();
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
internal class MultiNodePickerPreValueEditor : PreValueEditor
{
public MultiNodePickerPreValueEditor()
{
//create the fields
Fields.Add(new PreValueField()
{
Key = "startNode",
View = "treesource",
Name = "Node type",
Config = new Dictionary<string, object>
{
{"idType", "udi"}
}
});
Fields.Add(new PreValueField()
{
Key = "filter",
View = "textstring",
Name = "Allow items of type",
Description = "Separate with comma"
});
Fields.Add(new PreValueField()
{
Key = "minNumber",
View = "number",
Name = "Minimum number of items"
});
Fields.Add(new PreValueField()
{
Key = "maxNumber",
View = "number",
Name = "Maximum number of items"
});
Fields.Add(new PreValueField()
{
Key = "showOpenButton",
View = "boolean",
Name = "Show open button (this feature is in preview!)",
Description = "Opens the node in a dialog"
});
}
/// <summary>
/// This ensures the multiPicker pre-val is set based on the maxNumber of nodes set
/// </summary>
/// <param name="defaultPreVals"></param>
/// <param name="persistedPreVals"></param>
/// <returns></returns>
/// <remarks>
/// Due to compatibility with 7.0.0 the multiPicker pre-val might already exist in the db, but we've removed that setting in 7.0.1 so we need to detect it and if it is
/// there, then we'll set the maxNumber to '1'
/// </remarks>
public override IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
{
var result = base.ConvertDbToEditor(defaultPreVals, persistedPreVals);
//backwards compatibility check
if (result.ContainsKey("multiPicker") && result["multiPicker"].ToString() == "0")
{
result["maxNumber"] = "1";
}
//set the multiPicker val correctly depending on the maxNumber
if (result.ContainsKey("maxNumber"))
{
var asNumber = result["maxNumber"].TryConvertTo<int>();
if (asNumber.Success)
{
if (asNumber.Result <= 1)
{
result["multiPicker"] = "0";
}
else
{
result["multiPicker"] = "1";
}
}
}
return result;
}
}
}
}
@@ -1,15 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[Obsolete("This editor is obsolete, use MultiNodeTreePickerPropertyEditor2 instead which stores UDI")]
[PropertyEditor(Constants.PropertyEditors.MultiNodeTreePickerAlias, "(Obsolete) Multinode Treepicker", "contentpicker", Group = "pickers", Icon = "icon-page-add", IsDeprecated = true)]
public class MultiNodeTreePickerPropertyEditor : MultiNodeTreePickerPropertyEditor2
public class MultiNodeTreePickerPropertyEditor : MultiNodeTreePicker2PropertyEditor
{
public MultiNodeTreePickerPropertyEditor()
{
@@ -27,118 +25,4 @@ namespace Umbraco.Web.PropertyEditors
return preValEditor;
}
}
[PropertyEditor(Constants.PropertyEditors.MultiNodeTreePicker2Alias, "Multinode Treepicker", PropertyEditorValueTypes.Text, "contentpicker", Group="pickers", Icon="icon-page-add")]
public class MultiNodeTreePickerPropertyEditor2 : PropertyEditor
{
public MultiNodeTreePickerPropertyEditor2()
{
InternalPreValues = new Dictionary<string, object>
{
{"multiPicker", "1"},
{"showOpenButton", "0"},
{"showEditButton", "0"},
{"showPathOnHover", "0"},
{"idType", "udi"}
};
}
protected override PreValueEditor CreatePreValueEditor()
{
return new MultiNodePickerPreValueEditor();
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
internal class MultiNodePickerPreValueEditor : PreValueEditor
{
public MultiNodePickerPreValueEditor()
{
//create the fields
Fields.Add(new PreValueField()
{
Key = "startNode",
View = "treesource",
Name = "Node type",
Config = new Dictionary<string, object>
{
{"idType", "udi"}
}
});
Fields.Add(new PreValueField()
{
Key = "filter",
View = "textstring",
Name = "Allow items of type",
Description = "Separate with comma"
});
Fields.Add(new PreValueField()
{
Key = "minNumber",
View = "number",
Name = "Minimum number of items"
});
Fields.Add(new PreValueField()
{
Key = "maxNumber",
View = "number",
Name = "Maximum number of items"
});
Fields.Add(new PreValueField()
{
Key = "showOpenButton",
View = "boolean",
Name = "Show open button (this feature is in preview!)",
Description = "Opens the node in a dialog"
});
}
/// <summary>
/// This ensures the multiPicker pre-val is set based on the maxNumber of nodes set
/// </summary>
/// <param name="defaultPreVals"></param>
/// <param name="persistedPreVals"></param>
/// <returns></returns>
/// <remarks>
/// Due to compatibility with 7.0.0 the multiPicker pre-val might already exist in the db, but we've removed that setting in 7.0.1 so we need to detect it and if it is
/// there, then we'll set the maxNumber to '1'
/// </remarks>
public override IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
{
var result = base.ConvertDbToEditor(defaultPreVals, persistedPreVals);
//backwards compatibility check
if (result.ContainsKey("multiPicker") && result["multiPicker"].ToString() == "0")
{
result["maxNumber"] = "1";
}
//set the multiPicker val correctly depending on the maxNumber
if (result.ContainsKey("maxNumber"))
{
var asNumber = result["maxNumber"].TryConvertTo<int>();
if (asNumber.Success)
{
if (asNumber.Result <= 1)
{
result["multiPicker"] = "0";
}
else
{
result["multiPicker"] = "1";
}
}
}
return result;
}
}
}
}
@@ -7,7 +7,7 @@ namespace Umbraco.Web.PropertyEditors
{
[Obsolete("This editor is obsolete, use MultipleMediaPickerPropertyEditor2 instead which stores UDI")]
[PropertyEditor(Constants.PropertyEditors.MultipleMediaPickerAlias, "(Obsolete) Media Picker", "mediapicker", Group = "media", Icon = "icon-pictures-alt-2", IsDeprecated = true)]
public class MultipleMediaPickerPropertyEditor : MediaPickerPropertyEditor2
public class MultipleMediaPickerPropertyEditor : MediaPicker2PropertyEditor
{
public MultipleMediaPickerPropertyEditor()
{
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[PropertyEditor(Constants.PropertyEditors.RelatedLinks2Alias, "Related links", "relatedlinks", ValueType = PropertyEditorValueTypes.Json, Icon = "icon-thumbnail-list", Group = "pickers")]
public class RelatedLinks2PropertyEditor : PropertyEditor
{
public RelatedLinks2PropertyEditor()
{
InternalPreValues = new Dictionary<string, object>
{
{"idType", "udi"}
};
}
internal IDictionary<string, object> InternalPreValues;
public override IDictionary<string, object> DefaultPreValues
{
get { return InternalPreValues; }
set { InternalPreValues = value; }
}
protected override PreValueEditor CreatePreValueEditor()
{
return new RelatedLinksPreValueEditor();
}
internal class RelatedLinksPreValueEditor : PreValueEditor
{
[PreValueField("max", "Maximum number of links", "number", Description = "Enter the maximum amount of links to be added, enter 0 for unlimited")]
public int Maximum { get; set; }
}
}
}
@@ -8,18 +8,16 @@ using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[PropertyEditor(Constants.PropertyEditors.RelatedLinksAlias, "Related links", "relatedlinks", ValueType = PropertyEditorValueTypes.Json, Icon="icon-thumbnail-list", Group="pickers")]
public class RelatedLinksPropertyEditor : PropertyEditor
[Obsolete("This editor is obsolete, use RelatedLinks2PropertyEditor instead which stores UDI")]
[PropertyEditor(Constants.PropertyEditors.RelatedLinksAlias, "(Obsolete) Related links", "relatedlinks", ValueType = PropertyEditorValueTypes.Json, Icon="icon-thumbnail-list", Group="pickers", IsDeprecated = true)]
public class RelatedLinksPropertyEditor : RelatedLinks2PropertyEditor
{
protected override PreValueEditor CreatePreValueEditor()
public RelatedLinksPropertyEditor()
{
return new RelatedLinksPreValueEditor();
}
internal class RelatedLinksPreValueEditor : PreValueEditor
{
[PreValueField("max", "Maximum number of links", "number", Description = "Enter the maximum amount of links to be added, enter 0 for unlimited")]
public int Maximum { get; set; }
InternalPreValues = new Dictionary<string, object>
{
{"idType", "int"}
};
}
}
}
@@ -15,16 +15,22 @@ using Umbraco.Core.PropertyEditors.ValueConverters;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(JArray))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
[DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
[PropertyValueType(typeof(JArray))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class LegacyRelatedLinksEditorValueConvertor : PropertyValueConverterBase
{
private static readonly string[] MatchingEditors = new string[]
{
Constants.PropertyEditors.RelatedLinksAlias,
Constants.PropertyEditors.RelatedLinks2Alias
};
public override bool IsConverter(PublishedPropertyType propertyType)
{
if (UmbracoConfig.For.UmbracoSettings().Content.EnablePropertyValueConverters == false)
{
return Constants.PropertyEditors.RelatedLinksAlias.Equals(propertyType.PropertyEditorAlias);
return MatchingEditors.Contains(propertyType.PropertyEditorAlias);
}
return false;
}
@@ -50,9 +56,23 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
{
if (type == "internal")
{
var linkId = a.Value<int>("link");
var link = helper.NiceUrl(linkId);
a["link"] = link;
switch (propertyType.PropertyEditorAlias)
{
case Constants.PropertyEditors.RelatedLinksAlias:
var intLinkId = a.Value<int>("link");
var intLink = helper.NiceUrl(intLinkId);
a["link"] = intLink;
break;
case Constants.PropertyEditors.RelatedLinks2Alias:
var strLinkId = a.Value<string>("link");
var udiLinkId = strLinkId.TryConvertTo<GuidUdi>();
if (udiLinkId)
{
var udiLink = helper.UrlProvider.GetUrl(udiLinkId.Result.Guid);
a["link"] = udiLink;
}
break;
}
}
}
}
@@ -16,6 +16,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
@@ -23,7 +24,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
/// <summary>
/// The multi node tree picker property editor value converter.
/// </summary>
[DefaultPropertyValueConverter]
[DefaultPropertyValueConverter(typeof(MustBeStringValueConverter))]
[PropertyValueType(typeof(IEnumerable<IPublishedContent>))]
[PropertyValueCache(PropertyCacheValue.Object, PropertyCacheLevel.ContentCache)]
[PropertyValueCache(PropertyCacheValue.Source, PropertyCacheLevel.Content)]
@@ -17,6 +17,7 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Services;
namespace Umbraco.Web.PropertyEditors.ValueConverters
@@ -24,7 +25,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
/// <summary>
/// The multiple media picker property value converter.
/// </summary>
[DefaultPropertyValueConverter]
[DefaultPropertyValueConverter(typeof(MustBeStringValueConverter))]
public class MultipleMediaPickerPropertyConverter : PropertyValueConverterBase, IPropertyValueConverterMeta
{
private readonly IDataTypeService _dataTypeService;
@@ -15,6 +15,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Web.Models;
using Umbraco.Web.Routing;
@@ -23,7 +24,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
/// <summary>
/// The related links property value converter.
/// </summary>
[DefaultPropertyValueConverter]
[DefaultPropertyValueConverter(typeof(LegacyRelatedLinksEditorValueConvertor), typeof(JsonValueConverter))]
[PropertyValueType(typeof(RelatedLinks))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.ContentCache)]
public class RelatedLinksPropertyConverter : PropertyValueConverterBase
+67
View File
@@ -5,6 +5,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Web.PublishedCache;
using Umbraco.Core;
using Umbraco.Core.Models;
namespace Umbraco.Web.Routing
{
@@ -65,6 +66,72 @@ namespace Umbraco.Web.Routing
#region GetUrl
/// <summary>
/// Gets the url of a published content.
/// </summary>
/// <param name="id">The published content identifier.</param>
/// <returns>The url for the published content.</returns>
/// <remarks>
/// <para>The url is absolute or relative depending on <c>Mode</c> and on the current url.</para>
/// <para>If the provider is unable to provide a url, it returns "#".</para>
/// </remarks>
public string GetUrl(Guid id)
{
var intId = _umbracoContext.Application.Services.EntityService.GetIdForKey(id, UmbracoObjectTypes.Document);
return GetUrl(intId.Success ? intId.Result : -1);
}
/// <summary>
/// Gets the nice url of a published content.
/// </summary>
/// <param name="id">The published content identifier.</param>
/// <param name="absolute">A value indicating whether the url should be absolute in any case.</param>
/// <returns>The url for the published content.</returns>
/// <remarks>
/// <para>The url is absolute or relative depending on <c>Mode</c> and on <c>current</c>, unless
/// <c>absolute</c> is true, in which case the url is always absolute.</para>
/// <para>If the provider is unable to provide a url, it returns "#".</para>
/// </remarks>
public string GetUrl(Guid id, bool absolute)
{
var intId = _umbracoContext.Application.Services.EntityService.GetIdForKey(id, UmbracoObjectTypes.Document);
return GetUrl(intId.Success ? intId.Result : -1, absolute);
}
/// <summary>
/// Gets the nice url of a published content.
/// </summary>
/// <param name="id">The published content id.</param>
/// <param name="current">The current absolute url.</param>
/// <param name="absolute">A value indicating whether the url should be absolute in any case.</param>
/// <returns>The url for the published content.</returns>
/// <remarks>
/// <para>The url is absolute or relative depending on <c>Mode</c> and on <c>current</c>, unless
/// <c>absolute</c> is true, in which case the url is always absolute.</para>
/// <para>If the provider is unable to provide a url, it returns "#".</para>
/// </remarks>
public string GetUrl(Guid id, Uri current, bool absolute)
{
var intId = _umbracoContext.Application.Services.EntityService.GetIdForKey(id, UmbracoObjectTypes.Document);
return GetUrl(intId.Success ? intId.Result : -1, current, absolute);
}
/// <summary>
/// Gets the nice url of a published content.
/// </summary>
/// <param name="id">The published content identifier.</param>
/// <param name="mode">The url mode.</param>
/// <returns>The url for the published content.</returns>
/// <remarks>
/// <para>The url is absolute or relative depending on <c>mode</c> and on the current url.</para>
/// <para>If the provider is unable to provide a url, it returns "#".</para>
/// </remarks>
public string GetUrl(Guid id, UrlProviderMode mode)
{
var intId = _umbracoContext.Application.Services.EntityService.GetIdForKey(id, UmbracoObjectTypes.Document);
return GetUrl(intId.Success ? intId.Result : -1, mode);
}
/// <summary>
/// Gets the url of a published content.
/// </summary>
+5 -4
View File
@@ -300,10 +300,6 @@
<Project>{D7636876-0756-43CB-A192-138C6F0D5E42}</Project>
<Name>umbraco.providers</Name>
</ProjectReference>
<Reference Include="UrlRewritingNet.UrlRewriter, Version=2.0.7.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\UrlRewritingNet.UrlRewriter.2.0.7\lib\UrlRewritingNet.UrlRewriter.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\SolutionInfo.cs">
@@ -402,9 +398,14 @@
<Compile Include="OwinMiddlewareConfiguredEventArgs.cs" />
<Compile Include="Profiling\WebProfilerProvider.cs" />
<Compile Include="Profiling\WebProfiler.cs" />
<Compile Include="PropertyEditors\ContentPicker2PropertyEditor.cs" />
<Compile Include="PropertyEditors\DatePreValueEditor.cs" />
<Compile Include="PropertyEditors\DateTimePreValueEditor.cs" />
<Compile Include="PropertyEditors\DecimalPropertyEditor.cs" />
<Compile Include="PropertyEditors\MediaPicker2PropertyEditor.cs" />
<Compile Include="PropertyEditors\MemberPicker2PropertyEditor.cs" />
<Compile Include="PropertyEditors\MultiNodeTreePicker2PropertyEditor.cs" />
<Compile Include="PropertyEditors\RelatedLinks2PropertyEditor.cs" />
<Compile Include="PropertyEditors\ValueConverters\ContentPickerPropertyConverter.cs" />
<Compile Include="PropertyEditors\ParameterEditors\MultipleContentPickerParameterEditor.cs" />
<Compile Include="PropertyEditors\ValueConverters\ImageCropDataSetConverter.cs" />
+2 -1
View File
@@ -10,6 +10,7 @@ using Umbraco.Web.Routing;
using Umbraco.Web.Security;
using umbraco.BusinessLogic;
using umbraco.presentation.preview;
using Umbraco.Core.CodeAnnotations;
using GlobalSettings = umbraco.GlobalSettings;
using IOHelper = Umbraco.Core.IO.IOHelper;
using SystemDirectories = Umbraco.Core.IO.SystemDirectories;
@@ -324,7 +325,7 @@ namespace Umbraco.Web
/// <summary>
/// Gets the current ApplicationContext
/// </summary>
[Obsolete("Do not access the ApplicationContext via the UmbracoContext, either inject the ApplicationContext into the services you need or access it via it's own Singleton accessor ApplicationContext.Current")]
[UmbracoWillObsolete("Do not access the ApplicationContext via the UmbracoContext, either inject the ApplicationContext into the services you need or access it via it's own Singleton accessor ApplicationContext.Current")]
[EditorBrowsable(EditorBrowsableState.Never)]
public ApplicationContext Application { get; private set; }
@@ -51,7 +51,7 @@ namespace Umbraco.Web.WebServices
[HttpGet]
public bool CheckMediaXmlTable()
{
var total = Services.MediaService.Count();
var total = Services.MediaService.CountNotTrashed();
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
var subQuery = new Sql()
.Select("Count(*)")
-1
View File
@@ -33,6 +33,5 @@
<package id="System.Runtime.InteropServices" version="4.1.0" targetFramework="net45" />
<package id="System.Text.RegularExpressions" version="4.1.0" targetFramework="net45" />
<package id="System.Threading.Tasks.Dataflow" version="4.6.0" targetFramework="net45" />
<package id="UrlRewritingNet.UrlRewriter" version="2.0.7" targetFramework="net45" />
<package id="xmlrpcnet" version="2.5.0" targetFramework="net45" />
</packages>
@@ -775,7 +775,6 @@ namespace umbraco
internal void SaveXmlToFile()
{
LogHelper.Info<content>("Save Xml to file...");
try
{
// ok to access _xmlContent here - capture (atomic + volatile), immutable anyway
@@ -793,7 +792,7 @@ namespace umbraco
Directory.CreateDirectory(directoryName);
// save
using (var fs = new FileStream(_xmlFileName, FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true))
using (var fs = new FileStream(_xmlFileName, FileMode.Create, FileAccess.Write, FileShare.Read))
{
SaveXmlToStream(xml, fs);
}
@@ -88,19 +88,20 @@ namespace umbraco
string originalPath = IOHelper.MapPath(VirtualPathUtility.ToAbsolute(MasterPageFile));
string copyPath = IOHelper.MapPath(VirtualPathUtility.ToAbsolute(path));
FileStream fs = new FileStream(originalPath, FileMode.Open, FileAccess.ReadWrite);
StreamReader f = new StreamReader(fs);
String newfile = f.ReadToEnd();
f.Close();
fs.Close();
string newFile;
using (var fs = new FileStream(originalPath, FileMode.Open, FileAccess.ReadWrite))
using (var f = new StreamReader(fs))
{
newFile = f.ReadToEnd();
}
newfile = newfile.Replace("MasterPageFile=\"~/masterpages/", "MasterPageFile=\"");
newFile = newFile.Replace("MasterPageFile=\"~/masterpages/", "MasterPageFile=\"");
fs = new FileStream(copyPath, FileMode.Create, FileAccess.Write);
StreamWriter replacement = new StreamWriter(fs);
replacement.Write(newfile);
replacement.Close();
using (var fs = new FileStream(copyPath, FileMode.Create, FileAccess.Write))
using (var replacement = new StreamWriter(fs))
{
replacement.Write(newFile);
}
}
return path;

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