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