Compare commits
64 Commits
release-6.1.4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4935525591 | |||
| 693778fe74 | |||
| 8eee7cae2f | |||
| 226e35d65a | |||
| cdda69c4cd | |||
| 0cff484113 | |||
| 830fde372e | |||
| 35f65a2c64 | |||
| e5320f0abd | |||
| 965a7fc500 | |||
| abbf8aeb42 | |||
| 328ada2f38 | |||
| 767252cdf1 | |||
| 010d47c68b | |||
| a353f6fb74 | |||
| a64efb93b3 | |||
| cf9f11ff45 | |||
| d7481b5ca4 | |||
| 2fb55cb831 | |||
| 0e6a926a3f | |||
| 173ac65eb5 | |||
| 7c28e1aeba | |||
| 5989d19f7f | |||
| da1c33a034 | |||
| 2111a5e31e | |||
| 5478de911b | |||
| 7765acb130 | |||
| 5640daff32 | |||
| a1cae3f286 | |||
| d22dbb4654 | |||
| 4d5a8298b0 | |||
| 9e2733ce69 | |||
| fbfdd8d398 | |||
| 2552dffdad | |||
| 52540165f1 | |||
| 2b408df24c | |||
| d559411187 | |||
| 3a4a6579d3 | |||
| 1e76cf67d3 | |||
| 61149f8112 | |||
| b5494546c7 | |||
| 7bac1ef1cd | |||
| da15d40b04 | |||
| 67bd303173 | |||
| 20e6843bf0 | |||
| 85c80b07f9 | |||
| 557dccd88b | |||
| 334f0bfd2b | |||
| 986d37afd6 | |||
| 63ea79a4d6 | |||
| e4df176a37 | |||
| d926180e3a | |||
| 72bb1b3583 | |||
| 240e58e061 | |||
| e980296d6d | |||
| d23482b7a6 | |||
| 212800f706 | |||
| d47ff4005c | |||
| dfeb1c7a0b | |||
| 9a3c2bbc5c | |||
| 0b0fb92cf1 | |||
| 6f09da0927 | |||
| febe6ec241 | |||
| 6f85eefd85 |
@@ -81,3 +81,6 @@ build/_BuildOutput/
|
||||
tools/NDepend/
|
||||
src/*.vspx
|
||||
src/*.psess
|
||||
NDependOut/*
|
||||
QueryResult.htm
|
||||
*.ndproj
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
@ECHO OFF
|
||||
SET release=6.1.4
|
||||
SET release=6.1.6
|
||||
SET comment=
|
||||
SET version=%release%
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-16"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms.Core</id>
|
||||
<version>6.1.2</version>
|
||||
<version>6.2.0</version>
|
||||
<title>Umbraco Cms Core Binaries</title>
|
||||
<authors>Morten Christensen</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
@@ -14,57 +14,57 @@
|
||||
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="4.0" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="4.0" />
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" />
|
||||
<dependency id="MiniProfiler" version="2.1.0" />
|
||||
<dependency id="HtmlAgilityPack" version="1.4.6" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1]" />
|
||||
<dependency id="SharpZipLib" version="0.86.0" />
|
||||
<dependency id="MySql.Data" version="[6.6.5]" />
|
||||
<dependency id="xmlrpcnet" version="2.5.0" />
|
||||
<dependency id="ClientDependency" version="[1.7.0,1.7.1)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.7.0,1.7.1)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="4.0" />
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" />
|
||||
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.6.5]" />
|
||||
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.7.0, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.7.0, 2.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\businesslogic.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\cms.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\cms.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\controls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\controls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Examine.dll" target="lib\Examine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\interfaces.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\interfaces.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.Web.Helpers.dll" target="lib\Microsoft.Web.Helpers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Our.Umbraco.uGoLive.47x.dll" target="lib\Our.Umbraco.uGoLive.47x.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Our.Umbraco.uGoLive.Checks.dll" target="lib\Our.Umbraco.uGoLive.Checks.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Our.Umbraco.uGoLive.dll" target="lib\Our.Umbraco.uGoLive.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\TidyNet.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\umbraco.DataLayer.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\umbraco.editorControls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\umbraco.MacroEngines.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.macroRenderings.dll" target="lib\umbraco.macroRenderings.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.macroRenderings.xml" target="lib\umbraco.macroRenderings.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.XmlSerializers.dll" target="lib\umbraco.XmlSerializers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
|
||||
</files>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\businesslogic.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\cms.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\cms.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\controls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\controls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Examine.dll" target="lib\Examine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\interfaces.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\interfaces.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.Web.Helpers.dll" target="lib\Microsoft.Web.Helpers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Our.Umbraco.uGoLive.47x.dll" target="lib\Our.Umbraco.uGoLive.47x.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Our.Umbraco.uGoLive.Checks.dll" target="lib\Our.Umbraco.uGoLive.Checks.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Our.Umbraco.uGoLive.dll" target="lib\Our.Umbraco.uGoLive.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\TidyNet.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\umbraco.DataLayer.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\umbraco.editorControls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\umbraco.MacroEngines.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.macroRenderings.dll" target="lib\umbraco.macroRenderings.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.macroRenderings.xml" target="lib\umbraco.macroRenderings.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.XmlSerializers.dll" target="lib\umbraco.XmlSerializers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-16"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms</id>
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("6.1.4");
|
||||
private static readonly Version Version = new Version("6.1.6");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace Umbraco.Core
|
||||
public void ConfigureEmbeddedDatabaseConnection()
|
||||
{
|
||||
const string providerName = "System.Data.SqlServerCe.4.0";
|
||||
const string connectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;File Access Retry Timeout=10";
|
||||
const string connectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;";
|
||||
|
||||
SaveConnectionString(connectionString, providerName);
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Any class implementing this interface that is added to the httpcontext.items keys or values will be disposed of at the end of the request.
|
||||
/// </summary>
|
||||
public interface IDisposeOnRequestEnd : IDisposable
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -65,12 +65,12 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
return Date.Value;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(VarChar))
|
||||
if(string.IsNullOrEmpty(VarChar) == false)
|
||||
{
|
||||
return VarChar;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(Text))
|
||||
if(string.IsNullOrEmpty(Text) == false)
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
|
||||
@@ -9,7 +10,8 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public static class UmbracoObjectTypesExtensions
|
||||
{
|
||||
private static readonly Dictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new Dictionary<UmbracoObjectTypes,Guid>();
|
||||
//MUST be concurrent to avoid thread collisions!
|
||||
private static readonly ConcurrentDictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new ConcurrentDictionary<UmbracoObjectTypes, Guid>();
|
||||
|
||||
/// <summary>
|
||||
/// Get an UmbracoObjectTypes value from it's name
|
||||
@@ -48,24 +50,22 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>a GUID value of the UmbracoObjectTypes</returns>
|
||||
public static Guid GetGuid(this UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
if (UmbracoObjectTypeCache.ContainsKey(umbracoObjectType))
|
||||
return UmbracoObjectTypeCache[umbracoObjectType];
|
||||
return UmbracoObjectTypeCache.GetOrAdd(umbracoObjectType, types =>
|
||||
{
|
||||
var type = typeof(UmbracoObjectTypes);
|
||||
var memInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
|
||||
false);
|
||||
|
||||
var type = typeof(UmbracoObjectTypes);
|
||||
var memInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
|
||||
false);
|
||||
if (attributes.Length == 0)
|
||||
return Guid.Empty;
|
||||
|
||||
if (attributes.Length == 0)
|
||||
return Guid.Empty;
|
||||
var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
|
||||
if (attribute == null)
|
||||
return Guid.Empty;
|
||||
|
||||
var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
|
||||
if (attribute == null)
|
||||
return Guid.Empty;
|
||||
|
||||
UmbracoObjectTypeCache.Add(umbracoObjectType, attribute.ObjectId);
|
||||
|
||||
return attribute.ObjectId;
|
||||
return attribute.ObjectId;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Data;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
{
|
||||
@@ -107,6 +108,12 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
var constraintAttribute = propertyInfo.FirstAttribute<ConstraintAttribute>();
|
||||
if (constraintAttribute != null)
|
||||
{
|
||||
//Special case for MySQL as it can't have multiple default DateTime values, which
|
||||
//is what the umbracoServer table definition is trying to create
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider && definition.TableName == "umbracoServer" &&
|
||||
definition.TableName.ToLowerInvariant() == "lastNotifiedDate".ToLowerInvariant())
|
||||
return definition;
|
||||
|
||||
definition.ConstraintName = constraintAttribute.Name ?? string.Empty;
|
||||
definition.DefaultValue = constraintAttribute.Default ?? string.Empty;
|
||||
}
|
||||
|
||||
@@ -170,11 +170,31 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return content;
|
||||
}
|
||||
|
||||
public override void DeleteVersion(Guid versionId)
|
||||
{
|
||||
var sql = new Sql()
|
||||
.Select("*")
|
||||
.From<DocumentDto>()
|
||||
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, DocumentDto>(left => left.VersionId, right => right.VersionId)
|
||||
.Where<ContentVersionDto>(x => x.VersionId == versionId)
|
||||
.Where<DocumentDto>(x => x.Newest == true);
|
||||
var dto = Database.Fetch<DocumentDto, ContentVersionDto>(sql).FirstOrDefault();
|
||||
|
||||
if(dto == null) return;
|
||||
|
||||
using (var transaction = Database.GetTransaction())
|
||||
{
|
||||
PerformDeleteVersion(dto.NodeId, versionId);
|
||||
|
||||
transaction.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PerformDeleteVersion(int id, Guid versionId)
|
||||
{
|
||||
Database.Delete<PreviewXmlDto>("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<PropertyDataDto>("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<ContentVersionDto>("WHERE nodeId = @Id AND VersionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<PropertyDataDto>("WHERE contentNodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<ContentVersionDto>("WHERE ContentId = @Id AND VersionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<DocumentDto>("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
}
|
||||
|
||||
@@ -340,19 +360,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
//Look up (newest) entries by id in cmsDocument table to set newest = false
|
||||
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true });
|
||||
foreach (var documentDto in documentDtos)
|
||||
{
|
||||
var docDto = documentDto;
|
||||
docDto.Newest = false;
|
||||
Database.Update(docDto);
|
||||
}
|
||||
|
||||
var contentVersionDto = dto.ContentVersionDto;
|
||||
if (shouldCreateNewVersion)
|
||||
{
|
||||
//Look up (newest) entries by id in cmsDocument table to set newest = false
|
||||
//NOTE: This is only relevant when a new version is created, which is why its done inside this if-statement.
|
||||
var documentDtos = Database.Fetch<DocumentDto>("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true });
|
||||
foreach (var documentDto in documentDtos)
|
||||
{
|
||||
var docDto = documentDto;
|
||||
docDto.Newest = false;
|
||||
Database.Update(docDto);
|
||||
}
|
||||
|
||||
//Create a new version - cmsContentVersion
|
||||
//Assumes a new Version guid and Version date (modified date) has been set
|
||||
Database.Insert(contentVersionDto);
|
||||
|
||||
@@ -176,8 +176,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
protected override void PerformDeleteVersion(int id, Guid versionId)
|
||||
{
|
||||
Database.Delete<PreviewXmlDto>("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<PropertyDataDto>("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<ContentVersionDto>("WHERE nodeId = @Id AND VersionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<PropertyDataDto>("WHERE contentNodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
Database.Delete<ContentVersionDto>("WHERE ContentId = @Id AND VersionId = @VersionId", new { Id = id, VersionId = versionId });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -43,8 +43,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public virtual void DeleteVersion(Guid versionId)
|
||||
{
|
||||
var dto = Database.FirstOrDefault<ContentVersionDto>("WHERE versionId = @VersionId AND newest = @Newest", new { VersionId = versionId, Newest = false });
|
||||
Mandate.That<Exception>(dto != null);
|
||||
var dto = Database.FirstOrDefault<ContentVersionDto>("WHERE versionId = @VersionId", new { VersionId = versionId });
|
||||
if(dto == null) return;
|
||||
|
||||
using (var transaction = Database.GetTransaction())
|
||||
{
|
||||
@@ -56,8 +56,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public virtual void DeleteVersions(int id, DateTime versionDate)
|
||||
{
|
||||
var list = Database.Fetch<ContentVersionDto>("WHERE nodeId = @Id AND VersionDate < @VersionDate", new { Id = id, VersionDate = versionDate });
|
||||
Mandate.That<Exception>(list.Any());
|
||||
var list = Database.Fetch<ContentVersionDto>("WHERE ContentId = @Id AND VersionDate < @VersionDate", new { Id = id, VersionDate = versionDate });
|
||||
if (list.Any() == false) return;
|
||||
|
||||
using (var transaction = Database.GetTransaction())
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// can then override any additional execution (such as additional loggging, functionality, etc...) that we need to without breaking compatibility since we'll always be exposing
|
||||
/// this object instead of the base PetaPoco database object.
|
||||
/// </remarks>
|
||||
public class UmbracoDatabase : Database
|
||||
public class UmbracoDatabase : Database, IDisposeOnRequestEnd
|
||||
{
|
||||
private readonly Guid _instanceId = Guid.NewGuid();
|
||||
/// <summary>
|
||||
|
||||
+367
-342
@@ -19,54 +19,56 @@ using Umbraco.Core.IO;
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A utility class to find all classes of a certain type by reflection in the current bin folder
|
||||
/// of the web application.
|
||||
/// </summary>
|
||||
public static class TypeFinder
|
||||
{
|
||||
|
||||
private static readonly ConcurrentBag<Assembly> LocalFilteredAssemblyCache = new ConcurrentBag<Assembly>();
|
||||
private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
|
||||
private static ReadOnlyCollection<Assembly> _allAssemblies = null;
|
||||
private static ReadOnlyCollection<Assembly> _binFolderAssemblies = null;
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
/// <summary>
|
||||
/// A utility class to find all classes of a certain type by reflection in the current bin folder
|
||||
/// of the web application.
|
||||
/// </summary>
|
||||
public static class TypeFinder
|
||||
{
|
||||
private static readonly HashSet<Assembly> LocalFilteredAssemblyCache = new HashSet<Assembly>();
|
||||
private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim();
|
||||
private static HashSet<Assembly> _allAssemblies = null;
|
||||
private static HashSet<Assembly> _binFolderAssemblies = null;
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// lazily load a reference to all assemblies and only local assemblies.
|
||||
/// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
/// loaded in the CLR, not all assemblies.
|
||||
/// See these threads:
|
||||
/// http://issues.umbraco.org/issue/U5-198
|
||||
/// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
|
||||
/// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
|
||||
/// </remarks>
|
||||
internal static IEnumerable<Assembly> GetAllAssemblies()
|
||||
{
|
||||
if (_allAssemblies == null)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
List<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
var isHosted = HttpContext.Current != null;
|
||||
/// <summary>
|
||||
/// lazily load a reference to all assemblies and only local assemblies.
|
||||
/// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
|
||||
/// loaded in the CLR, not all assemblies.
|
||||
/// See these threads:
|
||||
/// http://issues.umbraco.org/issue/U5-198
|
||||
/// http://stackoverflow.com/questions/3552223/asp-net-appdomain-currentdomain-getassemblies-assemblies-missing-after-app
|
||||
/// http://stackoverflow.com/questions/2477787/difference-between-appdomain-getassemblies-and-buildmanager-getreferencedassembl
|
||||
/// </remarks>
|
||||
internal static HashSet<Assembly> GetAllAssemblies()
|
||||
{
|
||||
using (var lck = new UpgradeableReadLock(Locker))
|
||||
{
|
||||
if (_allAssemblies == null)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
assemblies = new List<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
}
|
||||
lck.UpgradeToWriteLock();
|
||||
|
||||
HashSet<Assembly> assemblies = null;
|
||||
try
|
||||
{
|
||||
var isHosted = HttpContext.Current != null;
|
||||
|
||||
try
|
||||
{
|
||||
if (isHosted)
|
||||
{
|
||||
assemblies = new HashSet<Assembly>(BuildManager.GetReferencedAssemblies().Cast<Assembly>());
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
if (assemblies == null)
|
||||
@@ -77,7 +79,7 @@ namespace Umbraco.Core
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
//var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
//var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
assemblies = new List<Assembly>();
|
||||
assemblies = new HashSet<Assembly>();
|
||||
foreach (var a in binAssemblyFiles)
|
||||
{
|
||||
try
|
||||
@@ -99,151 +101,161 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//if for some reason they are still no assemblies, then use the AppDomain to load in already loaded assemblies.
|
||||
if (!assemblies.Any())
|
||||
{
|
||||
assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().ToList());
|
||||
}
|
||||
if (!assemblies.Any())
|
||||
{
|
||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
assemblies.Add(a);
|
||||
}
|
||||
}
|
||||
|
||||
//here we are trying to get the App_Code assembly
|
||||
var fileExtensions = new[] {".cs", ".vb"}; //only vb and cs files are supported
|
||||
var appCodeFolder = new DirectoryInfo(IOHelper.MapPath(IOHelper.ResolveUrl("~/App_code")));
|
||||
//check if the folder exists and if there are any files in it with the supported file extensions
|
||||
if (appCodeFolder.Exists && (fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any())))
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
//here we are trying to get the App_Code assembly
|
||||
var fileExtensions = new[] { ".cs", ".vb" }; //only vb and cs files are supported
|
||||
var appCodeFolder = new DirectoryInfo(IOHelper.MapPath(IOHelper.ResolveUrl("~/App_code")));
|
||||
//check if the folder exists and if there are any files in it with the supported file extensions
|
||||
if (appCodeFolder.Exists && (fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any())))
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
|
||||
//now set the _allAssemblies
|
||||
_allAssemblies = new ReadOnlyCollection<Assembly>(assemblies);
|
||||
//now set the _allAssemblies
|
||||
_allAssemblies = new HashSet<Assembly>(assemblies);
|
||||
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
throw;
|
||||
|
||||
_binFolderAssemblies = _allAssemblies;
|
||||
}
|
||||
}
|
||||
}
|
||||
_binFolderAssemblies = _allAssemblies;
|
||||
}
|
||||
}
|
||||
|
||||
return _allAssemblies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns only assemblies found in the bin folder that have been loaded into the app domain.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
|
||||
/// </remarks>
|
||||
internal static IEnumerable<Assembly> GetBinAssemblies()
|
||||
{
|
||||
return _allAssemblies;
|
||||
}
|
||||
}
|
||||
|
||||
if (_binFolderAssemblies == null)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var assemblies = GetAssembliesWithKnownExclusions().ToArray();
|
||||
var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
var domainAssemblyNames = binAssemblyFiles.Select(AssemblyName.GetAssemblyName);
|
||||
var safeDomainAssemblies = new List<Assembly>();
|
||||
var binFolderAssemblies = new List<Assembly>();
|
||||
/// <summary>
|
||||
/// Returns only assemblies found in the bin folder that have been loaded into the app domain.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used.
|
||||
/// </remarks>
|
||||
internal static HashSet<Assembly> GetBinAssemblies()
|
||||
{
|
||||
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
//do a test to see if its queryable in med trust
|
||||
var assemblyFile = a.GetAssemblyFile();
|
||||
safeDomainAssemblies.Add(a);
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because this will fail
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
if (_binFolderAssemblies == null)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var assemblies = GetAssembliesWithKnownExclusions().ToArray();
|
||||
var binFolder = Assembly.GetExecutingAssembly().GetAssemblyFile().Directory;
|
||||
var binAssemblyFiles = Directory.GetFiles(binFolder.FullName, "*.dll", SearchOption.TopDirectoryOnly).ToList();
|
||||
var domainAssemblyNames = binAssemblyFiles.Select(AssemblyName.GetAssemblyName);
|
||||
var safeDomainAssemblies = new HashSet<Assembly>();
|
||||
var binFolderAssemblies = new HashSet<Assembly>();
|
||||
|
||||
foreach (var assemblyName in domainAssemblyNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
var foundAssembly =
|
||||
safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
|
||||
if (foundAssembly != null)
|
||||
{
|
||||
binFolderAssemblies.Add(foundAssembly);
|
||||
}
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because if we are trying to do a call to:
|
||||
// AssemblyName.ReferenceMatchesDefinition(a.GetName(), assemblyName)))
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
//do a test to see if its queryable in med trust
|
||||
var assemblyFile = a.GetAssemblyFile();
|
||||
safeDomainAssemblies.Add(a);
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because this will fail
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
|
||||
_binFolderAssemblies = new ReadOnlyCollection<Assembly>(binFolderAssemblies);
|
||||
}
|
||||
}
|
||||
return _binFolderAssemblies;
|
||||
}
|
||||
foreach (var assemblyName in domainAssemblyNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
var foundAssembly =
|
||||
safeDomainAssemblies.FirstOrDefault(a => a.GetAssemblyFile() == assemblyName.GetAssemblyFile());
|
||||
if (foundAssembly != null)
|
||||
{
|
||||
binFolderAssemblies.Add(foundAssembly);
|
||||
}
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because if we are trying to do a call to:
|
||||
// AssemblyName.ReferenceMatchesDefinition(a.GetName(), assemblyName)))
|
||||
//in medium trust for system assemblies, we get an exception but we just want to continue until we get to
|
||||
//an assembly that is ok.
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
|
||||
/// cached for perforance reasons.
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <returns></returns>
|
||||
internal static IEnumerable<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
{
|
||||
if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
|
||||
using (new WriteLock(LocalFilteredAssemblyCacheLocker))
|
||||
{
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
assemblies.ForEach(LocalFilteredAssemblyCache.Add);
|
||||
}
|
||||
return LocalFilteredAssemblyCache;
|
||||
}
|
||||
_binFolderAssemblies = new HashSet<Assembly>(binFolderAssemblies);
|
||||
}
|
||||
}
|
||||
return _binFolderAssemblies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <param name="exclusionFilter"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
IEnumerable<Assembly> excludeFromResults = null,
|
||||
string[] exclusionFilter = null)
|
||||
{
|
||||
if (excludeFromResults == null)
|
||||
excludeFromResults = new List<Assembly>();
|
||||
if (exclusionFilter == null)
|
||||
exclusionFilter = new string[] { };
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
|
||||
/// cached for perforance reasons.
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <returns></returns>
|
||||
internal static HashSet<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
{
|
||||
using (var lck = new UpgradeableReadLock(LocalFilteredAssemblyCacheLocker))
|
||||
{
|
||||
if (LocalFilteredAssemblyCache.Any()) return LocalFilteredAssemblyCache;
|
||||
|
||||
return GetAllAssemblies()
|
||||
.Where(x => !excludeFromResults.Contains(x)
|
||||
&& !x.GlobalAssemblyCache
|
||||
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
|
||||
}
|
||||
lck.UpgradeToWriteLock();
|
||||
|
||||
/// <summary>
|
||||
/// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
|
||||
/// </remarks>
|
||||
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
LocalFilteredAssemblyCache.Add(a);
|
||||
}
|
||||
|
||||
return LocalFilteredAssemblyCache;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a distinct list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter
|
||||
/// </summary>
|
||||
/// <param name="excludeFromResults"></param>
|
||||
/// <param name="exclusionFilter"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Assembly> GetFilteredAssemblies(
|
||||
IEnumerable<Assembly> excludeFromResults = null,
|
||||
string[] exclusionFilter = null)
|
||||
{
|
||||
if (excludeFromResults == null)
|
||||
excludeFromResults = new HashSet<Assembly>();
|
||||
if (exclusionFilter == null)
|
||||
exclusionFilter = new string[] { };
|
||||
|
||||
return GetAllAssemblies()
|
||||
.Where(x => !excludeFromResults.Contains(x)
|
||||
&& !x.GlobalAssemblyCache
|
||||
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
|
||||
/// </remarks>
|
||||
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
|
||||
{
|
||||
"mscorlib,",
|
||||
"System.",
|
||||
@@ -287,11 +299,11 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>()
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
@@ -300,11 +312,11 @@ namespace Umbraco.Core
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
|
||||
}
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(IEnumerable<Assembly> assemblies)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<T, TAttribute>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the type T that contain the attribute TAttribute
|
||||
@@ -314,13 +326,13 @@ namespace Umbraco.Core
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<TAttribute>(typeof (T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<T, TAttribute>(
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
return FindClassesOfTypeWithAttribute<TAttribute>(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute
|
||||
@@ -330,85 +342,85 @@ namespace Umbraco.Core
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<TAttribute>(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
public static IEnumerable<Type> FindClassesOfTypeWithAttribute<TAttribute>(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(assignTypeFrom, assemblies, onlyConcreteClasses,
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(assignTypeFrom, assemblies, onlyConcreteClasses,
|
||||
//the additional filter will ensure that any found types also have the attribute applied.
|
||||
t => t.GetCustomAttributes<TAttribute>(false).Any());
|
||||
}
|
||||
t => t.GetCustomAttributes<TAttribute>(false).Any());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches all filtered local assemblies specified for classes of the type passed in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>()
|
||||
{
|
||||
return FindClassesOfType<T>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
/// <summary>
|
||||
/// Searches all filtered local assemblies specified for classes of the type passed in.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>()
|
||||
{
|
||||
return FindClassesOfType<T>(GetAssembliesWithKnownExclusions(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return FindClassesOfType<T>(assemblies, true);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns all types found of in the assemblies specified of type T
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesOfType<T>(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
return FindClassesOfType<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies, bool onlyConcreteClasses)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds any classes with the attribute.
|
||||
/// </summary>
|
||||
/// <param name="attributeType">The attribute type </param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
/// <summary>
|
||||
/// Finds any classes with the attribute.
|
||||
/// </summary>
|
||||
/// <param name="attributeType">The attribute type </param>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <param name="onlyConcreteClasses">if set to <c>true</c> only concrete classes.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<Attribute>(attributeType) == false)
|
||||
throw new ArgumentException("The type specified: " + attributeType + " is not an Attribute type");
|
||||
if (TypeHelper.IsTypeAssignableFrom<Attribute>(attributeType) == false)
|
||||
throw new ArgumentException("The type specified: " + attributeType + " is not an Attribute type");
|
||||
|
||||
var foundAssignableTypes = new List<Type>();
|
||||
var foundAssignableTypes = new HashSet<Type>();
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
@@ -418,71 +430,74 @@ namespace Umbraco.Core
|
||||
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(attributeType, assemblyList);
|
||||
|
||||
foreach (var a in referencedAssemblies)
|
||||
{
|
||||
{
|
||||
//get all types in the assembly that are sub types of the current type
|
||||
var allTypes = GetTypesWithFormattedException(a).ToArray();
|
||||
|
||||
var types = allTypes.Where(t => TypeHelper.IsNonStaticClass(t)
|
||||
&& (onlyConcreteClasses == false || t.IsAbstract == false)
|
||||
//the type must have this attribute
|
||||
|
||||
var types = allTypes.Where(t => TypeHelper.IsNonStaticClass(t)
|
||||
&& (onlyConcreteClasses == false || t.IsAbstract == false)
|
||||
//the type must have this attribute
|
||||
&& t.GetCustomAttributes(attributeType, false).Any());
|
||||
|
||||
foundAssignableTypes.AddRange(types);
|
||||
}
|
||||
foreach (var t in types)
|
||||
{
|
||||
foundAssignableTypes.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(assemblies, true);
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="assemblies">The assemblies.</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>(IEnumerable<Assembly> assemblies)
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(assemblies, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute in filtered local assemblies
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute in filtered local assemblies
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Type> FindClassesWithAttribute<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
}
|
||||
|
||||
|
||||
#region Private methods
|
||||
|
||||
/// <summary>
|
||||
/// Finds types that are assignable from the assignTypeFrom parameter and will scan for these types in the assembly
|
||||
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
|
||||
/// deriving from the base type.
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <param name="additionalFilter">An additional filter to apply for what types will actually be included in the return value</param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Type> GetClasses(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
#region Private methods
|
||||
|
||||
/// <summary>
|
||||
/// Finds types that are assignable from the assignTypeFrom parameter and will scan for these types in the assembly
|
||||
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
|
||||
/// deriving from the base type.
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="onlyConcreteClasses"></param>
|
||||
/// <param name="additionalFilter">An additional filter to apply for what types will actually be included in the return value</param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<Type> GetClasses(
|
||||
Type assignTypeFrom,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses,
|
||||
Func<Type, bool> additionalFilter = null)
|
||||
{
|
||||
{
|
||||
//the default filter will always return true.
|
||||
if (additionalFilter == null)
|
||||
{
|
||||
additionalFilter = type => true;
|
||||
}
|
||||
|
||||
var foundAssignableTypes = new List<Type>();
|
||||
var foundAssignableTypes = new HashSet<Type>();
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
@@ -510,8 +525,11 @@ namespace Umbraco.Core
|
||||
.ToArray();
|
||||
|
||||
//add the types to our list to return
|
||||
foundAssignableTypes.AddRange(filteredTypes);
|
||||
|
||||
foreach (var t in filteredTypes)
|
||||
{
|
||||
foundAssignableTypes.Add(t);
|
||||
}
|
||||
|
||||
//now we need to include types that may be inheriting from sub classes of the type being searched for
|
||||
//so we will search in assemblies that reference those types too.
|
||||
foreach (var subTypesInAssembly in allSubTypes.GroupBy(x => x.Assembly))
|
||||
@@ -529,54 +547,61 @@ namespace Umbraco.Core
|
||||
|
||||
//if there's a base class amongst the types then we'll only search for that type.
|
||||
//otherwise we'll have to search for all of them.
|
||||
var subTypesToSearch = new List<Type>();
|
||||
var subTypesToSearch = new HashSet<Type>();
|
||||
if (baseClassAttempt.Success)
|
||||
{
|
||||
subTypesToSearch.Add(baseClassAttempt.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
subTypesToSearch.AddRange(subTypeList);
|
||||
foreach (var t in subTypeList)
|
||||
{
|
||||
subTypesToSearch.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (var typeToSearch in subTypesToSearch)
|
||||
{
|
||||
//recursively find the types inheriting from this sub type in the other non-scanned assemblies.
|
||||
var foundTypes = GetClasses(typeToSearch, otherAssemblies, onlyConcreteClasses, additionalFilter);
|
||||
foundAssignableTypes.AddRange(foundTypes);
|
||||
|
||||
foreach (var f in foundTypes)
|
||||
{
|
||||
foundAssignableTypes.Add(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
}
|
||||
return foundAssignableTypes;
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
{
|
||||
//if the assembly is dynamic, do not try to scan it
|
||||
if (a.IsDynamic)
|
||||
return Enumerable.Empty<Type>();
|
||||
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
{
|
||||
//if the assembly is dynamic, do not try to scan it
|
||||
if (a.IsDynamic)
|
||||
return Enumerable.Empty<Type>();
|
||||
|
||||
try
|
||||
{
|
||||
return a.GetExportedTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
|
||||
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
|
||||
{
|
||||
sb.AppendLine("Exception: " + loaderException);
|
||||
}
|
||||
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
return a.GetExportedTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
|
||||
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
|
||||
{
|
||||
sb.AppendLine("Exception: " + loaderException);
|
||||
}
|
||||
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,16 @@ namespace Umbraco.Core
|
||||
private static readonly ConcurrentDictionary<Type, FieldInfo[]> GetFieldsCache = new ConcurrentDictionary<Type, FieldInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]> GetPropertiesCache = new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the method is actually overriding a base method
|
||||
/// </summary>
|
||||
/// <param name="m"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsOverride(MethodInfo m)
|
||||
{
|
||||
return m.GetBaseDefinition().DeclaringType != m.DeclaringType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all assembly references that are referencing the assignTypeFrom Type's assembly found in the assemblyList
|
||||
/// </summary>
|
||||
|
||||
@@ -165,6 +165,7 @@
|
||||
<Compile Include="Events\SaveEventArgs.cs" />
|
||||
<Compile Include="Events\SendToPublishEventArgs.cs" />
|
||||
<Compile Include="IApplicationEventHandler.cs" />
|
||||
<Compile Include="IDisposeOnRequestEnd.cs" />
|
||||
<Compile Include="IO\ResizedImage.cs" />
|
||||
<Compile Include="IO\UmbracoMediaFile.cs" />
|
||||
<Compile Include="Media\MediaSubfolderCounter.cs" />
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</appSettings>
|
||||
|
||||
<connectionStrings>
|
||||
<add name="umbracoDbDSN" connectionString="Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;File Access Retry Timeout=10" providerName="System.Data.SqlServerCe.4.0"/>
|
||||
<add name="umbracoDbDSN" connectionString="Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;" providerName="System.Data.SqlServerCe.4.0"/>
|
||||
</connectionStrings>
|
||||
|
||||
<FileSystemProviders>
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Umbraco.Tests.BusinessLogic
|
||||
|
||||
private void InitializeDatabase()
|
||||
{
|
||||
ConfigurationManager.AppSettings.Set(Core.Configuration.GlobalSettings.UmbracoConnectionName, @"datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;data source=|DataDirectory|\UmbracoPetaPocoTests.sdf;Flush Interval=1;File Access Retry Timeout=10");
|
||||
ConfigurationManager.AppSettings.Set(Core.Configuration.GlobalSettings.UmbracoConnectionName, @"datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;data source=|DataDirectory|\UmbracoPetaPocoTests.sdf;Flush Interval=1;");
|
||||
|
||||
ClearDatabase();
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public override UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;File Access Retry Timeout=10", "System.Data.SqlServerCe.4.0");
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;", "System.Data.SqlServerCe.4.0");
|
||||
}
|
||||
|
||||
public override DatabaseProviders GetDatabaseProvider()
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public override UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;File Access Retry Timeout=10", "System.Data.SqlServerCe.4.0");
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;", "System.Data.SqlServerCe.4.0");
|
||||
}
|
||||
|
||||
public override DatabaseProviders GetDatabaseProvider()
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;File Access Retry Timeout=10", "System.Data.SqlServerCe.4.0");
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;", "System.Data.SqlServerCe.4.0");
|
||||
}
|
||||
|
||||
public string GetDatabaseSpecificSqlScript()
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace Umbraco.Tests.Models
|
||||
var dataTypeId = Guid.NewGuid();
|
||||
|
||||
var dataTypeData = MockRepository.GenerateMock<IData, IDataValueSetter>();
|
||||
|
||||
dataTypeData
|
||||
.Stub(data => data.ToXMl(Arg<XmlDocument>.Is.Anything))
|
||||
.Return(null) // you have to call Return() even though we're about to override it
|
||||
@@ -98,5 +99,18 @@ namespace Umbraco.Tests.Models
|
||||
((IDataValueSetter)dataTypeData).AssertWasCalled(setter => setter.SetValue("Hello world", DataTypeDatabaseType.Nvarchar.ToString()));
|
||||
}
|
||||
|
||||
[TestCase(DataTypeDatabaseType.Nvarchar)]
|
||||
[TestCase(DataTypeDatabaseType.Date)]
|
||||
[TestCase(DataTypeDatabaseType.Integer)]
|
||||
[TestCase(DataTypeDatabaseType.Ntext)]
|
||||
public void DefaultData_SetValue_Ensures_Empty_String_When_Null_Value_Any_Data_Type(DataTypeDatabaseType type)
|
||||
{
|
||||
var defaultData = new DefaultData(MockRepository.GenerateMock<BaseDataType>());
|
||||
|
||||
((IDataValueSetter)defaultData).SetValue(null, type.ToString());
|
||||
|
||||
Assert.AreEqual(string.Empty, defaultData.Value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace Umbraco.Tests.Persistence
|
||||
//Get the connectionstring settings from config
|
||||
var settings = ConfigurationManager.ConnectionStrings[Core.Configuration.GlobalSettings.UmbracoConnectionName];
|
||||
|
||||
//by default the conn string is: Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;File Access Retry Timeout=10
|
||||
//by default the conn string is: Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;
|
||||
//we'll just replace the sdf file with our custom one:
|
||||
//Create the Sql CE database
|
||||
var engine = new SqlCeEngine(settings.ConnectionString.Replace("UmbracoPetaPocoTests", "DatabaseContextTests"));
|
||||
|
||||
@@ -35,12 +35,12 @@ namespace Umbraco.Tests.Persistence
|
||||
}
|
||||
|
||||
//Create the Sql CE database
|
||||
var engine = new SqlCeEngine("Datasource=|DataDirectory|test.sdf;Flush Interval=1;File Access Retry Timeout=10");
|
||||
var engine = new SqlCeEngine("Datasource=|DataDirectory|test.sdf;Flush Interval=1;");
|
||||
engine.CreateDatabase();
|
||||
|
||||
SqlSyntaxContext.SqlSyntaxProvider = SqlCeSyntax.Provider;
|
||||
|
||||
_database = new Database("Datasource=|DataDirectory|test.sdf;Flush Interval=1;File Access Retry Timeout=10",
|
||||
_database = new Database("Datasource=|DataDirectory|test.sdf;Flush Interval=1;",
|
||||
"System.Data.SqlServerCe.4.0");
|
||||
}
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ namespace Umbraco.Tests
|
||||
public void Resolves_Trees()
|
||||
{
|
||||
var trees = PluginManager.Current.ResolveTrees();
|
||||
Assert.AreEqual(36, trees.Count());
|
||||
Assert.AreEqual(40, trees.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -861,6 +861,22 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(sut.GetValue<string>("imgCropper"), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Delete_Previous_Versions_Not_Latest()
|
||||
{
|
||||
// Arrange
|
||||
var contentService = ServiceContext.ContentService;
|
||||
var content = contentService.GetById(1049);
|
||||
var version = content.Version;
|
||||
|
||||
// Act
|
||||
contentService.DeleteVersion(1049, version, true, 0);
|
||||
var sut = contentService.GetById(1049);
|
||||
|
||||
// Assert
|
||||
Assert.That(sut.Version, Is.EqualTo(version));
|
||||
}
|
||||
|
||||
private IEnumerable<IContent> CreateContentHierarchy()
|
||||
{
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
/// </summary>
|
||||
protected virtual string GetDbConnectionString()
|
||||
{
|
||||
return @"Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;File Access Retry Timeout=10";
|
||||
return @"Datasource=|DataDirectory|UmbracoPetaPocoTests.sdf;Flush Interval=1;";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
/// </summary>
|
||||
public static void InitializeDatabase()
|
||||
{
|
||||
ConfigurationManager.AppSettings.Set(Core.Configuration.GlobalSettings.UmbracoConnectionName, @"datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;data source=|DataDirectory|\UmbracoPetaPocoTests.sdf;Flush Interval=1;File Access Retry Timeout=10");
|
||||
ConfigurationManager.AppSettings.Set(Core.Configuration.GlobalSettings.UmbracoConnectionName, @"datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;data source=|DataDirectory|\UmbracoPetaPocoTests.sdf;Flush Interval=1;");
|
||||
|
||||
ClearDatabase();
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
|
||||
namespace Umbraco.Tests.Trees
|
||||
{
|
||||
[TestFixture]
|
||||
public class BaseContentTreeTests
|
||||
{
|
||||
|
||||
[TearDown]
|
||||
public void TestTearDown()
|
||||
{
|
||||
BaseTree.AfterTreeRender -= EventHandler;
|
||||
BaseTree.BeforeTreeRender -= EventHandler;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Run_Optimized()
|
||||
{
|
||||
var tree1 = new MyOptimizedContentTree1("content");
|
||||
var tree2 = new MyOptimizedContentTree2("content");
|
||||
|
||||
Assert.IsTrue(tree1.UseOptimizedRendering);
|
||||
Assert.IsTrue(tree2.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Events_AfterRender()
|
||||
{
|
||||
var tree = new MyOptimizedContentTree1("content");
|
||||
|
||||
BaseTree.AfterTreeRender += EventHandler;
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Events_BeforeRender()
|
||||
{
|
||||
var tree = new MyOptimizedContentTree1("content");
|
||||
|
||||
BaseTree.BeforeTreeRender += EventHandler;
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Overriden_Method()
|
||||
{
|
||||
var tree = new MyNotOptimizedContentTree("content");
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
private void EventHandler(object sender, TreeEventArgs treeEventArgs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//optimized because we are not overriding OnRenderNode
|
||||
public class MyOptimizedContentTree1 : BaseContentTree
|
||||
{
|
||||
public MyOptimizedContentTree1(string application)
|
||||
: base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class MyOptimizedContentTree2 : BaseContentTree
|
||||
{
|
||||
public MyOptimizedContentTree2(string application)
|
||||
: base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool LoadMinimalDocument
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//even if we override it will still be optimized because of the LoadMinimalDocument flag
|
||||
protected override void OnRenderNode(ref XmlTreeNode xNode, umbraco.cms.businesslogic.web.Document doc)
|
||||
{
|
||||
base.OnRenderNode(ref xNode, doc);
|
||||
}
|
||||
}
|
||||
|
||||
public class MyNotOptimizedContentTree : BaseContentTree
|
||||
{
|
||||
public MyNotOptimizedContentTree(string application)
|
||||
: base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool LoadMinimalDocument
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected override void OnRenderNode(ref XmlTreeNode xNode, umbraco.cms.businesslogic.web.Document doc)
|
||||
{
|
||||
base.OnRenderNode(ref xNode, doc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using NUnit.Framework;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
|
||||
namespace Umbraco.Tests.Trees
|
||||
{
|
||||
[TestFixture]
|
||||
public class BaseMediaTreeTests
|
||||
{
|
||||
|
||||
[TearDown]
|
||||
public void TestTearDown()
|
||||
{
|
||||
BaseTree.AfterTreeRender -= EventHandler;
|
||||
BaseTree.BeforeTreeRender -= EventHandler;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Run_Optimized()
|
||||
{
|
||||
var tree = new MyOptimizedMediaTree("media");
|
||||
|
||||
Assert.IsTrue(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Events_AfterRender()
|
||||
{
|
||||
var tree = new MyOptimizedMediaTree("media");
|
||||
|
||||
BaseTree.AfterTreeRender += EventHandler;
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Events_BeforeRender()
|
||||
{
|
||||
var tree = new MyOptimizedMediaTree("media");
|
||||
|
||||
BaseTree.BeforeTreeRender += EventHandler;
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
private void EventHandler(object sender, TreeEventArgs treeEventArgs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class MyOptimizedMediaTree : BaseMediaTree
|
||||
{
|
||||
public MyOptimizedMediaTree(string application)
|
||||
: base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -350,6 +350,8 @@
|
||||
<Compile Include="TestHelpers\Entities\MockedContentTypes.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedEntity.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedMedia.cs" />
|
||||
<Compile Include="Trees\BaseContentTreeTests.cs" />
|
||||
<Compile Include="Trees\BaseMediaTreeTests.cs" />
|
||||
<Compile Include="UmbracoExamine\ContentServiceTest.cs" />
|
||||
<Compile Include="UmbracoExamine\EventsTest.cs" />
|
||||
<Compile Include="TypeHelperTests.cs" />
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<IISExpressUseClassicPipelineMode />
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
<MvcProjectUpgradeChecked>true</MvcProjectUpgradeChecked>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<OutputPath>bin\</OutputPath>
|
||||
@@ -2602,9 +2603,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>6140</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>6160</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:6140</IISUrl>
|
||||
<IISUrl>http://localhost:6160</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ namespace Umbraco.Web.UI.Install.Steps {
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.TextBox DatabaseName;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DatabaseIntegratedSecurity control.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<%@ Page MasterPageFile="../masterpages/umbracoPage.Master" Language="c#" CodeBehind="EditTemplate.aspx.cs"
|
||||
ValidateRequest="false" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.Settings.EditTemplate" %>
|
||||
<%@ Import Namespace="Umbraco.Core" %>
|
||||
<%@ Import Namespace="Umbraco.Core.IO" %>
|
||||
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
|
||||
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
|
||||
@@ -19,6 +20,7 @@
|
||||
jQuery(document).ready(function() {
|
||||
//create the editor
|
||||
editor = new Umbraco.Editors.EditTemplate({
|
||||
restServiceLocation: "<%= Url.GetSaveFileServicePath() %>",
|
||||
umbracoPath: '<%= IOHelper.ResolveUrl(SystemDirectories.Umbraco) %>',
|
||||
editorClientId: '<%= editorSource.ClientID %>',
|
||||
useMasterPages: <%=umbraco.UmbracoSettings.UseAspNetMasterPages.ToString().ToLower()%>,
|
||||
|
||||
@@ -114,11 +114,18 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views
|
||||
NameTxt.Text = OriginalFileName;
|
||||
var file = IOHelper.MapPath(SystemDirectories.MvcViews.EnsureEndsWith('/') + OriginalFileName);
|
||||
|
||||
// validate file path
|
||||
if (file.StartsWith(IOHelper.MapPath(SystemDirectories.MvcViews.EnsureEndsWith('/')))) {
|
||||
|
||||
using (var sr = File.OpenText(file))
|
||||
{
|
||||
var s = sr.ReadToEnd();
|
||||
editorSource.Text = s;
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
throw new ArgumentException("Couldn't open file - illegal path");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,9 +62,19 @@ $.datepicker._connectDatepicker = function(target, inst) {
|
||||
*/
|
||||
$.datepicker._showDatepickerOverride = $.datepicker._showDatepicker;
|
||||
$.datepicker._showDatepicker = function (input) {
|
||||
// keep the current value
|
||||
var originalval = input.value;
|
||||
|
||||
// Keep the first 10 chars for now yyyy-mm-dd - this removes the time part which was breaking the standardDatePicker parsing code
|
||||
input.value = originalval.length>10 ? originalval.substring(0, 10) : originalval;
|
||||
|
||||
|
||||
// Call the original method which will show the datepicker
|
||||
$.datepicker._showDatepickerOverride(input);
|
||||
|
||||
// Put it back
|
||||
input.value = originalval;
|
||||
|
||||
input = input.target || input;
|
||||
|
||||
// find from button/image trigger
|
||||
|
||||
@@ -101,27 +101,57 @@
|
||||
save: function(templateName, templateAlias, codeVal) {
|
||||
var self = this;
|
||||
|
||||
umbraco.presentation.webservices.codeEditorSave.SaveTemplate(
|
||||
templateName, templateAlias, codeVal, self._opts.templateId, this._opts.masterPageDropDown.val(),
|
||||
function(t) { self.submitSucces(t); },
|
||||
function(t) { self.submitFailure(t); });
|
||||
|
||||
$.post(self._opts.restServiceLocation + "SaveTemplate",
|
||||
JSON.stringify({
|
||||
templateName: templateName,
|
||||
templateAlias: templateAlias,
|
||||
templateContents: codeVal,
|
||||
templateId: self._opts.templateId,
|
||||
masterTemplateId: this._opts.masterPageDropDown.val()
|
||||
}),
|
||||
function (e) {
|
||||
if (e.success) {
|
||||
self.submitSuccess(e);
|
||||
} else {
|
||||
self.submitFailure(e.message, e.header);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
submitSucces: function(t) {
|
||||
if (t != 'true') {
|
||||
top.UmbSpeechBubble.ShowMessage('error', this._opts.text.templateErrorHeader, this._opts.text.templateErrorText);
|
||||
submitSuccess: function (args) {
|
||||
var msg = args.message;
|
||||
var header = args.header;
|
||||
var path = this._opts.treeSyncPath;
|
||||
var pathChanged = false;
|
||||
if (args.path) {
|
||||
if (path != args.path) {
|
||||
pathChanged = true;
|
||||
}
|
||||
path = args.path;
|
||||
}
|
||||
|
||||
top.UmbSpeechBubble.ShowMessage('save', header, msg);
|
||||
UmbClientMgr.mainTree().setActiveTreeType('templates');
|
||||
if (pathChanged) {
|
||||
UmbClientMgr.mainTree().moveNode(this._opts.templateId, path);
|
||||
}
|
||||
else {
|
||||
top.UmbSpeechBubble.ShowMessage('save', this._opts.text.templateSavedHeader, this._opts.text.templateSavedText);
|
||||
UmbClientMgr.mainTree().syncTree(path, true);
|
||||
}
|
||||
|
||||
UmbClientMgr.mainTree().setActiveTreeType('templates');
|
||||
UmbClientMgr.mainTree().syncTree(this._opts.treeSyncPath, true);
|
||||
},
|
||||
|
||||
submitFailure: function(t) {
|
||||
top.UmbSpeechBubble.ShowMessage('error', this._opts.text.templateErrorHeader, this._opts.text.templateErrorText);
|
||||
submitFailure: function (err, header) {
|
||||
top.UmbSpeechBubble.ShowMessage('error', header, err);
|
||||
}
|
||||
});
|
||||
|
||||
//Set defaults for jQuery ajax calls.
|
||||
$.ajaxSetup({
|
||||
dataType: 'json',
|
||||
cache: false,
|
||||
contentType: 'application/json; charset=utf-8'
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -80,7 +80,7 @@
|
||||
}),
|
||||
function(e) {
|
||||
if (e.success) {
|
||||
self.submitSuccess(e.message, e.header);
|
||||
self.submitSuccess(e);
|
||||
} else {
|
||||
self.submitFailure(e.message, e.header);
|
||||
}
|
||||
@@ -97,7 +97,7 @@
|
||||
}),
|
||||
function(e) {
|
||||
if (e.success) {
|
||||
self.submitSuccess(e.message, e.header);
|
||||
self.submitSuccess(e);
|
||||
} else {
|
||||
self.submitFailure(e.message, e.header);
|
||||
}
|
||||
@@ -105,8 +105,20 @@
|
||||
}
|
||||
},
|
||||
|
||||
submitSuccess: function (err, header) {
|
||||
top.UmbSpeechBubble.ShowMessage('save', header, err);
|
||||
submitSuccess: function (args) {
|
||||
|
||||
var msg = args.message;
|
||||
var header = args.header;
|
||||
var path = this._opts.treeSyncPath;
|
||||
var pathChanged = false;
|
||||
if (args.path) {
|
||||
if (path != args.path) {
|
||||
pathChanged = true;
|
||||
}
|
||||
path = args.path;
|
||||
}
|
||||
|
||||
top.UmbSpeechBubble.ShowMessage('save', header, msg);
|
||||
|
||||
UmbClientMgr.mainTree().setActiveTreeType(this._opts.currentTreeType);
|
||||
|
||||
@@ -114,11 +126,19 @@
|
||||
|
||||
if (this._opts.editorType == "Template") {
|
||||
//templates are different because they are ID based, whereas view files are file based without a static id
|
||||
UmbClientMgr.mainTree().syncTree(this._opts.treeSyncPath, true);
|
||||
|
||||
if (pathChanged) {
|
||||
UmbClientMgr.mainTree().moveNode(this._opts.templateId, path);
|
||||
}
|
||||
else {
|
||||
UmbClientMgr.mainTree().syncTree(path, true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
//we need to pass in the newId parameter so it knows which node to resync after retreival from the server
|
||||
UmbClientMgr.mainTree().syncTree(this._opts.treeSyncPath, true, null, newFilePath.split("/")[1]);
|
||||
UmbClientMgr.mainTree().syncTree(path, true, null, newFilePath.split("/")[1]);
|
||||
}
|
||||
|
||||
//then we need to update our current tree sync path to represent the new one
|
||||
|
||||
@@ -88,14 +88,25 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
#region Utilities
|
||||
|
||||
private bool FindByUrlAliasEnabled
|
||||
private static bool FindByUrlAliasEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
var hasFinder = ContentFinderResolver.Current.ContainsType<ContentFinderByUrlAlias>();
|
||||
var hasHandler = ContentFinderResolver.Current.ContainsType<ContentFinderByNotFoundHandlers>()
|
||||
&& NotFoundHandlerHelper.CustomHandlerTypes.Contains(typeof(global::umbraco.SearchForAlias));
|
||||
return hasFinder || hasHandler;
|
||||
// finder
|
||||
if (ContentFinderResolver.Current.ContainsType<ContentFinderByUrlAlias>())
|
||||
return true;
|
||||
|
||||
// handler wrapped into a finder
|
||||
if (ContentFinderResolver.Current.ContainsType<ContentFinderByNotFoundHandler<global::umbraco.SearchForAlias>>())
|
||||
return true;
|
||||
|
||||
// handler wrapped into special finder
|
||||
if (ContentFinderResolver.Current.ContainsType<ContentFinderByNotFoundHandlers>()
|
||||
&& NotFoundHandlerHelper.IsNotFoundHandlerEnabled<global::umbraco.SearchForAlias>())
|
||||
return true;
|
||||
|
||||
// anything else, we can't detect
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,115 +29,77 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
#region Copied over and adapted from presentation.requestHandler
|
||||
|
||||
void HandlePageNotFound(PublishedContentRequest docRequest)
|
||||
private static void HandlePageNotFound(PublishedContentRequest docRequest)
|
||||
{
|
||||
var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers();
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Running for legacy url='{0}'.", () => url);
|
||||
|
||||
foreach (var handler in GetNotFoundHandlers())
|
||||
foreach (var handler in NotFoundHandlerHelper.GetNotFoundHandlers())
|
||||
{
|
||||
IContentFinder finder = null;
|
||||
var handlerName = handler.GetType().FullName;
|
||||
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}'.", () => handlerName);
|
||||
|
||||
// replace with our own implementation
|
||||
if (handler is global::umbraco.SearchForAlias)
|
||||
finder = new ContentFinderByUrlAlias();
|
||||
else if (handler is global::umbraco.SearchForProfile)
|
||||
finder = new ContentFinderByProfile();
|
||||
else if (handler is global::umbraco.SearchForTemplate)
|
||||
finder = new ContentFinderByNiceUrlAndTemplate();
|
||||
else if (handler is global::umbraco.handle404)
|
||||
finder = new ContentFinderByLegacy404();
|
||||
|
||||
var finder = NotFoundHandlerHelper.SubsituteFinder(handler);
|
||||
if (finder != null)
|
||||
{
|
||||
var finderName = finder.GetType().FullName;
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Replace handler '{0}' by new finder '{1}'.", () => handlerName, () => finderName);
|
||||
if (finder.TryFindContent(docRequest))
|
||||
{
|
||||
// do NOT set docRequest.PublishedContent again here as
|
||||
// it would clear any template that the finder might have set
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id);
|
||||
if (docRequest.Is404)
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' set status to 404.", () => finderName);
|
||||
|
||||
// if we found a document, break, don't look at more handler -- we're done
|
||||
break;
|
||||
}
|
||||
// can't find a document => continue with other handlers
|
||||
if (finder.TryFindContent(docRequest) == false)
|
||||
continue;
|
||||
|
||||
// if we did not find a document, continue, look at other handlers
|
||||
continue;
|
||||
}
|
||||
// found a document => break, don't run other handlers, we're done
|
||||
|
||||
// else it's a legacy handler, run
|
||||
// in theory an IContentFinder can return true yet set no document
|
||||
// but none of the substitued finders (see SubstituteFinder) do it.
|
||||
|
||||
if (handler.Execute(url) && handler.redirectID > 0)
|
||||
{
|
||||
var redirectId = handler.redirectID;
|
||||
docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId);
|
||||
// do NOT set docRequest.PublishedContent again here
|
||||
// as it would clear any template that the finder might have set
|
||||
|
||||
if (!docRequest.HasPublishedContent)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId);
|
||||
break;
|
||||
}
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id);
|
||||
if (docRequest.Is404)
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Finder '{0}' set status to 404.", () => finderName);
|
||||
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId);
|
||||
|
||||
if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' set status code to 404.", () => handlerName);
|
||||
docRequest.Is404 = true;
|
||||
}
|
||||
|
||||
//// check for caching
|
||||
//if (handler.CacheUrl)
|
||||
//{
|
||||
// if (url.StartsWith("/"))
|
||||
// url = "/" + url;
|
||||
|
||||
// var cacheKey = (currentDomain == null ? "" : currentDomain.Name) + url;
|
||||
// var culture = currentDomain == null ? null : currentDomain.Language.CultureAlias;
|
||||
// SetCache(cacheKey, new CacheEntry(handler.redirectID.ToString(), culture));
|
||||
|
||||
// HttpContext.Current.Trace.Write("NotFoundHandler",
|
||||
// string.Format("Added to cache '{0}', {1}.", url, handler.redirectID));
|
||||
//}
|
||||
|
||||
// if we found a document, break, don't look at more handler -- we're done
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => docRequest.PublishedContent.Id);
|
||||
break;
|
||||
}
|
||||
|
||||
// if we did not find a document, continue, look at other handlers
|
||||
// else it's a legacy handler: run
|
||||
|
||||
// can't find a document => continue with other handlers
|
||||
if (handler.Execute(url) == false || handler.redirectID <= 0)
|
||||
continue;
|
||||
|
||||
// found a document ID => ensure it's a valid document
|
||||
var redirectId = handler.redirectID;
|
||||
docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId);
|
||||
|
||||
if (docRequest.HasPublishedContent == false)
|
||||
{
|
||||
// the handler said it could handle the url, and returned a content ID
|
||||
// yet that content ID is invalid... should we run the other handlers?
|
||||
// I don't think so, not here, let the "last chance" finder take care.
|
||||
// so, break.
|
||||
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId);
|
||||
break;
|
||||
}
|
||||
|
||||
// found a valid document => break, don't run other handlers, we're done
|
||||
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId);
|
||||
|
||||
if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404)
|
||||
{
|
||||
LogHelper.Debug<ContentFinderByNotFoundHandlers>("Handler '{0}' set status code to 404.", () => handlerName);
|
||||
docRequest.Is404 = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<INotFoundHandler> GetNotFoundHandlers()
|
||||
{
|
||||
// instanciate new handlers
|
||||
// using definition cache
|
||||
|
||||
var handlers = new List<INotFoundHandler>();
|
||||
|
||||
foreach (var type in NotFoundHandlerHelper.CustomHandlerTypes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var handler = Activator.CreateInstance(type) as INotFoundHandler;
|
||||
if (handler != null)
|
||||
handlers.Add(handler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<ContentFinderByNotFoundHandlers>(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e);
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="IContentFinder"/> that runs legacy <c>INotFoundHandler</c> in "last chance" situation.
|
||||
/// </summary>
|
||||
public class ContentLastChanceFinderByNotFoundHandlers : IContentFinder
|
||||
{
|
||||
// notes
|
||||
//
|
||||
// at the moment we load the legacy INotFoundHandler
|
||||
// excluding those that have been replaced by proper finders,
|
||||
// and run them.
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find and assign an Umbraco document to a <c>PublishedContentRequest</c>.
|
||||
/// </summary>
|
||||
/// <param name="docRequest">The <c>PublishedContentRequest</c>.</param>
|
||||
/// <returns>A value indicating whether an Umbraco document was found and assigned.</returns>
|
||||
public bool TryFindContent(PublishedContentRequest docRequest)
|
||||
{
|
||||
HandlePageNotFound(docRequest);
|
||||
return docRequest.HasPublishedContent;
|
||||
}
|
||||
|
||||
#region Copied over and adapted from presentation.requestHandler
|
||||
|
||||
private static void HandlePageNotFound(PublishedContentRequest docRequest)
|
||||
{
|
||||
var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers();
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Running for legacy url='{0}'.", () => url);
|
||||
|
||||
var handler = NotFoundHandlerHelper.GetNotFoundLastChanceHandler();
|
||||
var handlerName = handler.GetType().FullName;
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}'.", () => handlerName);
|
||||
|
||||
var finder = NotFoundHandlerHelper.SubsituteFinder(handler);
|
||||
if (finder != null)
|
||||
{
|
||||
var finderName = finder.GetType().FullName;
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Replace handler '{0}' by new finder '{1}'.", () => handlerName, () => finderName);
|
||||
|
||||
// can't find a document => exit
|
||||
if (finder.TryFindContent(docRequest) == false)
|
||||
return;
|
||||
|
||||
// found a document => we're done
|
||||
|
||||
// in theory an IContentFinder can return true yet set no document
|
||||
// but none of the substitued finders (see SubstituteFinder) do it.
|
||||
|
||||
// do NOT set docRequest.PublishedContent again here
|
||||
// as it would clear any template that the finder might have set
|
||||
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id);
|
||||
if (docRequest.Is404)
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Finder '{0}' set status to 404.", () => finderName);
|
||||
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => docRequest.PublishedContent.Id);
|
||||
return;
|
||||
}
|
||||
|
||||
// else it's a legacy handler, run
|
||||
|
||||
// can't find a document => exit
|
||||
if (handler.Execute(url) == false || handler.redirectID <= 0)
|
||||
return;
|
||||
|
||||
// found a document ID => ensure it's a valid document
|
||||
var redirectId = handler.redirectID;
|
||||
docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId);
|
||||
|
||||
if (docRequest.HasPublishedContent == false)
|
||||
{
|
||||
// the handler said it could handle the url, and returned a content ID
|
||||
// yet that content ID is invalid... exit.
|
||||
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId);
|
||||
return;
|
||||
}
|
||||
|
||||
// found a valid document => return
|
||||
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId);
|
||||
|
||||
if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404)
|
||||
{
|
||||
LogHelper.Debug<ContentLastChanceFinderByNotFoundHandlers>("Handler '{0}' set status code to 404.", () => handlerName);
|
||||
docRequest.Is404 = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
@@ -36,14 +39,14 @@ namespace Umbraco.Web.Routing
|
||||
return url;
|
||||
|
||||
// code from requestModule.UmbracoRewrite
|
||||
string tmp = httpContext.Request.Path.ToLower();
|
||||
var tmp = httpContext.Request.Path.ToLower();
|
||||
|
||||
// note: requestModule.UmbracoRewrite also did some stripping of &umbPage
|
||||
// from the querystring... that was in v3.x to fix some issues with pre-forms
|
||||
// auth. Paul Sterling confirmed in jan. 2013 that we can get rid of it.
|
||||
|
||||
// code from requestHandler.cleanUrl
|
||||
string root = Core.IO.SystemDirectories.Root.ToLower();
|
||||
var root = Core.IO.SystemDirectories.Root.ToLower();
|
||||
if (!string.IsNullOrEmpty(root) && tmp.StartsWith(root))
|
||||
tmp = tmp.Substring(root.Length);
|
||||
tmp = tmp.TrimEnd('/');
|
||||
@@ -55,7 +58,7 @@ namespace Umbraco.Web.Routing
|
||||
// code from UmbracoDefault.Page_PreInit
|
||||
if (tmp != "" && httpContext.Request["umbPageID"] == null)
|
||||
{
|
||||
string tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty);
|
||||
var tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty);
|
||||
int result;
|
||||
if (int.TryParse(tryIntParse, out result))
|
||||
tmp = tmp.Replace(".aspx", string.Empty);
|
||||
@@ -77,7 +80,8 @@ namespace Umbraco.Web.Routing
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static IEnumerable<Type> _customHandlerTypes;
|
||||
private static IEnumerable<Type> _customHandlerTypes;
|
||||
private static Type _customLastChanceHandlerType;
|
||||
|
||||
static void InitializeNotFoundHandlers()
|
||||
{
|
||||
@@ -87,46 +91,128 @@ namespace Umbraco.Web.Routing
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Registering custom handlers.");
|
||||
|
||||
var customHandlerTypes = new List<Type>();
|
||||
Type customHandlerType = null;
|
||||
|
||||
var customHandlers = new XmlDocument();
|
||||
customHandlers.Load(Core.IO.IOHelper.MapPath(Core.IO.SystemFiles.NotFoundhandlersConfig));
|
||||
|
||||
foreach (XmlNode n in customHandlers.DocumentElement.SelectNodes("notFound"))
|
||||
{
|
||||
if (customHandlerType != null)
|
||||
{
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Registering '{0}'.", () => customHandlerType.FullName);
|
||||
customHandlerTypes.Add(customHandlerType);
|
||||
}
|
||||
|
||||
var assemblyName = n.Attributes.GetNamedItem("assembly").Value;
|
||||
var typeName = n.Attributes.GetNamedItem("type").Value;
|
||||
|
||||
string ns = assemblyName;
|
||||
var ns = assemblyName;
|
||||
var nsAttr = n.Attributes.GetNamedItem("namespace");
|
||||
if (nsAttr != null && !string.IsNullOrWhiteSpace(nsAttr.Value))
|
||||
if (nsAttr != null && string.IsNullOrWhiteSpace(nsAttr.Value) == false)
|
||||
ns = nsAttr.Value;
|
||||
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName);
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Configured: '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName);
|
||||
|
||||
Type type = null;
|
||||
customHandlerType = null;
|
||||
try
|
||||
{
|
||||
var assembly = Assembly.Load(new AssemblyName(assemblyName));
|
||||
type = assembly.GetType(ns + "." + typeName);
|
||||
customHandlerType = assembly.GetType(ns + "." + typeName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<NotFoundHandlerHelper>("Error registering handler, ignoring.", e);
|
||||
LogHelper.Error<NotFoundHandlerHelper>("Error: could not load handler, ignoring.", e);
|
||||
}
|
||||
|
||||
if (type != null)
|
||||
customHandlerTypes.Add(type);
|
||||
}
|
||||
|
||||
_customHandlerTypes = customHandlerTypes;
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> CustomHandlerTypes
|
||||
{
|
||||
get
|
||||
// what shall we do with the last one, assuming it's not null?
|
||||
// if the last chance finder wants a handler, then use the last one as the last chance handler
|
||||
// else assume that the last one is a normal handler since noone else wants it, and add it to the list
|
||||
if (customHandlerType != null)
|
||||
{
|
||||
return _customHandlerTypes;
|
||||
var lastChanceFinder = ContentLastChanceFinderResolver.Current.Finder; // can be null
|
||||
var finderWantsHandler = lastChanceFinder != null &&
|
||||
lastChanceFinder.GetType() == typeof(ContentLastChanceFinderByNotFoundHandlers);
|
||||
|
||||
if (finderWantsHandler)
|
||||
{
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Registering '{0}' as \"last chance\" handler.", () => customHandlerType.FullName);
|
||||
_customLastChanceHandlerType = customHandlerType;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Debug<NotFoundHandlerHelper>("Registering '{0}'.", () => customHandlerType.FullName);
|
||||
customHandlerTypes.Add(customHandlerType);
|
||||
_customLastChanceHandlerType = null;
|
||||
}
|
||||
}
|
||||
|
||||
_customHandlerTypes = customHandlerTypes.ToArray();
|
||||
}
|
||||
|
||||
public static IEnumerable<INotFoundHandler> GetNotFoundHandlers()
|
||||
{
|
||||
// instanciate new handlers
|
||||
// using definition cache
|
||||
|
||||
var handlers = new List<INotFoundHandler>();
|
||||
|
||||
foreach (var type in _customHandlerTypes)
|
||||
{
|
||||
try
|
||||
{
|
||||
var handler = Activator.CreateInstance(type) as INotFoundHandler;
|
||||
if (handler != null)
|
||||
handlers.Add(handler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<ContentFinderByNotFoundHandlers>(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e);
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static bool IsNotFoundHandlerEnabled<T>()
|
||||
{
|
||||
return _customHandlerTypes.Contains(typeof (T));
|
||||
}
|
||||
|
||||
public static INotFoundHandler GetNotFoundLastChanceHandler()
|
||||
{
|
||||
if (_customLastChanceHandlerType == null) return null;
|
||||
|
||||
try
|
||||
{
|
||||
var handler = Activator.CreateInstance(_customLastChanceHandlerType) as INotFoundHandler;
|
||||
if (handler != null)
|
||||
return handler;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<ContentFinderByNotFoundHandlers>(string.Format("Error instanciating handler {0}, ignoring.", _customLastChanceHandlerType.FullName), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IContentFinder SubsituteFinder(INotFoundHandler handler)
|
||||
{
|
||||
IContentFinder finder = null;
|
||||
|
||||
if (handler is global::umbraco.SearchForAlias)
|
||||
finder = new ContentFinderByUrlAlias();
|
||||
else if (handler is global::umbraco.SearchForProfile)
|
||||
finder = new ContentFinderByProfile();
|
||||
else if (handler is global::umbraco.SearchForTemplate)
|
||||
finder = new ContentFinderByNiceUrlAndTemplate();
|
||||
else if (handler is global::umbraco.handle404)
|
||||
finder = new ContentFinderByLegacy404();
|
||||
|
||||
return finder;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,12 +140,35 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
// unless a template has been set already by the finder,
|
||||
// template should be null at that point.
|
||||
var initial = IsInitialPublishedContent;
|
||||
|
||||
// IsInternalRedirect if IsInitial, or already IsInternalRedirect
|
||||
var isInternalRedirect = IsInitialPublishedContent || IsInternalRedirectPublishedContent;
|
||||
|
||||
// redirecting to self
|
||||
if (content.Id == PublishedContent.Id) // neither can be null
|
||||
{
|
||||
// no need to set PublishedContent, we're done
|
||||
IsInternalRedirectPublishedContent = isInternalRedirect;
|
||||
return;
|
||||
}
|
||||
|
||||
// else
|
||||
|
||||
// save
|
||||
var template = _template;
|
||||
var renderingEngine = RenderingEngine;
|
||||
|
||||
// set published content - this resets the template, and sets IsInternalRedirect to false
|
||||
PublishedContent = content;
|
||||
IsInternalRedirectPublishedContent = (initial && !IsInitialPublishedContent);
|
||||
if (IsInternalRedirectPublishedContent && UmbracoSettings.For<WebRouting>().InternalRedirectPreservesTemplate)
|
||||
IsInternalRedirectPublishedContent = isInternalRedirect;
|
||||
|
||||
// must restore the template if it's an internal redirect & the config option is set
|
||||
if (isInternalRedirect && UmbracoSettings.For<WebRouting>().InternalRedirectPreservesTemplate)
|
||||
{
|
||||
// restore
|
||||
_template = template;
|
||||
RenderingEngine = renderingEngine;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -179,9 +202,11 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the current published has been obtained from the
|
||||
/// initial published content following internal redirections exclusively.
|
||||
/// Gets or sets a value indicating whether the current published content has been obtained
|
||||
/// from the initial published content following internal redirections exclusively.
|
||||
/// </summary>
|
||||
/// <remarks>Used by PublishedContentRequestEngine.FindTemplate() to figure out whether to
|
||||
/// apply the internal redirect or not, when content is not the initial content.</remarks>
|
||||
public bool IsInternalRedirectPublishedContent { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -70,15 +70,15 @@ namespace Umbraco.Web.Security
|
||||
var allowGroupsList = allowGroups as IList<string> ?? allowGroups.ToList();
|
||||
if (allowAction && allowGroupsList.Any(allowGroup => allowGroup != string.Empty))
|
||||
{
|
||||
// Allow only if member's type is in list
|
||||
// Allow only if member is assigned to a group in the list
|
||||
var groups = Roles.GetRolesForUser(member.LoginName);
|
||||
allowAction = groups.Select(s => s.ToLowerInvariant()).Intersect(groups.Select(myGroup => myGroup.ToLowerInvariant())).Any();
|
||||
allowAction = allowGroupsList.Select(s => s.ToLowerInvariant()).Intersect(groups.Select(myGroup => myGroup.ToLowerInvariant())).Any();
|
||||
}
|
||||
|
||||
// If specific members defined, check member is of one of those
|
||||
if (allowAction && allowMembers.Any())
|
||||
{
|
||||
// Allow only if member's type is in list
|
||||
// Allow only if member's Id is in the list
|
||||
allowAction = allowMembers.Contains(member.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,6 +292,7 @@
|
||||
<Compile Include="Configuration\WebRouting.cs" />
|
||||
<Compile Include="Editors\MediaController.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentSortOrder.cs" />
|
||||
<Compile Include="Routing\ContentLastChanceFinderByNotFoundHandlers.cs" />
|
||||
<Compile Include="Security\Providers\MembersMembershipProvider.cs" />
|
||||
<Compile Include="Security\Providers\UsersMembershipProvider.cs" />
|
||||
<Compile Include="Standalone\ServiceContextManager.cs" />
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Web
|
||||
/// <summary>
|
||||
/// Class that encapsulates Umbraco information of a specific HTTP request
|
||||
/// </summary>
|
||||
public class UmbracoContext : DisposableObject
|
||||
public class UmbracoContext : DisposableObject, IDisposeOnRequestEnd
|
||||
{
|
||||
private const string HttpContextItemName = "Umbraco.Web.UmbracoContext";
|
||||
private static readonly object Locker = new object();
|
||||
@@ -370,8 +370,14 @@ namespace Umbraco.Web
|
||||
_umbracoContext = null;
|
||||
//ensure not to dispose this!
|
||||
Application = null;
|
||||
ContentCache = null;
|
||||
MediaCache = null;
|
||||
|
||||
//Before we set these to null but in fact these are application lifespan singletons so
|
||||
//there's no reason we need to set them to null and this also caused a problem with packages
|
||||
//trying to access the cache properties on RequestEnd.
|
||||
//http://issues.umbraco.org/issue/U4-2734
|
||||
//http://our.umbraco.org/projects/developer-tools/301-url-tracker/version-2/44327-Issues-with-URL-Tracker-in-614
|
||||
//ContentCache = null;
|
||||
//MediaCache = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -465,10 +466,38 @@ namespace Umbraco.Web
|
||||
/// <param name="http"></param>
|
||||
private static void DisposeHttpContextItems(HttpContext http)
|
||||
{
|
||||
// do not process if client-side request
|
||||
if (http.Request.Url.IsClientSideRequest())
|
||||
return;
|
||||
|
||||
//get a list of keys to dispose
|
||||
var keys = new HashSet<object>();
|
||||
foreach (DictionaryEntry i in http.Items)
|
||||
{
|
||||
i.Value.DisposeIfDisposable();
|
||||
i.Key.DisposeIfDisposable();
|
||||
if (i.Value is IDisposeOnRequestEnd || i.Key is IDisposeOnRequestEnd)
|
||||
{
|
||||
keys.Add(i.Key);
|
||||
}
|
||||
}
|
||||
//dispose each item and key that was found as disposable.
|
||||
foreach (var k in keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
http.Items[k].DisposeIfDisposable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<UmbracoModule>("Could not dispose item with key " + k, ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
k.DisposeIfDisposable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<UmbracoModule>("Could not dispose item key " + k, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -302,23 +302,31 @@ namespace Umbraco.Web
|
||||
typeof(DefaultUrlProvider)
|
||||
);
|
||||
|
||||
// the legacy 404 will run from within ContentFinderByNotFoundHandlers below
|
||||
// so for the time being there is no last chance finder
|
||||
ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver();
|
||||
ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver(
|
||||
// handled by ContentLastChanceFinderByNotFoundHandlers for the time being
|
||||
// soon as we get rid of INotFoundHandler support, we must enable this
|
||||
//new ContentFinderByLegacy404()
|
||||
|
||||
// implement INotFoundHandler support... remove once we get rid of it
|
||||
new ContentLastChanceFinderByNotFoundHandlers());
|
||||
|
||||
ContentFinderResolver.Current = new ContentFinderResolver(
|
||||
// add all known resolvers in the correct order, devs can then modify this list
|
||||
// on application startup either by binding to events or in their own global.asax
|
||||
typeof (ContentFinderByPageIdQuery),
|
||||
typeof (ContentFinderByNiceUrl),
|
||||
typeof (ContentFinderByIdPath),
|
||||
// these will be handled by ContentFinderByNotFoundHandlers
|
||||
// so they can be enabled/disabled even though resolvers are not public yet
|
||||
//typeof (ContentFinderByNiceUrlAndTemplate),
|
||||
//typeof (ContentFinderByProfile),
|
||||
//typeof (ContentFinderByUrlAlias),
|
||||
typeof (ContentFinderByNotFoundHandlers)
|
||||
);
|
||||
// all built-in finders in the correct order, devs can then modify this list
|
||||
// on application startup via an application event handler.
|
||||
typeof (ContentFinderByPageIdQuery),
|
||||
typeof (ContentFinderByNiceUrl),
|
||||
typeof (ContentFinderByIdPath),
|
||||
|
||||
// these will be handled by ContentFinderByNotFoundHandlers so they can be enabled/disabled
|
||||
// via the config file... soon as we get rid of INotFoundHandler support, we must enable
|
||||
// them here.
|
||||
//typeof (ContentFinderByNiceUrlAndTemplate),
|
||||
//typeof (ContentFinderByProfile),
|
||||
//typeof (ContentFinderByUrlAlias),
|
||||
|
||||
// implement INotFoundHandler support... remove once we get rid of it
|
||||
typeof (ContentFinderByNotFoundHandlers)
|
||||
);
|
||||
|
||||
SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper());
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ using Umbraco.Web.Macros;
|
||||
using Umbraco.Web.Mvc;
|
||||
using umbraco;
|
||||
using umbraco.cms.businesslogic.macro;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core;
|
||||
|
||||
using Template = umbraco.cms.businesslogic.template.Template;
|
||||
|
||||
namespace Umbraco.Web.WebServices
|
||||
@@ -90,15 +92,22 @@ namespace Umbraco.Web.WebServices
|
||||
public JsonResult SaveTemplate(string templateName, string templateAlias, string templateContents, int templateId, int masterTemplateId)
|
||||
{
|
||||
Template t;
|
||||
bool pathChanged = false;
|
||||
try
|
||||
{
|
||||
t = new Template(templateId)
|
||||
{
|
||||
Text = templateName,
|
||||
Alias = templateAlias,
|
||||
MasterTemplate = masterTemplateId,
|
||||
Alias = templateAlias,
|
||||
Design = templateContents
|
||||
};
|
||||
|
||||
//check if the master page has changed
|
||||
if (t.MasterTemplate != masterTemplateId)
|
||||
{
|
||||
pathChanged = true;
|
||||
t.MasterTemplate = masterTemplateId;
|
||||
}
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
@@ -110,7 +119,17 @@ namespace Umbraco.Web.WebServices
|
||||
{
|
||||
t.Save();
|
||||
|
||||
return Success(ui.Text("speechBubbles", "templateSavedText"), ui.Text("speechBubbles", "templateSavedHeader"));
|
||||
//ensure the correct path is synced as the parent might have been changed
|
||||
// http://issues.umbraco.org/issue/U4-2300
|
||||
if (pathChanged)
|
||||
{
|
||||
//need to re-look it up
|
||||
t = new Template(templateId);
|
||||
}
|
||||
var syncPath = "-1,init," + t.Path.Replace("-1,", "");
|
||||
|
||||
return Success(ui.Text("speechBubbles", "templateSavedText"), ui.Text("speechBubbles", "templateSavedHeader"),
|
||||
new {path = syncPath});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -118,20 +137,21 @@ namespace Umbraco.Web.WebServices
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a successful message
|
||||
/// </summary>
|
||||
/// <param name="message">The message to display in the speach bubble</param>
|
||||
/// <param name="header">The header to display in the speach bubble</param>
|
||||
/// <returns></returns>
|
||||
private JsonResult Success(string message, string header)
|
||||
{
|
||||
return Json(new
|
||||
{
|
||||
success = true,
|
||||
message = message,
|
||||
header = header
|
||||
});
|
||||
/// <summary>
|
||||
/// Returns a successful message
|
||||
/// </summary>
|
||||
/// <param name="message">The message to display in the speach bubble</param>
|
||||
/// <param name="header">The header to display in the speach bubble</param>
|
||||
/// <param name="additionalVals"></param>
|
||||
/// <returns></returns>
|
||||
private JsonResult Success(string message, string header, object additionalVals = null)
|
||||
{
|
||||
var d = additionalVals == null ? new Dictionary<string, object>() : additionalVals.ToDictionary<object>();
|
||||
d["success"] = true;
|
||||
d["message"] = message;
|
||||
d["header"] = header;
|
||||
|
||||
return Json(d);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -60,7 +60,11 @@ namespace umbraco.presentation.umbraco.Search
|
||||
}
|
||||
else
|
||||
{
|
||||
var operation = criteria.Field("__nodeName", txt.MultipleCharacterWildcard());
|
||||
var words = txt.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(w => w.ToLower().MultipleCharacterWildcard()).ToList();
|
||||
var operation = criteria.GroupedOr(new[] { "__nodeName" }, new[] { words[0] });
|
||||
words.RemoveAt(0);
|
||||
foreach (var word in words)
|
||||
operation = operation.And().GroupedOr(new[] { "__nodeName" }, new[] { word });
|
||||
|
||||
// ensure the user can only find nodes they are allowed to see
|
||||
if (UmbracoContext.Current.UmbracoUser.StartNodeId > 0)
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.BasePages;
|
||||
using umbraco.BusinessLogic;
|
||||
@@ -24,14 +26,7 @@ namespace umbraco.cms.presentation.Trees
|
||||
public BaseContentTree(string application) : base(application) { }
|
||||
|
||||
private User _user;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the (legacy) Document object passed to the OnRenderNode-method
|
||||
/// should be initialized with a full set of properties.
|
||||
/// By default the Document will be initialized, so setting the boolean to True will
|
||||
/// ensure that the Document object is loaded with a minimum set of properties to
|
||||
/// improve performance.
|
||||
/// </summary>
|
||||
|
||||
protected virtual bool LoadMinimalDocument { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -73,61 +68,69 @@ function openContent(id) {
|
||||
/// Renders the specified tree item.
|
||||
/// </summary>
|
||||
/// <param name="Tree">The tree.</param>
|
||||
/*public override void Render(ref XmlTree Tree)
|
||||
{
|
||||
//get documents to render
|
||||
Document[] docs = Document.GetChildrenForTree(m_id);
|
||||
|
||||
var args = new TreeEventArgs(Tree);
|
||||
OnBeforeTreeRender(docs, args);
|
||||
|
||||
foreach (Document dd in docs)
|
||||
{
|
||||
List<IAction> allowedUserOptions = GetUserActionsForNode(dd);
|
||||
if (CanUserAccessNode(dd, allowedUserOptions))
|
||||
{
|
||||
|
||||
XmlTreeNode node = CreateNode(dd, allowedUserOptions);
|
||||
|
||||
OnRenderNode(ref node, dd);
|
||||
|
||||
OnBeforeNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
if (node != null)
|
||||
{
|
||||
Tree.Add(node);
|
||||
OnAfterNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
OnAfterTreeRender(docs, args);
|
||||
}*/
|
||||
public override void Render(ref XmlTree Tree)
|
||||
{
|
||||
//get documents to render
|
||||
var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Document).ToArray();
|
||||
|
||||
var args = new TreeEventArgs(Tree);
|
||||
OnBeforeTreeRender(entities, args, true);
|
||||
|
||||
foreach (var entity in entities)
|
||||
if (UseOptimizedRendering == false)
|
||||
{
|
||||
var e = entity as UmbracoEntity;
|
||||
List<IAction> allowedUserOptions = GetUserActionsForNode(e);
|
||||
if (CanUserAccessNode(e, allowedUserOptions))
|
||||
//We cannot run optimized mode since there are subscribers to events/methods that require document instances
|
||||
// so we'll render the original way by looking up the docs.
|
||||
|
||||
//get documents to render
|
||||
var docs = Document.GetChildrenForTree(m_id);
|
||||
|
||||
var args = new TreeEventArgs(Tree);
|
||||
OnBeforeTreeRender(docs, args);
|
||||
|
||||
foreach (var dd in docs)
|
||||
{
|
||||
XmlTreeNode node = CreateNode(e, allowedUserOptions);
|
||||
|
||||
OnRenderNode(ref node, new Document(entity, LoadMinimalDocument));
|
||||
|
||||
OnBeforeNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
if (node != null)
|
||||
var allowedUserOptions = GetUserActionsForNode(dd);
|
||||
if (CanUserAccessNode(dd, allowedUserOptions))
|
||||
{
|
||||
Tree.Add(node);
|
||||
OnAfterNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
|
||||
var node = CreateNode(dd, allowedUserOptions);
|
||||
|
||||
OnRenderNode(ref node, dd);
|
||||
|
||||
OnBeforeNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
if (node != null)
|
||||
{
|
||||
Tree.Add(node);
|
||||
OnAfterNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
OnAfterTreeRender(docs, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//We ARE running in optmized mode, this means we will NOT be raising the BeforeTreeRender or AfterTreeRender
|
||||
// events and NOT calling the OnRenderNode method - we've already detected that there are not subscribers or implementations
|
||||
// to call so that is fine.
|
||||
|
||||
var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Document).ToArray();
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
var e = entity as UmbracoEntity;
|
||||
var allowedUserOptions = GetUserActionsForNode(e);
|
||||
if (CanUserAccessNode(e, allowedUserOptions))
|
||||
{
|
||||
var node = CreateNode(e, allowedUserOptions);
|
||||
|
||||
//in optimized mode the LoadMinimalDocument will ALWAYS be true, if it is not true then we will
|
||||
// be rendering in non-optimized mode and this code will not get executed so we don't need to worry
|
||||
// about performance here.
|
||||
OnRenderNode(ref node, new Document(e, LoadMinimalDocument));
|
||||
|
||||
OnBeforeNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
if (node != null)
|
||||
{
|
||||
Tree.Add(node);
|
||||
OnAfterNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OnAfterTreeRender(entities, args, true);
|
||||
}
|
||||
|
||||
#region Tree Create-node-helper Methods - Legacy
|
||||
@@ -475,5 +478,35 @@ function openContent(id) {
|
||||
return umbraco.BusinessLogic.Actions.Action.FromString(fullMenu);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if we can use the EntityService to render the tree or revert to the original way
|
||||
/// using normal documents
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We determine this by:
|
||||
/// * If there are any subscribers to the events: BeforeTreeRender or AfterTreeRender - then we cannot run optimized
|
||||
/// * If there are any overrides of the method: OnRenderNode - then we cannot run optimized
|
||||
/// </remarks>
|
||||
internal bool UseOptimizedRendering
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasEntityBasedEventSubscribers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//now we need to check if the current tree type has OnRenderNode overridden with a custom implementation
|
||||
//Strangely - this even works in med trust!
|
||||
var method = this.GetType().GetMethod("OnRenderNode", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(XmlTreeNode).MakeByRefType(), typeof(Document) }, null);
|
||||
if (TypeHelper.IsOverride(method) && LoadMinimalDocument == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.BasePages;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core;
|
||||
using Media = umbraco.cms.businesslogic.media.Media;
|
||||
@@ -17,7 +19,6 @@ namespace umbraco.cms.presentation.Trees
|
||||
{
|
||||
public abstract class BaseMediaTree : BaseTree
|
||||
{
|
||||
private DisposableTimer _timer;
|
||||
private User _user;
|
||||
|
||||
public BaseMediaTree(string application)
|
||||
@@ -57,78 +58,109 @@ function openMedia(id) {
|
||||
}
|
||||
}
|
||||
|
||||
//Updated Render method for improved performance, but currently not usable because of backwards compatibility
|
||||
//with the OnBeforeTreeRender/OnAfterTreeRender events, which sends an array for legacy Media items.
|
||||
public override void Render(ref XmlTree tree)
|
||||
{
|
||||
//_timer = DisposableTimer.Start(x => LogHelper.Debug<BaseMediaTree>("Media tree loaded" + " (took " + x + "ms)"));
|
||||
|
||||
var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Media).ToArray();
|
||||
|
||||
var args = new TreeEventArgs(tree);
|
||||
OnBeforeTreeRender(entities, args, false);
|
||||
|
||||
foreach (UmbracoEntity entity in entities)
|
||||
if (UseOptimizedRendering == false)
|
||||
{
|
||||
XmlTreeNode xNode = XmlTreeNode.Create(this);
|
||||
xNode.NodeID = entity.Id.ToString(CultureInfo.InvariantCulture);
|
||||
xNode.Text = entity.Name;
|
||||
//We cannot run optimized mode since there are subscribers to events/methods that require document instances
|
||||
// so we'll render the original way by looking up the docs.
|
||||
|
||||
xNode.HasChildren = entity.HasChildren;
|
||||
xNode.Source = this.IsDialog ? GetTreeDialogUrl(entity.Id) : GetTreeServiceUrl(entity.Id);
|
||||
var docs = new Media(m_id).Children;
|
||||
|
||||
xNode.Icon = entity.ContentTypeIcon;
|
||||
xNode.OpenIcon = entity.ContentTypeIcon;
|
||||
|
||||
if (IsDialog == false)
|
||||
var args = new TreeEventArgs(tree);
|
||||
OnBeforeTreeRender(docs, args);
|
||||
|
||||
foreach (var dd in docs)
|
||||
{
|
||||
if(this.ShowContextMenu == false)
|
||||
xNode.Menu = null;
|
||||
xNode.Action = "javascript:openMedia(" + entity.Id + ");";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Menu = this.ShowContextMenu ? new List<IAction>(new IAction[] { ActionRefresh.Instance }) : null;
|
||||
if (this.DialogMode == TreeDialogModes.fulllink)
|
||||
var e = dd;
|
||||
var xNode = PerformNodeRender(e.Id, e.Text, e.HasChildren, e.ContentType.IconUrl, e.ContentType.Alias, () => GetLinkValue(e, e.Id.ToString(CultureInfo.InvariantCulture)));
|
||||
|
||||
|
||||
OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
if (xNode != null)
|
||||
{
|
||||
string nodeLink = GetLinkValue(entity);
|
||||
if (string.IsNullOrEmpty(nodeLink) == false)
|
||||
{
|
||||
xNode.Action = "javascript:openMedia('" + nodeLink + "');";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.Equals(entity.ContentTypeAlias, Constants.Conventions.MediaTypes.Folder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
//#U4-2254 - Inspiration to use void from here: http://stackoverflow.com/questions/4924383/jquery-object-object-error
|
||||
xNode.Action = "javascript:void jQuery('.umbTree #" + entity.Id.ToString(CultureInfo.InvariantCulture) + "').click();";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Action = null;
|
||||
xNode.Style.DimNode();
|
||||
}
|
||||
}
|
||||
tree.Add(xNode);
|
||||
OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
OnAfterTreeRender(docs, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
//We ARE running in optmized mode, this means we will NOT be raising the BeforeTreeRender or AfterTreeRender
|
||||
// events - we've already detected that there are not subscribers or implementations
|
||||
// to call so that is fine.
|
||||
|
||||
var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Media).ToArray();
|
||||
|
||||
foreach (UmbracoEntity entity in entities)
|
||||
{
|
||||
var e = entity;
|
||||
var xNode = PerformNodeRender(e.Id, entity.Name, e.HasChildren, e.ContentTypeIcon, e.ContentTypeAlias, () => GetLinkValue(e));
|
||||
|
||||
OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
if (xNode != null)
|
||||
{
|
||||
tree.Add(xNode);
|
||||
OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private XmlTreeNode PerformNodeRender(int nodeId, string nodeName, bool hasChildren, string icon, string contentTypeAlias, Func<string> getLinkValue)
|
||||
{
|
||||
var xNode = XmlTreeNode.Create(this);
|
||||
xNode.NodeID = nodeId.ToString(CultureInfo.InvariantCulture);
|
||||
xNode.Text = nodeName;
|
||||
|
||||
xNode.HasChildren = hasChildren;
|
||||
xNode.Source = this.IsDialog ? GetTreeDialogUrl(nodeId) : GetTreeServiceUrl(nodeId);
|
||||
|
||||
xNode.Icon = icon;
|
||||
xNode.OpenIcon = icon;
|
||||
|
||||
if (IsDialog == false)
|
||||
{
|
||||
if (this.ShowContextMenu == false)
|
||||
xNode.Menu = null;
|
||||
xNode.Action = "javascript:openMedia(" + nodeId + ");";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Menu = this.ShowContextMenu ? new List<IAction>(new IAction[] { ActionRefresh.Instance }) : null;
|
||||
if (this.DialogMode == TreeDialogModes.fulllink)
|
||||
{
|
||||
string nodeLink = getLinkValue();
|
||||
if (string.IsNullOrEmpty(nodeLink) == false)
|
||||
{
|
||||
xNode.Action = "javascript:openMedia('" + nodeLink + "');";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Action = "javascript:openMedia('" + entity.Id.ToString(CultureInfo.InvariantCulture) + "');";
|
||||
if (string.Equals(contentTypeAlias, Constants.Conventions.MediaTypes.Folder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
//#U4-2254 - Inspiration to use void from here: http://stackoverflow.com/questions/4924383/jquery-object-object-error
|
||||
xNode.Action = "javascript:void jQuery('.umbTree #" + nodeId.ToString(CultureInfo.InvariantCulture) + "').click();";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Action = null;
|
||||
xNode.Style.DimNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
if (xNode != null)
|
||||
else
|
||||
{
|
||||
tree.Add(xNode);
|
||||
OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
xNode.Action = "javascript:openMedia('" + nodeId.ToString(CultureInfo.InvariantCulture) + "');";
|
||||
}
|
||||
}
|
||||
|
||||
//stop the timer and log the output
|
||||
//_timer.Dispose();
|
||||
|
||||
OnAfterTreeRender(entities, args, false);
|
||||
return xNode;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value for a link in WYSIWYG mode, by default only media items that have a
|
||||
@@ -183,5 +215,26 @@ function openMedia(id) {
|
||||
/// </summary>
|
||||
public static List<Guid> LinkableMediaDataTypes { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if we can use the EntityService to render the tree or revert to the original way
|
||||
/// using normal documents
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We determine this by:
|
||||
/// * If there are any subscribers to the events: BeforeTreeRender or AfterTreeRender - then we cannot run optimized
|
||||
/// </remarks>
|
||||
internal bool UseOptimizedRendering
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasEntityBasedEventSubscribers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,6 +527,7 @@ namespace umbraco.cms.presentation.Trees
|
||||
AfterTreeRender(sender, e);
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method to raise events, it is no longer used and will cause very high performance spikes!")]
|
||||
protected internal virtual void OnBeforeTreeRender(IEnumerable<IUmbracoEntity> sender, TreeEventArgs e, bool isContent)
|
||||
{
|
||||
if (BeforeTreeRender != null)
|
||||
@@ -542,6 +543,7 @@ namespace umbraco.cms.presentation.Trees
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method to raise events, it is no longer used and will cause very high performance spikes!")]
|
||||
protected internal virtual void OnAfterTreeRender(IEnumerable<IUmbracoEntity> sender, TreeEventArgs e, bool isContent)
|
||||
{
|
||||
if (AfterTreeRender != null)
|
||||
@@ -557,6 +559,14 @@ namespace umbraco.cms.presentation.Trees
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if there are subscribers to either BeforeTreeRender or AfterTreeRender
|
||||
/// </summary>
|
||||
internal bool HasEntityBasedEventSubscribers
|
||||
{
|
||||
get { return BeforeTreeRender != null || AfterTreeRender != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that is raised once actions are assigned to nodes
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using umbraco.businesslogic;
|
||||
using umbraco.cms.businesslogic;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using umbraco.businesslogic;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core;
|
||||
using Action = umbraco.BusinessLogic.Actions.Action;
|
||||
|
||||
namespace umbraco
|
||||
{
|
||||
|
||||
@@ -94,8 +94,7 @@ namespace umbraco
|
||||
{
|
||||
//write out the template header
|
||||
sw.Write("@inherits ");
|
||||
sw.Write(typeof(UmbracoViewPage<>).FullName.TrimEnd("`1"));
|
||||
sw.Write("<dynamic>");
|
||||
sw.Write(typeof(UmbracoTemplatePage).FullName.TrimEnd("`1"));
|
||||
}
|
||||
|
||||
public bool Delete()
|
||||
|
||||
@@ -272,11 +272,15 @@ namespace umbraco.dialogs
|
||||
{
|
||||
if (CurrentApp == Constants.Applications.Content)
|
||||
{
|
||||
Services.ContentService.Move((IContent)currContent, Request.GetItemAs<int>("copyTo"), getUser().Id);
|
||||
//Backwards comp. change, so old events are fired #U4-2731
|
||||
var doc = new Document(currContent as IContent);
|
||||
doc.Move(Request.GetItemAs<int>("copyTo"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Services.MediaService.Move((IMedia)currContent, Request.GetItemAs<int>("copyTo"), getUser().Id);
|
||||
//Backwards comp. change, so old events are fired #U4-2731
|
||||
var media = new umbraco.cms.businesslogic.media.Media(currContent as IMedia);
|
||||
media.Move(Request.GetItemAs<int>("copyTo"));
|
||||
library.ClearLibraryCacheForMedia(currContent.Id);
|
||||
}
|
||||
|
||||
@@ -290,7 +294,9 @@ namespace umbraco.dialogs
|
||||
{
|
||||
//NOTE: We ONLY support Copy on content not media for some reason.
|
||||
|
||||
var newContent = Services.ContentService.Copy((IContent)currContent, Request.GetItemAs<int>("copyTo"), RelateDocuments.Checked, getUser().Id);
|
||||
//Backwards comp. change, so old events are fired #U4-2731
|
||||
var newContent = new Document(currContent as IContent);
|
||||
newContent.Copy(Request.GetItemAs<int>("copyTo"), getUser(), RelateDocuments.Checked);
|
||||
|
||||
feedback.Text = ui.Text("moveOrCopy", "copyDone", nodes, getUser()) + "</p><p><a href='#' onclick='" + ClientTools.Scripts.CloseModalWindow() + "'>" + ui.Text("closeThisWindow") + "</a>";
|
||||
feedback.type = uicontrols.Feedback.feedbacktype.success;
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace umbraco.cms.presentation.members
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
setupExtraEditorControls();
|
||||
|
||||
return handled;
|
||||
}
|
||||
private void setupExtraEditorControls(){
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Xml;
|
||||
using Umbraco.Core.Logging;
|
||||
using umbraco.BasePages;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.businesslogic.Exceptions;
|
||||
using umbraco.cms.businesslogic.media;
|
||||
using umbraco.cms.businesslogic.propertytype;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
@@ -64,20 +65,27 @@ namespace umbraco.cms.presentation.user
|
||||
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
//if the current user is not an admin they cannot edit a user at all
|
||||
if (CurrentUser.IsAdmin() == false)
|
||||
{
|
||||
throw new UserAuthorizationException("Access denied");
|
||||
}
|
||||
|
||||
int UID = int.Parse(Request.QueryString["id"]);
|
||||
u = BusinessLogic.User.GetUser(UID);
|
||||
|
||||
// do initial check for edit rights
|
||||
//the true admin can only edit the true admin
|
||||
if (u.Id == 0 && CurrentUser.Id != 0)
|
||||
{
|
||||
throw new Exception("Only the root user can edit the 'root' user (id:0)");
|
||||
}
|
||||
else if (u.IsAdmin() && !CurrentUser.IsAdmin())
|
||||
|
||||
//only another admin can edit another admin (who is not the true admin)
|
||||
if (u.IsAdmin() && CurrentUser.IsAdmin() == false)
|
||||
{
|
||||
throw new Exception("Admin users can only be edited by admins");
|
||||
}
|
||||
|
||||
|
||||
// check if canvas editing is enabled
|
||||
DefaultToLiveEditing.Visible = UmbracoSettings.EnableCanvasEditing;
|
||||
|
||||
@@ -351,6 +359,8 @@ namespace umbraco.cms.presentation.user
|
||||
|
||||
protected override void OnInit(EventArgs e)
|
||||
{
|
||||
base.OnInit(e);
|
||||
|
||||
//lapps.SelectionMode = ListSelectionMode.Multiple;
|
||||
lapps.RepeatLayout = RepeatLayout.Flow;
|
||||
lapps.RepeatDirection = RepeatDirection.Vertical;
|
||||
|
||||
@@ -89,13 +89,24 @@ namespace umbraco.webservices
|
||||
{
|
||||
//NOTE: The legacy code threw an exception so will continue to do that.
|
||||
AuthorizeRequest(DefaultApps.settings.ToString(), true);
|
||||
|
||||
var templateFile =
|
||||
System.IO.File.OpenText(IOHelper.MapPath(SystemDirectories.Umbraco + "/scripting/templates/cshtml/" + templateId));
|
||||
var content = templateFile.ReadToEnd();
|
||||
templateFile.Close();
|
||||
|
||||
return content;
|
||||
var snippetPath = SystemDirectories.Umbraco + "/scripting/templates/cshtml/";
|
||||
var filePath = IOHelper.MapPath(snippetPath + templateId);
|
||||
|
||||
//Directory check.. only allow files in script dir and below to be edited
|
||||
if (filePath.StartsWith(IOHelper.MapPath(snippetPath)))
|
||||
{
|
||||
var templateFile =
|
||||
System.IO.File.OpenText(filePath);
|
||||
var content = templateFile.ReadToEnd();
|
||||
templateFile.Close();
|
||||
return content;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Couldn't open snippet - Illegal path");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,6 +65,17 @@ namespace umbraco.cms.businesslogic.datatype
|
||||
/// <param name="strDbType"></param>
|
||||
void IDataValueSetter.SetValue(object val, string strDbType)
|
||||
{
|
||||
//We need to ensure that val is not a null value, if it is then we'll convert this to an empty string.
|
||||
//The reason for this is because by default the DefaultData.Value property returns an empty string when
|
||||
// there is no value, this is based on the PropertyDataDto.GetValue return value which defaults to an
|
||||
// empty string (which is called from this class's method LoadValueFromDatabase).
|
||||
//Some legacy implementations of DefaultData are expecting an empty string when there is
|
||||
// no value so we need to keep this consistent.
|
||||
if (val == null)
|
||||
{
|
||||
val = string.Empty;
|
||||
}
|
||||
|
||||
_value = val;
|
||||
//now that we've set our value, we can update our BaseDataType object with the correct values from the db
|
||||
//instead of making it query for itself. This is a peformance optimization enhancement.
|
||||
|
||||
@@ -11,10 +11,17 @@ namespace umbraco.editorControls.datepicker
|
||||
|
||||
public override System.Xml.XmlNode ToXMl(System.Xml.XmlDocument d)
|
||||
{
|
||||
if (Value != null && Value.ToString() != "")
|
||||
return d.CreateTextNode(((DateTime) Value).ToString("s"));
|
||||
else
|
||||
return d.CreateTextNode("");
|
||||
if (Value != null && Value.ToString() != "")
|
||||
{
|
||||
if(Value is DateTime)
|
||||
return d.CreateTextNode(((DateTime) Value).ToString("s"));
|
||||
|
||||
DateTime convertedDate;
|
||||
if (DateTime.TryParse(Value.ToString(), out convertedDate))
|
||||
return d.CreateTextNode(convertedDate.ToString("s"));
|
||||
}
|
||||
|
||||
return d.CreateTextNode("");
|
||||
}
|
||||
|
||||
public override void MakeNew(int PropertyId)
|
||||
|
||||
@@ -8,14 +8,14 @@ namespace umbraco.editorControls.imagecropper
|
||||
|
||||
public override XmlNode ToXMl(XmlDocument data)
|
||||
{
|
||||
if (Value.ToString() != "") {
|
||||
XmlDocument xd = new XmlDocument();
|
||||
if (Value != null && Value.ToString() != "")
|
||||
{
|
||||
var xd = new XmlDocument();
|
||||
xd.LoadXml(Value.ToString());
|
||||
return data.ImportNode(xd.DocumentElement, true);
|
||||
} else {
|
||||
return base.ToXMl(data);
|
||||
}
|
||||
|
||||
return base.ToXMl(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user