Compare commits
141 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f61b7579a2 | |||
| 86a3780c61 | |||
| 552909fde2 | |||
| 7adae4d345 | |||
| d747cf69c3 | |||
| bc5e3b4d66 | |||
| febeb82d10 | |||
| 1c2b2c1409 | |||
| b4eb9f333e | |||
| af00a421cd | |||
| fed06c88e8 | |||
| 5dec2861d9 | |||
| 23b3bb37ee | |||
| 4dabb606e7 | |||
| d5f66ebe02 | |||
| c7783d1cd1 | |||
| 2104b109f2 | |||
| 578ca7d41d | |||
| bd38dde1fc | |||
| 42c23da9f5 | |||
| cab1536a30 | |||
| 33d35fd9f7 | |||
| cc885c1231 | |||
| 422dd1a627 | |||
| 759e444624 | |||
| 2a7ef5de26 | |||
| 43e892563d | |||
| 4d1e64b279 | |||
| 975c97cfb0 | |||
| 0c613347ae | |||
| 83f75fdaff | |||
| 487792920b | |||
| 6ae06ad2e0 | |||
| 8387c435d4 | |||
| 5807bbccc4 | |||
| 1bfc041bbe | |||
| a5ca058cb2 | |||
| 88a1ad04aa | |||
| e619c402b4 | |||
| c9294e5281 | |||
| 0074f57970 | |||
| 9b4a6f2761 | |||
| f889b5206c | |||
| 507d7dd4f0 | |||
| 55c5b41693 | |||
| b58d8677b3 | |||
| f30d7fc68c | |||
| f5a204d1de | |||
| d504d8f54e | |||
| 7c049b55a8 | |||
| b519d68e1a | |||
| deb8d652c5 | |||
| 051b3f2e6a | |||
| 21f947efbd | |||
| a68f4e284a | |||
| 90b43584d2 | |||
| 9461e35028 | |||
| 12dd01dd29 | |||
| c64e3a8908 | |||
| d554417fde | |||
| 74e8390bda | |||
| 4f9bbdf7f7 | |||
| 67fc8b6215 | |||
| 3840ac2fed | |||
| 7c64f1aa0d | |||
| 82c18955b0 | |||
| eedcfc122b | |||
| 8cf3110708 | |||
| 0dc0e68174 | |||
| aaa9c8f194 | |||
| dbe489c0f2 | |||
| 2652a583e0 | |||
| bc1758f569 | |||
| a898c2d697 | |||
| e612bcae58 | |||
| 308a61895e | |||
| 9c5526f281 | |||
| 9c803cc234 | |||
| f24fd42a69 | |||
| 9b7f459c44 | |||
| 273a5cef28 | |||
| 7da7c1e5a1 | |||
| 1901fbb6ed | |||
| 1de52482e3 | |||
| 49c2ae3673 | |||
| 5f22c81994 | |||
| f13427f5fb | |||
| 2785eaeda5 | |||
| a31cfb86f8 | |||
| e4802b592f | |||
| 548f9fd01f | |||
| 843796c9a4 | |||
| c060856782 | |||
| 857063ebd8 | |||
| a20cc60c10 | |||
| 846ac573cc | |||
| 2ba5627e2c | |||
| 122295c89f | |||
| 2669c68df0 | |||
| 912a6a52cc | |||
| 0e727f91da | |||
| 179523224a | |||
| 19e4bee34e | |||
| f1709f6066 | |||
| f2be235f85 | |||
| d97cc36c53 | |||
| db86f6e1ee | |||
| a03e0dfb53 | |||
| b4450ca7f2 | |||
| 7004765acf | |||
| 77a91bc017 | |||
| 14b96da588 | |||
| 99324035e5 | |||
| 8b9a5000be | |||
| c82bddb7dd | |||
| f2fd45576b | |||
| d5a687cf3d | |||
| ff6ea0b42e | |||
| 384a31e3c6 | |||
| 69b913c608 | |||
| 83757c60b5 | |||
| 26acecb720 | |||
| 7c42cd26c2 | |||
| 13758418ac | |||
| 77b04d74d4 | |||
| e95cb14d48 | |||
| bf797bccc7 | |||
| 4336f5201d | |||
| ed019a90e2 | |||
| 8d598cd37c | |||
| 30c2f95844 | |||
| 0078a5d8cc | |||
| 09085e3bcf | |||
| a31b03b3e2 | |||
| 9ef53536bf | |||
| 547351a719 | |||
| 371c4ae1a3 | |||
| 060137c798 | |||
| a5af5ba1a9 | |||
| ca1f43d048 | |||
| e962a48138 |
@@ -44,37 +44,37 @@
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\net462\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\net462\businesslogic.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\net462\cms.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\net462\cms.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\net462\controls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\net462\controls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\net462\interfaces.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\net462\interfaces.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\net462\log4net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\net462\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\net462\SQLCE4Umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.xml" target="lib\net462\SQLCE4Umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\net462\System.Data.SqlServerCe.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\net462\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\net462\TidyNet.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\net462\Umbraco.Core.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\net462\Umbraco.Core.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\net462\umbraco.DataLayer.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\net462\umbraco.DataLayer.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\net462\umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\net462\umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\net462\umbraco.editorControls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\net462\umbraco.editorControls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\net462\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\net462\umbraco.MacroEngines.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\net462\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\net462\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net462\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\net462\Umbraco.Web.UI.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\net462\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\net462\UmbracoExamine.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\net45\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\net45\businesslogic.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\net45\cms.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\net45\cms.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\net45\controls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\net45\controls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\net45\interfaces.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\net45\interfaces.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\net45\log4net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\net45\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\net45\SQLCE4Umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.xml" target="lib\net45\SQLCE4Umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\net45\System.Data.SqlServerCe.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\net45\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\net45\TidyNet.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\net45\Umbraco.Core.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\net45\Umbraco.Core.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\net45\umbraco.DataLayer.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\net45\umbraco.DataLayer.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\net45\umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\net45\umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\net45\umbraco.editorControls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\net45\umbraco.editorControls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\net45\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\net45\umbraco.MacroEngines.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\net45\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\net45\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net45\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\net45\Umbraco.Web.UI.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\net45\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\net45\UmbracoExamine.xml" />
|
||||
<file src="tools\install.core.ps1" target="tools\install.ps1" />
|
||||
|
||||
<!-- Added to be able to produce a symbols package -->
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.0
|
||||
alpha061
|
||||
alpha066
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha061")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha066")]
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.CodeAnnotations
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||
internal class UmbracoUdiTypeAttribute : Attribute
|
||||
{
|
||||
public string UdiType { get; private set; }
|
||||
|
||||
public UmbracoUdiTypeAttribute(string udiType)
|
||||
{
|
||||
UdiType = udiType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,6 +159,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return GetOptionalTextElement("defaultDocumentTypeProperty", "Textstring"); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("showDeprecatedPropertyEditors")]
|
||||
internal InnerTextConfigurationElement<bool> ShowDeprecatedPropertyEditors
|
||||
{
|
||||
get { return GetOptionalTextElement("showDeprecatedPropertyEditors", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("EnableInheritedDocumentTypes")]
|
||||
internal InnerTextConfigurationElement<bool> EnableInheritedDocumentTypes
|
||||
{
|
||||
@@ -306,6 +312,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return DefaultDocumentTypeProperty; }
|
||||
}
|
||||
|
||||
bool IContentSection.ShowDeprecatedPropertyEditors
|
||||
{
|
||||
get { return ShowDeprecatedPropertyEditors; }
|
||||
}
|
||||
|
||||
bool IContentSection.EnableInheritedDocumentTypes
|
||||
{
|
||||
get { return EnableInheritedDocumentTypes; }
|
||||
|
||||
@@ -60,6 +60,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
|
||||
string DefaultDocumentTypeProperty { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The default for this is false but if you would like deprecated property editors displayed
|
||||
/// in the data type editor you can enable this
|
||||
/// </summary>
|
||||
bool ShowDeprecatedPropertyEditors { get; }
|
||||
|
||||
bool EnableInheritedDocumentTypes { get; }
|
||||
|
||||
bool EnableInheritedMediaTypes { get; }
|
||||
|
||||
@@ -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 "alpha061"; } }
|
||||
public static string CurrentComment { get { return "alpha066"; } }
|
||||
|
||||
// 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
|
||||
|
||||
@@ -109,6 +109,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Media Type object.
|
||||
/// </summary>
|
||||
public static readonly Guid MemberGuid = new Guid(Member);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member Group object.
|
||||
/// </summary>
|
||||
@@ -174,24 +179,24 @@ namespace Umbraco.Core
|
||||
public static readonly Guid FormsFormGuid = new Guid(FormsForm);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Workflow.
|
||||
/// Guid for a Forms PreValue Source.
|
||||
/// </summary>
|
||||
public const string FormsWorkflow = "42D7BF9B-A362-4FEE-B45A-674D5C064B70";
|
||||
public const string FormsPreValue = "42D7BF9B-A362-4FEE-B45A-674D5C064B70";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Workflow.
|
||||
/// Guid for a Forms PreValue Source.
|
||||
/// </summary>
|
||||
public static readonly Guid FormsWorkflowGuid = new Guid(FormsWorkflow);
|
||||
public static readonly Guid FormsPreValueGuid = new Guid(FormsPreValue);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Record.
|
||||
/// Guid for a Forms DataSource.
|
||||
/// </summary>
|
||||
public const string FormsRecord = "CFED6CE4-9359-443E-9977-9956FEB1D867";
|
||||
public const string FormsDataSource = "CFED6CE4-9359-443E-9977-9956FEB1D867";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Record.
|
||||
/// Guid for a Forms DataSource.
|
||||
/// </summary>
|
||||
public static readonly Guid FormsRecordGuid = new Guid(FormsRecord);
|
||||
public static readonly Guid FormsDataSourceGuid = new Guid(FormsDataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,10 +42,14 @@ namespace Umbraco.Core
|
||||
[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 ContentPicker = "158AA029-24ED-4948-939E-C3DA209E5FBA";
|
||||
|
||||
|
||||
[Obsolete("This is an obsoleted content picker, use ContentPicker2Alias instead")]
|
||||
public const string ContentPickerAlias = "Umbraco.ContentPickerAlias";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Content Picker datatype.
|
||||
/// </summary>
|
||||
public const string ContentPickerAlias = "Umbraco.ContentPickerAlias";
|
||||
public const string ContentPicker2Alias = "Umbraco.ContentPicker2";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Date datatype.
|
||||
@@ -192,11 +196,15 @@ namespace Umbraco.Core
|
||||
[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 MediaPicker = "EAD69342-F06D-4253-83AC-28000225583B";
|
||||
|
||||
[Obsolete("This is an obsoleted picker, use MediaPicker2Alias instead")]
|
||||
public const string MediaPickerAlias = "Umbraco.MediaPicker";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Media Picker datatype.
|
||||
/// </summary>
|
||||
public const string MediaPickerAlias = "Umbraco.MediaPicker";
|
||||
public const string MediaPicker2Alias = "Umbraco.MediaPicker2";
|
||||
|
||||
[Obsolete("This is an obsoleted picker, use MediaPicker2Alias instead")]
|
||||
public const string MultipleMediaPickerAlias = "Umbraco.MultipleMediaPicker";
|
||||
|
||||
/// <summary>
|
||||
@@ -205,26 +213,32 @@ namespace Umbraco.Core
|
||||
[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 MemberPicker = "39F533E4-0551-4505-A64B-E0425C5CE775";
|
||||
|
||||
[Obsolete("This is an obsoleted picker, use MemberPicker2Alias instead")]
|
||||
public const string MemberPickerAlias = "Umbraco.MemberPicker";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Member Picker datatype.
|
||||
/// </summary>
|
||||
public const string MemberPickerAlias = "Umbraco.MemberPicker";
|
||||
public const string MemberPicker2Alias = "Umbraco.MemberPicker2";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Member Group Picker datatype.
|
||||
/// </summary>
|
||||
public const string MemberGroupPickerAlias = "Umbraco.MemberGroupPicker";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Multi-Node Tree Picker datatype
|
||||
/// </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 MultiNodeTreePicker = "7E062C13-7C41-4AD9-B389-41D88AEEF87C";
|
||||
|
||||
[Obsolete("This is an obsoleted picker, use MultiNodeTreePicker2Alias instead")]
|
||||
public const string MultiNodeTreePickerAlias = "Umbraco.MultiNodeTreePicker";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the Multi-Node Tree Picker datatype
|
||||
/// </summary>
|
||||
public const string MultiNodeTreePickerAlias = "Umbraco.MultiNodeTreePicker";
|
||||
public const string MultiNodeTreePicker2Alias = "Umbraco.MultiNodeTreePicker2";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Multiple Textstring datatype.
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Umbraco.Core.Deploy
|
||||
if (udi == null)
|
||||
throw new ArgumentNullException("udi");
|
||||
Udi = udi;
|
||||
Name = Udi.ToString();
|
||||
|
||||
Dependencies = dependencies ?? Enumerable.Empty<ArtifactDependency>();
|
||||
_checksum = new Lazy<string>(GetChecksum);
|
||||
@@ -48,5 +49,8 @@ namespace Umbraco.Core.Deploy
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Alias { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,8 @@ namespace Umbraco.Core.Deploy
|
||||
/// Represents an artifact ie an object that can be transfered between environments.
|
||||
/// </summary>
|
||||
public interface IArtifact : IArtifactSignature
|
||||
{ }
|
||||
{
|
||||
string Name { get; }
|
||||
string Alias { get; }
|
||||
}
|
||||
}
|
||||
@@ -66,10 +66,20 @@ namespace Umbraco.Core.Deploy
|
||||
/// <returns>The length of the file, or -1 if the file does not exist.</returns>
|
||||
Task<long> GetFileLengthAsync(StringUdi udi, CancellationToken token);
|
||||
|
||||
// fixme - doc
|
||||
void GetFiles(IEnumerable<StringUdi> udis, IFileStore fileStore);
|
||||
/// <summary>
|
||||
/// Gets files and store them using a file store.
|
||||
/// </summary>
|
||||
/// <param name="udis">The udis of the files to get.</param>
|
||||
/// <param name="fileTypes">A collection of file types which can store the files.</param>
|
||||
void GetFiles(IEnumerable<StringUdi> udis, IFileTypeCollection fileTypes);
|
||||
|
||||
Task GetFilesAsync(IEnumerable<StringUdi> udis, IFileStore fileStore, CancellationToken token);
|
||||
/// <summary>
|
||||
/// Gets files and store them using a file store.
|
||||
/// </summary>
|
||||
/// <param name="udis">The udis of the files to get.</param>
|
||||
/// <param name="fileTypes">A collection of file types which can store the files.</param>
|
||||
/// <param name="token">A cancellation token.</param>
|
||||
Task GetFilesAsync(IEnumerable<StringUdi> udis, IFileTypeCollection fileTypes, CancellationToken token);
|
||||
|
||||
///// <summary>
|
||||
///// Gets the content of a file as a bytes array.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Umbraco.Core.Deploy
|
||||
{
|
||||
public interface IFileStore
|
||||
{
|
||||
void SaveStream(StringUdi udi, Stream stream);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Umbraco.Core.Deploy
|
||||
{
|
||||
public interface IPrettyArtifact
|
||||
{
|
||||
string Name { get; }
|
||||
string Alias { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -67,22 +68,15 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The for each.</summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="func">The func.</param>
|
||||
/// <typeparam name="TItem">item type</typeparam>
|
||||
/// <typeparam name="TResult">Result type</typeparam>
|
||||
/// <returns>the Results</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use a normal foreach loop instead, this adds more allocations than necessary")]
|
||||
public static TResult[] ForEach<TItem, TResult>(this IEnumerable<TItem> items, Func<TItem, TResult> func)
|
||||
{
|
||||
return items.Select(func).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>The for each.</summary>
|
||||
/// <param name="items">The items.</param>
|
||||
/// <param name="action">The action.</param>
|
||||
/// <typeparam name="TItem">Item type</typeparam>
|
||||
/// <returns>list of TItem</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use a normal foreach loop instead, this adds more allocations than necessary")]
|
||||
public static IEnumerable<TItem> ForEach<TItem>(this IEnumerable<TItem> items, Action<TItem> action)
|
||||
{
|
||||
if (items != null)
|
||||
@@ -101,6 +95,7 @@ namespace Umbraco.Core
|
||||
/// <param name="f">The select child.</param>
|
||||
/// <typeparam name="T">Item type</typeparam>
|
||||
/// <returns>list of TItem</returns>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Do not use, use SelectRecursive instead which has far less potential of re-iterating an iterator which may cause significantly more SQL queries")]
|
||||
public static IEnumerable<T> FlattenList<T>(this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
public class DeleteEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<DeleteEventArgs<TEntity>>
|
||||
public class DeleteEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>, IEquatable<DeleteEventArgs<TEntity>>, IDeletingMediaFilesEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the delete operation
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
public enum EventsDispatchMode
|
||||
{
|
||||
// in 7.5 we'd do:
|
||||
//
|
||||
// using (var uow = ...)
|
||||
// { ... }
|
||||
// Done.RaiseEvent(...);
|
||||
//
|
||||
// and so the event would trigger only *after* the transaction has completed,
|
||||
// so actually PassThrough is more aggressive than what we had in 7.5 and should
|
||||
// not be used. now in 7.6 we do:
|
||||
//
|
||||
// using (var uow = ...)
|
||||
// {
|
||||
// ...
|
||||
// uow.Events.Dispatch(Done, ...);
|
||||
// }
|
||||
//
|
||||
// so the event can be collected, so the default "kinda compatible" more has to be
|
||||
// the Scope mode, and Passive is for Deploy only
|
||||
|
||||
Unspecified = 0,
|
||||
PassThrough, // both Doing and Done trigger immediately
|
||||
Scope, // Doing triggers immediately, Done queued and triggered when & if the scope completes
|
||||
Passive // Doing never triggers, Done queued and needs to be handled by custom code
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
internal interface IDeletingMediaFilesEventArgs
|
||||
{
|
||||
List<string> MediaFilesToDelete { get; }
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
public class RecycleBinEventArgs : CancellableEventArgs, IEquatable<RecycleBinEventArgs>
|
||||
public class RecycleBinEventArgs : CancellableEventArgs, IEquatable<RecycleBinEventArgs>, IDeletingMediaFilesEventArgs
|
||||
{
|
||||
public RecycleBinEventArgs(Guid nodeObjectType, Dictionary<int, IEnumerable<Property>> allPropertyData, bool emptiedSuccessfully)
|
||||
: base(false)
|
||||
@@ -97,6 +97,8 @@ namespace Umbraco.Core.Events
|
||||
/// </remarks>
|
||||
public List<string> Files { get; private set; }
|
||||
|
||||
public List<string> MediaFilesToDelete { get { return Files; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of all property data associated with a content id
|
||||
/// </summary>
|
||||
|
||||
@@ -1,126 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// This event manager is created for each scope and is aware of if it is nested in an outer scope
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The outer scope is the only scope that can raise events, the inner scope's will defer to the outer scope
|
||||
/// </remarks>
|
||||
internal class ScopeEventDispatcher : IEventDispatcher
|
||||
internal class ScopeEventDispatcher : ScopeEventDispatcherBase
|
||||
{
|
||||
private readonly EventsDispatchMode _mode;
|
||||
private List<IEventDefinition> _events;
|
||||
public ScopeEventDispatcher()
|
||||
: base(true)
|
||||
{ }
|
||||
|
||||
public ScopeEventDispatcher(EventsDispatchMode mode)
|
||||
{
|
||||
_mode = mode;
|
||||
}
|
||||
|
||||
private List<IEventDefinition> Events { get { return _events ?? (_events = new List<IEventDefinition>()); } }
|
||||
|
||||
private bool PassThroughCancelable { get { return _mode == EventsDispatchMode.PassThrough || _mode == EventsDispatchMode.Scope; } }
|
||||
|
||||
private bool PassThrough { get { return _mode == EventsDispatchMode.PassThrough; } }
|
||||
|
||||
private bool RaiseEvents { get { return _mode == EventsDispatchMode.Scope; } }
|
||||
|
||||
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string eventName = null)
|
||||
{
|
||||
if (eventHandler == null) return args.Cancel;
|
||||
if (PassThroughCancelable == false) return args.Cancel;
|
||||
eventHandler(sender, args);
|
||||
return args.Cancel;
|
||||
}
|
||||
|
||||
public bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
|
||||
where TArgs : CancellableEventArgs
|
||||
{
|
||||
if (eventHandler == null) return args.Cancel;
|
||||
if (PassThroughCancelable == false) return args.Cancel;
|
||||
eventHandler(sender, args);
|
||||
return args.Cancel;
|
||||
}
|
||||
|
||||
public bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
|
||||
where TArgs : CancellableEventArgs
|
||||
{
|
||||
if (eventHandler == null) return args.Cancel;
|
||||
if (PassThroughCancelable == false) return args.Cancel;
|
||||
eventHandler(sender, args);
|
||||
return args.Cancel;
|
||||
}
|
||||
|
||||
public void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string eventName = null)
|
||||
{
|
||||
if (eventHandler == null) return;
|
||||
if (PassThrough)
|
||||
eventHandler(sender, args);
|
||||
else
|
||||
Events.Add(new EventDefinition(eventHandler, sender, args, eventName));
|
||||
}
|
||||
|
||||
public void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
|
||||
{
|
||||
if (eventHandler == null) return;
|
||||
if (PassThrough)
|
||||
eventHandler(sender, args);
|
||||
else
|
||||
Events.Add(new EventDefinition<TArgs>(eventHandler, sender, args, eventName));
|
||||
}
|
||||
|
||||
public void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
|
||||
{
|
||||
if (eventHandler == null) return;
|
||||
if (PassThrough)
|
||||
eventHandler(sender, args);
|
||||
else
|
||||
Events.Add(new EventDefinition<TSender, TArgs>(eventHandler, sender, args, eventName));
|
||||
}
|
||||
|
||||
public IEnumerable<IEventDefinition> GetEvents(EventDefinitionFilter filter)
|
||||
{
|
||||
if (_events == null)
|
||||
return Enumerable.Empty<IEventDefinition>();
|
||||
|
||||
switch (filter)
|
||||
{
|
||||
case EventDefinitionFilter.All:
|
||||
return _events;
|
||||
case EventDefinitionFilter.FirstIn:
|
||||
var l1 = new OrderedHashSet<IEventDefinition>();
|
||||
foreach (var e in _events)
|
||||
{
|
||||
l1.Add(e);
|
||||
}
|
||||
return l1;
|
||||
case EventDefinitionFilter.LastIn:
|
||||
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest:false);
|
||||
foreach (var e in _events)
|
||||
{
|
||||
l2.Add(e);
|
||||
}
|
||||
return l2;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("filter", filter, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void ScopeExit(bool completed)
|
||||
protected override void ScopeExitCompleted()
|
||||
{
|
||||
// fixme - we'd need to de-duplicate events somehow, etc - and the deduplication should be last in wins
|
||||
|
||||
if (_events == null) return;
|
||||
foreach (var e in GetEvents(EventDefinitionFilter.All))
|
||||
{
|
||||
e.RaiseEvent();
|
||||
|
||||
if (RaiseEvents && completed)
|
||||
foreach (var e in _events)
|
||||
e.RaiseEvent();
|
||||
_events.Clear();
|
||||
// fixme - not sure I like doing it here - but then where? how?
|
||||
var delete = e.Args as IDeletingMediaFilesEventArgs;
|
||||
if (delete != null && delete.MediaFilesToDelete.Count > 0)
|
||||
MediaFileSystem.DeleteMediaFiles(delete.MediaFilesToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
private MediaFileSystem _mediaFileSystem;
|
||||
|
||||
private MediaFileSystem MediaFileSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mediaFileSystem != null) return _mediaFileSystem;
|
||||
|
||||
// fixme - insane! reading config goes cross AppDomain and serializes context?
|
||||
using (new SafeCallContext())
|
||||
{
|
||||
return _mediaFileSystem = FileSystemProviderManager.Current.MediaFileSystem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
public abstract class ScopeEventDispatcherBase : IEventDispatcher
|
||||
{
|
||||
private List<IEventDefinition> _events;
|
||||
private readonly bool _raiseCancelable;
|
||||
|
||||
protected ScopeEventDispatcherBase(bool raiseCancelable)
|
||||
{
|
||||
_raiseCancelable = raiseCancelable;
|
||||
}
|
||||
|
||||
private List<IEventDefinition> Events { get { return _events ?? (_events = new List<IEventDefinition>()); } }
|
||||
|
||||
public bool DispatchCancelable(EventHandler eventHandler, object sender, CancellableEventArgs args, string eventName = null)
|
||||
{
|
||||
if (eventHandler == null) return args.Cancel;
|
||||
if (_raiseCancelable == false) return args.Cancel;
|
||||
eventHandler(sender, args);
|
||||
return args.Cancel;
|
||||
}
|
||||
|
||||
public bool DispatchCancelable<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
|
||||
where TArgs : CancellableEventArgs
|
||||
{
|
||||
if (eventHandler == null) return args.Cancel;
|
||||
if (_raiseCancelable == false) return args.Cancel;
|
||||
eventHandler(sender, args);
|
||||
return args.Cancel;
|
||||
}
|
||||
|
||||
public bool DispatchCancelable<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
|
||||
where TArgs : CancellableEventArgs
|
||||
{
|
||||
if (eventHandler == null) return args.Cancel;
|
||||
if (_raiseCancelable == false) return args.Cancel;
|
||||
eventHandler(sender, args);
|
||||
return args.Cancel;
|
||||
}
|
||||
|
||||
public void Dispatch(EventHandler eventHandler, object sender, EventArgs args, string eventName = null)
|
||||
{
|
||||
if (eventHandler == null) return;
|
||||
Events.Add(new EventDefinition(eventHandler, sender, args, eventName));
|
||||
}
|
||||
|
||||
public void Dispatch<TArgs>(EventHandler<TArgs> eventHandler, object sender, TArgs args, string eventName = null)
|
||||
{
|
||||
if (eventHandler == null) return;
|
||||
Events.Add(new EventDefinition<TArgs>(eventHandler, sender, args, eventName));
|
||||
}
|
||||
|
||||
public void Dispatch<TSender, TArgs>(TypedEventHandler<TSender, TArgs> eventHandler, TSender sender, TArgs args, string eventName = null)
|
||||
{
|
||||
if (eventHandler == null) return;
|
||||
Events.Add(new EventDefinition<TSender, TArgs>(eventHandler, sender, args, eventName));
|
||||
}
|
||||
|
||||
public IEnumerable<IEventDefinition> GetEvents(EventDefinitionFilter filter)
|
||||
{
|
||||
if (_events == null)
|
||||
return Enumerable.Empty<IEventDefinition>();
|
||||
|
||||
switch (filter)
|
||||
{
|
||||
case EventDefinitionFilter.All:
|
||||
return _events;
|
||||
case EventDefinitionFilter.FirstIn:
|
||||
var l1 = new OrderedHashSet<IEventDefinition>();
|
||||
foreach (var e in _events)
|
||||
{
|
||||
l1.Add(e);
|
||||
}
|
||||
return l1;
|
||||
case EventDefinitionFilter.LastIn:
|
||||
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
|
||||
foreach (var e in _events)
|
||||
{
|
||||
l2.Add(e);
|
||||
}
|
||||
return l2;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("filter", filter, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void ScopeExit(bool completed)
|
||||
{
|
||||
if (_events == null) return;
|
||||
if (completed)
|
||||
ScopeExitCompleted();
|
||||
_events.Clear();
|
||||
}
|
||||
|
||||
protected abstract void ScopeExitCompleted();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the instance of EventMessages in the current scope.
|
||||
/// </summary>
|
||||
internal class ScopeLifespanMessagesFactory : IEventMessagesFactory
|
||||
{
|
||||
public const string ContextKey = "Umbraco.Core.Events.ScopeLifespanMessagesFactory";
|
||||
|
||||
private readonly IHttpContextAccessor _contextAccessor;
|
||||
private readonly IScopeProviderInternal _scopeProvider;
|
||||
|
||||
public static ScopeLifespanMessagesFactory Current { get; private set; }
|
||||
|
||||
public ScopeLifespanMessagesFactory(IHttpContextAccessor contextAccesor, IScopeProvider scopeProvider)
|
||||
{
|
||||
if (contextAccesor == null) throw new ArgumentNullException("contextAccesor");
|
||||
if (scopeProvider == null) throw new ArgumentNullException("scopeProvider");
|
||||
if (scopeProvider is IScopeProviderInternal == false) throw new ArgumentException("Not IScopeProviderInternal.", "scopeProvider");
|
||||
_contextAccessor = contextAccesor;
|
||||
_scopeProvider = (IScopeProviderInternal) scopeProvider;
|
||||
Current = this;
|
||||
}
|
||||
|
||||
public EventMessages Get()
|
||||
{
|
||||
var messages = GetFromHttpContext();
|
||||
if (messages != null) return messages;
|
||||
|
||||
var scope = _scopeProvider.GetAmbientOrNoScope();
|
||||
return scope.Messages;
|
||||
}
|
||||
|
||||
public EventMessages GetFromHttpContext()
|
||||
{
|
||||
if (_contextAccessor == null || _contextAccessor.Value == null) return null;
|
||||
return (EventMessages)_contextAccessor.Value.Items[ContextKey];
|
||||
}
|
||||
|
||||
public EventMessages TryGet()
|
||||
{
|
||||
var messages = GetFromHttpContext();
|
||||
if (messages != null) return messages;
|
||||
|
||||
var scope = _scopeProvider.AmbientScope;
|
||||
return scope == null ? null : scope.MessagesOrNull;
|
||||
}
|
||||
|
||||
public void Set(EventMessages messages)
|
||||
{
|
||||
if (_contextAccessor.Value == null) return;
|
||||
_contextAccessor.Value.Items[ContextKey] = messages;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public interface IHttpContextAccessor
|
||||
{
|
||||
HttpContextBase Value { get; }
|
||||
}
|
||||
}
|
||||
@@ -109,5 +109,24 @@ namespace Umbraco.Core.IO
|
||||
var wrapped2 = Wrapped as IFileSystem2;
|
||||
return wrapped2 == null ? Wrapped.GetSize(path) : wrapped2.GetSize(path);
|
||||
}
|
||||
|
||||
// explicitely implementing - not breaking
|
||||
bool IFileSystem2.CanAddPhysical
|
||||
{
|
||||
get
|
||||
{
|
||||
var wrapped2 = Wrapped as IFileSystem2;
|
||||
return wrapped2 != null && wrapped2.CanAddPhysical;
|
||||
}
|
||||
}
|
||||
|
||||
// explicitely implementing - not breaking
|
||||
void IFileSystem2.AddFile(string path, string physicalPath, bool overrideIfExists, bool copy)
|
||||
{
|
||||
var wrapped2 = Wrapped as IFileSystem2;
|
||||
if (wrapped2 == null)
|
||||
throw new NotSupportedException();
|
||||
wrapped2.AddFile(path, physicalPath, overrideIfExists, copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,10 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
long GetSize(string path);
|
||||
|
||||
bool CanAddPhysical { get; }
|
||||
|
||||
void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false);
|
||||
|
||||
// TODO: implement these
|
||||
//
|
||||
//void CreateDirectory(string path);
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -24,6 +25,7 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
private readonly IContentSection _contentConfig;
|
||||
private readonly UploadAutoFillProperties _uploadAutoFillProperties;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly object _folderCounterLock = new object();
|
||||
private long _folderCounter;
|
||||
@@ -42,6 +44,7 @@ namespace Umbraco.Core.IO
|
||||
public MediaFileSystem(IFileSystem wrapped, IContentSection contentConfig, ILogger logger)
|
||||
: base(wrapped)
|
||||
{
|
||||
_logger = logger;
|
||||
_contentConfig = contentConfig;
|
||||
_uploadAutoFillProperties = new UploadAutoFillProperties(this, logger, contentConfig);
|
||||
}
|
||||
@@ -99,7 +102,7 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
else
|
||||
{
|
||||
// new scheme: path is "<cuid>-<puid>/<filename>" OR "<cuid>-<puid>-<filename>"
|
||||
// new scheme: path is "<xuid>/<filename>" where xuid is a combination of cuid and puid
|
||||
// default media filesystem maps to "~/media/<filepath>"
|
||||
// assumes that cuid and puid keys can be trusted - and that a single property type
|
||||
// for a single content cannot store two different files with the same name
|
||||
@@ -435,6 +438,64 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteMediaFiles(IEnumerable<string> files)
|
||||
{
|
||||
files = files.Distinct();
|
||||
|
||||
Parallel.ForEach(files, file =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (file.IsNullOrWhiteSpace()) return;
|
||||
|
||||
if (FileExists(file) == false) return;
|
||||
DeleteFile(file, true);
|
||||
|
||||
if (UseTheNewMediaPathScheme == false)
|
||||
{
|
||||
// old scheme: filepath is "<int>/<filename>" OR "<int>-<filename>"
|
||||
// remove the directory if any
|
||||
var dir = Path.GetDirectoryName(file);
|
||||
if (string.IsNullOrWhiteSpace(dir) == false)
|
||||
DeleteDirectory(dir, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// new scheme: path is "<xuid>/<filename>" where xuid is a combination of cuid and puid
|
||||
// remove the directory
|
||||
var dir = Path.GetDirectoryName(file);
|
||||
DeleteDirectory(dir, true);
|
||||
}
|
||||
|
||||
// I don't even understand...
|
||||
/*
|
||||
|
||||
var relativeFilePath = GetRelativePath(file); // fixme - should be relative already
|
||||
if (FileExists(relativeFilePath) == false) return;
|
||||
|
||||
var parentDirectory = Path.GetDirectoryName(relativeFilePath);
|
||||
|
||||
// don't want to delete the media folder if not using directories.
|
||||
if (_contentSection.UploadAllowDirectories && parentDirectory != GetRelativePath("/"))
|
||||
{
|
||||
//issue U4-771: if there is a parent directory the recursive parameter should be true
|
||||
DeleteDirectory(parentDirectory, string.IsNullOrEmpty(parentDirectory) == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteFile(file, true);
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error<MediaFileSystem>("Failed to delete attached file \"" + file + "\".", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region GenerateThumbnails
|
||||
|
||||
@@ -364,6 +364,29 @@ namespace Umbraco.Core.IO
|
||||
return file.Exists ? file.Length : -1;
|
||||
}
|
||||
|
||||
public bool CanAddPhysical { get { return true; } }
|
||||
|
||||
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
|
||||
{
|
||||
var fullPath = GetFullPath(path);
|
||||
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
if (overrideIfExists == false)
|
||||
throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
|
||||
File.Delete(fullPath);
|
||||
}
|
||||
|
||||
var directory = Path.GetDirectoryName(fullPath);
|
||||
if (directory == null) throw new InvalidOperationException("Could not get directory.");
|
||||
Directory.CreateDirectory(directory); // ensure it exists
|
||||
|
||||
if (copy)
|
||||
File.Copy(physicalPath, fullPath);
|
||||
else
|
||||
File.Move(physicalPath, fullPath);
|
||||
}
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
protected virtual void EnsureDirectory(string path)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
@@ -33,8 +34,16 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stream = _sfs.OpenFile(kvp.Key))
|
||||
_fs.AddFile(kvp.Key, stream, true);
|
||||
var fs2 = _fs as IFileSystem2;
|
||||
if (fs2 != null && fs2.CanAddPhysical)
|
||||
{
|
||||
fs2.AddFile(kvp.Key, _sfs.GetFullPath(kvp.Key)); // overwrite, move
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var stream = _sfs.OpenFile(kvp.Key))
|
||||
_fs.AddFile(kvp.Key, stream, true);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -201,19 +210,20 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public IEnumerable<string> GetFiles(string path)
|
||||
{
|
||||
var normPath = NormPath(path);
|
||||
var shadows = Nodes.Where(kvp => IsChild(normPath, kvp.Key)).ToArray();
|
||||
var files = _fs.GetFiles(path);
|
||||
return files
|
||||
.Except(shadows.Where(kvp => (kvp.Value.IsFile && kvp.Value.IsDelete) || kvp.Value.IsDir)
|
||||
.Select(kvp => kvp.Key))
|
||||
.Union(shadows.Where(kvp => kvp.Value.IsFile && kvp.Value.IsExist).Select(kvp => kvp.Key))
|
||||
.Distinct();
|
||||
return GetFiles(path, null);
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetFiles(string path, string filter)
|
||||
{
|
||||
return _fs.GetFiles(path, filter);
|
||||
var normPath = NormPath(path);
|
||||
var shadows = Nodes.Where(kvp => IsChild(normPath, kvp.Key)).ToArray();
|
||||
var files = filter != null ? _fs.GetFiles(path, filter) : _fs.GetFiles(path);
|
||||
var regexFilter = FilterToRegex(filter);
|
||||
return files
|
||||
.Except(shadows.Where(kvp => (kvp.Value.IsFile && kvp.Value.IsDelete) || kvp.Value.IsDir)
|
||||
.Select(kvp => kvp.Key))
|
||||
.Union(shadows.Where(kvp => kvp.Value.IsFile && kvp.Value.IsExist && FilterByRegex(kvp.Key, regexFilter)).Select(kvp => kvp.Key))
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
public Stream OpenFile(string path)
|
||||
@@ -245,6 +255,9 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public string GetFullPath(string path)
|
||||
{
|
||||
ShadowNode sf;
|
||||
if (Nodes.TryGetValue(NormPath(path), out sf))
|
||||
return sf.IsDir || sf.IsDelete ? null : _sfs.GetFullPath(path);
|
||||
return _fs.GetFullPath(path);
|
||||
}
|
||||
|
||||
@@ -282,5 +295,63 @@ namespace Umbraco.Core.IO
|
||||
if (sf.IsDelete || sf.IsDir) throw new InvalidOperationException("Invalid path.");
|
||||
return _sfs.GetSize(path);
|
||||
}
|
||||
|
||||
public bool CanAddPhysical { get { return true; } }
|
||||
|
||||
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
|
||||
{
|
||||
ShadowNode sf;
|
||||
var normPath = NormPath(path);
|
||||
if (Nodes.TryGetValue(normPath, out sf) && sf.IsExist && (sf.IsDir || overrideIfExists == false))
|
||||
throw new InvalidOperationException(string.Format("A file at path '{0}' already exists", path));
|
||||
|
||||
var parts = normPath.Split('/');
|
||||
for (var i = 0; i < parts.Length - 1; i++)
|
||||
{
|
||||
var dirPath = string.Join("/", parts.Take(i + 1));
|
||||
ShadowNode sd;
|
||||
if (Nodes.TryGetValue(dirPath, out sd))
|
||||
{
|
||||
if (sd.IsFile) throw new InvalidOperationException("Invalid path.");
|
||||
if (sd.IsDelete) Nodes[dirPath] = new ShadowNode(false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_fs.DirectoryExists(dirPath)) continue;
|
||||
if (_fs.FileExists(dirPath)) throw new InvalidOperationException("Invalid path.");
|
||||
Nodes[dirPath] = new ShadowNode(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
_sfs.AddFile(path, physicalPath, overrideIfExists, copy);
|
||||
Nodes[normPath] = new ShadowNode(false, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function for filtering keys by Regex if a filter is specified.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="regexFilter"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool FilterByRegex(string input, string regexFilter)
|
||||
{
|
||||
if (regexFilter == null) return true;
|
||||
return regexFilter != string.Empty && Regex.IsMatch(input, regexFilter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms a filter pattern into a Regex pattern
|
||||
/// </summary>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Appending '$' only if not containing wildcard is stupid and broken.
|
||||
/// It is however what seems to be what they're doing in .NET so we need to match the functionality.
|
||||
/// </remarks>
|
||||
internal static string FilterToRegex(string pattern)
|
||||
{
|
||||
if (pattern == null) return null;
|
||||
return "^" + Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + (pattern.Contains("*") ? string.Empty : "$");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,5 +164,22 @@ namespace Umbraco.Core.IO
|
||||
var filesystem2 = filesystem as IFileSystem2;
|
||||
return filesystem2 == null ? filesystem.GetSize(path) : filesystem2.GetSize(path);
|
||||
}
|
||||
|
||||
public bool CanAddPhysical
|
||||
{
|
||||
get
|
||||
{
|
||||
var fileSystem2 = FileSystem as IFileSystem2;
|
||||
return fileSystem2 != null && fileSystem2.CanAddPhysical;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddFile(string path, string physicalPath, bool overrideIfExists = true, bool copy = false)
|
||||
{
|
||||
var fileSystem2 = FileSystem as IFileSystem2;
|
||||
if (fileSystem2 == null)
|
||||
throw new NotSupportedException();
|
||||
fileSystem2.AddFile(path, physicalPath, overrideIfExists, copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Core.Models
|
||||
return descendants;
|
||||
}
|
||||
|
||||
throw new NotSupportedException("The content type must be " + typeof(IContentType) + " or " + typeof(IMediaType));
|
||||
//No other content types have children (i.e. member types)
|
||||
return Enumerable.Empty<IContentTypeBase>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
|
||||
{
|
||||
config.CreateMap<IUser, BackOfficeIdentityUser>()
|
||||
.ForMember(user => user.LastLoginDateUtc, expression => expression.MapFrom(user => user.LastLoginDate.ToUniversalTime()))
|
||||
.ForMember(user => user.Email, expression => expression.MapFrom(user => user.Email))
|
||||
.ForMember(user => user.Id, expression => expression.MapFrom(user => user.Id))
|
||||
.ForMember(user => user.LockoutEndDateUtc, expression => expression.MapFrom(user => user.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?)null))
|
||||
|
||||
@@ -24,12 +24,17 @@ namespace Umbraco.Core.Models.Identity
|
||||
///
|
||||
/// </summary>
|
||||
public IdentityUser()
|
||||
{
|
||||
{
|
||||
this.Claims = new List<TClaim>();
|
||||
this.Roles = new List<TRole>();
|
||||
this.Logins = new List<TLogin>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Last login date
|
||||
/// </summary>
|
||||
public virtual DateTime? LastLoginDateUtc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Email
|
||||
///
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
internal class DataTypePreValueDto
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 6)]
|
||||
[PrimaryKeyColumn(IdentitySeed = 10)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("datatypeNodeId")]
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[Column("nodeId")]
|
||||
[ForeignKey(typeof(NodeDto))]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_umbracoUser2NodePermission_nodeId")]
|
||||
public int NodeId { get; set; }
|
||||
|
||||
[Column("permission")]
|
||||
|
||||
@@ -113,6 +113,11 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When resolved from EntityService this checks if the entity has the HasChildren flag
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasChildren(this IUmbracoEntity entity)
|
||||
{
|
||||
if (entity.AdditionalData.ContainsKey("HasChildren"))
|
||||
@@ -133,6 +138,11 @@ namespace Umbraco.Core.Models
|
||||
return entity.AdditionalData.GetValueIgnoreCase(key, defaultVal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When resolved from EntityService this checks if the entity has the IsContainer flag
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsContainer(this IUmbracoEntity entity)
|
||||
{
|
||||
if (entity.AdditionalData.ContainsKeyIgnoreCase("IsContainer") == false) return false;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Root
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.SystemRoot)]
|
||||
[UmbracoObjectType(Constants.ObjectTypes.SystemRoot)]
|
||||
[FriendlyName("Root")]
|
||||
ROOT,
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Document, typeof(IContent))]
|
||||
[FriendlyName("Document")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.Document)]
|
||||
Document,
|
||||
|
||||
/// <summary>
|
||||
@@ -42,6 +43,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Media, typeof(IMedia))]
|
||||
[FriendlyName("Media")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.Media)]
|
||||
Media,
|
||||
|
||||
/// <summary>
|
||||
@@ -49,6 +51,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.MemberType, typeof(IMemberType))]
|
||||
[FriendlyName("Member Type")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.MemberType)]
|
||||
MemberType,
|
||||
|
||||
/// <summary>
|
||||
@@ -56,6 +59,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Template, typeof(ITemplate))]
|
||||
[FriendlyName("Template")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.Template)]
|
||||
Template,
|
||||
|
||||
/// <summary>
|
||||
@@ -63,6 +67,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.MemberGroup)]
|
||||
[FriendlyName("Member Group")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.MemberGroup)]
|
||||
MemberGroup,
|
||||
|
||||
//TODO: What is a 'Content Item' supposed to be???
|
||||
@@ -80,6 +85,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.MediaType, typeof(IMediaType))]
|
||||
[FriendlyName("Media Type")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.MediaType)]
|
||||
MediaType,
|
||||
|
||||
/// <summary>
|
||||
@@ -87,13 +93,14 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DocumentType, typeof(IContentType))]
|
||||
[FriendlyName("Document Type")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.DocumentType)]
|
||||
DocumentType,
|
||||
|
||||
/// <summary>
|
||||
/// Recycle Bin
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.ContentRecycleBin)]
|
||||
[FriendlyName("Recycle Bin")]
|
||||
[FriendlyName("Recycle Bin")]
|
||||
RecycleBin,
|
||||
|
||||
/// <summary>
|
||||
@@ -101,6 +108,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Stylesheet)]
|
||||
[FriendlyName("Stylesheet")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.Stylesheet)]
|
||||
Stylesheet,
|
||||
|
||||
/// <summary>
|
||||
@@ -108,6 +116,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Member, typeof(IMember))]
|
||||
[FriendlyName("Member")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.Member)]
|
||||
Member,
|
||||
|
||||
/// <summary>
|
||||
@@ -115,6 +124,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DataType, typeof(IDataTypeDefinition))]
|
||||
[FriendlyName("Data Type")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.DataType)]
|
||||
DataType,
|
||||
|
||||
/// <summary>
|
||||
@@ -122,6 +132,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DocumentTypeContainer)]
|
||||
[FriendlyName("Document Type Container")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.DocumentTypeContainer)]
|
||||
DocumentTypeContainer,
|
||||
|
||||
/// <summary>
|
||||
@@ -129,6 +140,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.MediaTypeContainer)]
|
||||
[FriendlyName("Media Type Container")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.MediaTypeContainer)]
|
||||
MediaTypeContainer,
|
||||
|
||||
/// <summary>
|
||||
@@ -136,6 +148,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DataTypeContainer)]
|
||||
[FriendlyName("Data Type Container")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.DataTypeContainer)]
|
||||
DataTypeContainer,
|
||||
|
||||
/// <summary>
|
||||
@@ -143,6 +156,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.RelationType)]
|
||||
[FriendlyName("Relation Type")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.RelationType)]
|
||||
RelationType,
|
||||
|
||||
/// <summary>
|
||||
@@ -153,17 +167,17 @@ namespace Umbraco.Core.Models
|
||||
FormsForm,
|
||||
|
||||
/// <summary>
|
||||
/// Forms Workflow
|
||||
/// Forms PreValue
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsWorkflow)]
|
||||
[FriendlyName("Workflow")]
|
||||
FormsWorkflow,
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsPreValue)]
|
||||
[FriendlyName("PreValue")]
|
||||
FormsPreValue,
|
||||
|
||||
/// <summary>
|
||||
/// Forms Record
|
||||
/// Forms DataSource
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsRecord)]
|
||||
[FriendlyName("Record")]
|
||||
FormsRecord
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsDataSource)]
|
||||
[FriendlyName("DataSource")]
|
||||
FormsDataSource
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
//MUST be concurrent to avoid thread collisions!
|
||||
private static readonly ConcurrentDictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new ConcurrentDictionary<UmbracoObjectTypes, Guid>();
|
||||
private static readonly ConcurrentDictionary<UmbracoObjectTypes, string> UmbracoObjectTypeUdiCache = new ConcurrentDictionary<UmbracoObjectTypes, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Get an UmbracoObjectTypes value from it's name
|
||||
@@ -43,6 +44,21 @@ namespace Umbraco.Core.Models
|
||||
return umbracoObjectType;
|
||||
}
|
||||
|
||||
public static string GetUdiType(Guid guid)
|
||||
{
|
||||
var umbracoObjectType = Constants.UdiEntityType.Unknown;
|
||||
|
||||
foreach (var name in Enum.GetNames(typeof(UmbracoObjectTypes)))
|
||||
{
|
||||
var objType = GetUmbracoObjectType(name);
|
||||
if (objType.GetGuid() == guid)
|
||||
{
|
||||
umbracoObjectType = GetUdiType(objType);
|
||||
}
|
||||
}
|
||||
return umbracoObjectType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method for the UmbracoObjectTypes enum to return the enum GUID
|
||||
/// </summary>
|
||||
@@ -68,6 +84,26 @@ namespace Umbraco.Core.Models
|
||||
});
|
||||
}
|
||||
|
||||
public static string GetUdiType(this UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
return UmbracoObjectTypeUdiCache.GetOrAdd(umbracoObjectType, types =>
|
||||
{
|
||||
var type = typeof(UmbracoObjectTypes);
|
||||
var memInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoUdiTypeAttribute),
|
||||
false);
|
||||
|
||||
if (attributes.Length == 0)
|
||||
return Constants.UdiEntityType.Unknown;
|
||||
|
||||
var attribute = ((UmbracoUdiTypeAttribute)attributes[0]);
|
||||
if (attribute == null)
|
||||
return Constants.UdiEntityType.Unknown;
|
||||
|
||||
return attribute.UdiType;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method for the UmbracoObjectTypes enum to return the enum name
|
||||
/// </summary>
|
||||
|
||||
@@ -647,5 +647,10 @@ namespace Umbraco.Core
|
||||
return "[GetPropertyValueException]";
|
||||
}
|
||||
}
|
||||
|
||||
internal static Guid AsGuid(this object value)
|
||||
{
|
||||
return value is Guid ? (Guid) value : Guid.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
entity.ContentTypeThumbnail = asDictionary.ContainsKey("thumbnail") ? (d.thumbnail ?? string.Empty) : string.Empty;
|
||||
|
||||
var publishedVersion = default(Guid);
|
||||
//some content items don't have a published version
|
||||
//some content items don't have a published/newest version
|
||||
if (asDictionary.ContainsKey("publishedVersion") && asDictionary["publishedVersion"] != null)
|
||||
{
|
||||
Guid.TryParse(d.publishedVersion.ToString(), out publishedVersion);
|
||||
|
||||
@@ -130,21 +130,21 @@ 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 = 1034, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1034", SortOrder = 2, UniqueId = new Guid("a6857c73-d6e9-480c-b6e6-f15f6ad11125"), Text = "Content Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1035, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1035", SortOrder = 2, UniqueId = new Guid("93929b9a-93a2-4e2a-b239-d99334440a59"), Text = "Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1036, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1036", SortOrder = 2, UniqueId = new Guid("2b24165f-9782-4aa3-b459-1de4a4d21f60"), Text = "Member Picker", 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 = 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 = 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 });
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1045, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1045", SortOrder = 2, UniqueId = new Guid("7E3962CC-CE20-4FFC-B661-5897A894BA7E"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
|
||||
//New UDI pickers with newer Ids
|
||||
_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1046, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1046", SortOrder = 2, UniqueId = new Guid("FD1E0DA5-5606-4862-B679-5D0CF3A52A59"), Text = "Content Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
_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 });
|
||||
|
||||
//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 });
|
||||
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1038, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1038", SortOrder = 2, UniqueId = new Guid("1251c96c-185c-4e9b-93f4-b48205573cbd"), Text = "Simple Editor", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
|
||||
//_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1042, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1042", SortOrder = 2, UniqueId = new Guid("0a452bd5-83f9-4bc3-8403-1286e13fb77e"), Text = "Macro Container", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now });
|
||||
}
|
||||
|
||||
@@ -246,17 +246,19 @@ 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 = 16, DataTypeId = 1034, PropertyEditorAlias = Constants.PropertyEditors.ContentPickerAlias, DbType = "Integer" });
|
||||
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 18, DataTypeId = 1036, PropertyEditorAlias = Constants.PropertyEditors.MemberPickerAlias, DbType = "Integer" });
|
||||
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 17, DataTypeId = 1035, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Nvarchar" });
|
||||
_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 = 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 = 25, DataTypeId = 1045, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Nvarchar" });
|
||||
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -26, DataTypeId = Constants.System.DefaultContentListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
|
||||
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -27, DataTypeId = Constants.System.DefaultMediaListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
|
||||
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -28, DataTypeId = Constants.System.DefaultMembersListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
|
||||
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = -28, DataTypeId = Constants.System.DefaultMembersListViewDataTypeId, PropertyEditorAlias = Constants.PropertyEditors.ListViewAlias, DbType = "Nvarchar" });
|
||||
|
||||
//New UDI pickers with newer Ids
|
||||
_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 26, DataTypeId = 1046, PropertyEditorAlias = Constants.PropertyEditors.ContentPicker2Alias, DbType = "Nvarchar" });
|
||||
_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" });
|
||||
|
||||
//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" });
|
||||
@@ -268,10 +270,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 3, Alias = "", SortOrder = 0, DataTypeNodeId = -87, Value = ",code,undo,redo,cut,copy,mcepasteword,stylepicker,bold,italic,bullist,numlist,outdent,indent,mcelink,unlink,mceinsertanchor,mceimage,umbracomacro,mceinserttable,umbracoembed,mcecharmap,|1|1,2,3,|0|500,400|1049,|true|" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 4, Alias = "group", SortOrder = 0, DataTypeNodeId = 1041, Value = "default" });
|
||||
|
||||
//default's for MultipleMediaPickerAlias picker
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 5, Alias = "multiPicker", SortOrder = 0, DataTypeNodeId = 1045, Value = "1" });
|
||||
|
||||
|
||||
//defaults for the member list
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -1, Alias = "pageSize", SortOrder = 1, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "10" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -2, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "username" });
|
||||
@@ -288,6 +287,9 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -7, Alias = "orderDirection", SortOrder = 3, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "desc" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -8, Alias = "layouts", SortOrder = 4, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[" + cardLayout + "," + listLayout + "]" });
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -9, Alias = "includeProperties", SortOrder = 5, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1},{\"alias\":\"owner\",\"header\":\"Updated by\",\"isSystem\":1}]" });
|
||||
|
||||
//default's for MultipleMediaPickerAlias picker
|
||||
_database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = 6, Alias = "multiPicker", SortOrder = 0, DataTypeNodeId = 1049, Value = "1" });
|
||||
}
|
||||
|
||||
private void CreateUmbracoRelationTypeData()
|
||||
|
||||
+1
-8
@@ -14,14 +14,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database)
|
||||
.Select(x => new DbIndexDefinition()
|
||||
{
|
||||
TableName = x.Item1,
|
||||
IndexName = x.Item2,
|
||||
ColumnName = x.Item3,
|
||||
IsUnique = x.Item4
|
||||
}).ToArray();
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMember_LoginName")) == false)
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSixZero
|
||||
{
|
||||
[Migration("7.6.0", 0, Constants.System.UmbracoMigrationName)]
|
||||
public class AddIndexToUser2NodePermission : MigrationBase
|
||||
{
|
||||
public AddIndexToUser2NodePermission(ISqlSyntaxProvider sqlSyntax, ILogger logger)
|
||||
: base(sqlSyntax, logger)
|
||||
{ }
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
|
||||
|
||||
//make sure it doesn't already exist
|
||||
if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoUser2NodePermission_nodeId")) == false)
|
||||
{
|
||||
Create.Index("IX_umbracoUser2NodePermission_nodeId").OnTable("umbracoUser2NodePermission")
|
||||
.OnColumn("nodeId")
|
||||
.Ascending()
|
||||
.WithOptions()
|
||||
.NonClustered();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
Delete.Index("IX_umbracoUser2NodePermission_nodeId").OnTable("cmsMember");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -703,7 +703,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
|
||||
{
|
||||
sqlSelectRemoved = null;
|
||||
@@ -723,10 +723,9 @@ namespace Umbraco.Core.Persistence
|
||||
sqlCount = sql.Substring(0, g.Index) + "COUNT(" + m.Groups[1].ToString().Trim() + ") " + sql.Substring(g.Index + g.Length);
|
||||
else
|
||||
sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length);
|
||||
|
||||
|
||||
// Look for an "ORDER BY <whatever>" clause
|
||||
m = rxOrderBy.Match(sqlCount);
|
||||
|
||||
// Look for an "ORDER BY <whatever>" clause
|
||||
m = rxOrderBy.Match(sqlCount);
|
||||
if (!m.Success)
|
||||
{
|
||||
sqlOrderBy = null;
|
||||
@@ -737,8 +736,7 @@ namespace Umbraco.Core.Persistence
|
||||
sqlOrderBy = g.ToString();
|
||||
sqlCount = sqlCount.Substring(0, g.Index) + sqlCount.Substring(g.Index + g.Length);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -820,7 +818,7 @@ namespace Umbraco.Core.Persistence
|
||||
result.CurrentPage = page;
|
||||
result.ItemsPerPage = itemsPerPage;
|
||||
result.TotalItems = ExecuteScalar<long>(sqlCount, args);
|
||||
result.TotalPages = result.TotalItems / itemsPerPage;
|
||||
result.TotalPages = result.TotalItems / itemsPerPage;
|
||||
if ((result.TotalItems % itemsPerPage) != 0)
|
||||
result.TotalPages++;
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
// try to update
|
||||
var rowCount = updateCommand.IsNullOrWhiteSpace()
|
||||
? db.Update(poco)
|
||||
: db.Update<T>(updateCommand, updateArgs);
|
||||
? db.Update(poco)
|
||||
: db.Update<T>(updateCommand, updateArgs);
|
||||
if (rowCount > 0)
|
||||
return RecordPersistenceType.Update;
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
[Obsolete("Use the DatabaseSchemaHelper instead")]
|
||||
public static void CreateTable<T>(this Database db)
|
||||
where T : new()
|
||||
where T : new()
|
||||
{
|
||||
var creator = new DatabaseSchemaHelper(db, LoggerResolver.Current.Logger, SqlSyntaxContext.SqlSyntaxProvider);
|
||||
creator.CreateTable<T>();
|
||||
@@ -170,7 +170,7 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
[Obsolete("Use the DatabaseSchemaHelper instead")]
|
||||
public static void CreateTable<T>(this Database db, bool overwrite)
|
||||
where T : new()
|
||||
where T : new()
|
||||
{
|
||||
var creator = new DatabaseSchemaHelper(db, LoggerResolver.Current.Logger, SqlSyntaxContext.SqlSyntaxProvider);
|
||||
creator.CreateTable<T>(overwrite);
|
||||
@@ -231,6 +231,24 @@ namespace Umbraco.Core.Persistence
|
||||
ISqlSyntaxProvider syntaxProvider,
|
||||
bool useNativeSqlPlatformBulkInsert = true,
|
||||
bool commitTrans = false)
|
||||
{
|
||||
db.OpenSharedConnection();
|
||||
try
|
||||
{
|
||||
return BulkInsertRecordsTry(db, collection, tr, syntaxProvider, useNativeSqlPlatformBulkInsert, commitTrans);
|
||||
}
|
||||
finally
|
||||
{
|
||||
db.CloseSharedConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public static int BulkInsertRecordsTry<T>(this Database db,
|
||||
IEnumerable<T> collection,
|
||||
Transaction tr,
|
||||
ISqlSyntaxProvider syntaxProvider,
|
||||
bool useNativeSqlPlatformBulkInsert = true,
|
||||
bool commitTrans = false)
|
||||
{
|
||||
if (commitTrans && tr == null)
|
||||
throw new ArgumentNullException("tr", "The transaction cannot be null if commitTrans is true.");
|
||||
@@ -241,15 +259,15 @@ namespace Umbraco.Core.Persistence
|
||||
return 0;
|
||||
}
|
||||
|
||||
var pd = Database.PocoData.ForType(typeof(T));
|
||||
if (pd == null) throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
|
||||
var pd = Database.PocoData.ForType(typeof (T));
|
||||
if (pd == null) throw new InvalidOperationException("Could not find PocoData for " + typeof (T));
|
||||
|
||||
try
|
||||
{
|
||||
int processed = 0;
|
||||
|
||||
var usedNativeSqlPlatformInserts = useNativeSqlPlatformBulkInsert
|
||||
&& NativeSqlPlatformBulkInsertRecords(db, syntaxProvider, pd, collection, out processed);
|
||||
&& NativeSqlPlatformBulkInsertRecords(db, syntaxProvider, pd, collection, out processed);
|
||||
|
||||
if (usedNativeSqlPlatformInserts == false)
|
||||
{
|
||||
@@ -283,19 +301,13 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
|
||||
if (commitTrans)
|
||||
{
|
||||
if (tr == null) throw new ArgumentNullException("The transaction cannot be null if commitTrans is true");
|
||||
tr.Complete();
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (commitTrans)
|
||||
{
|
||||
if (tr == null) throw new ArgumentNullException("The transaction cannot be null if commitTrans is true");
|
||||
tr.Dispose();
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -337,13 +349,16 @@ namespace Umbraco.Core.Persistence
|
||||
IEnumerable<T> collection,
|
||||
out string[] sql)
|
||||
{
|
||||
if (db == null) throw new ArgumentNullException("db");
|
||||
if (db.Connection == null) throw new ArgumentException("db.Connection is null.");
|
||||
|
||||
var tableName = db.EscapeTableName(pd.TableInfo.TableName);
|
||||
|
||||
//get all columns to include and format for sql
|
||||
var cols = string.Join(", ",
|
||||
pd.Columns
|
||||
.Where(c => IncludeColumn(pd, c))
|
||||
.Select(c => tableName + "." + db.EscapeSqlIdentifier(c.Key)).ToArray());
|
||||
.Where(c => IncludeColumn(pd, c))
|
||||
.Select(c => tableName + "." + db.EscapeSqlIdentifier(c.Key)).ToArray());
|
||||
|
||||
var itemArray = collection.ToArray();
|
||||
|
||||
@@ -357,9 +372,9 @@ namespace Umbraco.Core.Persistence
|
||||
// 4168 / 262 = 15.908... = there will be 16 trans in total
|
||||
|
||||
//all items will be included if we have disabled db parameters
|
||||
var itemsPerTrans = Math.Floor(2000.00 / paramsPerItem);
|
||||
var itemsPerTrans = Math.Floor(2000.00/paramsPerItem);
|
||||
//there will only be one transaction if we have disabled db parameters
|
||||
var numTrans = Math.Ceiling(itemArray.Length / itemsPerTrans);
|
||||
var numTrans = Math.Ceiling(itemArray.Length/itemsPerTrans);
|
||||
|
||||
var sqlQueries = new List<string>();
|
||||
var commands = new List<IDbCommand>();
|
||||
@@ -367,8 +382,8 @@ namespace Umbraco.Core.Persistence
|
||||
for (var tIndex = 0; tIndex < numTrans; tIndex++)
|
||||
{
|
||||
var itemsForTrans = itemArray
|
||||
.Skip(tIndex * (int)itemsPerTrans)
|
||||
.Take((int)itemsPerTrans);
|
||||
.Skip(tIndex*(int) itemsPerTrans)
|
||||
.Take((int) itemsPerTrans);
|
||||
|
||||
var cmd = db.CreateCommand(db.Connection, string.Empty);
|
||||
var pocoValues = new List<string>();
|
||||
@@ -418,7 +433,6 @@ namespace Umbraco.Core.Persistence
|
||||
/// <param name="processed">The number of records inserted</param>
|
||||
private static bool NativeSqlPlatformBulkInsertRecords<T>(Database db, ISqlSyntaxProvider syntaxProvider, Database.PocoData pd, IEnumerable<T> collection, out int processed)
|
||||
{
|
||||
|
||||
var dbConnection = db.Connection;
|
||||
|
||||
//unwrap the profiled connection if there is one
|
||||
@@ -447,7 +461,6 @@ namespace Umbraco.Core.Persistence
|
||||
//could not use the SQL server's specific bulk insert operations
|
||||
processed = 0;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -785,13 +785,8 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
|
||||
public void ClearPublished(IContent content)
|
||||
{
|
||||
// race cond!
|
||||
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId=@id AND published=@published", new { id = content.Id, published = true });
|
||||
foreach (var documentDto in documentDtos)
|
||||
{
|
||||
documentDto.Published = false;
|
||||
Database.Update(documentDto);
|
||||
}
|
||||
var sql = "UPDATE cmsDocument SET published=0 WHERE nodeId=@id AND published=1";
|
||||
Database.Execute(sql, new {id = content.Id});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,6 +9,7 @@ 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;
|
||||
@@ -49,6 +50,124 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region Query Methods
|
||||
|
||||
public IEnumerable<IUmbracoEntity> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null)
|
||||
{
|
||||
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
|
||||
bool isMedia = objectTypeId == new Guid(Constants.ObjectTypes.Media);
|
||||
var factory = new UmbracoEntityFactory();
|
||||
|
||||
var sqlClause = GetBaseWhere(GetBase, isContent, isMedia, sql =>
|
||||
{
|
||||
if (filter != null)
|
||||
{
|
||||
foreach (var filterClaus in filter.GetWhereClauses())
|
||||
{
|
||||
sql.Where(filterClaus.Item1, filterClaus.Item2);
|
||||
}
|
||||
}
|
||||
}, objectTypeId);
|
||||
var translator = new SqlTranslator<IUmbracoEntity>(sqlClause, query);
|
||||
var entitySql = translator.Translate();
|
||||
var pagedSql = entitySql.Append(GetGroupBy(isContent, isMedia, false)).OrderBy("umbracoNode.id");
|
||||
|
||||
IEnumerable<IUmbracoEntity> result;
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var pagedResult = _work.Database.Page<dynamic>(pageIndex + 1, pageSize, pagedSql);
|
||||
|
||||
var ids = pagedResult.Items.Select(x => (int) x.id).InGroupsOf(2000);
|
||||
var entities = pagedResult.Items.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
|
||||
|
||||
//Now we need to merge in the property data since we need paging and we can't do this the way that the big media query was working before
|
||||
foreach (var idGroup in ids)
|
||||
{
|
||||
var propSql = GetPropertySql(Constants.ObjectTypes.Media)
|
||||
.Where("contentNodeId IN (@ids)", new {ids = idGroup})
|
||||
.OrderBy("contentNodeId");
|
||||
|
||||
//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 = _work.Database.Query<dynamic>(propSql);
|
||||
|
||||
//keep track of the current property data item being enumerated
|
||||
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
|
||||
var hasCurrent = false; // initially there is no enumerator.Current
|
||||
|
||||
try
|
||||
{
|
||||
//This must be sorted by node id (which is done by SQL) 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 entity in entities)
|
||||
{
|
||||
// assemble the dtos for this def
|
||||
// use the available enumerator.Current if any else move to next
|
||||
while (hasCurrent || propertyDataSetEnumerator.MoveNext())
|
||||
{
|
||||
if (propertyDataSetEnumerator.Current.contentNodeId == entity.Id)
|
||||
{
|
||||
hasCurrent = false; // enumerator.Current is not available
|
||||
|
||||
//the property data goes into the additional data
|
||||
entity.AdditionalData[propertyDataSetEnumerator.Current.propertyTypeAlias] = new UmbracoEntity.EntityProperty
|
||||
{
|
||||
PropertyEditorAlias = propertyDataSetEnumerator.Current.propertyEditorAlias,
|
||||
Value = StringExtensions.IsNullOrWhiteSpace(propertyDataSetEnumerator.Current.dataNtext)
|
||||
? propertyDataSetEnumerator.Current.dataNvarchar
|
||||
: StringExtensions.ConvertToJsonIfPossible(propertyDataSetEnumerator.Current.dataNtext)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
hasCurrent = true; // enumerator.Current is available for another def
|
||||
break; // no more propertyDataDto for this def
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
propertyDataSetEnumerator.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
result = entities;
|
||||
}
|
||||
else
|
||||
{
|
||||
var pagedResult = _work.Database.Page<dynamic>(pageIndex + 1, pageSize, pagedSql);
|
||||
result = pagedResult.Items.Select(factory.BuildEntityFromDynamic).Cast<IUmbracoEntity>().ToList();
|
||||
}
|
||||
|
||||
//The total items from the PetaPoco page query will be wrong due to the Outer join used on parent, depending on the search this will
|
||||
//return duplicate results when the COUNT is used in conjuction with it, so we need to get the total on our own.
|
||||
|
||||
//generate a query that does not contain the LEFT Join for parent, this would cause
|
||||
//the COUNT(*) query to return the wrong
|
||||
var sqlCountClause = GetBaseWhere(
|
||||
(isC, isM, f) => GetBase(isC, isM, f, true), //true == is a count query
|
||||
isContent, isMedia, sql =>
|
||||
{
|
||||
if (filter != null)
|
||||
{
|
||||
foreach (var filterClaus in filter.GetWhereClauses())
|
||||
{
|
||||
sql.Where(filterClaus.Item1, filterClaus.Item2);
|
||||
}
|
||||
}
|
||||
}, objectTypeId);
|
||||
var translatorCount = new SqlTranslator<IUmbracoEntity>(sqlCountClause, query);
|
||||
var countSql = translatorCount.Translate();
|
||||
|
||||
totalRecords = _work.Database.ExecuteScalar<int>(countSql);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IUmbracoEntity GetByKey(Guid key)
|
||||
{
|
||||
var sql = GetBaseWhere(GetBase, false, false, key);
|
||||
@@ -71,8 +190,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
|
||||
@@ -115,8 +233,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
|
||||
@@ -171,8 +288,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isMedia)
|
||||
{
|
||||
//for now treat media differently
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, sql);
|
||||
foreach (var entity in entities)
|
||||
@@ -231,8 +347,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
});
|
||||
|
||||
//treat media differently for now
|
||||
//TODO: We should really use this methodology for Content/Members too!! since it includes properties and ALL of the dynamic db fields
|
||||
//Treat media differently for now, as an Entity it will be returned with ALL of it's properties in the AdditionalData bag!
|
||||
var entities = _work.Database.Fetch<dynamic, UmbracoPropertyDto, UmbracoEntity>(
|
||||
new UmbracoEntityRelator().Map, mediaSql);
|
||||
return entities;
|
||||
@@ -278,11 +393,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return GetFullSqlForMedia(entitySql.Append(GetGroupBy(isContent, true, false)), filter);
|
||||
}
|
||||
|
||||
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
|
||||
private Sql GetPropertySql(string nodeObjectType)
|
||||
{
|
||||
//this will add any dataNvarchar property to the output which can be added to the additional properties
|
||||
|
||||
var joinSql = new Sql()
|
||||
var sql = new Sql()
|
||||
.Select("contentNodeId, versionId, dataNvarchar, dataNtext, propertyEditorAlias, alias as propertyTypeAlias")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
@@ -291,7 +404,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.On<PropertyTypeDto, PropertyDataDto>(dto => dto.Id, dto => dto.PropertyTypeId)
|
||||
.InnerJoin<DataTypeDto>()
|
||||
.On<PropertyTypeDto, DataTypeDto>(dto => dto.DataTypeId, dto => dto.DataTypeId)
|
||||
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new {nodeObjectType = Constants.ObjectTypes.Media});
|
||||
.Where("umbracoNode.nodeObjectType = @nodeObjectType", new { nodeObjectType = nodeObjectType });
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
private Sql GetFullSqlForMedia(Sql entitySql, Action<Sql> filter = null)
|
||||
{
|
||||
//this will add any dataNvarchar property to the output which can be added to the additional properties
|
||||
|
||||
var joinSql = GetPropertySql(Constants.ObjectTypes.Media);
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
@@ -310,34 +432,52 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.OrderBy("sortOrder, id");
|
||||
|
||||
return wrappedSql;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter)
|
||||
{
|
||||
var columns = new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate",
|
||||
"COUNT(parent.parentID) as children"
|
||||
};
|
||||
return GetBase(isContent, isMedia, customFilter, false);
|
||||
}
|
||||
|
||||
if (isContent || isMedia)
|
||||
protected virtual Sql GetBase(bool isContent, bool isMedia, Action<Sql> customFilter, bool isCount)
|
||||
{
|
||||
var columns = new List<object>();
|
||||
if (isCount)
|
||||
{
|
||||
columns.Add("published.versionId as publishedVersion");
|
||||
columns.Add("latest.versionId as newestVersion");
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
columns.Add("contenttype.isContainer");
|
||||
columns.Add("COUNT(*)");
|
||||
}
|
||||
else
|
||||
{
|
||||
columns.AddRange(new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate",
|
||||
"COUNT(parent.parentID) as children"
|
||||
});
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
if (isContent)
|
||||
{
|
||||
//only content has this info
|
||||
columns.Add("published.versionId as publishedVersion");
|
||||
columns.Add("document.versionId as newestVersion");
|
||||
}
|
||||
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
columns.Add("contenttype.isContainer");
|
||||
}
|
||||
}
|
||||
|
||||
//Creates an SQL query to return a single row for the entity
|
||||
@@ -348,17 +488,24 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id")
|
||||
.LeftJoin("cmsContentType contenttype").On("contenttype.nodeId = content.contentType")
|
||||
.LeftJoin(
|
||||
"(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published")
|
||||
.On("umbracoNode.id = published.nodeId")
|
||||
.LeftJoin(
|
||||
"(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest")
|
||||
.On("umbracoNode.id = latest.nodeId");
|
||||
entitySql.InnerJoin("cmsContent content").On("content.nodeId = umbracoNode.id");
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
//only content has this info
|
||||
entitySql
|
||||
.InnerJoin("cmsDocument document").On("document.nodeId = umbracoNode.id")
|
||||
.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("umbracoNode parent").On("parent.parentID = umbracoNode.id");
|
||||
if (isCount == false)
|
||||
{
|
||||
entitySql.LeftJoin("umbracoNode parent").On("parent.parentID = umbracoNode.id");
|
||||
}
|
||||
|
||||
if (customFilter != null)
|
||||
{
|
||||
@@ -372,22 +519,42 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, filter)
|
||||
.Where("umbracoNode.nodeObjectType = @NodeObjectType", new { NodeObjectType = nodeObjectType });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetBaseWhere(Func<bool, bool, Action<Sql>, Sql> baseQuery, bool isContent, bool isMedia, int id)
|
||||
{
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.id = @Id", new { Id = id })
|
||||
.Append(GetGroupBy(isContent, isMedia));
|
||||
.Where("umbracoNode.id = @Id", new { Id = id });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
sql.Append(GetGroupBy(isContent, isMedia));
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
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 })
|
||||
.Append(GetGroupBy(isContent, isMedia));
|
||||
.Where("umbracoNode.uniqueID = @UniqueID", new { UniqueID = key });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
sql.Append(GetGroupBy(isContent, isMedia));
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -396,6 +563,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.id = @Id AND umbracoNode.nodeObjectType = @NodeObjectType",
|
||||
new {Id = id, NodeObjectType = nodeObjectType});
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -404,30 +577,39 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = baseQuery(isContent, isMedia, null)
|
||||
.Where("umbracoNode.uniqueID = @UniqueID AND umbracoNode.nodeObjectType = @NodeObjectType",
|
||||
new { UniqueID = key, NodeObjectType = nodeObjectType });
|
||||
|
||||
if (isContent)
|
||||
{
|
||||
sql.Where("document.newest = 1");
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected virtual Sql GetGroupBy(bool isContent, bool isMedia, bool includeSort = true)
|
||||
{
|
||||
var columns = new List<object>
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate"
|
||||
};
|
||||
{
|
||||
"umbracoNode.id",
|
||||
"umbracoNode.trashed",
|
||||
"umbracoNode.parentID",
|
||||
"umbracoNode.nodeUser",
|
||||
"umbracoNode.level",
|
||||
"umbracoNode.path",
|
||||
"umbracoNode.sortOrder",
|
||||
"umbracoNode.uniqueID",
|
||||
"umbracoNode.text",
|
||||
"umbracoNode.nodeObjectType",
|
||||
"umbracoNode.createDate"
|
||||
};
|
||||
|
||||
if (isContent || isMedia)
|
||||
{
|
||||
columns.Add("published.versionId");
|
||||
columns.Add("latest.versionId");
|
||||
if (isContent)
|
||||
{
|
||||
columns.Add("published.versionId");
|
||||
columns.Add("document.versionId");
|
||||
}
|
||||
columns.Add("contenttype.alias");
|
||||
columns.Add("contenttype.icon");
|
||||
columns.Add("contenttype.thumbnail");
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
// cannot kill in v7 because it is public, kill in v8
|
||||
[Obsolete("Use MediaFileSystem.DeleteMediaFiles instead.", false)]
|
||||
public interface IDeleteMediaFilesRepository
|
||||
{
|
||||
/// <summary>
|
||||
@@ -9,6 +12,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="files"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Use MediaFileSystem.DeleteMediaFiles instead.", false)]
|
||||
bool DeleteMediaFiles(IEnumerable<string> files);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -16,6 +17,21 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query);
|
||||
IEnumerable<IUmbracoEntity> GetByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets paged results
|
||||
/// </summary>
|
||||
/// <param name="query">Query to excute</param>
|
||||
/// <param name="objectTypeId"></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="filter"></param>
|
||||
/// <returns>An Enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedResultsByQuery(IQuery<IUmbracoEntity> query, Guid objectTypeId, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection, IQuery<IUmbracoEntity> filter = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the entity exists
|
||||
/// </summary>
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
FormatDeleteStatement("cmsContentVersion", "ContentId"),
|
||||
FormatDeleteStatement("cmsContentXml", "nodeId"),
|
||||
FormatDeleteStatement("cmsContent", "nodeId"),
|
||||
//TODO: Why is this being done? We just delete this exact data in the next line
|
||||
"UPDATE umbracoNode SET parentID = '" + RecycleBinId + "' WHERE trashed = '1' AND nodeObjectType = @NodeObjectType",
|
||||
"DELETE FROM umbracoNode WHERE trashed = '1' AND nodeObjectType = @NodeObjectType"
|
||||
};
|
||||
@@ -91,14 +92,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delete statement that will delete anything in the table specified where its PK (keyName) is found in the
|
||||
/// list of umbracoNode.id that have trashed flag set
|
||||
/// </summary>
|
||||
/// <param name="tableName"></param>
|
||||
/// <param name="keyName"></param>
|
||||
/// <returns></returns>
|
||||
private string FormatDeleteStatement(string tableName, string keyName)
|
||||
{
|
||||
//This query works with sql ce and sql server:
|
||||
//DELETE FROM umbracoUser2NodeNotify WHERE umbracoUser2NodeNotify.nodeId IN
|
||||
//(SELECT nodeId FROM umbracoUser2NodeNotify as TB1 INNER JOIN umbracoNode as TB2 ON TB1.nodeId = TB2.id WHERE TB2.trashed = '1' AND TB2.nodeObjectType = 'C66BA18E-EAF3-4CFF-8A22-41B16D66A972')
|
||||
return
|
||||
string.Format(
|
||||
"DELETE FROM {0} WHERE {0}.{1} IN (SELECT TB1.{1} FROM {0} as TB1 INNER JOIN umbracoNode as TB2 ON TB1.{1} = TB2.id WHERE TB2.trashed = '1' AND TB2.nodeObjectType = @NodeObjectType)",
|
||||
"DELETE FROM {0} WHERE {0}.{1} IN (SELECT id FROM umbracoNode WHERE trashed = '1' AND nodeObjectType = @NodeObjectType)",
|
||||
tableName, keyName);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
public PreValueField()
|
||||
{
|
||||
Validators = new List<IPropertyValidator>();
|
||||
Config = new Dictionary<string, object>();
|
||||
|
||||
//check for an attribute and fill the values
|
||||
var att = GetType().GetCustomAttribute<PreValueFieldAttribute>(false);
|
||||
@@ -79,5 +80,11 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </summary>
|
||||
[JsonProperty("validation", ItemConverterType = typeof(ManifestValidatorConverter))]
|
||||
public List<IPropertyValidator> Validators { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This allows for custom configuration to be injected into the pre-value editor
|
||||
/// </summary>
|
||||
[JsonProperty("config")]
|
||||
public IDictionary<string, object> Config { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
IsParameterEditor = _attribute.IsParameterEditor;
|
||||
Icon = _attribute.Icon;
|
||||
Group = _attribute.Group;
|
||||
IsDeprecated = _attribute.IsDeprecated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +91,9 @@ namespace Umbraco.Core.PropertyEditors
|
||||
get { return CreateValueEditor(); }
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsDeprecated { get; internal set; }
|
||||
|
||||
[JsonIgnore]
|
||||
IValueEditor IParameterEditor.ValueEditor
|
||||
{
|
||||
|
||||
@@ -60,6 +60,12 @@ namespace Umbraco.Core.PropertyEditors
|
||||
public string ValueType { get; set; }
|
||||
public bool IsParameterEditor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set to true, this property editor will not show up in the DataType's drop down list
|
||||
/// if there is not already one of them chosen for a DataType
|
||||
/// </summary>
|
||||
public bool IsDeprecated { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If this is is true than the editor will be displayed full width without a label
|
||||
/// </summary>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Scoping
|
||||
{
|
||||
[Flags]
|
||||
public enum ActionTime
|
||||
{
|
||||
None = 0,
|
||||
BeforeCommit = 1,
|
||||
BeforeEvents = 2,
|
||||
BeforeDispose = 4
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Scoping
|
||||
{
|
||||
public interface IInstanceIdentifiable
|
||||
{
|
||||
Guid InstanceId { get; }
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Scoping
|
||||
/// <summary>
|
||||
/// Represents a scope.
|
||||
/// </summary>
|
||||
public interface IScope : IDisposable
|
||||
public interface IScope : IDisposable, IInstanceIdentifiable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the scope database.
|
||||
@@ -38,10 +38,8 @@ namespace Umbraco.Core.Scoping
|
||||
/// <summary>
|
||||
/// Completes the scope.
|
||||
/// </summary>
|
||||
void Complete();
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
Guid InstanceId { get; }
|
||||
#endif
|
||||
/// <returns>A value indicating whether the scope has been successfully completed.</returns>
|
||||
/// <remarks>Can return false if any child scope has not completed.</remarks>
|
||||
bool Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Umbraco.Core.Scoping
|
||||
internal interface IScopeInternal : IScope
|
||||
{
|
||||
IScopeInternal ParentScope { get; }
|
||||
EventsDispatchMode DispatchMode { get; }
|
||||
bool CallContext { get; }
|
||||
IsolationLevel IsolationLevel { get; }
|
||||
UmbracoDatabase DatabaseOrNull { get; }
|
||||
EventMessages MessagesOrNull { get; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Data;
|
||||
using System;
|
||||
using System.Data;
|
||||
using Umbraco.Core.Events;
|
||||
#if DEBUG_SCOPES
|
||||
using System.Collections.Generic;
|
||||
@@ -23,8 +24,9 @@ namespace Umbraco.Core.Scoping
|
||||
IScope CreateScope(
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
EventsDispatchMode dispatchMode = EventsDispatchMode.Unspecified,
|
||||
bool? scopeFileSystems = null);
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null,
|
||||
bool callContext = false);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a detached scope.
|
||||
@@ -37,17 +39,18 @@ namespace Umbraco.Core.Scoping
|
||||
IScope CreateDetachedScope(
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
EventsDispatchMode dispatchMode = EventsDispatchMode.Unspecified,
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null);
|
||||
|
||||
/// <summary>
|
||||
/// Attaches a scope.
|
||||
/// </summary>
|
||||
/// <param name="scope">The scope to attach.</param>
|
||||
/// <param name="callContext">A value indicating whether to force usage of call context.</param>
|
||||
/// <remarks>
|
||||
/// <para>Only a scope created by <see cref="CreateDetachedScope"/> can be attached.</para>
|
||||
/// </remarks>
|
||||
void AttachScope(IScope scope);
|
||||
void AttachScope(IScope scope, bool callContext = false);
|
||||
|
||||
/// <summary>
|
||||
/// Detaches a scope.
|
||||
@@ -64,7 +67,9 @@ namespace Umbraco.Core.Scoping
|
||||
ScopeContext Context { get; }
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
Dictionary<Guid, object> CallContextObjects { get; }
|
||||
IEnumerable<ScopeInfo> ScopeInfos { get; }
|
||||
ScopeInfo GetScopeInfo(IScope scope);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Umbraco.Core.Scoping
|
||||
private bool _disposed;
|
||||
|
||||
private UmbracoDatabase _database;
|
||||
private EventMessages _messages;
|
||||
|
||||
public NoScope(ScopeProvider scopeProvider)
|
||||
{
|
||||
@@ -24,10 +25,11 @@ namespace Umbraco.Core.Scoping
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
private readonly Guid _instanceId = Guid.NewGuid();
|
||||
public Guid InstanceId { get { return _instanceId; } }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CallContext { get { return false; } }
|
||||
|
||||
/// <inheritdoc />
|
||||
public RepositoryCacheMode RepositoryCacheMode
|
||||
@@ -60,12 +62,42 @@ namespace Umbraco.Core.Scoping
|
||||
/// <inheritdoc />
|
||||
public EventMessages Messages
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
get
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
if (_messages != null) return _messages;
|
||||
|
||||
// see comments in Scope
|
||||
|
||||
var factory = ScopeLifespanMessagesFactory.Current;
|
||||
if (factory == null)
|
||||
{
|
||||
_messages = new EventMessages();
|
||||
}
|
||||
else
|
||||
{
|
||||
_messages = factory.GetFromHttpContext();
|
||||
if (_messages == null)
|
||||
factory.Set(_messages = new EventMessages());
|
||||
}
|
||||
|
||||
return _messages;
|
||||
}
|
||||
}
|
||||
|
||||
public EventMessages MessagesOrNull
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
get
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
||||
// see comments in Scope
|
||||
|
||||
if (_messages != null) return _messages;
|
||||
|
||||
var factory = ScopeLifespanMessagesFactory.Current;
|
||||
return factory == null ? null : factory.GetFromHttpContext();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -75,7 +107,7 @@ namespace Umbraco.Core.Scoping
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Complete()
|
||||
public bool Complete()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
@@ -100,15 +132,13 @@ namespace Umbraco.Core.Scoping
|
||||
if (_database != null)
|
||||
_database.Dispose();
|
||||
|
||||
_scopeProvider.AmbientScope = null;
|
||||
_scopeProvider.AmbientContext = null;
|
||||
_scopeProvider.SetAmbient(null);
|
||||
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public IScopeInternal ParentScope { get { return null; } }
|
||||
public EventsDispatchMode DispatchMode { get {return EventsDispatchMode.Unspecified; } }
|
||||
public IsolationLevel IsolationLevel { get {return IsolationLevel.Unspecified; } }
|
||||
public bool ScopedFileSystems { get { return false; } }
|
||||
public void ChildCompleted(bool? completed) { }
|
||||
|
||||
@@ -16,14 +16,15 @@ namespace Umbraco.Core.Scoping
|
||||
private readonly ScopeProvider _scopeProvider;
|
||||
private readonly IsolationLevel _isolationLevel;
|
||||
private readonly RepositoryCacheMode _repositoryCacheMode;
|
||||
private readonly EventsDispatchMode _dispatchMode;
|
||||
private readonly bool? _scopeFileSystem;
|
||||
private readonly ScopeContext _scopeContext;
|
||||
private bool _callContext;
|
||||
private bool _disposed;
|
||||
private bool? _completed;
|
||||
|
||||
private IsolatedRuntimeCache _isolatedRuntimeCache;
|
||||
private UmbracoDatabase _database;
|
||||
private EventMessages _messages;
|
||||
private ICompletable _fscope;
|
||||
private IEventDispatcher _eventDispatcher;
|
||||
|
||||
@@ -35,15 +36,17 @@ namespace Umbraco.Core.Scoping
|
||||
Scope parent, ScopeContext scopeContext, bool detachable,
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
EventsDispatchMode dispatchMode = EventsDispatchMode.Unspecified,
|
||||
bool? scopeFileSystems = null)
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null,
|
||||
bool callContext = false)
|
||||
{
|
||||
_scopeProvider = scopeProvider;
|
||||
_scopeContext = scopeContext;
|
||||
_isolationLevel = isolationLevel;
|
||||
_repositoryCacheMode = repositoryCacheMode;
|
||||
_dispatchMode = dispatchMode;
|
||||
_eventDispatcher = eventDispatcher;
|
||||
_scopeFileSystem = scopeFileSystems;
|
||||
_callContext = callContext;
|
||||
Detachable = detachable;
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
@@ -74,9 +77,9 @@ namespace Umbraco.Core.Scoping
|
||||
if (repositoryCacheMode != RepositoryCacheMode.Unspecified && parent.RepositoryCacheMode != repositoryCacheMode)
|
||||
throw new ArgumentException("Cannot be different from parent.", "repositoryCacheMode");
|
||||
|
||||
// cannot specify a different mode!
|
||||
if (_dispatchMode != EventsDispatchMode.Unspecified && parent._dispatchMode != dispatchMode)
|
||||
throw new ArgumentException("Cannot be different from parent.", "dispatchMode");
|
||||
// cannot specify a dispatcher!
|
||||
if (_eventDispatcher != null)
|
||||
throw new ArgumentException("Cannot be specified on nested scope.", "eventDispatcher");
|
||||
|
||||
// cannot specify a different fs scope!
|
||||
if (scopeFileSystems != null && parent._scopeFileSystem != scopeFileSystems)
|
||||
@@ -97,43 +100,55 @@ namespace Umbraco.Core.Scoping
|
||||
ScopeContext scopeContext,
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
EventsDispatchMode dispatchMode = EventsDispatchMode.Unspecified,
|
||||
bool? scopeFileSystems = null)
|
||||
: this(scopeProvider, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, dispatchMode, scopeFileSystems)
|
||||
{
|
||||
}
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null,
|
||||
bool callContext = false)
|
||||
: this(scopeProvider, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext)
|
||||
{ }
|
||||
|
||||
// initializes a new scope in a nested scopes chain, with its parent
|
||||
public Scope(ScopeProvider scopeProvider, Scope parent,
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
EventsDispatchMode dispatchMode = EventsDispatchMode.Unspecified,
|
||||
bool? scopeFileSystems = null)
|
||||
: this(scopeProvider, parent, null, false, isolationLevel, repositoryCacheMode, dispatchMode, scopeFileSystems)
|
||||
{
|
||||
}
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null,
|
||||
bool callContext = false)
|
||||
: this(scopeProvider, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext)
|
||||
{ }
|
||||
|
||||
// initializes a new scope, replacing a NoScope instance
|
||||
public Scope(ScopeProvider scopeProvider, NoScope noScope,
|
||||
ScopeContext scopeContext,
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
EventsDispatchMode dispatchMode = EventsDispatchMode.Unspecified,
|
||||
bool? scopeFileSystems = null)
|
||||
: this(scopeProvider, null, scopeContext, false, isolationLevel, repositoryCacheMode, dispatchMode, scopeFileSystems)
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null,
|
||||
bool callContext = false)
|
||||
: this(scopeProvider, null, scopeContext, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext)
|
||||
{
|
||||
// steal everything from NoScope
|
||||
_database = noScope.DatabaseOrNull;
|
||||
_messages = noScope.MessagesOrNull;
|
||||
|
||||
// make sure the NoScope can be replaced ie not in a transaction
|
||||
if (_database != null && _database.InTransaction)
|
||||
throw new Exception("NoScope instance is not free.");
|
||||
}
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
private readonly Guid _instanceId = Guid.NewGuid();
|
||||
public Guid InstanceId { get { return _instanceId; } }
|
||||
#endif
|
||||
|
||||
// a value indicating whether to force call-context
|
||||
public bool CallContext
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_callContext) return true;
|
||||
if (ParentScope != null) return ParentScope.CallContext;
|
||||
return false;
|
||||
}
|
||||
set { _callContext = value; }
|
||||
}
|
||||
|
||||
public bool ScopedFileSystems
|
||||
{
|
||||
@@ -144,16 +159,6 @@ namespace Umbraco.Core.Scoping
|
||||
}
|
||||
}
|
||||
|
||||
public EventsDispatchMode DispatchMode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dispatchMode != EventsDispatchMode.Unspecified) return _dispatchMode;
|
||||
if (ParentScope != null) return ParentScope.DispatchMode;
|
||||
return EventsDispatchMode.Scope;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RepositoryCacheMode RepositoryCacheMode
|
||||
{
|
||||
@@ -184,6 +189,8 @@ namespace Umbraco.Core.Scoping
|
||||
// the parent scope (in a nested scopes chain)
|
||||
public IScopeInternal ParentScope { get; set; }
|
||||
|
||||
public bool Attached { get; set; }
|
||||
|
||||
// the original scope (when attaching a detachable scope)
|
||||
public IScopeInternal OrigScope { get; set; }
|
||||
|
||||
@@ -266,11 +273,27 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
if (ParentScope != null) return ParentScope.Messages;
|
||||
//return _messages ?? (_messages = new EventMessages());
|
||||
|
||||
// ok, this isn't pretty, but it works
|
||||
// TODO kill the message factory and let the scope manage it all
|
||||
return ApplicationContext.Current.Services.EventMessagesFactory.Get();
|
||||
if (_messages != null) return _messages;
|
||||
|
||||
// this is ugly - in v7 for backward compatibility reasons, EventMessages need
|
||||
// to survive way longer that the scopes, and kinda resides on its own in http
|
||||
// context, but must also be in scopes for when we do async and lose http context
|
||||
// TODO refactor in v8
|
||||
|
||||
var factory = ScopeLifespanMessagesFactory.Current;
|
||||
if (factory == null)
|
||||
{
|
||||
_messages = new EventMessages();
|
||||
}
|
||||
else
|
||||
{
|
||||
_messages = factory.GetFromHttpContext();
|
||||
if (_messages == null)
|
||||
factory.Set(_messages = new EventMessages());
|
||||
}
|
||||
|
||||
return _messages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +302,14 @@ namespace Umbraco.Core.Scoping
|
||||
get
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
return ParentScope == null ? null : ParentScope.MessagesOrNull;
|
||||
if (ParentScope != null) return ParentScope.MessagesOrNull;
|
||||
|
||||
// see comments in Messages
|
||||
|
||||
if (_messages != null) return _messages;
|
||||
|
||||
var factory = ScopeLifespanMessagesFactory.Current;
|
||||
return factory == null ? null : factory.GetFromHttpContext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,15 +320,16 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
if (ParentScope != null) return ParentScope.Events;
|
||||
return _eventDispatcher ?? (_eventDispatcher = new ScopeEventDispatcher(DispatchMode));
|
||||
return _eventDispatcher ?? (_eventDispatcher = new ScopeEventDispatcher());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Complete()
|
||||
public bool Complete()
|
||||
{
|
||||
if (_completed.HasValue == false)
|
||||
_completed = true;
|
||||
return _completed.Value;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
@@ -324,7 +355,18 @@ namespace Umbraco.Core.Scoping
|
||||
EnsureNotDisposed();
|
||||
|
||||
if (this != _scopeProvider.AmbientScope)
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
var ambient = _scopeProvider.AmbientScope;
|
||||
Logging.LogHelper.Debug<Scope>("Dispose error (" + (ambient == null ? "no" : "other") + " ambient)");
|
||||
if (ambient == null)
|
||||
throw new InvalidOperationException("Not the ambient scope (no ambient scope).");
|
||||
var infos = _scopeProvider.GetScopeInfo(ambient);
|
||||
throw new InvalidOperationException("Not the ambient scope (see current ambient ctor stack trace).\r\n" + infos.CtorStack);
|
||||
#else
|
||||
throw new InvalidOperationException("Not the ambient scope.");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
_scopeProvider.Disposed(this);
|
||||
@@ -418,7 +460,7 @@ namespace Umbraco.Core.Scoping
|
||||
}
|
||||
finally
|
||||
{
|
||||
_scopeProvider.AmbientContext = null;
|
||||
_scopeProvider.SetAmbient(null);
|
||||
}
|
||||
}
|
||||
}, () =>
|
||||
@@ -426,8 +468,10 @@ namespace Umbraco.Core.Scoping
|
||||
if (Detachable)
|
||||
{
|
||||
// get out of the way, restore original
|
||||
_scopeProvider.AmbientScope = OrigScope;
|
||||
_scopeProvider.AmbientContext = OrigContext;
|
||||
_scopeProvider.SetAmbient(OrigScope, OrigContext);
|
||||
Attached = false;
|
||||
OrigScope = null;
|
||||
OrigContext = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Scoping
|
||||
{
|
||||
public class ScopeContext
|
||||
public class ScopeContext : IInstanceIdentifiable
|
||||
{
|
||||
private Dictionary<string, IEnlistedObject> _enlisted;
|
||||
|
||||
@@ -27,6 +27,9 @@ namespace Umbraco.Core.Scoping
|
||||
throw new AggregateException("Exceptions were thrown by listed actions.", exceptions);
|
||||
}
|
||||
|
||||
private readonly Guid _instanceId = Guid.NewGuid();
|
||||
public Guid InstanceId { get { return _instanceId; } }
|
||||
|
||||
private IDictionary<string, IEnlistedObject> Enlisted
|
||||
{
|
||||
get
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Persistence;
|
||||
#if DEBUG_SCOPES
|
||||
using System.Linq;
|
||||
#endif
|
||||
|
||||
namespace Umbraco.Core.Scoping
|
||||
{
|
||||
@@ -24,17 +27,17 @@ namespace Umbraco.Core.Scoping
|
||||
SafeCallContext.Register(
|
||||
() =>
|
||||
{
|
||||
var scope = StaticAmbientScope;
|
||||
var context = StaticAmbientContext;
|
||||
StaticAmbientScope = null;
|
||||
StaticAmbientContext = null;
|
||||
var scope = GetCallContextObject<IScopeInternal>(ScopeItemKey);
|
||||
var context = GetCallContextObject<ScopeContext>(ContextItemKey);
|
||||
SetCallContextObject(ScopeItemKey, null);
|
||||
SetCallContextObject(ContextItemKey, null);
|
||||
return Tuple.Create(scope, context);
|
||||
},
|
||||
o =>
|
||||
{
|
||||
// cannot re-attached over leaked scope/context
|
||||
// except of course over NoScope (which leaks)
|
||||
var ambientScope = StaticAmbientScope;
|
||||
var ambientScope = GetCallContextObject<IScope>(ScopeItemKey);
|
||||
if (ambientScope != null)
|
||||
{
|
||||
var ambientNoScope = ambientScope as NoScope;
|
||||
@@ -44,59 +47,210 @@ namespace Umbraco.Core.Scoping
|
||||
// this should rollback any pending transaction
|
||||
ambientNoScope.Dispose();
|
||||
}
|
||||
if (StaticAmbientContext != null) throw new Exception("Found leaked context when restoring call context.");
|
||||
if (GetCallContextObject<ScopeContext>(ContextItemKey) != null)
|
||||
throw new Exception("Found leaked context when restoring call context.");
|
||||
|
||||
var t = (Tuple<IScopeInternal, ScopeContext>)o;
|
||||
StaticAmbientScope = t.Item1;
|
||||
StaticAmbientContext = t.Item2;
|
||||
var t = (Tuple<IScopeInternal, ScopeContext>) o;
|
||||
SetCallContextObject(ScopeItemKey, t.Item1);
|
||||
SetCallContextObject(ContextItemKey, t.Item2);
|
||||
});
|
||||
}
|
||||
|
||||
public IDatabaseFactory2 DatabaseFactory { get; private set; }
|
||||
|
||||
#region Context
|
||||
|
||||
// objects that go into the logical call context better be serializable else they'll eventually
|
||||
// cause issues whenever some cross-AppDomain code executes - could be due to ReSharper running
|
||||
// tests, any other things (see https://msdn.microsoft.com/en-us/library/dn458353(v=vs.110).aspx),
|
||||
// but we don't want to make all of our objects serializable since they are *not* meant to be
|
||||
// used in cross-AppDomain scenario anyways.
|
||||
// in addition, whatever goes into the logical call context is serialized back and forth any
|
||||
// time cross-AppDomain code executes, so if we put an "object" there, we'll can *another*
|
||||
// "object" instance - and so we cannot use a random object as a key.
|
||||
// so what we do is: we register a guid in the call context, and we keep a table mapping those
|
||||
// guids to the actual objects. the guid serializes back and forth without causing any issue,
|
||||
// and we can retrieve the actual objects from the table.
|
||||
// only issue: how are we supposed to clear the table? we can't, really. objects should take
|
||||
// care of de-registering themselves from context.
|
||||
// everything we use does, except the NoScope scope, which just stays there
|
||||
//
|
||||
// during tests, NoScope can to into call context... nothing much we can do about it
|
||||
|
||||
private static readonly object StaticCallContextObjectsLock = new object();
|
||||
private static readonly Dictionary<Guid, object> StaticCallContextObjects
|
||||
= new Dictionary<Guid, object>();
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
public Dictionary<Guid, object> CallContextObjects
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (StaticCallContextObjectsLock)
|
||||
{
|
||||
// capture in a dictionary
|
||||
return StaticCallContextObjects.ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private static T GetCallContextObject<T>(string key)
|
||||
where T : class
|
||||
{
|
||||
var objectKey = CallContext.LogicalGetData(key).AsGuid();
|
||||
lock (StaticCallContextObjectsLock)
|
||||
{
|
||||
object callContextObject;
|
||||
if (StaticCallContextObjects.TryGetValue(objectKey, out callContextObject))
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("GotObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
#endif
|
||||
return (T) callContextObject;
|
||||
}
|
||||
#if DEBUG_SCOPES
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("MissedObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetCallContextObject(string key, IInstanceIdentifiable value)
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
// manage the 'context' that contains the scope (null, "http" or "call")
|
||||
// only for scopes of course!
|
||||
if (key == ScopeItemKey)
|
||||
{
|
||||
// first, null-register the existing value
|
||||
var ambientKey = CallContext.LogicalGetData(ScopeItemKey).AsGuid();
|
||||
object o = null;
|
||||
lock (StaticCallContextObjectsLock)
|
||||
{
|
||||
if (ambientKey != default(Guid))
|
||||
StaticCallContextObjects.TryGetValue(ambientKey, out o);
|
||||
}
|
||||
var ambientScope = o as IScope;
|
||||
if (ambientScope != null) RegisterContext(ambientScope, null);
|
||||
// then register the new value
|
||||
var scope = value as IScope;
|
||||
if (scope != null) RegisterContext(scope, "call");
|
||||
}
|
||||
#endif
|
||||
if (value == null)
|
||||
{
|
||||
var objectKey = CallContext.LogicalGetData(key).AsGuid();
|
||||
CallContext.FreeNamedDataSlot(key);
|
||||
if (objectKey == default (Guid)) return;
|
||||
lock (StaticCallContextObjectsLock)
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("RemoveObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
#endif
|
||||
StaticCallContextObjects.Remove(objectKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// note - we are *not* detecting an already-existing value
|
||||
// because our code in this class *always* sets to null before
|
||||
// setting to a real value
|
||||
var objectKey = value.InstanceId;
|
||||
lock (StaticCallContextObjectsLock)
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("AddObject " + objectKey.ToString("N").Substring(0, 8));
|
||||
#endif
|
||||
StaticCallContextObjects.Add(objectKey, value);
|
||||
}
|
||||
CallContext.LogicalSetData(key, objectKey);
|
||||
}
|
||||
}
|
||||
|
||||
internal static Func<IDictionary> HttpContextItemsGetter { get; set; }
|
||||
|
||||
private static IDictionary HttpContextItems
|
||||
{
|
||||
get
|
||||
{
|
||||
return HttpContextItemsGetter == null
|
||||
? (HttpContext.Current == null ? null : HttpContext.Current.Items)
|
||||
: HttpContextItemsGetter();
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetHttpContextObject<T>(string key, bool required = true)
|
||||
where T : class
|
||||
{
|
||||
var httpContextItems = HttpContextItems;
|
||||
if (httpContextItems != null)
|
||||
return (T)httpContextItems[key];
|
||||
if (required)
|
||||
throw new Exception("HttpContext.Current is null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool SetHttpContextObject(string key, object value, bool required = true)
|
||||
{
|
||||
var httpContextItems = HttpContextItems;
|
||||
if (httpContextItems == null)
|
||||
{
|
||||
if (required)
|
||||
throw new Exception("HttpContext.Current is null.");
|
||||
return false;
|
||||
}
|
||||
#if DEBUG_SCOPES
|
||||
// manage the 'context' that contains the scope (null, "http" or "call")
|
||||
// only for scopes of course!
|
||||
if (key == ScopeItemKey)
|
||||
{
|
||||
// first, null-register the existing value
|
||||
var ambientScope = (IScope)httpContextItems[ScopeItemKey];
|
||||
if (ambientScope != null) RegisterContext(ambientScope, null);
|
||||
// then register the new value
|
||||
var scope = value as IScope;
|
||||
if (scope != null) RegisterContext(scope, "http");
|
||||
}
|
||||
#endif
|
||||
if (value == null)
|
||||
httpContextItems.Remove(key);
|
||||
else
|
||||
httpContextItems[key] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Ambient Context
|
||||
|
||||
internal const string ContextItemKey = "Umbraco.Core.Scoping.ScopeContext";
|
||||
|
||||
private static ScopeContext CallContextContextValue
|
||||
internal static ScopeContext AmbientContextInternal
|
||||
{
|
||||
get { return (ScopeContext)CallContext.LogicalGetData(ContextItemKey); }
|
||||
set
|
||||
get
|
||||
{
|
||||
if (value == null) CallContext.FreeNamedDataSlot(ContextItemKey);
|
||||
else CallContext.LogicalSetData(ContextItemKey, value);
|
||||
// try http context, fallback onto call context
|
||||
var value = GetHttpContextObject<ScopeContext>(ContextItemKey, false);
|
||||
return value ?? GetCallContextObject<ScopeContext>(ContextItemKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static ScopeContext HttpContextContextValue
|
||||
{
|
||||
get { return (ScopeContext)HttpContext.Current.Items[ContextItemKey]; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
HttpContext.Current.Items.Remove(ContextItemKey);
|
||||
else
|
||||
HttpContext.Current.Items[ContextItemKey] = value;
|
||||
}
|
||||
}
|
||||
// clear both
|
||||
SetHttpContextObject(ContextItemKey, null, false);
|
||||
SetCallContextObject(ContextItemKey, null);
|
||||
if (value == null) return;
|
||||
|
||||
private static ScopeContext StaticAmbientContext
|
||||
{
|
||||
get { return HttpContext.Current == null ? CallContextContextValue : HttpContextContextValue; }
|
||||
set
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
CallContextContextValue = value;
|
||||
else
|
||||
HttpContextContextValue = value;
|
||||
// set http/call context
|
||||
if (SetHttpContextObject(ContextItemKey, value, false) == false)
|
||||
SetCallContextObject(ContextItemKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScopeContext AmbientContext
|
||||
{
|
||||
get { return StaticAmbientContext; }
|
||||
set { StaticAmbientContext = value; }
|
||||
get { return AmbientContextInternal; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -109,86 +263,84 @@ namespace Umbraco.Core.Scoping
|
||||
// only 1 instance which can be disposed and disposed again
|
||||
private static readonly ScopeReference StaticScopeReference = new ScopeReference(new ScopeProvider(null));
|
||||
|
||||
private static IScopeInternal CallContextValue
|
||||
internal static IScopeInternal AmbientScopeInternal
|
||||
{
|
||||
get { return (IScopeInternal) CallContext.LogicalGetData(ScopeItemKey); }
|
||||
set
|
||||
get
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
// manage the 'context' that contains the scope (null, "http" or "lcc")
|
||||
var ambientScope = (IScope) CallContext.LogicalGetData(ScopeItemKey);
|
||||
if (ambientScope != null) RegisterContext(ambientScope, null);
|
||||
if (value != null) RegisterContext(value, "lcc");
|
||||
#endif
|
||||
if (value == null) CallContext.FreeNamedDataSlot(ScopeItemKey);
|
||||
else CallContext.LogicalSetData(ScopeItemKey, value);
|
||||
// try http context, fallback onto call context
|
||||
var value = GetHttpContextObject<IScopeInternal>(ScopeItemKey, false);
|
||||
return value ?? GetCallContextObject<IScopeInternal>(ScopeItemKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static IScopeInternal HttpContextValue
|
||||
{
|
||||
get { return (IScopeInternal) HttpContext.Current.Items[ScopeItemKey]; }
|
||||
set
|
||||
{
|
||||
#if DEBUG_SCOPES
|
||||
// manage the 'context' that contains the scope (null, "http" or "lcc")
|
||||
var ambientScope = (IScope) HttpContext.Current.Items[ScopeItemKey];
|
||||
if (ambientScope != null) RegisterContext(ambientScope, null);
|
||||
if (value != null) RegisterContext(value, "http");
|
||||
#endif
|
||||
if (value == null)
|
||||
{
|
||||
HttpContext.Current.Items.Remove(ScopeItemKey);
|
||||
HttpContext.Current.Items.Remove(ScopeRefItemKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpContext.Current.Items[ScopeItemKey] = value;
|
||||
if (HttpContext.Current.Items[ScopeRefItemKey] == null)
|
||||
HttpContext.Current.Items[ScopeRefItemKey] = StaticScopeReference;
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear both
|
||||
SetHttpContextObject(ScopeItemKey, null, false);
|
||||
SetHttpContextObject(ScopeRefItemKey, null, false);
|
||||
SetCallContextObject(ScopeItemKey, null);
|
||||
if (value == null) return;
|
||||
|
||||
private static IScopeInternal StaticAmbientScope
|
||||
{
|
||||
get { return HttpContext.Current == null ? CallContextValue : HttpContextValue; }
|
||||
set
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
CallContextValue = value;
|
||||
// set http/call context
|
||||
if (value.CallContext == false && SetHttpContextObject(ScopeItemKey, value, false))
|
||||
SetHttpContextObject(ScopeRefItemKey, StaticScopeReference);
|
||||
else
|
||||
HttpContextValue = value;
|
||||
SetCallContextObject(ScopeItemKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IScopeInternal AmbientScope
|
||||
{
|
||||
get { return StaticAmbientScope; }
|
||||
set { StaticAmbientScope = value; }
|
||||
get { return AmbientScopeInternal; }
|
||||
internal set { AmbientScopeInternal = value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IScopeInternal GetAmbientOrNoScope()
|
||||
{
|
||||
return AmbientScope ?? (AmbientScope = new NoScope(this));
|
||||
return AmbientScope ?? (AmbientScope = new NoScope(this));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void SetAmbient(IScopeInternal scope, ScopeContext context = null)
|
||||
{
|
||||
// clear all
|
||||
SetHttpContextObject(ScopeItemKey, null, false);
|
||||
SetHttpContextObject(ScopeRefItemKey, null, false);
|
||||
SetCallContextObject(ScopeItemKey, null);
|
||||
SetHttpContextObject(ContextItemKey, null, false);
|
||||
SetCallContextObject(ContextItemKey, null);
|
||||
if (scope == null)
|
||||
{
|
||||
if (context != null)
|
||||
throw new ArgumentException("Must be null if scope is null.", "context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (scope.CallContext == false && SetHttpContextObject(ScopeItemKey, scope, false))
|
||||
{
|
||||
SetHttpContextObject(ScopeRefItemKey, StaticScopeReference);
|
||||
SetHttpContextObject(ContextItemKey, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCallContextObject(ScopeItemKey, scope);
|
||||
SetCallContextObject(ContextItemKey, context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IScope CreateDetachedScope(
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
EventsDispatchMode dispatchMode = EventsDispatchMode.Unspecified,
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null)
|
||||
{
|
||||
return new Scope(this, true, null, isolationLevel, repositoryCacheMode, dispatchMode, scopeFileSystems);
|
||||
return new Scope(this, true, null, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AttachScope(IScope other)
|
||||
public void AttachScope(IScope other, bool callContext = false)
|
||||
{
|
||||
var otherScope = other as Scope;
|
||||
if (otherScope == null)
|
||||
@@ -197,10 +349,15 @@ namespace Umbraco.Core.Scoping
|
||||
if (otherScope.Detachable == false)
|
||||
throw new ArgumentException("Not a detachable scope.");
|
||||
|
||||
if (otherScope.Attached)
|
||||
throw new InvalidOperationException("Already attached.");
|
||||
|
||||
otherScope.Attached = true;
|
||||
otherScope.OrigScope = AmbientScope;
|
||||
otherScope.OrigContext = AmbientContext;
|
||||
AmbientScope = otherScope;
|
||||
AmbientContext = otherScope.Context;
|
||||
|
||||
otherScope.CallContext = callContext;
|
||||
SetAmbient(otherScope, otherScope.Context);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -221,10 +378,10 @@ namespace Umbraco.Core.Scoping
|
||||
if (scope.Detachable == false)
|
||||
throw new InvalidOperationException("Ambient scope is not detachable.");
|
||||
|
||||
AmbientScope = scope.OrigScope;
|
||||
AmbientContext = scope.OrigContext;
|
||||
SetAmbient(scope.OrigScope, scope.OrigContext);
|
||||
scope.OrigScope = null;
|
||||
scope.OrigContext = null;
|
||||
scope.Attached = false;
|
||||
return scope;
|
||||
}
|
||||
|
||||
@@ -232,16 +389,19 @@ namespace Umbraco.Core.Scoping
|
||||
public IScope CreateScope(
|
||||
IsolationLevel isolationLevel = IsolationLevel.Unspecified,
|
||||
RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified,
|
||||
EventsDispatchMode dispatchMode = EventsDispatchMode.Unspecified,
|
||||
bool? scopeFileSystems = null)
|
||||
IEventDispatcher eventDispatcher = null,
|
||||
bool? scopeFileSystems = null,
|
||||
bool callContext = false)
|
||||
{
|
||||
var ambient = AmbientScope;
|
||||
if (ambient == null)
|
||||
{
|
||||
var context = AmbientContext == null ? new ScopeContext() : null;
|
||||
var scope = new Scope(this, false, context, isolationLevel, repositoryCacheMode, dispatchMode, scopeFileSystems);
|
||||
if (AmbientContext == null) AmbientContext = context; // assign only if scope creation did not throw!
|
||||
return AmbientScope = scope;
|
||||
var ambientContext = AmbientContext;
|
||||
var newContext = ambientContext == null ? new ScopeContext() : null;
|
||||
var scope = new Scope(this, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext);
|
||||
// assign only if scope creation did not throw!
|
||||
SetAmbient(scope, newContext ?? ambientContext);
|
||||
return scope;
|
||||
}
|
||||
|
||||
// replace noScope with a real one
|
||||
@@ -255,16 +415,20 @@ namespace Umbraco.Core.Scoping
|
||||
var database = noScope.DatabaseOrNull;
|
||||
if (database != null && database.InTransaction)
|
||||
throw new Exception("NoScope is in a transaction.");
|
||||
var context = AmbientContext == null ? new ScopeContext() : null;
|
||||
var scope = new Scope(this, noScope, context, isolationLevel, repositoryCacheMode, dispatchMode, scopeFileSystems);
|
||||
if (AmbientContext == null) AmbientContext = context; // assign only if scope creation did not throw!
|
||||
return AmbientScope = scope;
|
||||
var ambientContext = AmbientContext;
|
||||
var newContext = ambientContext == null ? new ScopeContext() : null;
|
||||
var scope = new Scope(this, noScope, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext);
|
||||
// assign only if scope creation did not throw!
|
||||
SetAmbient(scope, newContext ?? ambientContext);
|
||||
return scope;
|
||||
}
|
||||
|
||||
var ambientScope = ambient as Scope;
|
||||
if (ambientScope == null) throw new Exception("Ambient scope is not a Scope instance.");
|
||||
|
||||
return AmbientScope = new Scope(this, ambientScope, isolationLevel, repositoryCacheMode, dispatchMode, scopeFileSystems);
|
||||
var nested = new Scope(this, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext);
|
||||
SetAmbient(nested, AmbientContext);
|
||||
return nested;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -309,7 +473,7 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
// all scope instances that are currently beeing tracked
|
||||
private static readonly object StaticScopeInfosLock = new object();
|
||||
private static readonly List<ScopeInfo> StaticScopeInfos = new List<ScopeInfo>();
|
||||
private static readonly Dictionary<IScope, ScopeInfo> StaticScopeInfos = new Dictionary<IScope, ScopeInfo>();
|
||||
|
||||
public IEnumerable<ScopeInfo> ScopeInfos
|
||||
{
|
||||
@@ -317,37 +481,53 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
lock (StaticScopeInfosLock)
|
||||
{
|
||||
return StaticScopeInfos.ToArray(); // capture in an array
|
||||
return StaticScopeInfos.Values.ToArray(); // capture in an array
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ScopeInfo GetScopeInfo(IScope scope)
|
||||
{
|
||||
lock (StaticScopeInfosLock)
|
||||
{
|
||||
ScopeInfo scopeInfo;
|
||||
return StaticScopeInfos.TryGetValue(scope, out scopeInfo) ? scopeInfo : null;
|
||||
}
|
||||
}
|
||||
|
||||
//private static void Log(string message, UmbracoDatabase database)
|
||||
//{
|
||||
// LogHelper.Debug<ScopeProvider>(message + " (" + (database == null ? "" : database.InstanceSid) + ").");
|
||||
//}
|
||||
|
||||
// register a scope and capture its ctor stacktrace
|
||||
public void RegisterScope(IScope scope)
|
||||
{
|
||||
lock (StaticScopeInfosLock)
|
||||
{
|
||||
if (StaticScopeInfos.Any(x => x.Scope == scope)) throw new Exception("oops: already registered.");
|
||||
StaticScopeInfos.Add(new ScopeInfo(scope, Environment.StackTrace));
|
||||
if (StaticScopeInfos.ContainsKey(scope)) throw new Exception("oops: already registered.");
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("Register " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
StaticScopeInfos[scope] = new ScopeInfo(scope, Environment.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
// 'context' that contains the scope (null, "http" or "lcc")
|
||||
// register that a scope is in a 'context'
|
||||
// 'context' that contains the scope (null, "http" or "call")
|
||||
public static void RegisterContext(IScope scope, string context)
|
||||
{
|
||||
lock (StaticScopeInfosLock)
|
||||
{
|
||||
var info = StaticScopeInfos.FirstOrDefault(x => x.Scope == scope);
|
||||
ScopeInfo info;
|
||||
if (StaticScopeInfos.TryGetValue(scope, out info) == false) info = null;
|
||||
if (info == null)
|
||||
{
|
||||
if (context == null) return;
|
||||
throw new Exception("oops: unregistered scope.");
|
||||
}
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("Register context " + (context ?? "null") + " for " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
if (context == null) info.NullStack = Environment.StackTrace;
|
||||
//if (context == null)
|
||||
// Logging.LogHelper.Debug<ScopeProvider>("STACK\r\n" + info.NullStack);
|
||||
info.Context = context;
|
||||
}
|
||||
}
|
||||
@@ -356,11 +536,12 @@ namespace Umbraco.Core.Scoping
|
||||
{
|
||||
lock (StaticScopeInfosLock)
|
||||
{
|
||||
var info = StaticScopeInfos.FirstOrDefault(x => x.Scope == scope);
|
||||
if (info != null)
|
||||
if (StaticScopeInfos.ContainsKey(scope))
|
||||
{
|
||||
// enable this by default
|
||||
StaticScopeInfos.Remove(info);
|
||||
//Console.WriteLine("unregister " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
StaticScopeInfos.Remove(scope);
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("Remove " + scope.InstanceId.ToString("N").Substring(0, 8));
|
||||
|
||||
// instead, enable this to keep *all* scopes
|
||||
// beware, there can be a lot of scopes!
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace Umbraco.Core.Security
|
||||
AllowRefresh = true,
|
||||
IssuedUtc = nowUtc,
|
||||
ExpiresUtc = nowUtc.AddMinutes(GlobalSettings.TimeOutInMinutes)
|
||||
}, userIdentity, rememberBrowserIdentity);
|
||||
}, userIdentity, rememberBrowserIdentity);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -189,6 +189,10 @@ namespace Umbraco.Core.Security
|
||||
}, userIdentity);
|
||||
}
|
||||
|
||||
//track the last login date
|
||||
user.LastLoginDateUtc = DateTime.UtcNow;
|
||||
await UserManager.UpdateAsync(user);
|
||||
|
||||
_logger.WriteCore(TraceEventType.Information, 0,
|
||||
string.Format(
|
||||
"Login attempt succeeded for username {0} from IP address {1}",
|
||||
|
||||
@@ -625,6 +625,12 @@ namespace Umbraco.Core.Security
|
||||
var anythingChanged = false;
|
||||
//don't assign anything if nothing has changed as this will trigger
|
||||
//the track changes of the model
|
||||
if ((user.LastLoginDate != default(DateTime) && identityUser.LastLoginDateUtc.HasValue == false)
|
||||
|| identityUser.LastLoginDateUtc.HasValue && user.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)
|
||||
{
|
||||
anythingChanged = true;
|
||||
user.LastLoginDate = identityUser.LastLoginDateUtc.Value.ToLocalTime();
|
||||
}
|
||||
if (user.Name != identityUser.Name && identityUser.Name.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
anythingChanged = true;
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Umbraco.Core.Services
|
||||
uow.Events.Dispatch(Created, this, new NewEventArgs<IContent>(content, false, contentTypeAlias, parentId));
|
||||
//Created.RaiseEvent(new NewEventArgs<IContent>(content, false, contentTypeAlias, parentId), this, uow.Events);
|
||||
|
||||
// fixme
|
||||
// fixme
|
||||
var auditRepo = RepositoryFactory.CreateAuditRepository(uow);
|
||||
auditRepo.AddOrUpdate(new AuditItem(content.Id, string.Format("Content '{0}' was created", name), AuditType.New, content.CreatorId));
|
||||
uow.Commit();
|
||||
@@ -1051,9 +1051,9 @@ namespace Umbraco.Core.Services
|
||||
UnPublish(content, userId);
|
||||
}
|
||||
content.WriterId = userId;
|
||||
content.ChangeTrashedState(true);
|
||||
content.ChangeTrashedState(true);
|
||||
repository.AddOrUpdate(content);
|
||||
|
||||
|
||||
//Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
|
||||
foreach (var descendant in descendants)
|
||||
{
|
||||
@@ -1063,14 +1063,14 @@ namespace Umbraco.Core.Services
|
||||
descendant.ChangeTrashedState(true, descendant.ParentId);
|
||||
repository.AddOrUpdate(descendant);
|
||||
|
||||
moveInfo.Add(new MoveEventInfo<IContent>(descendant, descendant.Path, descendant.ParentId));
|
||||
moveInfo.Add(new MoveEventInfo<IContent>(descendant, descendant.Path, descendant.ParentId));
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
|
||||
uow.Events.Dispatch(Trashed, this, new MoveEventArgs<IContent>(false, evtMsgs, moveInfo.ToArray()), "Trashed");
|
||||
}
|
||||
|
||||
|
||||
Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
@@ -1285,9 +1285,6 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var args = new DeleteEventArgs<IContent>(content, false, evtMsgs);
|
||||
uow.Events.Dispatch(Deleted, this, args, "Deleted"); // fixme why the event name?!
|
||||
|
||||
//remove any flagged media files
|
||||
repository.DeleteMediaFiles(args.MediaFilesToDelete);
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, "Delete Content performed by user", userId, content.Id);
|
||||
@@ -1335,7 +1332,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all content of the specified types. All Descendants of deleted content that is not of these types is moved to Recycle Bin.
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
/// <param name="contentTypeIds">Id of the <see cref="IContentType"/></param>
|
||||
/// <param name="userId">Optional Id of the user issueing the delete operation</param>
|
||||
public void DeleteContentOfTypes(IEnumerable<int> contentTypeIds, int userId = 0)
|
||||
@@ -1344,7 +1341,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateContentRepository(uow);
|
||||
|
||||
|
||||
//track the 'root' items of the collection of nodes discovered to delete, we need to use
|
||||
//these items to lookup descendants that are not of this doc type so they can be transfered
|
||||
//to the recycle bin
|
||||
@@ -1559,9 +1556,6 @@ namespace Umbraco.Core.Services
|
||||
|
||||
success = repository.EmptyRecycleBin();
|
||||
|
||||
if (success)
|
||||
repository.DeleteMediaFiles(files);
|
||||
|
||||
uow.Events.Dispatch(EmptiedRecycleBin, this, new RecycleBinEventArgs(nodeObjectType, entities, files, success));
|
||||
uow.Commit();
|
||||
}
|
||||
@@ -1610,7 +1604,6 @@ namespace Umbraco.Core.Services
|
||||
// fixme mess!
|
||||
using (var scope = UowProvider.ScopeProvider.CreateScope())
|
||||
{
|
||||
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Copying, this, new CopyEventArgs<IContent>(content, copy, parentId)))
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Umbraco.Core.Services
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
|
||||
uow.Events.Dispatch(SavedContentTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
uow.Events.Dispatch(SavedContentTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), "SavedContentTypeContainer");
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
@@ -106,7 +106,7 @@ namespace Umbraco.Core.Services
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
|
||||
uow.Events.Dispatch(SavedMediaTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
uow.Events.Dispatch(SavedMediaTypeContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), "SavedMediaTypeContainer");
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
@@ -122,14 +122,16 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
return SaveContainer(
|
||||
SavingContentTypeContainer, SavedContentTypeContainer,
|
||||
container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type", userId);
|
||||
container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type",
|
||||
"SavedContentTypeContainer", userId);
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus> SaveMediaTypeContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
return SaveContainer(
|
||||
SavingMediaTypeContainer, SavedMediaTypeContainer,
|
||||
container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type", userId);
|
||||
container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type",
|
||||
"SavedMediaTypeContainer", userId);
|
||||
}
|
||||
|
||||
private Attempt<OperationStatus> SaveContainer(
|
||||
@@ -137,7 +139,9 @@ namespace Umbraco.Core.Services
|
||||
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savedEvent,
|
||||
EntityContainer container,
|
||||
Guid containerObjectType,
|
||||
string objectTypeName, int userId)
|
||||
string objectTypeName,
|
||||
string savedEventName,
|
||||
int userId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
@@ -165,7 +169,7 @@ namespace Umbraco.Core.Services
|
||||
var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType);
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
uow.Events.Dispatch(savedEvent, this, new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
uow.Events.Dispatch(savedEvent, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), savedEventName);
|
||||
}
|
||||
|
||||
//TODO: Audit trail ?
|
||||
@@ -756,6 +760,7 @@ namespace Umbraco.Core.Services
|
||||
using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess
|
||||
{
|
||||
scope.Events.Dispatch(SavedContentType, this, new SaveEventArgs<IContentType>(contentType, false));
|
||||
scope.Complete();
|
||||
}
|
||||
Audit(AuditType.Save, "Save ContentType performed by user", userId, contentType.Id);
|
||||
}
|
||||
@@ -800,8 +805,9 @@ namespace Umbraco.Core.Services
|
||||
using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess
|
||||
{
|
||||
scope.Events.Dispatch(SavedContentType, this, new SaveEventArgs<IContentType>(asArray, false));
|
||||
scope.Complete();
|
||||
}
|
||||
Audit(AuditType.Save, "Save ContentTypes performed by user", userId, -1);
|
||||
Audit(AuditType.Save, "Save ContentTypes performed by user", userId, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1211,6 +1217,7 @@ namespace Umbraco.Core.Services
|
||||
using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess
|
||||
{
|
||||
scope.Events.Dispatch(SavedMediaType, this, new SaveEventArgs<IMediaType>(mediaType, false));
|
||||
scope.Complete();
|
||||
}
|
||||
Audit(AuditType.Save, "Save MediaType performed by user", userId, mediaType.Id);
|
||||
}
|
||||
@@ -1255,6 +1262,7 @@ namespace Umbraco.Core.Services
|
||||
using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess
|
||||
{
|
||||
scope.Events.Dispatch(SavedMediaType, this, new SaveEventArgs<IMediaType>(asArray, false));
|
||||
scope.Complete();
|
||||
}
|
||||
Audit(AuditType.Save, "Save MediaTypes performed by user", userId, -1);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -91,6 +92,7 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
case UmbracoObjectTypes.DocumentTypeContainer:
|
||||
uow.Commit();
|
||||
return uow.Database.ExecuteScalar<int?>(new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.UniqueId == key));
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
@@ -129,6 +131,7 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.DocumentType:
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
uow.Commit();
|
||||
return uow.Database.ExecuteScalar<Guid?>(new Sql().Select("uniqueID").From<NodeDto>().Where<NodeDto>(dto => dto.NodeId == id));
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
@@ -374,6 +377,115 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of children
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent id to return children for</param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedChildren(int parentId, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == parentId && x.Trashed == false);
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedDescendants(int id, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
|
||||
var query = Query<IUmbracoEntity>.Builder;
|
||||
//if the id is System Root, then just get all
|
||||
if (id != Constants.System.Root)
|
||||
query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar));
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants from the root
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="includeTrashed">true/false to include trashed objects</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IUmbracoEntity> GetPagedDescendantsFromRoot(UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true)
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
|
||||
var query = Query<IUmbracoEntity>.Builder;
|
||||
//don't include trashed if specfied
|
||||
if (includeTrashed == false)
|
||||
{
|
||||
query.Where(x => x.Trashed == false);
|
||||
}
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IUmbracoEntity>.Builder.Where(x => x.Name.Contains(filter));
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of descendents by the parents Id
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
@@ -137,6 +138,51 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
IEnumerable<IUmbracoEntity> GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of children
|
||||
/// </summary>
|
||||
/// <param name="parentId">The parent id to return children for</param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedChildren(int parentId, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedDescendants(int id, UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
|
||||
|
||||
/// <summary>
|
||||
/// Returns a paged collection of descendants from the root
|
||||
/// </summary>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <param name="includeTrashed">true/false to include trashed objects</param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUmbracoEntity> GetPagedDescendantsFromRoot(UmbracoObjectTypes umbracoObjectType, long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of descendents by the parents Id
|
||||
/// </summary>
|
||||
|
||||
@@ -831,9 +831,6 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var args = new DeleteEventArgs<IMedia>(media, false, evtMsgs);
|
||||
uow.Events.Dispatch(Deleted, this, args);
|
||||
|
||||
//remove any flagged media files
|
||||
repository.DeleteMediaFiles(args.MediaFilesToDelete);
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, "Delete Media performed by user", userId, media.Id);
|
||||
@@ -958,9 +955,6 @@ namespace Umbraco.Core.Services
|
||||
success = repository.EmptyRecycleBin();
|
||||
// FIXME shouldn't we commit here?!
|
||||
uow.Events.Dispatch(EmptiedRecycleBin, this, new RecycleBinEventArgs(nodeObjectType, entities, files, success));
|
||||
|
||||
if (success)
|
||||
repository.DeleteMediaFiles(files);
|
||||
}
|
||||
}
|
||||
Audit(AuditType.Delete, "Empty Media Recycle Bin performed by user", 0, -21);
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Gets the default MemberType alias
|
||||
/// </summary>
|
||||
/// <remarks>By default we'll return the 'writer', but we need to check it exists. If it doesn't we'll
|
||||
/// <remarks>By default we'll return the 'writer', but we need to check it exists. If it doesn't we'll
|
||||
/// return the first type that is not an admin, otherwise if there's only one we will return that one.</remarks>
|
||||
/// <returns>Alias of the default MemberType</returns>
|
||||
public string GetDefaultMemberType()
|
||||
@@ -86,7 +86,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method
|
||||
/// </summary>
|
||||
/// <remarks>This method exists so that Umbraco developers can use one entry point to create/update
|
||||
/// <remarks>This method exists so that Umbraco developers can use one entry point to create/update
|
||||
/// Members if they choose to. </remarks>
|
||||
/// <param name="member">The Member to save the password for</param>
|
||||
/// <param name="password">The password to encrypt and save</param>
|
||||
@@ -776,7 +776,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Creates and persists a Member
|
||||
/// </summary>
|
||||
/// <remarks>Using this method will persist the Member object before its returned
|
||||
/// <remarks>Using this method will persist the Member object before its returned
|
||||
/// meaning that it will have an Id available (unlike the CreateMember method)</remarks>
|
||||
/// <param name="username">Username of the Member to create</param>
|
||||
/// <param name="email">Email of the Member to create</param>
|
||||
@@ -792,7 +792,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Creates and persists a Member
|
||||
/// </summary>
|
||||
/// <remarks>Using this method will persist the Member object before its returned
|
||||
/// <remarks>Using this method will persist the Member object before its returned
|
||||
/// meaning that it will have an Id available (unlike the CreateMember method)</remarks>
|
||||
/// <param name="username">Username of the Member to create</param>
|
||||
/// <param name="email">Email of the Member to create</param>
|
||||
@@ -806,7 +806,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Creates and persists a Member
|
||||
/// </summary>
|
||||
/// <remarks>Using this method will persist the Member object before its returned
|
||||
/// <remarks>Using this method will persist the Member object before its returned
|
||||
/// meaning that it will have an Id available (unlike the CreateMember method)</remarks>
|
||||
/// <param name="username">Username of the Member to create</param>
|
||||
/// <param name="email">Email of the Member to create</param>
|
||||
@@ -836,7 +836,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Creates and persists a Member
|
||||
/// </summary>
|
||||
/// <remarks>Using this method will persist the Member object before its returned
|
||||
/// <remarks>Using this method will persist the Member object before its returned
|
||||
/// meaning that it will have an Id available (unlike the CreateMember method)</remarks>
|
||||
/// <param name="username">Username of the Member to create</param>
|
||||
/// <param name="email">Email of the Member to create</param>
|
||||
@@ -921,7 +921,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns><see cref="IMember"/></returns>
|
||||
public IMember GetByUsername(string username)
|
||||
{
|
||||
//TODO: Somewhere in here, whether at this level or the repository level, we need to add
|
||||
//TODO: Somewhere in here, whether at this level or the repository level, we need to add
|
||||
// a caching mechanism since this method is used by all the membership providers and could be
|
||||
// called quite a bit when dealing with members.
|
||||
|
||||
@@ -953,9 +953,6 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var args = new DeleteEventArgs<IMember>(member, false);
|
||||
uow.Events.Dispatch(Deleted, this, args);
|
||||
|
||||
//remove any flagged media files
|
||||
repository.DeleteMediaFiles(args.MediaFilesToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,7 +960,7 @@ namespace Umbraco.Core.Services
|
||||
/// Saves an <see cref="IMember"/>
|
||||
/// </summary>
|
||||
/// <param name="entity"><see cref="IMember"/> to Save</param>
|
||||
/// <param name="raiseEvents">Optional parameter to raise events.
|
||||
/// <param name="raiseEvents">Optional parameter to raise events.
|
||||
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
|
||||
public void Save(IMember entity, bool raiseEvents = true)
|
||||
{
|
||||
@@ -1004,7 +1001,7 @@ namespace Umbraco.Core.Services
|
||||
/// Saves a list of <see cref="IMember"/> objects
|
||||
/// </summary>
|
||||
/// <param name="entities"><see cref="IEnumerable{IMember}"/> to save</param>
|
||||
/// <param name="raiseEvents">Optional parameter to raise events.
|
||||
/// <param name="raiseEvents">Optional parameter to raise events.
|
||||
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
|
||||
public void Save(IEnumerable<IMember> entities, bool raiseEvents = true)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Services
|
||||
private readonly IMemberService _memberService;
|
||||
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
|
||||
|
||||
|
||||
public MemberTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberService memberService)
|
||||
: base(provider, repositoryFactory, logger, eventMessagesFactory)
|
||||
@@ -110,7 +110,7 @@ namespace Umbraco.Core.Services
|
||||
public void Save(IEnumerable<IMemberType> memberTypes, int userId = 0)
|
||||
{
|
||||
var asArray = memberTypes.ToArray();
|
||||
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
@@ -137,7 +137,7 @@ namespace Umbraco.Core.Services
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMemberType>(asArray, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Delete(IMemberType memberType, int userId = 0)
|
||||
@@ -167,7 +167,7 @@ namespace Umbraco.Core.Services
|
||||
public void Delete(IEnumerable<IMemberType> memberTypes, int userId = 0)
|
||||
{
|
||||
var asArray = memberTypes.ToArray();
|
||||
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
using (var scope = UowProvider.ScopeProvider.CreateScope())
|
||||
|
||||
@@ -425,7 +425,28 @@ namespace Umbraco.Core
|
||||
assemblyName.FullName.StartsWith("App_Code.") ? "App_Code" : assemblyName.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the given <paramref name="type"/> is an array or some other collection
|
||||
/// comprised of 0 or more instances of a "subtype", get that type
|
||||
/// </summary>
|
||||
/// <param name="type">the source type</param>
|
||||
/// <returns></returns>
|
||||
internal static Type GetEnumeratedType(this Type type)
|
||||
{
|
||||
if (typeof(IEnumerable).IsAssignableFrom(type) == false)
|
||||
return null;
|
||||
|
||||
// provided by Array
|
||||
var elType = type.GetElementType();
|
||||
if (null != elType) return elType;
|
||||
|
||||
// otherwise provided by collection
|
||||
var elTypes = type.GetGenericArguments();
|
||||
if (elTypes.Length > 0) return elTypes[0];
|
||||
|
||||
// otherwise is not an 'enumerated' type
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+55
-34
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Deploy;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -10,9 +12,10 @@ namespace Umbraco.Core
|
||||
/// Represents an entity identifier.
|
||||
/// </summary>
|
||||
/// <remarks>An Udi can be fully qualified or "closed" eg umb://document/{guid} or "open" eg umb://document.</remarks>
|
||||
[TypeConverter(typeof(UdiTypeConverter))]
|
||||
public abstract class Udi : IComparable<Udi>
|
||||
{
|
||||
private static readonly Dictionary<string, UdiType> UdiTypes = new Dictionary<string, UdiType>();
|
||||
private static readonly Lazy<Dictionary<string, UdiType>> UdiTypes;
|
||||
private static readonly ConcurrentDictionary<string, Udi> RootUdis = new ConcurrentDictionary<string, Udi>();
|
||||
internal readonly Uri UriValue; // internal for UdiRange
|
||||
|
||||
@@ -39,32 +42,50 @@ namespace Umbraco.Core
|
||||
|
||||
static Udi()
|
||||
{
|
||||
// for tests etc.
|
||||
UdiTypes[Constants.DeployEntityType.AnyGuid] = UdiType.GuidUdi;
|
||||
UdiTypes[Constants.DeployEntityType.AnyString] = UdiType.StringUdi;
|
||||
|
||||
// we don't have connectors for these...
|
||||
UdiTypes[Constants.DeployEntityType.Member] = UdiType.GuidUdi;
|
||||
UdiTypes[Constants.DeployEntityType.MemberGroup] = UdiType.GuidUdi;
|
||||
|
||||
// fixme - or inject from...?
|
||||
// there is no way we can get the "registered" service connectors, as registration
|
||||
// happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we
|
||||
// just pick every service connectors - just making sure that not two of them
|
||||
// would register the same entity type, with different udi types (would not make
|
||||
// much sense anyways).
|
||||
var connectors = PluginManager.Current.ResolveTypes<IServiceConnector>();
|
||||
foreach (var connector in connectors)
|
||||
UdiTypes = new Lazy<Dictionary<string, UdiType>>(() =>
|
||||
{
|
||||
var attrs = connector.GetCustomAttributes<UdiDefinitionAttribute>(false);
|
||||
foreach (var attr in attrs)
|
||||
var result = new Dictionary<string, UdiType>();
|
||||
|
||||
// known types:
|
||||
foreach (var fi in typeof(Constants.UdiEntityType).GetFields(BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
UdiType udiType;
|
||||
if (UdiTypes.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType)
|
||||
throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType));
|
||||
UdiTypes[attr.EntityType] = attr.UdiType;
|
||||
// IsLiteral determines if its value is written at
|
||||
// compile time and not changeable
|
||||
// IsInitOnly determine if the field can be set
|
||||
// in the body of the constructor
|
||||
// for C# a field which is readonly keyword would have both true
|
||||
// but a const field would have only IsLiteral equal to true
|
||||
if (fi.IsLiteral && fi.IsInitOnly == false)
|
||||
{
|
||||
var udiType = fi.GetCustomAttribute<Constants.UdiTypeAttribute>();
|
||||
|
||||
if (udiType == null)
|
||||
throw new InvalidOperationException("All Constants listed in UdiEntityType must be attributed with " + typeof(Constants.UdiTypeAttribute));
|
||||
result[fi.GetValue(null).ToString()] = udiType.UdiType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scan for unknown UDI types
|
||||
// there is no way we can get the "registered" service connectors, as registration
|
||||
// happens in Deploy, not in Core, and the Udi class belongs to Core - therefore, we
|
||||
// just pick every service connectors - just making sure that not two of them
|
||||
// would register the same entity type, with different udi types (would not make
|
||||
// much sense anyways).
|
||||
var connectors = PluginManager.Current.ResolveTypes<IServiceConnector>();
|
||||
foreach (var connector in connectors)
|
||||
{
|
||||
var attrs = connector.GetCustomAttributes<UdiDefinitionAttribute>(false);
|
||||
foreach (var attr in attrs)
|
||||
{
|
||||
UdiType udiType;
|
||||
if (result.TryGetValue(attr.EntityType, out udiType) && udiType != attr.UdiType)
|
||||
throw new Exception(string.Format("Entity type \"{0}\" is declared by more than one IServiceConnector, with different UdiTypes.", attr.EntityType));
|
||||
result[attr.EntityType] = attr.UdiType;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,8 +126,8 @@ namespace Umbraco.Core
|
||||
udi = null;
|
||||
Uri uri;
|
||||
|
||||
if (!Uri.IsWellFormedUriString(s, UriKind.Absolute)
|
||||
|| !Uri.TryCreate(s, UriKind.Absolute, out uri))
|
||||
if (Uri.IsWellFormedUriString(s, UriKind.Absolute) == false
|
||||
|| Uri.TryCreate(s, UriKind.Absolute, out uri) == false)
|
||||
{
|
||||
if (tryParse) return false;
|
||||
throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s));
|
||||
@@ -114,7 +135,7 @@ namespace Umbraco.Core
|
||||
|
||||
var entityType = uri.Host;
|
||||
UdiType udiType;
|
||||
if (!UdiTypes.TryGetValue(entityType, out udiType))
|
||||
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
|
||||
{
|
||||
if (tryParse) return false;
|
||||
throw new FormatException(string.Format("Unknown entity type \"{0}\".", entityType));
|
||||
@@ -128,7 +149,7 @@ namespace Umbraco.Core
|
||||
return true;
|
||||
}
|
||||
Guid guid;
|
||||
if (!Guid.TryParse(path, out guid))
|
||||
if (Guid.TryParse(path, out guid) == false)
|
||||
{
|
||||
if (tryParse) return false;
|
||||
throw new FormatException(string.Format("String \"{0}\" is not a valid udi.", s));
|
||||
@@ -150,7 +171,7 @@ namespace Umbraco.Core
|
||||
return RootUdis.GetOrAdd(entityType, x =>
|
||||
{
|
||||
UdiType udiType;
|
||||
if (!UdiTypes.TryGetValue(x, out udiType))
|
||||
if (UdiTypes.Value.TryGetValue(x, out udiType) == false)
|
||||
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType));
|
||||
return udiType == UdiType.StringUdi
|
||||
? (Udi)new StringUdi(entityType, string.Empty)
|
||||
@@ -177,7 +198,7 @@ namespace Umbraco.Core
|
||||
public static Udi Create(string entityType, string id)
|
||||
{
|
||||
UdiType udiType;
|
||||
if (!UdiTypes.TryGetValue(entityType, out udiType))
|
||||
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
|
||||
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType");
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
throw new ArgumentException("Value cannot be null or whitespace.", "id");
|
||||
@@ -196,7 +217,7 @@ namespace Umbraco.Core
|
||||
public static Udi Create(string entityType, Guid id)
|
||||
{
|
||||
UdiType udiType;
|
||||
if (!UdiTypes.TryGetValue(entityType, out udiType))
|
||||
if (UdiTypes.Value.TryGetValue(entityType, out udiType) == false)
|
||||
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", entityType), "entityType");
|
||||
if (udiType != UdiType.GuidUdi)
|
||||
throw new InvalidOperationException(string.Format("Entity type \"{0}\" does not have guid udis.", entityType));
|
||||
@@ -208,7 +229,7 @@ namespace Umbraco.Core
|
||||
internal static Udi Create(Uri uri)
|
||||
{
|
||||
UdiType udiType;
|
||||
if (!UdiTypes.TryGetValue(uri.Host, out udiType))
|
||||
if (UdiTypes.Value.TryGetValue(uri.Host, out udiType) == false)
|
||||
throw new ArgumentException(string.Format("Unknown entity type \"{0}\".", uri.Host), "uri");
|
||||
if (udiType == UdiType.GuidUdi)
|
||||
return new GuidUdi(uri);
|
||||
@@ -219,7 +240,7 @@ namespace Umbraco.Core
|
||||
|
||||
public void EnsureType(params string[] validTypes)
|
||||
{
|
||||
if (!validTypes.Contains(EntityType))
|
||||
if (validTypes.Contains(EntityType) == false)
|
||||
throw new Exception(string.Format("Unexpected entity type \"{0}\".", EntityType));
|
||||
}
|
||||
|
||||
@@ -260,7 +281,7 @@ namespace Umbraco.Core
|
||||
|
||||
public static bool operator !=(Udi udi1, Udi udi2)
|
||||
{
|
||||
return !(udi1 == udi2);
|
||||
return (udi1 == udi2) == false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+52
-13
@@ -7,52 +7,82 @@ namespace Umbraco.Core
|
||||
|
||||
public static partial class Constants
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Defines well-known entity types.
|
||||
/// </summary>
|
||||
/// <remarks>Well-known entity types are those that Deploy already knows about,
|
||||
/// but entity types are strings and so can be extended beyond what is defined here.</remarks>
|
||||
public static class DeployEntityType
|
||||
public static class UdiEntityType
|
||||
{
|
||||
[UdiType(UdiType.Unknown)]
|
||||
public const string Unknown = "unknown";
|
||||
|
||||
// guid entity types
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string AnyGuid = "any-guid"; // that one is for tests
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Document = "document";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Media = "media";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Member = "member";
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DictionaryItem = "dictionary-item";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Macro = "macro";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string Template = "template";
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DocumentType = "document-type";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DocumentTypeContainer = "document-type-container";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string MediaType = "media-type";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string MediaTypeContainer = "media-type-container";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DataType = "data-type";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string DataTypeContainer = "data-type-container";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string MemberType = "member-type";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string MemberGroup = "member-group";
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string RelationType = "relation-type";
|
||||
|
||||
|
||||
// forms
|
||||
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string FormsForm = "forms-form";
|
||||
public const string FormsWorkflow = "forms-workflow";
|
||||
public const string FormsRecord = "forms-record";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string FormsPreValue = "forms-prevalue";
|
||||
[UdiType(UdiType.GuidUdi)]
|
||||
public const string FormsDataSource = "forms-datasource";
|
||||
|
||||
// string entity types
|
||||
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string AnyString = "any-string"; // that one is for tests
|
||||
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string MediaFile = "media-file";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string TemplateFile = "template-file";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Script = "script";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Stylesheet = "stylesheet";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string PartialView = "partial-view";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string PartialViewMacro = "partial-view-macro";
|
||||
[UdiType(UdiType.StringUdi)]
|
||||
public const string Xslt = "xslt";
|
||||
|
||||
public static string FromUmbracoObjectType(UmbracoObjectTypes umbracoObjectType)
|
||||
@@ -89,10 +119,10 @@ namespace Umbraco.Core
|
||||
return RelationType;
|
||||
case UmbracoObjectTypes.FormsForm:
|
||||
return FormsForm;
|
||||
case UmbracoObjectTypes.FormsWorkflow:
|
||||
return FormsWorkflow;
|
||||
case UmbracoObjectTypes.FormsRecord:
|
||||
return FormsRecord;
|
||||
case UmbracoObjectTypes.FormsPreValue:
|
||||
return FormsPreValue;
|
||||
case UmbracoObjectTypes.FormsDataSource:
|
||||
return FormsDataSource;
|
||||
}
|
||||
throw new NotSupportedException(string.Format("UmbracoObjectType \"{0}\" does not have a matching EntityType.", umbracoObjectType));
|
||||
}
|
||||
@@ -131,16 +161,25 @@ namespace Umbraco.Core
|
||||
return UmbracoObjectTypes.RelationType;
|
||||
case FormsForm:
|
||||
return UmbracoObjectTypes.FormsForm;
|
||||
case FormsWorkflow:
|
||||
return UmbracoObjectTypes.FormsWorkflow;
|
||||
case FormsRecord:
|
||||
return UmbracoObjectTypes.FormsRecord;
|
||||
case FormsPreValue:
|
||||
return UmbracoObjectTypes.FormsPreValue;
|
||||
case FormsDataSource:
|
||||
return UmbracoObjectTypes.FormsDataSource;
|
||||
}
|
||||
throw new NotSupportedException(
|
||||
string.Format("EntityType \"{0}\" does not have a matching UmbracoObjectType.", entityType));
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
internal class UdiTypeAttribute : Attribute
|
||||
{
|
||||
public UdiType UdiType { get; private set; }
|
||||
|
||||
public UdiTypeAttribute(UdiType udiType)
|
||||
{
|
||||
UdiType = udiType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this ITemplate entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.Template, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.Template, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -28,7 +28,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IContentType entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.DocumentType, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.DocumentType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IMediaType entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.MediaType, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.MediaType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IMemberType entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.MemberType, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.MemberType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -61,7 +61,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IMemberGroup entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.MemberGroup, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.MemberGroup, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,9 +74,9 @@ namespace Umbraco.Core
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
|
||||
string type;
|
||||
if (entity is IContentType) type = Constants.DeployEntityType.DocumentType;
|
||||
else if (entity is IMediaType) type = Constants.DeployEntityType.MediaType;
|
||||
else if (entity is IMemberType) type = Constants.DeployEntityType.MemberType;
|
||||
if (entity is IContentType) type = Constants.UdiEntityType.DocumentType;
|
||||
else if (entity is IMediaType) type = Constants.UdiEntityType.MediaType;
|
||||
else if (entity is IMemberType) type = Constants.UdiEntityType.MemberType;
|
||||
else throw new NotSupportedException(string.Format("Composition type {0} is not supported.", entity.GetType().FullName));
|
||||
return new GuidUdi(type, entity.Key).EnsureClosed();
|
||||
}
|
||||
@@ -89,7 +89,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IDataTypeDefinition entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.DataType, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.DataType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -103,11 +103,11 @@ namespace Umbraco.Core
|
||||
|
||||
string entityType;
|
||||
if (entity.ContainedObjectType == Constants.ObjectTypes.DataTypeGuid)
|
||||
entityType = Constants.DeployEntityType.DataTypeContainer;
|
||||
entityType = Constants.UdiEntityType.DataTypeContainer;
|
||||
else if (entity.ContainedObjectType == Constants.ObjectTypes.DocumentTypeGuid)
|
||||
entityType = Constants.DeployEntityType.DocumentTypeContainer;
|
||||
entityType = Constants.UdiEntityType.DocumentTypeContainer;
|
||||
else if (entity.ContainedObjectType == Constants.ObjectTypes.MediaTypeGuid)
|
||||
entityType = Constants.DeployEntityType.MediaTypeContainer;
|
||||
entityType = Constants.UdiEntityType.MediaTypeContainer;
|
||||
else
|
||||
throw new NotSupportedException(string.Format("Contained object type {0} is not supported.", entity.ContainedObjectType));
|
||||
return new GuidUdi(entityType, entity.Key).EnsureClosed();
|
||||
@@ -121,7 +121,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IMedia entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.Media, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.Media, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,7 +132,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IContent entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.Document, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.Document, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -143,7 +143,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IMember entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.Member, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.Member, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -154,7 +154,7 @@ namespace Umbraco.Core
|
||||
public static StringUdi GetUdi(this Stylesheet entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new StringUdi(Constants.DeployEntityType.Stylesheet, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
return new StringUdi(Constants.UdiEntityType.Stylesheet, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -165,7 +165,7 @@ namespace Umbraco.Core
|
||||
public static StringUdi GetUdi(this Script entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new StringUdi(Constants.DeployEntityType.Script, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
return new StringUdi(Constants.UdiEntityType.Script, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -176,7 +176,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IDictionaryItem entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.DictionaryItem, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.DictionaryItem, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -187,7 +187,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IMacro entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.Macro, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.Macro, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,7 +198,7 @@ namespace Umbraco.Core
|
||||
public static StringUdi GetUdi(this IPartialView entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new StringUdi(Constants.DeployEntityType.PartialView, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
return new StringUdi(Constants.UdiEntityType.PartialView, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -209,7 +209,7 @@ namespace Umbraco.Core
|
||||
public static StringUdi GetUdi(this IXsltFile entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new StringUdi(Constants.DeployEntityType.Xslt, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
return new StringUdi(Constants.UdiEntityType.Xslt, entity.Path.TrimStart('/')).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -222,9 +222,9 @@ namespace Umbraco.Core
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
|
||||
string type;
|
||||
if (entity is IContent) type = Constants.DeployEntityType.Document;
|
||||
else if (entity is IMedia) type = Constants.DeployEntityType.Media;
|
||||
else if (entity is IMember) type = Constants.DeployEntityType.Member;
|
||||
if (entity is IContent) type = Constants.UdiEntityType.Document;
|
||||
else if (entity is IMedia) type = Constants.UdiEntityType.Media;
|
||||
else if (entity is IMember) type = Constants.UdiEntityType.Member;
|
||||
else throw new NotSupportedException(string.Format("ContentBase type {0} is not supported.", entity.GetType().FullName));
|
||||
return new GuidUdi(type, entity.Key).EnsureClosed();
|
||||
}
|
||||
@@ -237,7 +237,7 @@ namespace Umbraco.Core
|
||||
public static GuidUdi GetUdi(this IRelationType entity)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
return new GuidUdi(Constants.DeployEntityType.RelationType, entity.Key).EnsureClosed();
|
||||
return new GuidUdi(Constants.UdiEntityType.RelationType, entity.Key).EnsureClosed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom type converter for UDI
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Primarily this is used so that WebApi can auto-bind a string parameter to a UDI instance
|
||||
/// </remarks>
|
||||
internal class UdiTypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
if (sourceType == typeof(string))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
Udi udi;
|
||||
if (Udi.TryParse((string)value, out udi))
|
||||
{
|
||||
return udi;
|
||||
}
|
||||
}
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,6 +163,7 @@
|
||||
<Compile Include="Cache\DeepCloneRuntimeCacheProvider.cs" />
|
||||
<Compile Include="CodeAnnotations\FriendlyNameAttribute.cs" />
|
||||
<Compile Include="CodeAnnotations\UmbracoObjectTypeAttribute.cs" />
|
||||
<Compile Include="CodeAnnotations\UmbracoUdiTypeAttribute.cs" />
|
||||
<Compile Include="CodeAnnotations\UmbracoWillObsoleteAttribute.cs" />
|
||||
<Compile Include="CodeAnnotations\UmbracoExperimentalFeatureAttribute.cs" />
|
||||
<Compile Include="CodeAnnotations\UmbracoProposedPublicAttribute.cs" />
|
||||
@@ -289,7 +290,6 @@
|
||||
<Compile Include="Configuration\UmbracoSettings\WebRoutingElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoVersion.cs" />
|
||||
<Compile Include="Attempt.cs" />
|
||||
<Compile Include="Constants-DeployEntityType.cs" />
|
||||
<Compile Include="Constants-DeploySelector.cs" />
|
||||
<Compile Include="Constants-Examine.cs" />
|
||||
<Compile Include="Constants-Icons.cs" />
|
||||
@@ -311,8 +311,13 @@
|
||||
<Compile Include="Deploy\ArtifactSignature.cs" />
|
||||
<Compile Include="Deploy\Difference.cs" />
|
||||
<Compile Include="Deploy\Direction.cs" />
|
||||
<Compile Include="Deploy\IFileStore.cs" />
|
||||
<Compile Include="Deploy\IFileType.cs" />
|
||||
<Compile Include="Deploy\IFileTypeCollection.cs" />
|
||||
<Compile Include="Events\EventDefinitionFilter.cs" />
|
||||
<Compile Include="Events\IDeletingMediaFilesEventArgs.cs" />
|
||||
<Compile Include="Events\ScopeEventDispatcherBase.cs" />
|
||||
<Compile Include="Events\ScopeLifespanMessagesFactory.cs" />
|
||||
<Compile Include="IHttpContextAccessor.cs" />
|
||||
<Compile Include="OrderedHashSet.cs" />
|
||||
<Compile Include="Events\UninstallPackageEventArgs.cs" />
|
||||
<Compile Include="Models\GridValue.cs" />
|
||||
@@ -324,7 +329,6 @@
|
||||
<Compile Include="Deploy\IImageSourceParser.cs" />
|
||||
<Compile Include="Deploy\ILocalLinkParser.cs" />
|
||||
<Compile Include="Deploy\IMacroParser.cs" />
|
||||
<Compile Include="Deploy\IPrettyArtifact.cs" />
|
||||
<Compile Include="Deploy\IPreValueConnector.cs" />
|
||||
<Compile Include="Deploy\IServiceConnector.cs" />
|
||||
<Compile Include="Deploy\IValueConnector.cs" />
|
||||
@@ -362,7 +366,6 @@
|
||||
<Compile Include="Events\MoveEventInfo.cs" />
|
||||
<Compile Include="Events\PublishEventArgs.cs" />
|
||||
<Compile Include="Events\RecycleBinEventArgs.cs" />
|
||||
<Compile Include="Events\EventsDispatchMode.cs" />
|
||||
<Compile Include="Events\TransientMessagesFactory.cs" />
|
||||
<Compile Include="Events\TypedEventHandler.cs" />
|
||||
<Compile Include="Events\MoveEventArgs.cs" />
|
||||
@@ -484,6 +487,7 @@
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToCmsMemberLoginName.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexesToUmbracoRelationTables.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToUmbracoNodePath.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddIndexToUser2NodePermission.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddRelationTypeUniqueIdColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\AddMacroUniqueIdColumn.cs" />
|
||||
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\RemovePropertyDataIdIndex.cs" />
|
||||
@@ -562,7 +566,7 @@
|
||||
<Compile Include="Publishing\UnPublishedStatusType.cs" />
|
||||
<Compile Include="Publishing\UnPublishStatus.cs" />
|
||||
<Compile Include="SafeCallContext.cs" />
|
||||
<Compile Include="Scoping\ActionTime.cs" />
|
||||
<Compile Include="Scoping\IInstanceIdentifiable.cs" />
|
||||
<Compile Include="Scoping\IScope.cs" />
|
||||
<Compile Include="Scoping\IScopeInternal.cs" />
|
||||
<Compile Include="Scoping\IScopeProvider.cs" />
|
||||
@@ -1439,9 +1443,11 @@
|
||||
<Compile Include="TypeHelper.cs" />
|
||||
<Compile Include="Udi.cs" />
|
||||
<Compile Include="UdiDefinitionAttribute.cs" />
|
||||
<Compile Include="UdiEntityType.cs" />
|
||||
<Compile Include="UdiGetterExtensions.cs" />
|
||||
<Compile Include="UdiRange.cs" />
|
||||
<Compile Include="UdiType.cs" />
|
||||
<Compile Include="UdiTypeConverter.cs" />
|
||||
<Compile Include="UmbracoApplicationBase.cs" />
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="Constants-Applications.cs">
|
||||
|
||||
@@ -336,8 +336,9 @@ namespace Umbraco.Tests.IO
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("path/to/some/dir/f1.txt", ms);
|
||||
|
||||
// file is only written to the shadow fs
|
||||
Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt"));
|
||||
|
||||
Assert.IsFalse(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt"));
|
||||
// let the shadow fs die
|
||||
}
|
||||
|
||||
@@ -364,7 +365,8 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
ss.Complete();
|
||||
|
||||
Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt")); // *not* cleaning
|
||||
// yes we are cleaning now
|
||||
//Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt")); // *not* cleaning
|
||||
Assert.IsTrue(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt"));
|
||||
Assert.IsFalse(File.Exists(path + "/ShadowTests/sub/sub/f2.txt"));
|
||||
}
|
||||
@@ -381,7 +383,7 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", scopeProvider);
|
||||
var swa = new[] { sw };
|
||||
var swa = new[] {sw};
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
@@ -462,7 +464,7 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", scopeProvider);
|
||||
var swa = new[] { sw };
|
||||
var swa = new[] {sw};
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
@@ -511,7 +513,7 @@ namespace Umbraco.Tests.IO
|
||||
|
||||
var fs = new PhysicalFileSystem(path, "ignore");
|
||||
var sw = new ShadowWrapper(fs, "shadow", scopeProvider);
|
||||
var swa = new[] { sw };
|
||||
var swa = new[] {sw};
|
||||
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
sw.AddFile("sub/f1.txt", ms);
|
||||
@@ -558,7 +560,7 @@ namespace Umbraco.Tests.IO
|
||||
Assert.AreEqual(1, ae.InnerExceptions.Count);
|
||||
e = ae.InnerExceptions[0];
|
||||
Assert.IsNotNull(e.InnerException);
|
||||
Assert.IsInstanceOf<UnauthorizedAccessException>(e.InnerException);
|
||||
Assert.IsInstanceOf<Exception>(e.InnerException);
|
||||
}
|
||||
|
||||
// still, the rest of the changes has been applied ok
|
||||
@@ -622,5 +624,385 @@ namespace Umbraco.Tests.IO
|
||||
providerMock.Setup(x => x.AmbientScope).Returns(scopeMock.Object);
|
||||
return providerMock.Object;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that GetFiles will return all files on the shadow, while returning
|
||||
/// just one on each of the filesystems used by the shadow.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ShadowGetFiles()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 2 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(2, getFiles.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, sfsFiles.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that GetFiles using the filter function with empty string will return expected results
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingEmptyFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 2 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(2, getFiles.Count());
|
||||
// ensure we get 0 files when using a empty filter
|
||||
var getFilesWithEmptyFilter = ss.GetFiles(string.Empty, "");
|
||||
Assert.AreEqual(0, getFilesWithEmptyFilter.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, sfsFiles.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that GetFiles using the filter function with null will return expected results
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingNullFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 2 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(2, getFiles.Count());
|
||||
// ensure we get 2 files when using null in filter parameter
|
||||
var getFilesWithNullFilter = ss.GetFiles(string.Empty, null);
|
||||
Assert.AreEqual(2, getFilesWithNullFilter.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(1, sfsFiles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingWildcardFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.doc", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 4 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(4, getFiles.Count());
|
||||
// ensure we get only 2 of 4 files from the shadow when using filter
|
||||
var getFilesWithWildcardFilter = ss.GetFiles(string.Empty, "*.doc");
|
||||
Assert.AreEqual(2, getFilesWithWildcardFilter.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(2, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(2, sfsFiles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingSingleCharacterFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.docx", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.doc", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.docx", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 6 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(6, getFiles.Count());
|
||||
// ensure we get only 2 of 6 files from the shadow when using filter on shadow
|
||||
var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "f1.d?c");
|
||||
Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter.Count());
|
||||
// ensure we get only 2 of 6 files from the shadow when using filter on disk
|
||||
var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "f2.d?c");
|
||||
Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter2.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(3, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(3, sfsFiles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowGetFilesUsingWildcardAndSingleCharacterFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
|
||||
File.WriteAllText(path + "/ShadowTests/f2.docx", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.txt", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.doc", ms);
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f1.docx", ms);
|
||||
|
||||
// Assert
|
||||
// ensure we get 6 files from the shadow
|
||||
var getFiles = ss.GetFiles(string.Empty);
|
||||
Assert.AreEqual(6, getFiles.Count());
|
||||
var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "*.d?c");
|
||||
|
||||
Assert.AreEqual(4, getFilesWithWildcardSinglecharFilter.Count());
|
||||
var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "*.d?cx");
|
||||
Assert.AreEqual(2, getFilesWithWildcardSinglecharFilter2.Count());
|
||||
|
||||
var fsFiles = fs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(3, fsFiles.Length);
|
||||
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
|
||||
Assert.AreEqual(3, sfsFiles.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShadowFileSystemFilterIsAsBrokenAsRealFileSystemFilter()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/filter");
|
||||
// create files on disk and create a "fake" list of files to verify filters against
|
||||
File.WriteAllText(path + "/filter/f1.txt", "foo");
|
||||
File.WriteAllText(path + "/filter/f1.doc", "foo");
|
||||
File.WriteAllText(path + "/filter/f1.docx", "foo");
|
||||
var files = new string[]
|
||||
{
|
||||
"f1.txt",
|
||||
"f1.doc",
|
||||
"f1.docx",
|
||||
};
|
||||
var filter1 = "";
|
||||
var filter2 = "*";
|
||||
var filter3 = "*.doc";
|
||||
var filter4 = "*.d?c";
|
||||
var filter5 = "f1.doc";
|
||||
var filter6 = "f1.d?c";
|
||||
var filter7 = "**.d?c";
|
||||
var filter8 = "f*.doc";
|
||||
|
||||
// Act & Assert
|
||||
var result1Disk = Directory.GetFiles(path + "/filter/", filter1).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result1Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter1))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result1Disk, result1Fake);
|
||||
var result2Disk = Directory.GetFiles(path + "/filter/", filter2).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result2Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter2))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result2Disk, result2Fake);
|
||||
var result3Disk = Directory.GetFiles(path + "/filter/", filter3).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result3Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter3))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result3Disk, result3Fake);
|
||||
var result4Disk = Directory.GetFiles(path + "/filter/", filter4).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result4Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter4))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result4Disk, result4Fake);
|
||||
var result5Disk = Directory.GetFiles(path + "/filter/", filter5).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result5Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter5))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result5Disk, result5Fake);
|
||||
var result6Disk = Directory.GetFiles(path + "/filter/", filter6).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result6Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter6))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result6Disk, result6Fake);
|
||||
var result7Disk = Directory.GetFiles(path + "/filter/", filter7).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result7Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter7))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result7Disk, result7Fake);
|
||||
var result8Disk = Directory.GetFiles(path + "/filter/", filter8).Select(Path.GetFileName).OrderBy(x => x).ToArray();
|
||||
var result8Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter8))).OrderBy(x => x).ToArray();
|
||||
Assert.AreEqual(result8Disk, result8Fake);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the full paths of the files on the disk.
|
||||
/// Note that this will be the *actual* path of the file, meaning a file existing on the initialized FS
|
||||
/// will be in one location, while a file written after initializing the shadow, will exist at the
|
||||
/// shadow location directory.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ShadowGetFullPath()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f2.txt", ms);
|
||||
|
||||
// Assert
|
||||
var f1FullPath = ss.GetFullPath("f1.txt");
|
||||
var f2FullPath = ss.GetFullPath("f2.txt");
|
||||
Assert.AreEqual(Path.Combine(path, "ShadowTests", "f1.txt"), f1FullPath);
|
||||
Assert.AreEqual(Path.Combine(path, "ShadowSystem", "f2.txt"), f2FullPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path relative to the filesystem root
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This file stuff in this test is kinda irrelevant with the current implementation.
|
||||
/// We do tests that the files are written to the correct places and the relative path is returned correct,
|
||||
/// but GetRelativePath is currently really just string manipulation so files are not actually hit by the code.
|
||||
/// Leaving the file stuff in here for now in case the method becomes more clever at some point.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void ShadowGetRelativePath()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f2.txt", ms);
|
||||
|
||||
// Assert
|
||||
var f1RelativePath = ss.GetRelativePath("f1.txt");
|
||||
var f2RelativePath = ss.GetRelativePath("f2.txt");
|
||||
Assert.AreEqual("f1.txt", f1RelativePath);
|
||||
Assert.AreEqual("f2.txt", f2RelativePath);
|
||||
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt")));
|
||||
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt")));
|
||||
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt")));
|
||||
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt")));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure the url returned contains the path relative to the FS root,
|
||||
/// but including the rootUrl the FS was initialized with.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This file stuff in this test is kinda irrelevant with the current implementation.
|
||||
/// We do tests that the files are written to the correct places and the url is returned correct,
|
||||
/// but GetUrl is currently really just string manipulation so files are not actually hit by the code.
|
||||
/// Leaving the file stuff in here for now in case the method becomes more clever at some point.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void ShadowGetUrl()
|
||||
{
|
||||
// Arrange
|
||||
var path = IOHelper.MapPath("FileSysTests");
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.CreateDirectory(path + "/ShadowTests");
|
||||
Directory.CreateDirectory(path + "/ShadowSystem");
|
||||
|
||||
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "rootUrl");
|
||||
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "rootUrl");
|
||||
var ss = new ShadowFileSystem(fs, sfs);
|
||||
|
||||
// Act
|
||||
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
|
||||
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
|
||||
ss.AddFile("f2.txt", ms);
|
||||
|
||||
// Assert
|
||||
var f1Url = ss.GetUrl("f1.txt");
|
||||
var f2Url = ss.GetUrl("f2.txt");
|
||||
Assert.AreEqual("rootUrl/f1.txt", f1Url);
|
||||
Assert.AreEqual("rootUrl/f2.txt", f2Url);
|
||||
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt")));
|
||||
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt")));
|
||||
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt")));
|
||||
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
|
||||
// Act
|
||||
var exists = repository.Exists(1034); //Content picker
|
||||
var exists = repository.Exists(1046); //Content picker
|
||||
var doesntExist = repository.Exists(-80);
|
||||
|
||||
// Assert
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Data;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
@@ -38,11 +39,14 @@ namespace Umbraco.Tests.Scoping
|
||||
_database.BeginTransaction(); // opens and maintains a connection
|
||||
|
||||
// the test is leaking a scope with a non-null database
|
||||
var contextScope = CallContext.LogicalGetData(ScopeProvider.ScopeItemKey);
|
||||
Assert.IsNotNull(contextScope);
|
||||
Assert.IsInstanceOf<NoScope>(CallContext.LogicalGetData(ScopeProvider.ScopeItemKey));
|
||||
Assert.IsNotNull(((NoScope) contextScope).DatabaseOrNull);
|
||||
Assert.AreSame(_database, ((NoScope)contextScope).DatabaseOrNull);
|
||||
var contextGuid = CallContext.LogicalGetData(ScopeProvider.ScopeItemKey).AsGuid();
|
||||
Assert.AreNotEqual(Guid.Empty, contextGuid);
|
||||
|
||||
// only if Core.DEBUG_SCOPES are defined
|
||||
//var contextScope = DatabaseContext.ScopeProvider.CallContextObjects[contextGuid] as NoScope;
|
||||
//Assert.IsNotNull(contextScope);
|
||||
//Assert.IsNotNull(contextScope.DatabaseOrNull);
|
||||
//Assert.AreSame(_database, contextScope.DatabaseOrNull);
|
||||
|
||||
// save the connection
|
||||
_connection = _database.Connection;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
@@ -8,7 +9,6 @@ using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Tests.Scoping
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class ScopeEventDispatcherTests
|
||||
{
|
||||
@@ -21,11 +21,15 @@ namespace Umbraco.Tests.Scoping
|
||||
DoThing3 = null;
|
||||
}
|
||||
|
||||
[TestCase(EventsDispatchMode.PassThrough, true, true)]
|
||||
[TestCase(EventsDispatchMode.PassThrough, true, false)]
|
||||
[TestCase(EventsDispatchMode.PassThrough, false, true)]
|
||||
[TestCase(EventsDispatchMode.PassThrough, false, false)]
|
||||
public void PassThroughCancelable(EventsDispatchMode mode, bool cancel, bool complete)
|
||||
[TestCase(false, true, true)]
|
||||
[TestCase(false, true, false)]
|
||||
[TestCase(false, false, true)]
|
||||
[TestCase(false, false, false)]
|
||||
[TestCase(true, true, true)]
|
||||
[TestCase(true, true, false)]
|
||||
[TestCase(true, false, true)]
|
||||
[TestCase(true, false, false)]
|
||||
public void EventsHandling(bool passive, bool cancel, bool complete)
|
||||
{
|
||||
var counter1 = 0;
|
||||
var counter2 = 0;
|
||||
@@ -34,7 +38,7 @@ namespace Umbraco.Tests.Scoping
|
||||
DoThing2 += (sender, args) => { counter2++; };
|
||||
|
||||
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
|
||||
using (var scope = scopeProvider.CreateScope(dispatchMode: mode))
|
||||
using (var scope = scopeProvider.CreateScope(eventDispatcher: passive ? new PassiveEventDispatcher() : null))
|
||||
{
|
||||
var cancelled = scope.Events.DispatchCancelable(DoThing1, this, new SaveEventArgs<string>("test"));
|
||||
if (cancelled == false)
|
||||
@@ -43,22 +47,15 @@ namespace Umbraco.Tests.Scoping
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
var expected1 = mode == EventsDispatchMode.Passive ? 0 : 1;
|
||||
var expected1 = passive ? 0 : 1;
|
||||
Assert.AreEqual(expected1, counter1);
|
||||
|
||||
var expected2 = -1;
|
||||
switch (mode)
|
||||
{
|
||||
case EventsDispatchMode.PassThrough:
|
||||
expected2 = cancel ? 0 : 1;
|
||||
break;
|
||||
case EventsDispatchMode.Scope:
|
||||
expected2 = cancel ? 0 : (complete ? 1 : 0);
|
||||
break;
|
||||
case EventsDispatchMode.Passive:
|
||||
expected2 = 0;
|
||||
break;
|
||||
}
|
||||
int expected2;
|
||||
if (passive)
|
||||
expected2 = 0;
|
||||
else
|
||||
expected2 = cancel ? 0 : (complete ? 1 : 0);
|
||||
|
||||
Assert.AreEqual(expected2, counter2);
|
||||
}
|
||||
|
||||
@@ -70,7 +67,7 @@ namespace Umbraco.Tests.Scoping
|
||||
DoThing3 += OnDoThingFail;
|
||||
|
||||
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
|
||||
using (var scope = scopeProvider.CreateScope(dispatchMode: EventsDispatchMode.Passive))
|
||||
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
|
||||
{
|
||||
scope.Events.Dispatch(DoThing1, this, new SaveEventArgs<string>("test"));
|
||||
scope.Events.Dispatch(DoThing2, this, new SaveEventArgs<int>(0));
|
||||
@@ -94,45 +91,14 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void EventsDispatchmode_PassThrough(bool complete)
|
||||
{
|
||||
var counter = 0;
|
||||
|
||||
DoThing1 += (sender, args) => { counter++; };
|
||||
DoThing2 += (sender, args) => { counter++; };
|
||||
DoThing3 += (sender, args) => { counter++; };
|
||||
|
||||
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
|
||||
using (var scope = scopeProvider.CreateScope(dispatchMode: EventsDispatchMode.PassThrough))
|
||||
{
|
||||
scope.Events.Dispatch(DoThing1, this, new SaveEventArgs<string>("test"));
|
||||
scope.Events.Dispatch(DoThing2, this, new SaveEventArgs<int>(0));
|
||||
scope.Events.Dispatch(DoThing3, this, new SaveEventArgs<decimal>(0));
|
||||
|
||||
// events have not been queued
|
||||
Assert.IsEmpty(scope.Events.GetEvents(EventDefinitionFilter.All));
|
||||
|
||||
// events have been raised
|
||||
Assert.AreEqual(3, counter);
|
||||
|
||||
if (complete)
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
// nothing has changed
|
||||
Assert.AreEqual(3, counter);
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void EventsDispatchMode_Passive(bool complete)
|
||||
public void EventsDispatching_Passive(bool complete)
|
||||
{
|
||||
DoThing1 += OnDoThingFail;
|
||||
DoThing2 += OnDoThingFail;
|
||||
DoThing3 += OnDoThingFail;
|
||||
|
||||
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
|
||||
using (var scope = scopeProvider.CreateScope(dispatchMode: EventsDispatchMode.Passive))
|
||||
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
|
||||
{
|
||||
scope.Events.Dispatch(DoThing1, this, new SaveEventArgs<string>("test"));
|
||||
scope.Events.Dispatch(DoThing2, this, new SaveEventArgs<int>(0));
|
||||
@@ -150,7 +116,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void EventsDispatchMode_Scope(bool complete)
|
||||
public void EventsDispatching_Scope(bool complete)
|
||||
{
|
||||
var counter = 0;
|
||||
IScope ambientScope = null;
|
||||
@@ -170,7 +136,7 @@ namespace Umbraco.Tests.Scoping
|
||||
};
|
||||
|
||||
Guid guid;
|
||||
using (var scope = scopeProvider.CreateScope(dispatchMode: EventsDispatchMode.Scope))
|
||||
using (var scope = scopeProvider.CreateScope())
|
||||
{
|
||||
Assert.IsNotNull(scopeProvider.AmbientContext);
|
||||
guid = scopeProvider.Context.Enlist("value", Guid.NewGuid, (c, o) => { });
|
||||
@@ -181,6 +147,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
// events have been queued
|
||||
Assert.AreEqual(3, scope.Events.GetEvents(EventDefinitionFilter.All).Count());
|
||||
Assert.AreEqual(0, counter);
|
||||
|
||||
if (complete)
|
||||
scope.Complete();
|
||||
@@ -215,5 +182,17 @@ namespace Umbraco.Tests.Scoping
|
||||
public static event EventHandler<SaveEventArgs<int>> DoThing2;
|
||||
|
||||
public static event TypedEventHandler<ScopeEventDispatcherTests, SaveEventArgs<decimal>> DoThing3;
|
||||
}
|
||||
|
||||
public class PassiveEventDispatcher : ScopeEventDispatcherBase
|
||||
{
|
||||
public PassiveEventDispatcher()
|
||||
: base(false)
|
||||
{ }
|
||||
|
||||
protected override void ScopeExitCompleted()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Core.Events;
|
||||
|
||||
namespace Umbraco.Tests.Scoping
|
||||
{
|
||||
@@ -97,6 +99,54 @@ namespace Umbraco.Tests.Scoping
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NestedMigrateScope()
|
||||
{
|
||||
var scopeProvider = DatabaseContext.ScopeProvider;
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
|
||||
var httpContextItems = new Hashtable();
|
||||
ScopeProvider.HttpContextItemsGetter = () => httpContextItems;
|
||||
try
|
||||
{
|
||||
using (var scope = scopeProvider.CreateScope())
|
||||
{
|
||||
Assert.IsInstanceOf<Scope>(scope);
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.AreSame(scope, scopeProvider.AmbientScope);
|
||||
Assert.AreSame(scope, httpContextItems[ScopeProvider.ScopeItemKey]);
|
||||
|
||||
// only if Core.DEBUG_SCOPES are defined
|
||||
//Assert.IsEmpty(scopeProvider.CallContextObjects);
|
||||
|
||||
using (var nested = scopeProvider.CreateScope(callContext: true))
|
||||
{
|
||||
Assert.IsInstanceOf<Scope>(nested);
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.AreSame(nested, scopeProvider.AmbientScope);
|
||||
Assert.AreSame(scope, ((Scope) nested).ParentScope);
|
||||
|
||||
// it's moved over to call context
|
||||
Assert.IsNull(httpContextItems[ScopeProvider.ScopeItemKey]);
|
||||
var callContextKey = CallContext.LogicalGetData(ScopeProvider.ScopeItemKey).AsGuid();
|
||||
Assert.AreNotEqual(Guid.Empty, callContextKey);
|
||||
|
||||
// only if Core.DEBUG_SCOPES are defined
|
||||
//var ccnested = scopeProvider.CallContextObjects[callContextKey];
|
||||
//Assert.AreSame(nested, ccnested);
|
||||
}
|
||||
|
||||
// it's naturally back in http context
|
||||
Assert.AreSame(scope, httpContextItems[ScopeProvider.ScopeItemKey]);
|
||||
}
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ScopeProvider.HttpContextItemsGetter = null;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NestedCreateScopeContext()
|
||||
{
|
||||
@@ -478,17 +528,82 @@ namespace Umbraco.Tests.Scoping
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CallContextScope()
|
||||
public void CallContextScope1()
|
||||
{
|
||||
var scopeProvider = DatabaseContext.ScopeProvider;
|
||||
var scope = scopeProvider.CreateScope();
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
using (new SafeCallContext())
|
||||
using (var scope = scopeProvider.CreateScope())
|
||||
{
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNotNull(scopeProvider.AmbientContext);
|
||||
using (new SafeCallContext())
|
||||
{
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
|
||||
using (var newScope = scopeProvider.CreateScope())
|
||||
{
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientScope.ParentScope);
|
||||
Assert.IsNotNull(scopeProvider.AmbientContext);
|
||||
}
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
}
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.AreSame(scope, scopeProvider.AmbientScope);
|
||||
}
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CallContextScope2()
|
||||
{
|
||||
var scopeProvider = DatabaseContext.ScopeProvider;
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
|
||||
var httpContextItems = new Hashtable();
|
||||
ScopeProvider.HttpContextItemsGetter = () => httpContextItems;
|
||||
try
|
||||
{
|
||||
using (var scope = scopeProvider.CreateScope())
|
||||
{
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNotNull(scopeProvider.AmbientContext);
|
||||
using (new SafeCallContext())
|
||||
{
|
||||
// pretend it's another thread
|
||||
ScopeProvider.HttpContextItemsGetter = null;
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
|
||||
using (var newScope = scopeProvider.CreateScope())
|
||||
{
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientScope.ParentScope);
|
||||
Assert.IsNotNull(scopeProvider.AmbientContext);
|
||||
}
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
|
||||
// back to original thread
|
||||
ScopeProvider.HttpContextItemsGetter = () => httpContextItems;
|
||||
}
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.AreSame(scope, scopeProvider.AmbientScope);
|
||||
}
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ScopeProvider.HttpContextItemsGetter = null;
|
||||
}
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
Assert.AreSame(scope, scopeProvider.AmbientScope);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -213,12 +213,8 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
var scopeProvider = ApplicationContext.Current.ScopeProvider as IScopeProviderInternal;
|
||||
Assert.IsNotNull(scopeProvider);
|
||||
if (complete)
|
||||
// because some event handlers trigger xml refresh with directly uses the DB
|
||||
Assert.IsNotNull(scopeProvider.AmbientScope);
|
||||
else
|
||||
// because nothing happened
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
// ambient scope may be null, or maybe not, depending on whether the code that
|
||||
// was called did proper scoped work, or some direct (NoScope) use of the database
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
|
||||
// limited number of clones!
|
||||
|
||||
@@ -1343,6 +1343,69 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(contents.Any(), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Empty_RecycleBin_With_Content_That_Has_All_Related_Data()
|
||||
{
|
||||
// Arrange
|
||||
//need to:
|
||||
// * add relations
|
||||
// * add permissions
|
||||
// * add notifications
|
||||
// * public access
|
||||
// * tags
|
||||
// * domain
|
||||
// * published & preview data
|
||||
// * multiple versions
|
||||
|
||||
var contentType = MockedContentTypes.CreateAllTypesContentType("test", "test");
|
||||
ServiceContext.ContentTypeService.Save(contentType, 0);
|
||||
|
||||
object obj =
|
||||
new
|
||||
{
|
||||
tags = "Hello,World"
|
||||
};
|
||||
var content1 = MockedContent.CreateBasicContent(contentType);
|
||||
content1.PropertyValues(obj);
|
||||
content1.ResetDirtyProperties(false);
|
||||
ServiceContext.ContentService.Save(content1, 0);
|
||||
Assert.IsTrue(ServiceContext.ContentService.PublishWithStatus(content1, 0).Success);
|
||||
var content2 = MockedContent.CreateBasicContent(contentType);
|
||||
content2.PropertyValues(obj);
|
||||
content2.ResetDirtyProperties(false);
|
||||
ServiceContext.ContentService.Save(content2, 0);
|
||||
Assert.IsTrue(ServiceContext.ContentService.PublishWithStatus(content2, 0).Success);
|
||||
|
||||
ServiceContext.RelationService.Save(new RelationType(Constants.ObjectTypes.DocumentGuid, Constants.ObjectTypes.DocumentGuid, "test"));
|
||||
Assert.IsNotNull(ServiceContext.RelationService.Relate(content1, content2, "test"));
|
||||
|
||||
ServiceContext.PublicAccessService.Save(new PublicAccessEntry(content1, content2, content2, new List<PublicAccessRule>
|
||||
{
|
||||
new PublicAccessRule
|
||||
{
|
||||
RuleType = "test",
|
||||
RuleValue = "test"
|
||||
}
|
||||
}));
|
||||
Assert.IsTrue(ServiceContext.PublicAccessService.AddRule(content1, "test2", "test2").Success);
|
||||
|
||||
Assert.IsNotNull(ServiceContext.NotificationService.CreateNotification(ServiceContext.UserService.GetUserById(0), content1, "test"));
|
||||
|
||||
ServiceContext.ContentService.AssignContentPermission(content1, 'A', new[] {0});
|
||||
|
||||
Assert.IsTrue(ServiceContext.DomainService.Save(new UmbracoDomain("www.test.com", "en-AU")
|
||||
{
|
||||
RootContentId = content1.Id
|
||||
}).Success);
|
||||
|
||||
// Act
|
||||
ServiceContext.ContentService.EmptyRecycleBin();
|
||||
var contents = ServiceContext.ContentService.GetContentInRecycleBin();
|
||||
|
||||
// Assert
|
||||
Assert.That(contents.Any(), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Move_Content()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -25,8 +26,368 @@ namespace Umbraco.Tests.Services
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Children()
|
||||
{
|
||||
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 0, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(6));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Document, 1, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(4));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var count = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
count++;
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(31));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 1, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(29));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_Including_Recycled()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var toDelete = new List<IContent>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.ContentService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Document, 0, 1000, out total)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var c in toDelete)
|
||||
{
|
||||
Assert.True(entities.Contains(c.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_Without_Recycled()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
var toDelete = new List<IContent>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, Guid.NewGuid().ToString(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.ContentService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendantsFromRoot(UmbracoObjectTypes.Document, 0, 1000, out total, includeTrashed:false)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var c in toDelete)
|
||||
{
|
||||
Assert.IsFalse(entities.Contains(c.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Content_Descendants_With_Search()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
var root = MockedContent.CreateSimpleContent(contentType);
|
||||
ServiceContext.ContentService.Save(root);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedContent.CreateSimpleContent(contentType, "ssss" + Guid.NewGuid(), root);
|
||||
ServiceContext.ContentService.Save(c1);
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedContent.CreateSimpleContent(contentType, "tttt" + Guid.NewGuid(), c1);
|
||||
ServiceContext.ContentService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 10, out total, filter: "ssss").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(10));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Document, 0, 50, out total, filter: "tttt").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(50));
|
||||
Assert.That(total, Is.EqualTo(50));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Children()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 0, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(6));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedChildren(root.Id, UmbracoObjectTypes.Media, 1, 6, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(4));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var count = 0;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
count++;
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(31));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 1, 31, out total).ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(29));
|
||||
Assert.That(total, Is.EqualTo(60));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_Including_Recycled()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var toDelete = new List<IMedia>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.MediaService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendants(-1, UmbracoObjectTypes.Media, 0, 1000, out total)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var media in toDelete)
|
||||
{
|
||||
Assert.IsTrue(entities.Contains(media.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_Without_Recycled()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
var toDelete = new List<IMedia>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
toDelete.Add(c1);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var content in toDelete)
|
||||
{
|
||||
ServiceContext.MediaService.MoveToRecycleBin(content);
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
//search at root to see if it returns recycled
|
||||
var entities = service.GetPagedDescendantsFromRoot(UmbracoObjectTypes.Media, 0, 1000, out total, includeTrashed:false)
|
||||
.Select(x => x.Id)
|
||||
.ToArray();
|
||||
|
||||
foreach (var media in toDelete)
|
||||
{
|
||||
Assert.IsFalse(entities.Contains(media.Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Paged_Media_Descendants_With_Search()
|
||||
{
|
||||
var folderType = ServiceContext.ContentTypeService.GetMediaType(1031);
|
||||
var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
|
||||
|
||||
var root = MockedMedia.CreateMediaFolder(folderType, -1);
|
||||
ServiceContext.MediaService.Save(root);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var c1 = MockedMedia.CreateMediaImage(imageMediaType, root.Id);
|
||||
c1.Name = "ssss" + Guid.NewGuid();
|
||||
ServiceContext.MediaService.Save(c1);
|
||||
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
var c2 = MockedMedia.CreateMediaImage(imageMediaType, c1.Id);
|
||||
c2.Name = "tttt" + Guid.NewGuid();
|
||||
ServiceContext.MediaService.Save(c2);
|
||||
}
|
||||
}
|
||||
|
||||
var service = ServiceContext.EntityService;
|
||||
|
||||
long total;
|
||||
var entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 10, out total, filter: "ssss").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(10));
|
||||
Assert.That(total, Is.EqualTo(10));
|
||||
entities = service.GetPagedDescendants(root.Id, UmbracoObjectTypes.Media, 0, 50, out total, filter: "tttt").ToArray();
|
||||
Assert.That(entities.Length, Is.EqualTo(50));
|
||||
Assert.That(total, Is.EqualTo(50));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Find_All_Content_By_UmbracoObjectTypes()
|
||||
{
|
||||
|
||||
@@ -72,11 +72,12 @@ namespace Umbraco.Tests.TestHelpers
|
||||
GetDbProviderName(),
|
||||
Logger);
|
||||
|
||||
// fixme - bah - this is needed to reset static properties? Stephen to update this note
|
||||
// ensure we start tests in a clean state ie without any scope in context
|
||||
// anything that used a true 'Scope' would have removed it, but there could
|
||||
// be a rogue 'NoScope' there - and we want to make sure it is gone
|
||||
var scopeProvider = new ScopeProvider(null);
|
||||
if (scopeProvider.AmbientScope != null)
|
||||
scopeProvider.AmbientScope.Dispose();
|
||||
scopeProvider.AmbientScope = null;
|
||||
scopeProvider.AmbientScope.Dispose(); // removes scope from context
|
||||
|
||||
base.Initialize();
|
||||
|
||||
|
||||
@@ -358,9 +358,9 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.DateAlias, DataTypeDatabaseType.Date) { Alias = "date", Name = "Date", Mandatory = false, SortOrder = 13, DataTypeDefinitionId = -41 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.DropDownListAlias, DataTypeDatabaseType.Integer) { Alias = "ddl", Name = "Dropdown List", Mandatory = false, SortOrder = 14, DataTypeDefinitionId = -42 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.CheckBoxListAlias, DataTypeDatabaseType.Nvarchar) { Alias = "chklist", Name = "Checkbox List", Mandatory = false, SortOrder = 15, DataTypeDefinitionId = -43 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.ContentPickerAlias, DataTypeDatabaseType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeDefinitionId = 1034 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.MediaPickerAlias, DataTypeDatabaseType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeDefinitionId = 1035 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.MemberPickerAlias, DataTypeDatabaseType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeDefinitionId = 1036 });
|
||||
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.TagsAlias, DataTypeDatabaseType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeDefinitionId = 1041 });
|
||||
|
||||
|
||||
@@ -13,41 +13,41 @@ namespace Umbraco.Tests
|
||||
[Test]
|
||||
public void StringEntityCtorTest()
|
||||
{
|
||||
var udi = new StringUdi(Constants.DeployEntityType.AnyString, "test-id");
|
||||
Assert.AreEqual(Constants.DeployEntityType.AnyString, udi.EntityType);
|
||||
var udi = new StringUdi(Constants.UdiEntityType.AnyString, "test-id");
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType);
|
||||
Assert.AreEqual("test-id", udi.Id);
|
||||
Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyString + "/test-id", udi.ToString());
|
||||
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StringEntityParseTest()
|
||||
{
|
||||
var udi = Udi.Parse("umb://" + Constants.DeployEntityType.AnyString + "/test-id");
|
||||
Assert.AreEqual(Constants.DeployEntityType.AnyString, udi.EntityType);
|
||||
var udi = Udi.Parse("umb://" + Constants.UdiEntityType.AnyString + "/test-id");
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyString, udi.EntityType);
|
||||
Assert.IsInstanceOf<StringUdi>(udi);
|
||||
var stringEntityId = udi as StringUdi;
|
||||
Assert.IsNotNull(stringEntityId);
|
||||
Assert.AreEqual("test-id", stringEntityId.Id);
|
||||
Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyString + "/test-id", udi.ToString());
|
||||
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyString + "/test-id", udi.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GuidEntityCtorTest()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
var udi = new GuidUdi(Constants.DeployEntityType.AnyGuid, guid);
|
||||
Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType);
|
||||
var udi = new GuidUdi(Constants.UdiEntityType.AnyGuid, guid);
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType);
|
||||
Assert.AreEqual(guid, udi.Guid);
|
||||
Assert.AreEqual("umb://" + Constants.DeployEntityType.AnyGuid + "/" + guid.ToString("N"), udi.ToString());
|
||||
Assert.AreEqual("umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N"), udi.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GuidEntityParseTest()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
var s = "umb://" + Constants.DeployEntityType.AnyGuid + "/" + guid.ToString("N");
|
||||
var s = "umb://" + Constants.UdiEntityType.AnyGuid + "/" + guid.ToString("N");
|
||||
var udi = Udi.Parse(s);
|
||||
Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType);
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType);
|
||||
Assert.IsInstanceOf<GuidUdi>(udi);
|
||||
var gudi = udi as GuidUdi;
|
||||
Assert.IsNotNull(gudi);
|
||||
@@ -82,9 +82,9 @@ namespace Umbraco.Tests
|
||||
var guid1 = Guid.NewGuid();
|
||||
var entities = new[]
|
||||
{
|
||||
new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1),
|
||||
new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1),
|
||||
new GuidUdi(Constants.DeployEntityType.AnyGuid, guid1),
|
||||
new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1),
|
||||
new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1),
|
||||
new GuidUdi(Constants.UdiEntityType.AnyGuid, guid1),
|
||||
};
|
||||
Assert.AreEqual(1, entities.Distinct().Count());
|
||||
}
|
||||
@@ -93,12 +93,12 @@ namespace Umbraco.Tests
|
||||
public void CreateTest()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
var udi = Udi.Create(Constants.DeployEntityType.AnyGuid, guid);
|
||||
Assert.AreEqual(Constants.DeployEntityType.AnyGuid, udi.EntityType);
|
||||
var udi = Udi.Create(Constants.UdiEntityType.AnyGuid, guid);
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, udi.EntityType);
|
||||
Assert.AreEqual(guid, ((GuidUdi)udi).Guid);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.DeployEntityType.AnyString, guid));
|
||||
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.DeployEntityType.AnyGuid, "foo"));
|
||||
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.UdiEntityType.AnyString, guid));
|
||||
Assert.Throws<InvalidOperationException>(() => Udi.Create(Constants.UdiEntityType.AnyGuid, "foo"));
|
||||
Assert.Throws<ArgumentException>(() => Udi.Create("barf", "foo"));
|
||||
}
|
||||
|
||||
@@ -106,13 +106,13 @@ namespace Umbraco.Tests
|
||||
public void RangeTest()
|
||||
{
|
||||
// can parse open string udi
|
||||
var stringUdiString = "umb://" + Constants.DeployEntityType.AnyString;
|
||||
var stringUdiString = "umb://" + Constants.UdiEntityType.AnyString;
|
||||
Udi stringUdi;
|
||||
Assert.IsTrue(Udi.TryParse(stringUdiString, out stringUdi));
|
||||
Assert.AreEqual(string.Empty, ((StringUdi)stringUdi).Id);
|
||||
|
||||
// can parse open guid udi
|
||||
var guidUdiString = "umb://" + Constants.DeployEntityType.AnyGuid;
|
||||
var guidUdiString = "umb://" + Constants.UdiEntityType.AnyGuid;
|
||||
Udi guidUdi;
|
||||
Assert.IsTrue(Udi.TryParse(guidUdiString, out guidUdi));
|
||||
Assert.AreEqual(Guid.Empty, ((GuidUdi)guidUdi).Guid);
|
||||
@@ -134,12 +134,12 @@ namespace Umbraco.Tests
|
||||
|
||||
|
||||
var guid = Guid.NewGuid();
|
||||
var udi = new GuidUdi(Constants.DeployEntityType.AnyGuid, guid);
|
||||
var udi = new GuidUdi(Constants.UdiEntityType.AnyGuid, guid);
|
||||
var json = JsonConvert.SerializeObject(udi, settings);
|
||||
Assert.AreEqual(string.Format("\"umb://any-guid/{0:N}\"", guid), json);
|
||||
|
||||
var dudi = JsonConvert.DeserializeObject<Udi>(json, settings);
|
||||
Assert.AreEqual(Constants.DeployEntityType.AnyGuid, dudi.EntityType);
|
||||
Assert.AreEqual(Constants.UdiEntityType.AnyGuid, dudi.EntityType);
|
||||
Assert.AreEqual(guid, ((GuidUdi)dudi).Guid);
|
||||
|
||||
var range = new UdiRange(udi, Constants.DeploySelector.ChildrenOfThis);
|
||||
|
||||
+38
-15
@@ -40,27 +40,50 @@ Use this directive to generate a list of breadcrumbs.
|
||||
|
||||
@param {array} ancestors Array of ancestors
|
||||
@param {string} entityType The content entity type (member, media, content).
|
||||
@param {callback} Callback when an ancestor is clicked. It will override the default link behaviour.
|
||||
**/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function BreadcrumbsDirective() {
|
||||
function BreadcrumbsDirective() {
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/editor/umb-breadcrumbs.html',
|
||||
scope: {
|
||||
ancestors: "=",
|
||||
entityType: "@"
|
||||
}
|
||||
};
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
return directive;
|
||||
scope.allowOnOpen = false;
|
||||
|
||||
}
|
||||
scope.open = function(ancestor) {
|
||||
if(scope.onOpen && scope.allowOnOpen) {
|
||||
scope.onOpen({'ancestor': ancestor});
|
||||
}
|
||||
};
|
||||
|
||||
angular.module('umbraco.directives').directive('umbBreadcrumbs', BreadcrumbsDirective);
|
||||
function onInit() {
|
||||
if ("onOpen" in attr) {
|
||||
scope.allowOnOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
onInit();
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/editor/umb-breadcrumbs.html',
|
||||
scope: {
|
||||
ancestors: "=",
|
||||
entityType: "@",
|
||||
onOpen: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbBreadcrumbs', BreadcrumbsDirective);
|
||||
|
||||
})();
|
||||
|
||||
+3
-2
@@ -21,7 +21,8 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
customtreeparams: '@',
|
||||
eventhandler: '=',
|
||||
enablecheckboxes: '@',
|
||||
enablelistviewsearch: '@'
|
||||
enablelistviewsearch: '@',
|
||||
enablelistviewexpand: '@'
|
||||
},
|
||||
|
||||
compile: function(element, attrs) {
|
||||
@@ -35,7 +36,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
'<a class="umb-options" ng-hide="tree.root.isContainer || !tree.root.menuUrl" ng-click="options(tree.root, $event)" ng-swipe-right="options(tree.root, $event)"><i></i><i></i><i></i></a>' +
|
||||
'</div>';
|
||||
template += '<ul>' +
|
||||
'<umb-tree-item ng-repeat="child in tree.root.children" eventhandler="eventhandler" node="child" current-node="currentNode" tree="this" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
|
||||
'<umb-tree-item ng-repeat="child in tree.root.children" enablelistviewexpand="{{enablelistviewexpand}}" eventhandler="eventhandler" node="child" current-node="currentNode" tree="this" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
|
||||
'</ul>' +
|
||||
'</li>' +
|
||||
'</ul>';
|
||||
|
||||
+8
-6
@@ -27,6 +27,7 @@ angular.module("umbraco.directives")
|
||||
section: '@',
|
||||
eventhandler: '=',
|
||||
currentNode: '=',
|
||||
enablelistviewexpand: '@',
|
||||
node: '=',
|
||||
tree: '='
|
||||
},
|
||||
@@ -38,7 +39,7 @@ angular.module("umbraco.directives")
|
||||
'<div ng-class="getNodeCssClass(node)" ng-swipe-right="options(node, $event)" >' +
|
||||
//NOTE: This ins element is used to display the search icon if the node is a container/listview and the tree is currently in dialog
|
||||
//'<ins ng-if="tree.enablelistviewsearch && node.metaData.isContainer" class="umb-tree-node-search icon-search" ng-click="searchNode(node, $event)" alt="searchAltText"></ins>' +
|
||||
'<ins ng-class="{\'icon-navigation-right\': !node.expanded, \'icon-navigation-down\': node.expanded}" ng-click="load(node)"> </ins>' +
|
||||
'<ins ng-class="{\'icon-navigation-right\': !node.expanded || node.metaData.isContainer, \'icon-navigation-down\': node.expanded && !node.metaData.isContainer}" ng-click="load(node)"> </ins>' +
|
||||
'<i class="icon umb-tree-icon sprTree" ng-click="select(node, $event)"></i>' +
|
||||
'<a href="#/{{node.routePath}}" ng-click="select(node, $event)"></a>' +
|
||||
//NOTE: These are the 'option' elipses
|
||||
@@ -74,11 +75,12 @@ angular.module("umbraco.directives")
|
||||
|
||||
//toggle visibility of last 'ins' depending on children
|
||||
//visibility still ensure the space is "reserved", so both nodes with and without children are aligned.
|
||||
if (!node.hasChildren) {
|
||||
element.find("ins").last().css("visibility", "hidden");
|
||||
|
||||
if (node.hasChildren || node.metaData.isContainer && scope.enablelistviewexpand === "true") {
|
||||
element.find("ins").last().css("visibility", "visible");
|
||||
}
|
||||
else {
|
||||
element.find("ins").last().css("visibility", "visible");
|
||||
element.find("ins").last().css("visibility", "hidden");
|
||||
}
|
||||
|
||||
var icon = element.find("i:first");
|
||||
@@ -192,7 +194,7 @@ angular.module("umbraco.directives")
|
||||
emits treeNodeCollapsing event if already expanded and treeNodeExpanding if collapsed
|
||||
*/
|
||||
scope.load = function (node) {
|
||||
if (node.expanded) {
|
||||
if (node.expanded && !node.metaData.isContainer) {
|
||||
deleteAnimations = false;
|
||||
emitEvent("treeNodeCollapsing", { tree: scope.tree, node: node, element: element });
|
||||
node.expanded = false;
|
||||
@@ -227,7 +229,7 @@ angular.module("umbraco.directives")
|
||||
|
||||
setupNodeDom(scope.node, scope.tree);
|
||||
|
||||
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" eventhandler="eventhandler" tree="tree" current-node="currentNode" node="child" section="{{section}}" ng-animate="animation()"></umb-tree-item></ul>';
|
||||
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" enablelistviewexpand="{{enablelistviewexpand}}" eventhandler="eventhandler" tree="tree" current-node="currentNode" node="child" section="{{section}}" ng-animate="animation()"></umb-tree-item></ul>';
|
||||
var newElement = angular.element(template);
|
||||
$compile(newElement)(scope);
|
||||
element.append(newElement);
|
||||
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MiniListViewDirective(entityResource) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
scope.search = "";
|
||||
scope.miniListViews = [];
|
||||
scope.breadcrumb = [];
|
||||
|
||||
var miniListViewsHistory = [];
|
||||
var goingForward = true;
|
||||
var skipAnimation = true;
|
||||
|
||||
function onInit() {
|
||||
open(scope.node);
|
||||
}
|
||||
|
||||
function open(node) {
|
||||
|
||||
goingForward = true;
|
||||
|
||||
var miniListView = {
|
||||
node: node,
|
||||
loading: true,
|
||||
pagination: {
|
||||
pageSize: 10,
|
||||
pageNumber: 1,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder",
|
||||
orderBySystemField: true
|
||||
}
|
||||
};
|
||||
|
||||
// clear and push mini list view in dom so we only render 1 view
|
||||
scope.miniListViews = [];
|
||||
scope.miniListViews.push(miniListView);
|
||||
|
||||
// store in history so we quickly can navigate back
|
||||
miniListViewsHistory.push(miniListView);
|
||||
|
||||
// get children
|
||||
getChildrenForMiniListView(miniListView);
|
||||
|
||||
makeBreadcrumb();
|
||||
|
||||
}
|
||||
|
||||
function getChildrenForMiniListView(miniListView) {
|
||||
|
||||
// start loading animation list view
|
||||
miniListView.loading = true;
|
||||
|
||||
entityResource.getPagedChildren(miniListView.node.id, scope.entityType, miniListView.pagination)
|
||||
.then(function (data) {
|
||||
// update children
|
||||
miniListView.children = data.items;
|
||||
_.each(miniListView.children, function(c) {
|
||||
if (c.metaData) {
|
||||
c.hasChildren = c.metaData.HasChildren;
|
||||
if(scope.entityType === "Document") {
|
||||
c.published = c.metaData.IsPublished;
|
||||
}
|
||||
}
|
||||
});
|
||||
// update pagination
|
||||
miniListView.pagination.totalItems = data.totalItems;
|
||||
miniListView.pagination.totalPages = data.totalPages;
|
||||
// stop load indicator
|
||||
miniListView.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
scope.openNode = function(event, node) {
|
||||
open(node);
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
scope.selectNode = function(node) {
|
||||
if(scope.onSelect) {
|
||||
scope.onSelect({'node': node});
|
||||
}
|
||||
};
|
||||
|
||||
/* Pagination */
|
||||
scope.goToPage = function(pageNumber, miniListView) {
|
||||
// set new page number
|
||||
miniListView.pagination.pageNumber = pageNumber;
|
||||
// get children
|
||||
getChildrenForMiniListView(miniListView);
|
||||
};
|
||||
|
||||
/* Breadcrumb */
|
||||
scope.clickBreadcrumb = function(ancestor) {
|
||||
|
||||
var found = false;
|
||||
goingForward = false;
|
||||
|
||||
angular.forEach(miniListViewsHistory, function(historyItem, index){
|
||||
// We need to make sure we can compare the two id's.
|
||||
// Some id's are integers and others are strings.
|
||||
// Members have string ids like "all-members".
|
||||
if(historyItem.node.id.toString() === ancestor.id.toString()) {
|
||||
// load the list view from history
|
||||
scope.miniListViews = [];
|
||||
scope.miniListViews.push(historyItem);
|
||||
// clean up history - remove all children after
|
||||
miniListViewsHistory.splice(index + 1, miniListViewsHistory.length);
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(!found) {
|
||||
// if we can't find the view in the history - close the list view
|
||||
scope.exitMiniListView();
|
||||
}
|
||||
|
||||
// update the breadcrumb
|
||||
makeBreadcrumb();
|
||||
|
||||
};
|
||||
|
||||
scope.showBackButton = function() {
|
||||
// don't show the back button if the start node is a list view
|
||||
if(scope.node.metaData && scope.node.metaData.IsContainer || scope.node.isContainer) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
scope.exitMiniListView = function() {
|
||||
miniListViewsHistory = [];
|
||||
scope.miniListViews = [];
|
||||
if(scope.onClose) {
|
||||
scope.onClose();
|
||||
}
|
||||
};
|
||||
|
||||
function makeBreadcrumb() {
|
||||
scope.breadcrumb = [];
|
||||
angular.forEach(miniListViewsHistory, function(historyItem){
|
||||
scope.breadcrumb.push(historyItem.node);
|
||||
});
|
||||
}
|
||||
|
||||
/* Search */
|
||||
scope.searchMiniListView = function(search, miniListView) {
|
||||
// set search value
|
||||
miniListView.pagination.filter = search;
|
||||
// reset pagination
|
||||
miniListView.pagination.pageNumber = 1;
|
||||
// start loading animation list view
|
||||
miniListView.loading = true;
|
||||
searchMiniListView(miniListView);
|
||||
};
|
||||
|
||||
var searchMiniListView = _.debounce(function (miniListView) {
|
||||
scope.$apply(function () {
|
||||
getChildrenForMiniListView(miniListView);
|
||||
});
|
||||
}, 500);
|
||||
|
||||
/* Animation */
|
||||
scope.getMiniListViewAnimation = function() {
|
||||
|
||||
// disable the first "slide-in-animation"" if the start node is a list view
|
||||
if(scope.node.metaData && scope.node.metaData.IsContainer && skipAnimation || scope.node.isContainer && skipAnimation) {
|
||||
skipAnimation = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(goingForward) {
|
||||
return 'umb-mini-list-view--forward';
|
||||
} else {
|
||||
return 'umb-mini-list-view--backwards';
|
||||
}
|
||||
};
|
||||
|
||||
onInit();
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/umb-mini-list-view.html',
|
||||
scope: {
|
||||
node: "=",
|
||||
entityType: "@",
|
||||
startNodeId: "=",
|
||||
onSelect: "&",
|
||||
onClose: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbMiniListView', MiniListViewDirective);
|
||||
|
||||
})();
|
||||
+32
-16
@@ -134,25 +134,40 @@ Use this directive to generate a pagination.
|
||||
|
||||
}
|
||||
|
||||
scope.next = function() {
|
||||
if (scope.onNext && scope.pageNumber < scope.totalPages) {
|
||||
scope.pageNumber++;
|
||||
scope.onNext(scope.pageNumber);
|
||||
}
|
||||
scope.next = function () {
|
||||
if (scope.pageNumber < scope.totalPages) {
|
||||
scope.pageNumber++;
|
||||
if (scope.onNext) {
|
||||
scope.onNext(scope.pageNumber);
|
||||
}
|
||||
if (scope.onChange) {
|
||||
scope.onChange({ "pageNumber": scope.pageNumber });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.prev = function(pageNumber) {
|
||||
if (scope.onPrev && scope.pageNumber > 1) {
|
||||
scope.pageNumber--;
|
||||
scope.onPrev(scope.pageNumber);
|
||||
}
|
||||
scope.prev = function (pageNumber) {
|
||||
if (scope.pageNumber > 1) {
|
||||
scope.pageNumber--;
|
||||
if (scope.onPrev) {
|
||||
scope.onPrev(scope.pageNumber);
|
||||
}
|
||||
if (scope.onChange) {
|
||||
scope.onChange({ "pageNumber": scope.pageNumber });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.goToPage = function(pageNumber) {
|
||||
if(scope.onGoToPage) {
|
||||
scope.pageNumber = pageNumber + 1;
|
||||
scope.onGoToPage(scope.pageNumber);
|
||||
}
|
||||
scope.goToPage = function (pageNumber) {
|
||||
scope.pageNumber = pageNumber + 1;
|
||||
if (scope.onGoToPage) {
|
||||
scope.onGoToPage(scope.pageNumber);
|
||||
}
|
||||
if (scope.onChange) {
|
||||
if (scope.onChange) {
|
||||
scope.onChange({ "pageNumber": scope.pageNumber });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var unbindPageNumberWatcher = scope.$watch('pageNumber', function(newValue, oldValue){
|
||||
@@ -176,7 +191,8 @@ Use this directive to generate a pagination.
|
||||
totalPages: "=",
|
||||
onNext: "=",
|
||||
onPrev: "=",
|
||||
onGoToPage: "="
|
||||
onGoToPage: "=",
|
||||
onChange: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
@@ -477,20 +477,20 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetChildren",
|
||||
[
|
||||
{ id: parentId },
|
||||
{ pageNumber: options.pageNumber },
|
||||
{ pageSize: options.pageSize },
|
||||
{ orderBy: options.orderBy },
|
||||
{ orderDirection: options.orderDirection },
|
||||
{ orderBySystemField: toBool(options.orderBySystemField) },
|
||||
{ filter: options.filter }
|
||||
])),
|
||||
'Failed to retrieve children for content item ' + parentId);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetChildren",
|
||||
{
|
||||
id: parentId,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
orderBySystemField: toBool(options.orderBySystemField),
|
||||
filter: options.filter
|
||||
})),
|
||||
'Failed to retrieve children for content item ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,10 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
|
||||
getSafeAlias: function (value, camelCase) {
|
||||
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -68,6 +72,11 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
getPath: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return "-1";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -98,7 +107,12 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the url.
|
||||
*
|
||||
*/
|
||||
getUrl: function(id, type) {
|
||||
getUrl: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return "";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -131,7 +145,12 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the entity.
|
||||
*
|
||||
*/
|
||||
getById: function (id, type) {
|
||||
getById: function (id, type) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -166,24 +185,17 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
*/
|
||||
getByIds: function (ids, type) {
|
||||
|
||||
var query = "";
|
||||
_.each(ids, function(item) {
|
||||
query += "ids=" + item + "&";
|
||||
});
|
||||
|
||||
// if ids array is empty we need a empty variable in the querystring otherwise the service returns a error
|
||||
if (ids.length === 0) {
|
||||
query += "ids=&";
|
||||
}
|
||||
|
||||
query += "type=" + type;
|
||||
var query = "type=" + type;
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetByIds",
|
||||
query)),
|
||||
query),
|
||||
{
|
||||
ids: ids
|
||||
}),
|
||||
'Failed to retrieve entity data for ids ' + ids);
|
||||
},
|
||||
|
||||
@@ -292,18 +304,19 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getAncestors
|
||||
* @name umbraco.resources.entityResource#getChildren
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets children entities for a given item
|
||||
*
|
||||
*
|
||||
* @param {Int} parentid id of content item to return children of
|
||||
* @param {string} type Object type name
|
||||
* @returns {Promise} resourcePromise object containing the entity.
|
||||
*
|
||||
*/
|
||||
getChildren: function (id, type) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -312,6 +325,146 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
[{ id: id }, { type: type }])),
|
||||
'Failed to retrieve child data for id ' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getPagedChildren
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets paged children of a content item with a given id
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getPagedChildren(1234, "Content", {pageSize: 10, pageNumber: 2})
|
||||
* .then(function(contentArray) {
|
||||
* var children = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentid id of content item to return children of
|
||||
* @param {string} type Object type name
|
||||
* @param {Object} options optional options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 1
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 100
|
||||
* @param {String} options.filter if provided, query will only return those with names matching the filter
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending`
|
||||
* @param {String} options.orderBy property to order items by, default: `SortOrder`
|
||||
* @returns {Promise} resourcePromise object containing an array of content items.
|
||||
*
|
||||
*/
|
||||
getPagedChildren: function (parentId, type, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 1,
|
||||
pageNumber: 100,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder"
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetPagedChildren",
|
||||
{
|
||||
id: parentId,
|
||||
type: type,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
filter: encodeURIComponent(options.filter)
|
||||
}
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getPagedDescendants
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets paged descendants of a content item with a given id
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getPagedDescendants(1234, "Content", {pageSize: 10, pageNumber: 2})
|
||||
* .then(function(contentArray) {
|
||||
* var children = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} parentid id of content item to return descendants of
|
||||
* @param {string} type Object type name
|
||||
* @param {Object} options optional options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 1
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 100
|
||||
* @param {String} options.filter if provided, query will only return those with names matching the filter
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Ascending`
|
||||
* @param {String} options.orderBy property to order items by, default: `SortOrder`
|
||||
* @returns {Promise} resourcePromise object containing an array of content items.
|
||||
*
|
||||
*/
|
||||
getPagedDescendants: function (parentId, type, options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 1,
|
||||
pageNumber: 100,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder"
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetPagedDescendants",
|
||||
{
|
||||
id: parentId,
|
||||
type: type,
|
||||
pageNumber: options.pageNumber,
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
filter: encodeURIComponent(options.filter)
|
||||
}
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
||||
@@ -482,7 +482,49 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
"mediaApiBaseUrl",
|
||||
"EmptyRecycleBin")),
|
||||
'Failed to empty the recycle bin');
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.mediaResource#search
|
||||
* @methodOf umbraco.resources.mediaResource
|
||||
*
|
||||
* @description
|
||||
* Empties the media recycle bin
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* mediaResource.search("my search", 1, 100, -1)
|
||||
* .then(function(searchResult) {
|
||||
* alert('it's here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {string} query The search query
|
||||
* @param {int} pageNumber The page number
|
||||
* @param {int} pageSize The number of media items on a page
|
||||
* @param {int} searchFrom Id to search from
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
search: function (query, pageNumber, pageSize, searchFrom) {
|
||||
|
||||
var args = [
|
||||
{ "query": query },
|
||||
{ "pageNumber": pageNumber },
|
||||
{ "pageSize": pageSize },
|
||||
{ "searchFrom": searchFrom }
|
||||
];
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"mediaApiBaseUrl",
|
||||
"Search",
|
||||
args)),
|
||||
'Failed to retrieve media items for search: ' + query);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,8 @@
|
||||
@import "components/umb-avatar.less";
|
||||
@import "components/umb-progress-bar.less";
|
||||
@import "components/umb-querybuilder.less";
|
||||
@import "components/umb-pagination.less";
|
||||
@import "components/umb-mini-list-view.less";
|
||||
|
||||
@import "components/buttons/umb-button.less";
|
||||
@import "components/buttons/umb-button-group.less";
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
.umb-mini-list-view__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__title-text {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__title-icon {
|
||||
font-size: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back {
|
||||
font-size: 11px;
|
||||
margin-right: 5px;
|
||||
color: @gray;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back-icon {
|
||||
margin-right: 4px;
|
||||
height: 11px;
|
||||
line-height: 11px;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back-text {
|
||||
text-decoration: underline;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back:hover {
|
||||
opacity: 1;
|
||||
text-decoration: none;
|
||||
color: @black;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
|
||||
/* Forward */
|
||||
|
||||
.umb-mini-list-view--forward-enter,
|
||||
.umb-mini-list-view--forward-leave
|
||||
{
|
||||
transition: 120ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--forward-enter {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--forward-enter.umb-mini-list-view--forward-enter-active {
|
||||
left: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--forward-leave {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--forward-leave.umb-mini-list-view--forward-leave-active{
|
||||
left: -100%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Backwards */
|
||||
|
||||
.umb-mini-list-view--backwards-enter,
|
||||
.umb-mini-list-view--backwards-leave
|
||||
{
|
||||
transition: 120ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--backwards-enter {
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--backwards-enter.umb-mini-list-view--backwards-enter-active {
|
||||
right: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--backwards-leave {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.umb-mini-list-view--backwards-leave.umb-mini-list-view--backwards-leave-active{
|
||||
right: -100%;
|
||||
opacity: 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.umb-pagination ul {
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
|
||||
min-width: 640px;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.umb-table.umb-table-inactive {
|
||||
@@ -103,11 +103,17 @@ input.umb-table__input {
|
||||
|
||||
|
||||
// Table Body Styles
|
||||
.umb-table-body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-table-body .umb-table-row {
|
||||
color: fade(@gray, 75%);
|
||||
border-top: 1px solid @grayLight;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
position: relative;
|
||||
min-height: 32px;
|
||||
|
||||
&:hover {
|
||||
background-color: fade(@grayLighter, 90%);
|
||||
@@ -198,30 +204,33 @@ input.umb-table__input {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Table Row Styles
|
||||
.umb-table-row {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.umb-table-body .umb-table-row--empty {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 5px 0;
|
||||
cursor: auto;
|
||||
user-select: auto;
|
||||
}
|
||||
|
||||
.umb-table-body .umb-table-row--empty:hover {
|
||||
background-color: transparent;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.umb-table-row.-selected,
|
||||
.umb-table-row.-selected:hover {
|
||||
background-color: fade(@blueDark, 4%);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Table Cell Styles
|
||||
.umb-table-cell {
|
||||
display: flex;
|
||||
@@ -250,9 +259,48 @@ input.umb-table__input {
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
.umb-table-cell--auto-width {
|
||||
flex: 0 0 auto !important;
|
||||
}
|
||||
|
||||
.umb-table-cell--faded {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
|
||||
// Increases the space for the name cell
|
||||
.umb-table__name {
|
||||
flex: 1 1 25%;
|
||||
max-width: 25%;
|
||||
}
|
||||
|
||||
.umb-table__loading-overlay {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.umb-table__row-expand {
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
color: @black;
|
||||
}
|
||||
|
||||
.umb-table__row-expand--hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.umb-table--condensed {
|
||||
|
||||
.umb-table-cell:first-of-type:not(.not-fixed) {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.umb-table-body__icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -156,6 +156,11 @@ h5.-black {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* CONTROL VALIDATION */
|
||||
.umb-control-required {
|
||||
color: @controlRequiredColor;
|
||||
}
|
||||
|
||||
.controls-row {
|
||||
padding-bottom: 5px;
|
||||
margin-left: 240px;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user