Compare commits

...

18 Commits

Author SHA1 Message Date
Sebastiaan Janssen 173ac65eb5 Remove misleading comment as this has been moved out of the if statement 2013-09-02 11:41:13 +02:00
Sebastiaan Janssen 7c28e1aeba Fixed U4-2763 Content rollback generates duplicates 2013-09-02 10:56:42 +02:00
Shannon 5989d19f7f Re-fixes the issue with using IDataValueSetter.SetValue on the DefaultData implementation and ensures that when there is a null value that it reverts to an empty string since this was what the default value was in the Value getter of DefaultData when there was no value. Have added a couple unit tests to support. 2013-09-02 13:27:48 +10:00
Shannon da1c33a034 Fixes unit test 2013-09-02 12:57:56 +10:00
Sebastiaan Janssen 2111a5e31e Fix MySQL install failing on UmbracoServer table 2013-09-01 17:28:22 +02:00
Sebastiaan Janssen 5478de911b Merge pull request #115 from stocksr/6.2.0
U4-516 - Fix DatePicker with time default value
2013-09-01 17:24:03 +02:00
Sebastiaan Janssen 7765acb130 Merge pull request #124 from AndyButland/wip-u4-2759
U4-2759 - member authorise attribute was not restricting for group
2013-09-01 17:23:53 +02:00
Morten Christensen 5640daff32 Fixes U4-2752 ContentService.DeleteVersion and DeleteVersions fail
Signed-off-by: Sebastiaan Janssen <sebastiaan@umbraco.com>
2013-08-31 19:19:25 +02:00
Morten Christensen a1cae3f286 Fixes U4-2731 Document.BeforeMove + Document.AfterMove Doesn't get fired.
Using the legacy Document and Media classes for the .Move and .Copy calls as they already use the new services under the hood, so shouldn't make any noticeable difference except that the legacy events will also work.

Signed-off-by: Sebastiaan Janssen <sebastiaan@umbraco.com>
2013-08-31 19:18:47 +02:00
Shannon d22dbb4654 Fixes U4-2734 Don't set the cache references to null when disposing the UmbracoContext 2013-08-31 11:11:25 +02:00
Stephan 4d5a8298b0 U4-2549 - fix it differently 2013-08-30 12:22:58 +02:00
Stephan 9e2733ce69 U4-2549 - fix issue with last chance content finder
Conflicts:
	src/Umbraco.Web/Umbraco.Web.csproj

Conflicts:
	src/Umbraco.Web/Umbraco.Web.csproj
2013-08-30 12:22:36 +02:00
Sebastiaan Janssen fbfdd8d398 Bump version number 2013-08-30 12:00:33 +02:00
Stephan 2552dffdad U4-2691 - fix issue with alt template and internal redirects 2013-08-30 11:59:28 +02:00
Sebastiaan Janssen 52540165f1 Creating a partial view now inherits from UmbracoTemplatePage (in 6.2.0 there will be 2 snippets, one for UmbracoViewPage<dynamic>, for MVC experts and one for UmbracoTemplatePage, the default). 2013-08-30 11:47:39 +02:00
Shannon 2b408df24c Fixes: U4-2727 PluginManager's TypeList can contain duplicates - updates the locks to be upgradeable read locks, changes over all lists/collecitons to be HashSet<T> this ensures no duplicates and also improves performance. 2013-08-30 10:51:06 +02:00
Shannon d559411187 Fixes U4-2300 6.1.0: Changing a template's parent causes tree to collapse 2013-08-30 10:45:13 +02:00
Sebastiaan Janssen 3a4a6579d3 Fixes: U4-2711 DAMP throws unknown exception on image upload with image cropper 2013-08-30 10:40:29 +02:00
29 changed files with 926 additions and 544 deletions
+3
View File
@@ -81,3 +81,6 @@ build/_BuildOutput/
tools/NDepend/
src/*.vspx
src/*.psess
NDependOut/*
QueryResult.htm
*.ndproj
+1 -1
View File
@@ -1,5 +1,5 @@
@ECHO OFF
SET release=6.1.4
SET release=6.1.5
SET comment=
SET version=%release%
@@ -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.5");
/// <summary>
/// Gets the current version of Umbraco.
@@ -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())
{
+367 -342
View File
@@ -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
}
}
}
@@ -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);
}
}
}
@@ -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");
+2 -2
View File
@@ -2602,9 +2602,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>6140</DevelopmentServerPort>
<DevelopmentServerPort>6150</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:6140</IISUrl>
<IISUrl>http://localhost:6150</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -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()%>,
@@ -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
+16 -5
View File
@@ -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
}
}
+106 -20
View File
@@ -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>
+3 -3
View File
@@ -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);
}
}
+1
View File
@@ -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" />
+8 -2
View File
@@ -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;
}
}
}
+23 -15
View File
@@ -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>
@@ -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;
@@ -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.
@@ -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);
}
}
}