diff --git a/.gitignore b/.gitignore index 848fce32ff..a7f7bec4ca 100644 --- a/.gitignore +++ b/.gitignore @@ -91,3 +91,6 @@ src/Umbraco.Web.UI/App_Plugins/* src/*.psess src/*.vspx src/Umbraco.Web.UI/umbraco/js/routes.js.* +NDependOut/* +*.ndproj +QueryResult.htm diff --git a/src/Umbraco.Core/DictionaryExtensions.cs b/src/Umbraco.Core/DictionaryExtensions.cs index 73866f2c9b..de12e0b3b1 100644 --- a/src/Umbraco.Core/DictionaryExtensions.cs +++ b/src/Umbraco.Core/DictionaryExtensions.cs @@ -187,6 +187,25 @@ namespace Umbraco.Core return String.Empty; } + /// + /// Returns the value of the key value based on the key as it's string value, if the key is not found or is an empty string, then the provided default value is returned + /// + /// + /// + /// + /// + public static string GetValueAsString(this IDictionary d, TKey key, string defaultValue) + { + if (d.ContainsKey(key)) + { + var value = d[key].ToString(); + if (value != string.Empty) + return value; + } + + return defaultValue; + } + /// contains key ignore case. /// The dictionary. /// The key. diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index b50102396a..a2963343e3 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -146,7 +146,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial private void CreateUmbracoUserTypeData() { - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F" }); + _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F7" }); _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 2, Alias = "writer", Name = "Writer", DefaultPermissions = "CAH:F" }); _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 3, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5F" }); _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 4, Alias = "translator", Name = "Translator", DefaultPermissions = "AF" }); diff --git a/src/Umbraco.Core/PublishedContentHelper.cs b/src/Umbraco.Core/PublishedContentHelper.cs index 1e7fc1ef18..86513ede02 100644 --- a/src/Umbraco.Core/PublishedContentHelper.cs +++ b/src/Umbraco.Core/PublishedContentHelper.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Xml.Linq; using Umbraco.Core.Configuration; using Umbraco.Core.Dynamics; +using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -35,7 +36,7 @@ namespace Umbraco.Core /// internal static Func GetDataTypeCallback = null; - private static readonly ConcurrentDictionary, Guid> PropertyTypeCache = new ConcurrentDictionary, Guid>(); + private static readonly ConcurrentDictionary, Guid> PropertyTypeCache = new ConcurrentDictionary, Guid>(); /// /// Return the GUID Id for the data type assigned to the document type with the property alias @@ -43,16 +44,29 @@ namespace Umbraco.Core /// /// /// + /// /// - internal static Guid GetDataType(ApplicationContext applicationContext, string docTypeAlias, string propertyAlias) + internal static Guid GetDataType(ApplicationContext applicationContext, string docTypeAlias, string propertyAlias, PublishedItemType itemType) { if (GetDataTypeCallback != null) return GetDataTypeCallback(docTypeAlias, propertyAlias); - var key = new Tuple(docTypeAlias, propertyAlias); + var key = new Tuple(docTypeAlias, propertyAlias, itemType); return PropertyTypeCache.GetOrAdd(key, tuple => { - var result = applicationContext.Services.ContentTypeService.GetContentType(docTypeAlias); + IContentTypeComposition result = null; + switch (itemType) + { + case PublishedItemType.Content: + result = applicationContext.Services.ContentTypeService.GetContentType(docTypeAlias); + break; + case PublishedItemType.Media: + result = applicationContext.Services.ContentTypeService.GetMediaType(docTypeAlias); + break; + default: + throw new ArgumentOutOfRangeException("itemType"); + } + if (result == null) return Guid.Empty; //SD: we need to check for 'any' here because the collection is backed by KeyValuePair which is a struct diff --git a/src/Umbraco.Core/TypeFinder.cs b/src/Umbraco.Core/TypeFinder.cs index e327b3df00..9a1478ff38 100644 --- a/src/Umbraco.Core/TypeFinder.cs +++ b/src/Umbraco.Core/TypeFinder.cs @@ -19,54 +19,56 @@ using Umbraco.Core.IO; namespace Umbraco.Core { - /// - /// A utility class to find all classes of a certain type by reflection in the current bin folder - /// of the web application. - /// - public static class TypeFinder - { - - private static readonly ConcurrentBag LocalFilteredAssemblyCache = new ConcurrentBag(); - private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim(); - private static ReadOnlyCollection _allAssemblies = null; - private static ReadOnlyCollection _binFolderAssemblies = null; - private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); + /// + /// A utility class to find all classes of a certain type by reflection in the current bin folder + /// of the web application. + /// + public static class TypeFinder + { + private static readonly HashSet LocalFilteredAssemblyCache = new HashSet(); + private static readonly ReaderWriterLockSlim LocalFilteredAssemblyCacheLocker = new ReaderWriterLockSlim(); + private static HashSet _allAssemblies = null; + private static HashSet _binFolderAssemblies = null; + private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); - /// - /// 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 - /// - /// - /// 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 - /// - internal static IEnumerable GetAllAssemblies() - { - if (_allAssemblies == null) - { - using (new WriteLock(Locker)) - { - List assemblies = null; - try - { - var isHosted = HttpContext.Current != null; + /// + /// 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 + /// + /// + /// 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 + /// + internal static HashSet GetAllAssemblies() + { + using (var lck = new UpgradeableReadLock(Locker)) + { + if (_allAssemblies == null) + { - try - { - if (isHosted) - { - assemblies = new List(BuildManager.GetReferencedAssemblies().Cast()); - } - } - catch (InvalidOperationException e) - { - if (!(e.InnerException is SecurityException)) - throw; - } + lck.UpgradeToWriteLock(); + + HashSet assemblies = null; + try + { + var isHosted = HttpContext.Current != null; + + try + { + if (isHosted) + { + assemblies = new HashSet(BuildManager.GetReferencedAssemblies().Cast()); + } + } + 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(); + assemblies = new HashSet(); 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(assemblies); + //now set the _allAssemblies + _allAssemblies = new HashSet(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; - } - - /// - /// Returns only assemblies found in the bin folder that have been loaded into the app domain. - /// - /// - /// - /// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used. - /// - internal static IEnumerable 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(); - var binFolderAssemblies = new List(); + /// + /// Returns only assemblies found in the bin folder that have been loaded into the app domain. + /// + /// + /// + /// This will be used if we implement App_Plugins from Umbraco v5 but currently it is not used. + /// + internal static HashSet 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(); + var binFolderAssemblies = new HashSet(); - 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(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. + } + } - /// - /// 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. - /// - /// - /// - internal static IEnumerable GetAssembliesWithKnownExclusions( - IEnumerable 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(binFolderAssemblies); + } + } + return _binFolderAssemblies; + } - /// - /// Return a list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter - /// - /// - /// - /// - private static IEnumerable GetFilteredAssemblies( - IEnumerable excludeFromResults = null, - string[] exclusionFilter = null) - { - if (excludeFromResults == null) - excludeFromResults = new List(); - if (exclusionFilter == null) - exclusionFilter = new string[] { }; + /// + /// 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. + /// + /// + /// + internal static HashSet GetAssembliesWithKnownExclusions( + IEnumerable 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(); - /// - /// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins - /// - /// - /// 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 - /// - internal static readonly string[] KnownAssemblyExclusionFilter = new[] + var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter); + foreach (var a in assemblies) + { + LocalFilteredAssemblyCache.Add(a); + } + + return LocalFilteredAssemblyCache; + } + } + + /// + /// Return a distinct list of found local Assemblies and exluding the ones passed in and excluding the exclusion list filter + /// + /// + /// + /// + private static IEnumerable GetFilteredAssemblies( + IEnumerable excludeFromResults = null, + string[] exclusionFilter = null) + { + if (excludeFromResults == null) + excludeFromResults = new HashSet(); + if (exclusionFilter == null) + exclusionFilter = new string[] { }; + + return GetAllAssemblies() + .Where(x => !excludeFromResults.Contains(x) + && !x.GlobalAssemblyCache + && !exclusionFilter.Any(f => x.FullName.StartsWith(f))); + } + + /// + /// this is our assembly filter to filter out known types that def dont contain types we'd like to find or plugins + /// + /// + /// 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 + /// + internal static readonly string[] KnownAssemblyExclusionFilter = new[] { "mscorlib,", "System.", @@ -287,11 +299,11 @@ namespace Umbraco.Core /// /// /// - public static IEnumerable FindClassesOfTypeWithAttribute() - where TAttribute : Attribute - { - return FindClassesOfTypeWithAttribute(GetAssembliesWithKnownExclusions(), true); - } + public static IEnumerable FindClassesOfTypeWithAttribute() + where TAttribute : Attribute + { + return FindClassesOfTypeWithAttribute(GetAssembliesWithKnownExclusions(), true); + } /// /// Finds any classes derived from the type T that contain the attribute TAttribute @@ -300,11 +312,11 @@ namespace Umbraco.Core /// /// /// - public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies) - where TAttribute : Attribute - { - return FindClassesOfTypeWithAttribute(assemblies, true); - } + public static IEnumerable FindClassesOfTypeWithAttribute(IEnumerable assemblies) + where TAttribute : Attribute + { + return FindClassesOfTypeWithAttribute(assemblies, true); + } /// /// Finds any classes derived from the type T that contain the attribute TAttribute @@ -314,13 +326,13 @@ namespace Umbraco.Core /// /// /// - public static IEnumerable FindClassesOfTypeWithAttribute( - IEnumerable assemblies, - bool onlyConcreteClasses) - where TAttribute : Attribute - { - return FindClassesOfTypeWithAttribute(typeof (T), assemblies, onlyConcreteClasses); - } + public static IEnumerable FindClassesOfTypeWithAttribute( + IEnumerable assemblies, + bool onlyConcreteClasses) + where TAttribute : Attribute + { + return FindClassesOfTypeWithAttribute(typeof(T), assemblies, onlyConcreteClasses); + } /// /// Finds any classes derived from the assignTypeFrom Type that contain the attribute TAttribute @@ -330,85 +342,85 @@ namespace Umbraco.Core /// /// /// - public static IEnumerable FindClassesOfTypeWithAttribute( - Type assignTypeFrom, - IEnumerable assemblies, + public static IEnumerable FindClassesOfTypeWithAttribute( + Type assignTypeFrom, + IEnumerable 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(false).Any()); - } + t => t.GetCustomAttributes(false).Any()); + } - /// - /// Searches all filtered local assemblies specified for classes of the type passed in. - /// - /// - /// - public static IEnumerable FindClassesOfType() - { - return FindClassesOfType(GetAssembliesWithKnownExclusions(), true); - } + /// + /// Searches all filtered local assemblies specified for classes of the type passed in. + /// + /// + /// + public static IEnumerable FindClassesOfType() + { + return FindClassesOfType(GetAssembliesWithKnownExclusions(), true); + } - /// - /// Returns all types found of in the assemblies specified of type T - /// - /// - /// - /// - /// - public static IEnumerable FindClassesOfType(IEnumerable assemblies, bool onlyConcreteClasses) - { - if (assemblies == null) throw new ArgumentNullException("assemblies"); + /// + /// Returns all types found of in the assemblies specified of type T + /// + /// + /// + /// + /// + public static IEnumerable FindClassesOfType(IEnumerable assemblies, bool onlyConcreteClasses) + { + if (assemblies == null) throw new ArgumentNullException("assemblies"); return GetClasses(typeof(T), assemblies, onlyConcreteClasses); - } + } - /// - /// Returns all types found of in the assemblies specified of type T - /// - /// - /// - /// - public static IEnumerable FindClassesOfType(IEnumerable assemblies) - { - return FindClassesOfType(assemblies, true); - } + /// + /// Returns all types found of in the assemblies specified of type T + /// + /// + /// + /// + public static IEnumerable FindClassesOfType(IEnumerable assemblies) + { + return FindClassesOfType(assemblies, true); + } - /// - /// Finds the classes with attribute. - /// - /// - /// The assemblies. - /// if set to true only concrete classes. - /// - public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses) - where T : Attribute - { - return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses); - } + /// + /// Finds the classes with attribute. + /// + /// + /// The assemblies. + /// if set to true only concrete classes. + /// + public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies, bool onlyConcreteClasses) + where T : Attribute + { + return FindClassesWithAttribute(typeof(T), assemblies, onlyConcreteClasses); + } - /// - /// Finds any classes with the attribute. - /// - /// The attribute type - /// The assemblies. - /// if set to true only concrete classes. - /// - public static IEnumerable FindClassesWithAttribute( - Type attributeType, - IEnumerable assemblies, - bool onlyConcreteClasses) - { - if (assemblies == null) throw new ArgumentNullException("assemblies"); + /// + /// Finds any classes with the attribute. + /// + /// The attribute type + /// The assemblies. + /// if set to true only concrete classes. + /// + public static IEnumerable FindClassesWithAttribute( + Type attributeType, + IEnumerable assemblies, + bool onlyConcreteClasses) + { + if (assemblies == null) throw new ArgumentNullException("assemblies"); - if (TypeHelper.IsTypeAssignableFrom(attributeType) == false) - throw new ArgumentException("The type specified: " + attributeType + " is not an Attribute type"); + if (TypeHelper.IsTypeAssignableFrom(attributeType) == false) + throw new ArgumentException("The type specified: " + attributeType + " is not an Attribute type"); - var foundAssignableTypes = new List(); + var foundAssignableTypes = new HashSet(); 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; + } - /// - /// Finds the classes with attribute. - /// - /// - /// The assemblies. - /// - public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies) - where T : Attribute - { - return FindClassesWithAttribute(assemblies, true); - } + /// + /// Finds the classes with attribute. + /// + /// + /// The assemblies. + /// + public static IEnumerable FindClassesWithAttribute(IEnumerable assemblies) + where T : Attribute + { + return FindClassesWithAttribute(assemblies, true); + } - /// - /// Finds the classes with attribute in filtered local assemblies - /// - /// - /// - public static IEnumerable FindClassesWithAttribute() - where T : Attribute - { - return FindClassesWithAttribute(GetAssembliesWithKnownExclusions()); - } + /// + /// Finds the classes with attribute in filtered local assemblies + /// + /// + /// + public static IEnumerable FindClassesWithAttribute() + where T : Attribute + { + return FindClassesWithAttribute(GetAssembliesWithKnownExclusions()); + } - #region Private methods - - /// - /// 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. - /// - /// - /// - /// - /// An additional filter to apply for what types will actually be included in the return value - /// - private static IEnumerable GetClasses( - Type assignTypeFrom, - IEnumerable assemblies, + #region Private methods + + /// + /// 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. + /// + /// + /// + /// + /// An additional filter to apply for what types will actually be included in the return value + /// + private static IEnumerable GetClasses( + Type assignTypeFrom, + IEnumerable assemblies, bool onlyConcreteClasses, Func additionalFilter = null) - { + { //the default filter will always return true. if (additionalFilter == null) { additionalFilter = type => true; } - var foundAssignableTypes = new List(); + var foundAssignableTypes = new HashSet(); 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,55 +547,62 @@ 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(); + var subTypesToSearch = new HashSet(); 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 GetTypesWithFormattedException(Assembly a) - { - //if the assembly is dynamic, do not try to scan it - if (a.IsDynamic) - return Enumerable.Empty(); + private static IEnumerable GetTypesWithFormattedException(Assembly a) + { + //if the assembly is dynamic, do not try to scan it + if (a.IsDynamic) + return Enumerable.Empty(); - try - { + try + { //return a.GetExportedTypes(); return a.GetTypes(); - } - 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()); - } - } + } + 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 - - } + + } } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 2086b9b5d0..efa50075bf 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; +using System.Web; using System.Xml.Linq; using System.Xml.XPath; using Examine; @@ -16,6 +17,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.UmbracoExamine; using Umbraco.Web; using Umbraco.Web.PublishedCache; @@ -68,6 +70,38 @@ namespace Umbraco.Tests.PublishedContent return GetNode(id, GetUmbracoContext("/test", 1234)); } + [Test] + public void Get_Property_Value_Uses_Converter() + { + var mType = MockedContentTypes.CreateImageMediaType(); + //lets add an RTE to this + mType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType(new Guid(), DataTypeDatabaseType.Nvarchar) + { + Alias = "content", + Name = "Rich Text", + DataTypeDefinitionId = -87 //tiny mce + }); + ServiceContext.ContentTypeService.Save(mType); + var media = MockedMedia.CreateMediaImage(mType, -1); + media.Properties["content"].Value = "
This is some content
"; + ServiceContext.MediaService.Save(media); + + var publishedMedia = GetNode(media.Id); + + var propVal = publishedMedia.GetPropertyValue("content"); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(propVal.GetType())); + Assert.AreEqual("
This is some content
", propVal.ToString()); + + var propVal2 = publishedMedia.GetPropertyValue("content"); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(propVal2.GetType())); + Assert.AreEqual("
This is some content
", propVal2.ToString()); + + var propVal3 = publishedMedia.GetPropertyValue("Content"); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(propVal3.GetType())); + Assert.AreEqual("
This is some content
", propVal3.ToString()); + } + [Test] public void Ensure_Children_Sorted_With_Examine() { @@ -339,7 +373,6 @@ namespace Umbraco.Tests.PublishedContent Assert.AreEqual(mChild1.Id, publishedSubChild1.Parent.Id); } - [Test] public void Ancestors_Without_Examine() { diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index fd6d008c03..7765380db3 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2163,6 +2163,8 @@ + + diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EditProfile.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EditProfile.cshtml new file mode 100644 index 0000000000..27457c2f7e --- /dev/null +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EditProfile.cshtml @@ -0,0 +1,52 @@ +@inherits Umbraco.Web.Macros.PartialViewMacroPage + +@using System.Web.Mvc.Html +@using ClientDependency.Core.Mvc +@using umbraco.cms.businesslogic.member +@using Umbraco.Web +@using Umbraco.Web.Models +@using Umbraco.Web.Controllers + +@{ + var profileModel = new ProfileModel(); + + Html.EnableClientValidation(); + Html.EnableUnobtrusiveJavaScript(); + Html.RequiresJs("/umbraco_client/ui/jquery.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); +} + +@if (Member.IsLoggedOn()) +{ + @Html.RenderJsHere() + + using (Html.BeginUmbracoForm("HandleUpdateProfile")) + { +
+ Edit profile + + @Html.LabelFor(m => profileModel.Name) + @Html.TextBoxFor(m => profileModel.Name) + @Html.ValidationMessageFor(m => profileModel.Name) +
+ + @Html.LabelFor(m => profileModel.Email) + @Html.TextBoxFor(m => profileModel.Email) + @Html.ValidationMessageFor(m => profileModel.Email) +
+ + @for (var i = 0; i < profileModel.MemberProperties.Count; i++) + { + @Html.LabelFor(m => profileModel.MemberProperties[i].Value, profileModel.MemberProperties[i].Name) + @Html.EditorFor(m => profileModel.MemberProperties[i].Value) + @Html.HiddenFor(m => profileModel.MemberProperties[i].Alias) +
+ } + + @Html.HiddenFor(m => profileModel.MemberTypeAlias) + + +
+ } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml index f8e40a5677..dda3a17f51 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EmptyTemplate.cshtml @@ -1 +1 @@ -@using Umbraco.Web.Macros.PartialViewMacroPage \ No newline at end of file +@inherits Umbraco.Web.Macros.PartialViewMacroPage \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml index 032a3c4283..5eb4529001 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml @@ -2,24 +2,21 @@ @using System.Web.Mvc.Html @using ClientDependency.Core.Mvc -@using Umbraco.Web.UmbracoModels -@using Umbraco.Web.UmbracoControllers +@using Umbraco.Web +@using Umbraco.Web.Models +@using Umbraco.Web.Controllers @{ + var loginModel = new LoginModel(); + Html.EnableClientValidation(); Html.EnableUnobtrusiveJavaScript(); - - // TODO: CDF doesn't work at the moment, Shannon is looking at it - //Html.RequiresJs("/umbraco_client/ui/jquery.js"); - //Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); - //Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); - - var loginModel = new LoginModel(); + Html.RequiresJs("/umbraco_client/ui/jquery.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); } - - - +@Html.RenderJsHere() @using (Html.BeginUmbracoForm("HandleLogin")) { diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml new file mode 100644 index 0000000000..d889c67391 --- /dev/null +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml @@ -0,0 +1,30 @@ +@inherits Umbraco.Web.Macros.PartialViewMacroPage +@using ClientDependency.Core.Mvc +@using Umbraco.Web +@using Umbraco.Web.Models +@using Umbraco.Web.Controllers + +@{ + var loginStatusModel = new LoginStatusModel(); + + Html.EnableClientValidation(); + Html.EnableUnobtrusiveJavaScript(); + Html.RequiresJs("/umbraco_client/ui/jquery.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); +} + +@Html.RenderJsHere() + +@if (loginStatusModel.IsLoggedIn) +{ +

You are currently logged in as @loginStatusModel.Name

+ + using (Html.BeginUmbracoForm("HandleLogout")) + { +
+ Logout + +
+ } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml index 46422928a6..6574c56690 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml @@ -2,53 +2,32 @@ @using System.Web.Mvc.Html @using ClientDependency.Core.Mvc -@using umbraco.cms.businesslogic.member -@using Umbraco.Web.UmbracoModels -@using Umbraco.Web.UmbracoControllers +@using Umbraco.Web +@using Umbraco.Web.Models +@using Umbraco.Web.Controllers @{ + var registerModel = new RegisterModel(); + Html.EnableClientValidation(); Html.EnableUnobtrusiveJavaScript(); - - // TODO: CDF doesn't work at the moment, Shannon is looking at it - //Html.RequiresJs("/umbraco_client/ui/jquery.js"); - //Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); - //Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); - - // TODO: Make a helper for this - var memberTypeAlias = "UmbracoMember"; - if (Model.MacroParameters.Any() && Model.MacroParameters.ContainsKey("memberTypeAlias")) - { - var alias = Model.MacroParameters["memberTypeAlias"]; - if (string.IsNullOrWhiteSpace(alias.ToString()) == false) - { - memberTypeAlias = alias.ToString(); - } - } - - var registerModel = new RegisterModel - { - MemberProperties = new List(), - MemberTypeAlias = memberTypeAlias - }; - - // TODO: Fill model somewhere else - var memberType = MemberType.GetByAlias(registerModel.MemberTypeAlias); - foreach (var prop in memberType.PropertyTypes.Where(memberType.MemberCanEdit)) - { - registerModel.MemberProperties.Add(new UmbracoProperty {Alias = prop.Alias, Name = prop.Name, Value = string.Empty}); - } + Html.RequiresJs("/umbraco_client/ui/jquery.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); } - - - +@Html.RenderJsHere() @using (Html.BeginUmbracoForm("HandleRegisterMember")) {
Register Member + @Html.LabelFor(m => registerModel.Name) + @Html.TextBoxFor(m => registerModel.Name) + @Html.ValidationMessageFor(m => registerModel.Name) +
+ @Html.LabelFor(m => registerModel.Email) @Html.TextBoxFor(m => registerModel.Email) @Html.ValidationMessageFor(m => registerModel.Email) @@ -59,14 +38,16 @@ @Html.ValidationMessageFor(m => registerModel.Password)
- @for (var i = 0; i < registerModel.MemberProperties.Count; i++) - { - @Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name) - @Html.EditorFor(m => registerModel.MemberProperties[i].Value) - @Html.HiddenFor(m => registerModel.MemberProperties[i].Alias) -
+ @if (registerModel.MemberProperties != null) { + for (var i = 0; i < registerModel.MemberProperties.Count; i++) + { + @Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name) + @Html.EditorFor(m => registerModel.MemberProperties[i].Value) + @Html.HiddenFor(m => registerModel.MemberProperties[i].Alias) +
+ } } - + @Html.HiddenFor(m => registerModel.MemberTypeAlias) diff --git a/src/Umbraco.Web.UI/config/404handlers.Release.config b/src/Umbraco.Web.UI/config/404handlers.Release.config index 11bdbaf8ef..770f7ca64b 100644 --- a/src/Umbraco.Web.UI/config/404handlers.Release.config +++ b/src/Umbraco.Web.UI/config/404handlers.Release.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/config/404handlers.config b/src/Umbraco.Web.UI/config/404handlers.config index 69bf6f1dd0..b6dd88fa8b 100644 --- a/src/Umbraco.Web.UI/config/404handlers.config +++ b/src/Umbraco.Web.UI/config/404handlers.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Web/UmbracoControllers/LoginController.cs b/src/Umbraco.Web/Controllers/LoginController.cs similarity index 90% rename from src/Umbraco.Web/UmbracoControllers/LoginController.cs rename to src/Umbraco.Web/Controllers/LoginController.cs index 0b58073c70..df6675dfd8 100644 --- a/src/Umbraco.Web/UmbracoControllers/LoginController.cs +++ b/src/Umbraco.Web/Controllers/LoginController.cs @@ -1,10 +1,10 @@ using System.Linq; using System.Web.Mvc; using umbraco.cms.businesslogic.member; +using Umbraco.Web.Models; using Umbraco.Web.Mvc; -using Umbraco.Web.UmbracoModels; -namespace Umbraco.Web.UmbracoControllers +namespace Umbraco.Web.Controllers { public class LoginController : SurfaceController { diff --git a/src/Umbraco.Web/Controllers/LoginStatusController.cs b/src/Umbraco.Web/Controllers/LoginStatusController.cs new file mode 100644 index 0000000000..4dbe5836db --- /dev/null +++ b/src/Umbraco.Web/Controllers/LoginStatusController.cs @@ -0,0 +1,34 @@ +using System.Linq; +using System.Web.Mvc; +using umbraco.cms.businesslogic.member; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; + +namespace Umbraco.Web.Controllers +{ + public class LoginStatusController : SurfaceController + { + [HttpPost] + public ActionResult HandleLogout([Bind(Prefix = "loginStatusModel")]LoginStatusModel model) + { + // TODO: Use new Member API + if (ModelState.IsValid) + { + if (Member.IsLoggedOn()) + { + var member = Member.GetCurrentMember(); + if (member != null) + { + var memberId = member.Id; + Member.RemoveMemberFromCache(memberId); + Member.ClearMemberFromClient(memberId); + } + } + + return Redirect("/"); + } + + return CurrentUmbracoPage(); + } + } +} diff --git a/src/Umbraco.Web/Controllers/ProfileController.cs b/src/Umbraco.Web/Controllers/ProfileController.cs new file mode 100644 index 0000000000..cfa2d387ca --- /dev/null +++ b/src/Umbraco.Web/Controllers/ProfileController.cs @@ -0,0 +1,50 @@ +using System.Linq; +using System.Web.Mvc; +using System.Xml; +using umbraco.cms.businesslogic.member; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; + +namespace Umbraco.Web.Controllers +{ + public class ProfileController : SurfaceController + { + [HttpPost] + public ActionResult HandleUpdateProfile([Bind(Prefix="profileModel")]ProfileModel model) + { + //TODO: Use new Member API + if (ModelState.IsValid) + { + var member = Member.GetCurrentMember(); + if (member != null) + { + if (model.Name != null) + { + member.Text = model.Name; + } + + member.Email = model.Email; + member.LoginName = model.Email; + + if (model.MemberProperties != null) + { + foreach (var property in model.MemberProperties.Where(p => p.Value != null)) + { + member.getProperty(property.Alias).Value = property.Value; + } + } + + member.Save(); + + member.XmlGenerate(new XmlDocument()); + + Member.AddMemberToCache(member); + + Response.Redirect("/"); + } + } + + return CurrentUmbracoPage(); + } + } +} diff --git a/src/Umbraco.Web/UmbracoControllers/RegisterController.cs b/src/Umbraco.Web/Controllers/RegisterController.cs similarity index 70% rename from src/Umbraco.Web/UmbracoControllers/RegisterController.cs rename to src/Umbraco.Web/Controllers/RegisterController.cs index e3b9e66d3b..ef9c8d9e03 100644 --- a/src/Umbraco.Web/UmbracoControllers/RegisterController.cs +++ b/src/Umbraco.Web/Controllers/RegisterController.cs @@ -3,10 +3,10 @@ using System.Web.Mvc; using System.Xml; using umbraco.BusinessLogic; using umbraco.cms.businesslogic.member; +using Umbraco.Web.Models; using Umbraco.Web.Mvc; -using Umbraco.Web.UmbracoModels; -namespace Umbraco.Web.UmbracoControllers +namespace Umbraco.Web.Controllers { public class RegisterController : SurfaceController { @@ -21,13 +21,22 @@ namespace Umbraco.Web.UmbracoControllers var mt = MemberType.GetByAlias(model.MemberTypeAlias) ?? MemberType.MakeNew(user, model.MemberTypeAlias); var member = Member.MakeNew(model.Email, mt, user); + + if (model.Name != null) + { + member.Text = model.Name; + } + member.Email = model.Email; member.LoginName = model.Email; member.Password = model.Password; - foreach (var property in model.MemberProperties) + if (model.MemberProperties != null) { - member.getProperty(property.Alias).Value = property.Value; + foreach (var property in model.MemberProperties.Where(p => p.Value != null)) + { + member.getProperty(property.Alias).Value = property.Value; + } } member.Save(); diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs index 35f2040410..3ff0732f99 100644 --- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs +++ b/src/Umbraco.Web/Models/DynamicPublishedContent.cs @@ -236,10 +236,11 @@ namespace Umbraco.Web.Models } //get the data type id for the current property - var dataType = Umbraco.Core.PublishedContentHelper.GetDataType( + var dataType = PublishedContentHelper.GetDataType( ApplicationContext.Current, userProperty.DocumentTypeAlias, - userProperty.Alias); + userProperty.Alias, + ItemType); //convert the string value to a known type var converted = Umbraco.Core.PublishedContentHelper.ConvertPropertyValue(result, dataType, userProperty.DocumentTypeAlias, userProperty.Alias); diff --git a/src/Umbraco.Web/UmbracoModels/LoginModel.cs b/src/Umbraco.Web/Models/LoginModel.cs similarity index 80% rename from src/Umbraco.Web/UmbracoModels/LoginModel.cs rename to src/Umbraco.Web/Models/LoginModel.cs index 4cd627e490..f0cea26b0e 100644 --- a/src/Umbraco.Web/UmbracoModels/LoginModel.cs +++ b/src/Umbraco.Web/Models/LoginModel.cs @@ -1,7 +1,6 @@ using System.ComponentModel.DataAnnotations; -using System.Linq; -namespace Umbraco.Web.UmbracoModels +namespace Umbraco.Web.Models { public class LoginModel { diff --git a/src/Umbraco.Web/Models/LoginStatusModel.cs b/src/Umbraco.Web/Models/LoginStatusModel.cs new file mode 100644 index 0000000000..9be7602541 --- /dev/null +++ b/src/Umbraco.Web/Models/LoginStatusModel.cs @@ -0,0 +1,28 @@ +using umbraco.cms.businesslogic.member; + +namespace Umbraco.Web.Models +{ + public class LoginStatusModel + { + public LoginStatusModel() + { + //TODO Use new Member API + if (Member.IsLoggedOn()) + { + var member = Member.GetCurrentMember(); + if (member != null) + { + this.Name = member.Text; + this.Username = member.LoginName; + this.Email = member.Email; + this.IsLoggedIn = true; + } + } + } + + public string Name { get; set; } + public string Username { get; set; } + public string Email { get; set; } + public bool IsLoggedIn { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ProfileModel.cs b/src/Umbraco.Web/Models/ProfileModel.cs new file mode 100644 index 0000000000..437a53972c --- /dev/null +++ b/src/Umbraco.Web/Models/ProfileModel.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using umbraco.cms.businesslogic.member; + +namespace Umbraco.Web.Models +{ + public class ProfileModel + { + public ProfileModel() + { + if (Member.IsLoggedOn()) + { + //TODO Use new Member API + var member = Member.GetCurrentMember(); + if (member != null) + { + this.Name = member.Text; + + this.Email = member.Email; + + this.MemberProperties = new List(); + + var memberType = MemberType.GetByAlias(member.ContentType.Alias); + var memberTypeProperties = memberType.PropertyTypes.ToList(); + + if (memberTypeProperties.Where(memberType.MemberCanEdit).Any()) + { + memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList(); + } + + foreach (var prop in memberTypeProperties) + { + + var value = string.Empty; + var propValue = member.getProperty(prop.Alias); + if (propValue != null) + { + value = propValue.Value.ToString(); + } + + this.MemberProperties.Add(new UmbracoProperty + { + Alias = prop.Alias, + Name = prop.Name, + Value = value + }); + } + } + } + } + + [Required] + [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", + ErrorMessage = "Please enter a valid e-mail address")] + public string Email { get; set; } + + public string Name { get; set; } + + public string MemberTypeAlias { get; set; } + + public List MemberProperties { get; set; } + } +} diff --git a/src/Umbraco.Web/Models/RegisterModel.cs b/src/Umbraco.Web/Models/RegisterModel.cs new file mode 100644 index 0000000000..be3c314ebe --- /dev/null +++ b/src/Umbraco.Web/Models/RegisterModel.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using umbraco.cms.businesslogic.member; + +namespace Umbraco.Web.Models +{ + public class RegisterModel + { + public RegisterModel() + { + this.MemberTypeAlias = "UmbracoMember"; + + var memberType = MemberType.GetByAlias(this.MemberTypeAlias); + + if (memberType != null) + { + this.MemberProperties = new List(); + + var memberTypeProperties = memberType.PropertyTypes.ToList(); + + if (memberTypeProperties.Where(memberType.MemberCanEdit).Any()) + { + memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList(); + } + + foreach (var prop in memberTypeProperties) + { + this.MemberProperties.Add(new UmbracoProperty + { + Alias = prop.Alias, + Name = prop.Name, + Value = string.Empty + }); + } + } + } + + [Required] + [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", + ErrorMessage = "Please enter a valid e-mail address")] + public string Email { get; set; } + + [Required] + public string Password { get; set; } + + public string Name { get; set; } + + public string MemberTypeAlias { get; set; } + + public List MemberProperties { get; set; } + } +} diff --git a/src/Umbraco.Web/Mvc/UmbracoPageResult.cs b/src/Umbraco.Web/Mvc/UmbracoPageResult.cs index db0f352645..fa009a9c46 100644 --- a/src/Umbraco.Web/Mvc/UmbracoPageResult.cs +++ b/src/Umbraco.Web/Mvc/UmbracoPageResult.cs @@ -34,8 +34,13 @@ namespace Umbraco.Web.Mvc //ensure TempData and ViewData is copied across foreach (var d in context.Controller.ViewData) routeDef.Controller.ViewData[d.Key] = d.Value; - routeDef.Controller.TempData = context.Controller.TempData; + //We cannot simply merge the temp data because during controller execution it will attempt to 'load' temp data + // but since it has not been saved, there will be nothing to load and it will revert to nothing, so the trick is + // to Save the state of the temp data first then it will automatically be picked up. + // http://issues.umbraco.org/issue/U4-1339 + context.Controller.TempData.Save(context, ((Controller)context.Controller).TempDataProvider); + using (DisposableTimer.TraceDuration("Executing Umbraco RouteDefinition controller", "Finished")) { try diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index a6655c55ce..29d7e1f22c 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -153,7 +153,10 @@ namespace Umbraco.Web //Here we need to put the value through the IPropertyEditorValueConverter's //get the data type id for the current property - var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, doc.DocumentTypeAlias, alias); + var dataType = PublishedContentHelper.GetDataType( + ApplicationContext.Current, doc.DocumentTypeAlias, alias, + doc.ItemType); + //convert the string value to a known type var converted = PublishedContentHelper.ConvertPropertyValue(p.Value, dataType, doc.DocumentTypeAlias, alias); return converted.Success @@ -188,7 +191,7 @@ namespace Umbraco.Web //before we try to convert it manually, lets see if the PropertyEditorValueConverter does this for us //Here we need to put the value through the IPropertyEditorValueConverter's //get the data type id for the current property - var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, prop.DocumentTypeAlias, alias); + var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, prop.DocumentTypeAlias, alias, prop.ItemType); //convert the value to a known type var converted = PublishedContentHelper.ConvertPropertyValue(p.Value, dataType, prop.DocumentTypeAlias, alias); object parsedLinksVal; diff --git a/src/Umbraco.Web/Routing/AliasUrlProvider.cs b/src/Umbraco.Web/Routing/AliasUrlProvider.cs index f8e270a16c..d8846afd60 100644 --- a/src/Umbraco.Web/Routing/AliasUrlProvider.cs +++ b/src/Umbraco.Web/Routing/AliasUrlProvider.cs @@ -88,14 +88,25 @@ namespace Umbraco.Web.Routing #region Utilities - private bool FindByUrlAliasEnabled + private static bool FindByUrlAliasEnabled { get { - var hasFinder = ContentFinderResolver.Current.ContainsType(); - var hasHandler = ContentFinderResolver.Current.ContainsType() - && NotFoundHandlerHelper.CustomHandlerTypes.Contains(typeof(global::umbraco.SearchForAlias)); - return hasFinder || hasHandler; + // finder + if (ContentFinderResolver.Current.ContainsType()) + return true; + + // handler wrapped into a finder + if (ContentFinderResolver.Current.ContainsType>()) + return true; + + // handler wrapped into special finder + if (ContentFinderResolver.Current.ContainsType() + && NotFoundHandlerHelper.IsNotFoundHandlerEnabled()) + return true; + + // anything else, we can't detect + return false; } } diff --git a/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs b/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs index 6c10a45dd7..cb80429167 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs @@ -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("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("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("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("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id); - if (docRequest.Is404) - LogHelper.Debug("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("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId); - break; - } + LogHelper.Debug("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id); + if (docRequest.Is404) + LogHelper.Debug("Finder '{0}' set status to 404.", () => finderName); - LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId); - - if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404) - { - LogHelper.Debug("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("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("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("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId); + + if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404) + { + LogHelper.Debug("Handler '{0}' set status code to 404.", () => handlerName); + docRequest.Is404 = true; + } + + break; } } - IEnumerable GetNotFoundHandlers() - { - // instanciate new handlers - // using definition cache - - var handlers = new List(); - - 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(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e); - } - } - - return handlers; - } - #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Web/Routing/ContentLastChanceFinderByNotFoundHandlers.cs b/src/Umbraco.Web/Routing/ContentLastChanceFinderByNotFoundHandlers.cs new file mode 100644 index 0000000000..115e8cabc0 --- /dev/null +++ b/src/Umbraco.Web/Routing/ContentLastChanceFinderByNotFoundHandlers.cs @@ -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 +{ + /// + /// Provides an implementation of that runs legacy INotFoundHandler in "last chance" situation. + /// + 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. + + /// + /// Tries to find and assign an Umbraco document to a PublishedContentRequest. + /// + /// The PublishedContentRequest. + /// A value indicating whether an Umbraco document was found and assigned. + 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("Running for legacy url='{0}'.", () => url); + + var handler = NotFoundHandlerHelper.GetNotFoundLastChanceHandler(); + var handlerName = handler.GetType().FullName; + LogHelper.Debug("Handler '{0}'.", () => handlerName); + + var finder = NotFoundHandlerHelper.SubsituteFinder(handler); + if (finder != null) + { + var finderName = finder.GetType().FullName; + LogHelper.Debug("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("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id); + if (docRequest.Is404) + LogHelper.Debug("Finder '{0}' set status to 404.", () => finderName); + + LogHelper.Debug("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("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId); + return; + } + + // found a valid document => return + + LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId); + + if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404) + { + LogHelper.Debug("Handler '{0}' set status code to 404.", () => handlerName); + docRequest.Is404 = true; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs index 4287b215d3..36d4a55bc9 100644 --- a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs +++ b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs @@ -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 _customHandlerTypes; + private static IEnumerable _customHandlerTypes; + private static Type _customLastChanceHandlerType; static void InitializeNotFoundHandlers() { @@ -87,6 +91,8 @@ namespace Umbraco.Web.Routing LogHelper.Debug("Registering custom handlers."); var customHandlerTypes = new List(); + Type customLastChanceHandlerType = null; + var hasLast = false; var customHandlers = new XmlDocument(); customHandlers.Load(Core.IO.IOHelper.MapPath(Core.IO.SystemFiles.NotFoundhandlersConfig)); @@ -96,12 +102,23 @@ namespace Umbraco.Web.Routing 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("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName); + var lcAttr = n.Attributes.GetNamedItem("last"); + var last = lcAttr != null && lcAttr.Value != null && lcAttr.Value.InvariantEquals("true"); + + if (last) // there can only be one last chance handler in the config file + { + if (hasLast) + throw new Exception(); + hasLast = true; + } + + LogHelper.Debug("Registering '{0}.{1},{2}'{3}", () => ns, () => typeName, () => assemblyName, + () => last ? " (last)." : "."); Type type = null; try @@ -114,19 +131,79 @@ namespace Umbraco.Web.Routing LogHelper.Error("Error registering handler, ignoring.", e); } - if (type != null) + if (type == null) continue; + + if (last) + _customLastChanceHandlerType = type; + else customHandlerTypes.Add(type); } - _customHandlerTypes = customHandlerTypes; + _customHandlerTypes = customHandlerTypes.ToArray(); } - public static IEnumerable CustomHandlerTypes + public static IEnumerable GetNotFoundHandlers() { - get + // instanciate new handlers + // using definition cache + + var handlers = new List(); + + foreach (var type in _customHandlerTypes) { - return _customHandlerTypes; + try + { + var handler = Activator.CreateInstance(type) as INotFoundHandler; + if (handler != null) + handlers.Add(handler); + } + catch (Exception e) + { + LogHelper.Error(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e); + } } + + return handlers; } + + public static bool IsNotFoundHandlerEnabled() + { + 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(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; + } + } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c4435b86f1..21ec6579eb 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -298,6 +298,8 @@ + + @@ -343,9 +345,12 @@ - - - + + + + + + @@ -530,7 +535,8 @@ ASPXCodeBehind - + + diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 5db0d8bfd0..a0d2dbf39d 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -445,8 +445,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; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/UmbracoModels/RegisterModel.cs b/src/Umbraco.Web/UmbracoModels/RegisterModel.cs deleted file mode 100644 index 498b68db90..0000000000 --- a/src/Umbraco.Web/UmbracoModels/RegisterModel.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; - -namespace Umbraco.Web.UmbracoModels -{ - public class RegisterModel - { - [Required] - [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", - ErrorMessage = "Please enter a valid e-mail address")] - public string Email { get; set; } - - [Required] - public string Password { get; set; } - - public string MemberTypeAlias { get; set; } - - public List MemberProperties { get; set; } - } - - public class UmbracoProperty - { - public string Alias { get; set; } - public string Value { get; set; } - public string Name { get; set; } - } -} diff --git a/src/Umbraco.Web/UmbracoProperty.cs b/src/Umbraco.Web/UmbracoProperty.cs new file mode 100644 index 0000000000..4e7f17953e --- /dev/null +++ b/src/Umbraco.Web/UmbracoProperty.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Web +{ + public class UmbracoProperty + { + public string Alias { get; set; } + public string Value { get; set; } + public string Name { get; set; } + } +} diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 549491a0e3..0b63d0ab80 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -313,23 +313,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()); diff --git a/src/umbraco.editorControls/imagecropper/DataTypeData.cs b/src/umbraco.editorControls/imagecropper/DataTypeData.cs index 7c667aaa24..9c68edb04d 100644 --- a/src/umbraco.editorControls/imagecropper/DataTypeData.cs +++ b/src/umbraco.editorControls/imagecropper/DataTypeData.cs @@ -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); } } } \ No newline at end of file