Compare commits
197 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31767a4152 | |||
| d79134c710 | |||
| 2ed4948619 | |||
| 0e67c787a8 | |||
| ebfb2b536f | |||
| 81010444f3 | |||
| bbbc1949bc | |||
| 7b34e59222 | |||
| 3706405bff | |||
| 8a0efd7790 | |||
| bd2ac3d128 | |||
| c25b710b80 | |||
| 09e060ff92 | |||
| 2248a85876 | |||
| a3f4b2db5d | |||
| 5947f01590 | |||
| 75a006ca87 | |||
| cee5880501 | |||
| f65002ea16 | |||
| bd1bfa416c | |||
| 317f96a1bd | |||
| a42d6b954f | |||
| 71b8674664 | |||
| 9e3ca51286 | |||
| 0e6f2b542e | |||
| 218f523022 | |||
| 50c6fb036a | |||
| bc2115ff0a | |||
| 9eee5c2bc0 | |||
| 038163421b | |||
| 7ce58f6e5f | |||
| c6470decb2 | |||
| 8a28639331 | |||
| 65b2b7cb82 | |||
| 2daf71aee4 | |||
| 339edb2295 | |||
| e117b764fb | |||
| ed3096642d | |||
| d51082f651 | |||
| f2fb275b34 | |||
| 95508c4fb7 | |||
| 4677faff38 | |||
| c5f388f6bc | |||
| 4419af427b | |||
| dbdee5fc2c | |||
| 725b3c5eca | |||
| 25f5179b29 | |||
| bf6d084f82 | |||
| 1a03bd9624 | |||
| 6a1d60c5a7 | |||
| 4fef17190f | |||
| 08ca75bb35 | |||
| 143b9c605b | |||
| d76a0271e9 | |||
| 5deb483b94 | |||
| db809f30fe | |||
| dcb50d10c4 | |||
| a409b8b0f7 | |||
| 0512eaa7fd | |||
| a91a67ed8d | |||
| e8df5f9eb4 | |||
| af1257d4ae | |||
| 1f3e568a0d | |||
| c46678c766 | |||
| cb539e82d0 | |||
| 1432d602ba | |||
| 841d2a7010 | |||
| 7cdb48b6c9 | |||
| a667058422 | |||
| 4ffa6bb41b | |||
| 77af16db55 | |||
| 2a44b73056 | |||
| 85d85fa587 | |||
| bd27ed739d | |||
| 3938868115 | |||
| 140792430f | |||
| c04cf1fe2e | |||
| d1d83c84a0 | |||
| 98acc50e13 | |||
| 1a0a02463e | |||
| 96c499a47e | |||
| f7e8aefeab | |||
| dfa803293f | |||
| 7ade64f855 | |||
| 346e8dcaf0 | |||
| ddfd07bf4a | |||
| a9fe46da0c | |||
| aca1f0d186 | |||
| 9eb415d398 | |||
| 8f6b728534 | |||
| 2e0c09ab39 | |||
| f211344786 | |||
| f8764cdd20 | |||
| 1d17bfd59a | |||
| 98ad6ad366 | |||
| 68702b98f5 | |||
| f93caf277b | |||
| 32db674397 | |||
| e0a7698780 | |||
| 783c74d3ba | |||
| 96d7bc3898 | |||
| 21963c03a2 | |||
| a2a9794fdb | |||
| 879a132077 | |||
| 9650d314c6 | |||
| fcc0c452bb | |||
| 606ebcae92 | |||
| af10ae9e34 | |||
| a23c150738 | |||
| 085a678266 | |||
| c73fb6144b | |||
| bfd201efcc | |||
| 5a2b4f031b | |||
| cf7cafeb4c | |||
| 870657affa | |||
| fe11d4770d | |||
| ac75d8148d | |||
| 4a32cddf08 | |||
| 7461e7c55b | |||
| c8fe9030c7 | |||
| 2ae236e98d | |||
| 802fb95784 | |||
| 0297fdb32f | |||
| 5bede4bf9f | |||
| d37106576d | |||
| ed0f0f7942 | |||
| 3d81c73495 | |||
| e7a540e717 | |||
| bb886c237e | |||
| 6c1e271fa8 | |||
| 4c1b807e4f | |||
| 3b22c0cdd7 | |||
| 31d8f49d3b | |||
| 631404743f | |||
| 1e154e8bc9 | |||
| d5c9639170 | |||
| b90cccbfff | |||
| 94b7c36d62 | |||
| 22f0641c54 | |||
| e465a937c5 | |||
| d2164bc94d | |||
| df9d09725b | |||
| 1ffdd1abd1 | |||
| a06de1b165 | |||
| 0a56f46b12 | |||
| 972f9b3546 | |||
| 0fd3af6828 | |||
| fafb207799 | |||
| b1aea424e8 | |||
| 3598acaddc | |||
| 8e03a1ffca | |||
| ded8afa8fc | |||
| dcd2b1eb6b | |||
| c04ef47be3 | |||
| 62f3c87e8a | |||
| 1b9776ecfb | |||
| 28ab176466 | |||
| 3f3db006e7 | |||
| 7801cdf9ff | |||
| de9c5b88ab | |||
| 77981f889f | |||
| 0a132ed5ed | |||
| 27ee192c8f | |||
| dfa58183c6 | |||
| e8668f3ed4 | |||
| c84e3dac38 | |||
| 72ab51ea60 | |||
| 1bfb63fe86 | |||
| 2cf68ab263 | |||
| 215bc64a83 | |||
| 73f0b1992d | |||
| 21f54dd4ff | |||
| a5903ec419 | |||
| a9c7a7a405 | |||
| ce8286dadd | |||
| 532b177d2e | |||
| 504aac0350 | |||
| fd0cb7da23 | |||
| 4093fd9b79 | |||
| 3d6f91cbef | |||
| fffd508bb2 | |||
| 333b35d8b9 | |||
| 890673a197 | |||
| 6344ad28aa | |||
| eadc3c8c5a | |||
| 27539d4aad | |||
| f7f23015d0 | |||
| e432b7061d | |||
| fc92d40b3a | |||
| 5027757760 | |||
| d4d040d9ec | |||
| 4f1b76f5ff | |||
| 3b3eda5bfc | |||
| becc07c2bd | |||
| 5841377431 | |||
| 5d69ec2391 | |||
| 9f9b4d2e84 |
@@ -33,7 +33,7 @@
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[9.0.1, 10.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.81, 1.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.82, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.5.2, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.8.2, 5.0.0)" />
|
||||
<dependency id="semver" version="[2.0.4, 3.0.0)" />
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[9.0.1, 10.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.5, 4.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.6, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.0, 3.0.0)" />
|
||||
</dependencies>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<httpRuntime xdt:Transform="InsertIfMissing" />
|
||||
<httpRuntime maxRequestLength="51200" fcnMode="Single" xdt:Transform="SetAttributes(fcnMode,maxRequestLength)" />
|
||||
<httpRuntime targetFramework="4.5" xdt:Locator="Condition(count(@targetFramework) != 1)" xdt:Transform="SetAttributes(targetFramework)" />
|
||||
|
||||
|
||||
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
|
||||
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>
|
||||
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>>
|
||||
@@ -337,7 +337,7 @@
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.9.0" newVersion="1.4.9.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.9.5" newVersion="1.4.9.5" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="AutoMapper" publicKeyToken="be96cd2c38ef1005" culture="neutral" />
|
||||
|
||||
@@ -34,10 +34,15 @@
|
||||
xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="templates" title="Templates" type="Umbraco.Web.Trees.TemplatesTreeController, umbraco" iconClosed="icon-folder" iconOpen="icon-folder-open" sortOrder="1"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
<add application="settings" alias="partialViews" title="Partial Views" silent="false" initialize="true" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.PartialViewsTree, umbraco" sortOrder="2"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
xdt:Transform="SetAttributes()" />
|
||||
|
||||
<add application="settings" alias="partialViews" type="Umbraco.Web.Trees.PartialViewsTree, umbraco"
|
||||
xdt:Locator="Match(application,alias,type)"
|
||||
xdt:Transform="Remove()" />
|
||||
<add application="settings" alias="partialViews" title="Partial Views" silent="false" initialize="true" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.PartialViewsTreeController, umbraco" sortOrder="2"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="InsertIfMissing" />
|
||||
|
||||
<add application="settings" alias="scripts" title="Scripts" type="umbraco.loadScripts, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
@@ -84,9 +89,14 @@
|
||||
<add application="developer" alias="xslt" title="XSLT Files" type="umbraco.loadXslt, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="5"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
<add application="developer" alias="partialViewMacros" type="Umbraco.Web.Trees.PartialViewMacrosTree, umbraco" silent="false" initialize="true" sortOrder="6" title="Partial View Macro Files" iconClosed="icon-folder" iconOpen="icon-folder"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
|
||||
<add application="developer" alias="partialViewMacros" type="Umbraco.Web.Trees.PartialViewMacrosTree, umbraco"
|
||||
xdt:Locator="Match(application,alias,type)"
|
||||
xdt:Transform="Remove()" />
|
||||
<add application="developer" alias="partialViewMacros" type="Umbraco.Web.Trees.PartialViewMacrosTreeController, umbraco" silent="false" initialize="true" sortOrder="6" title="Partial View Macro Files" iconClosed="icon-folder" iconOpen="icon-folder"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="InsertIfMissing" />
|
||||
|
||||
<add application="developer" alias="python"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="Remove" />
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.0
|
||||
beta03
|
||||
RC
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-beta03")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-RC")]
|
||||
@@ -17,9 +17,12 @@ namespace Umbraco.Core
|
||||
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
|
||||
}
|
||||
|
||||
private static readonly Regex Log4NetAssemblyPattern = new Regex("log4net, Version=([\\d\\.]+?), Culture=neutral, PublicKeyToken=null", RegexOptions.Compiled);
|
||||
private static readonly Regex Log4NetAssemblyPattern = new Regex("log4net, Version=([\\d\\.]+?), Culture=neutral, PublicKeyToken=null");
|
||||
private const string Log4NetReplacement = "log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a";
|
||||
|
||||
|
||||
private static readonly Regex HtmlAgilityAssemblyPattern = new Regex("HtmlAgilityPack, Version=([\\d\\.]+?), Culture=neutral, PublicKeyToken=bd319b19eaf3b43a");
|
||||
private const string HtmlAgilityReplacement = "HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a";
|
||||
|
||||
/// <summary>
|
||||
/// This is used to do an assembly binding redirect via code - normally required due to signature changes in assemblies
|
||||
/// </summary>
|
||||
@@ -28,13 +31,18 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
//log4net:
|
||||
// Use regex to match and replace
|
||||
//log4net:
|
||||
if (Log4NetAssemblyPattern.IsMatch(args.Name) && args.Name != Log4NetReplacement)
|
||||
{
|
||||
return Assembly.Load(Log4NetAssemblyPattern.Replace(args.Name, Log4NetReplacement));
|
||||
}
|
||||
|
||||
//HtmlAgility:
|
||||
if (HtmlAgilityAssemblyPattern.IsMatch(args.Name) && args.Name != HtmlAgilityReplacement)
|
||||
{
|
||||
return Assembly.Load(HtmlAgilityAssemblyPattern.Replace(args.Name, HtmlAgilityReplacement));
|
||||
}
|
||||
|
||||
//AutoMapper:
|
||||
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
|
||||
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider)
|
||||
{
|
||||
if (innerProvider.GetType() == typeof(DeepCloneRuntimeCacheProvider))
|
||||
throw new InvalidOperationException("A " + typeof(DeepCloneRuntimeCacheProvider) + " cannot wrap another instance of " + typeof(DeepCloneRuntimeCacheProvider));
|
||||
|
||||
InnerProvider = innerProvider;
|
||||
}
|
||||
|
||||
@@ -105,9 +108,11 @@ namespace Umbraco.Core.Cache
|
||||
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
|
||||
if (value == null) return null; // do not store null values (backward compat)
|
||||
|
||||
//Clone/reset to go into the cache
|
||||
return CheckCloneableAndTracksChanges(value);
|
||||
}, timeout, isSliding, priority, removedCallback, dependentFiles);
|
||||
|
||||
//Clone/reset to go out of the cache
|
||||
return CheckCloneableAndTracksChanges(cached);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,14 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
var appSettings = System.Configuration.ConfigurationManager.AppSettings;
|
||||
LogUncompletedScopes = string.Equals("true", appSettings["Umbraco.CoreDebug.LogUncompletedScopes"], StringComparison.OrdinalIgnoreCase);
|
||||
DumpOnTimeoutThreadAbort = string.Equals("true", appSettings["Umbraco.CoreDebug.DumpOnTimeoutThreadAbort"], StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// when true, Scope logs the stack trace for any scope that gets disposed without being completed.
|
||||
// this helps troubleshooting rogue scopes that we forget to complete
|
||||
public bool LogUncompletedScopes { get; private set; }
|
||||
// when true, the Logger creates a minidump of w3wp in ~/App_Data/MiniDump whenever it logs
|
||||
// an error due to a ThreadAbortException that is due to a timeout.
|
||||
public bool DumpOnTimeoutThreadAbort { get; private set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +183,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return GetOptionalTextElement("EnablePropertyValueConverters", false); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("loginBackgroundImage")]
|
||||
internal InnerTextConfigurationElement<string> LoginBackgroundImage
|
||||
{
|
||||
get { return GetOptionalTextElement("loginBackgroundImage", string.Empty); }
|
||||
}
|
||||
|
||||
string IContentSection.NotificationEmailAddress
|
||||
{
|
||||
get { return Notifications.NotificationEmailAddress; }
|
||||
@@ -336,5 +342,10 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
get { return EnablePropertyValueConverters; }
|
||||
}
|
||||
|
||||
string IContentSection.LoginBackgroundImage
|
||||
{
|
||||
get { return LoginBackgroundImage; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,5 +72,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
|
||||
bool EnablePropertyValueConverters { get; }
|
||||
|
||||
string LoginBackgroundImage { get; }
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "beta03"; } }
|
||||
public static string CurrentComment { get { return "RC"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Core.Deploy
|
||||
@@ -8,7 +9,7 @@ namespace Umbraco.Core.Deploy
|
||||
/// <summary>
|
||||
/// Connects to an Umbraco service.
|
||||
/// </summary>
|
||||
public interface IServiceConnector
|
||||
public interface IServiceConnector : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an artifact.
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Diagnostics
|
||||
{
|
||||
// taken from https://blogs.msdn.microsoft.com/dondu/2010/10/24/writing-minidumps-in-c/
|
||||
// and https://blogs.msdn.microsoft.com/dondu/2010/10/31/writing-minidumps-from-exceptions-in-c/
|
||||
// which itself got it from http://blog.kalmbach-software.de/2008/12/13/writing-minidumps-in-c/
|
||||
|
||||
internal static class MiniDump
|
||||
{
|
||||
private static readonly object LockO = new object();
|
||||
|
||||
[Flags]
|
||||
public enum Option : uint
|
||||
{
|
||||
// From dbghelp.h:
|
||||
Normal = 0x00000000,
|
||||
WithDataSegs = 0x00000001,
|
||||
WithFullMemory = 0x00000002,
|
||||
WithHandleData = 0x00000004,
|
||||
FilterMemory = 0x00000008,
|
||||
ScanMemory = 0x00000010,
|
||||
WithUnloadedModules = 0x00000020,
|
||||
WithIndirectlyReferencedMemory = 0x00000040,
|
||||
FilterModulePaths = 0x00000080,
|
||||
WithProcessThreadData = 0x00000100,
|
||||
WithPrivateReadWriteMemory = 0x00000200,
|
||||
WithoutOptionalData = 0x00000400,
|
||||
WithFullMemoryInfo = 0x00000800,
|
||||
WithThreadInfo = 0x00001000,
|
||||
WithCodeSegs = 0x00002000,
|
||||
WithoutAuxiliaryState = 0x00004000,
|
||||
WithFullAuxiliaryState = 0x00008000,
|
||||
WithPrivateWriteCopyMemory = 0x00010000,
|
||||
IgnoreInaccessibleMemory = 0x00020000,
|
||||
ValidTypeFlags = 0x0003ffff,
|
||||
}
|
||||
|
||||
//typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
|
||||
// DWORD ThreadId;
|
||||
// PEXCEPTION_POINTERS ExceptionPointers;
|
||||
// BOOL ClientPointers;
|
||||
//} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)] // Pack=4 is important! So it works also for x64!
|
||||
public struct MiniDumpExceptionInformation
|
||||
{
|
||||
public uint ThreadId;
|
||||
public IntPtr ExceptionPointers;
|
||||
[MarshalAs(UnmanagedType.Bool)]
|
||||
public bool ClientPointers;
|
||||
}
|
||||
|
||||
//BOOL
|
||||
//WINAPI
|
||||
//MiniDumpWriteDump(
|
||||
// __in HANDLE hProcess,
|
||||
// __in DWORD ProcessId,
|
||||
// __in HANDLE hFile,
|
||||
// __in MINIDUMP_TYPE DumpType,
|
||||
// __in_opt PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
// __in_opt PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
// __in_opt PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
||||
// );
|
||||
|
||||
// Overload requiring MiniDumpExceptionInformation
|
||||
[DllImport("dbghelp.dll", EntryPoint = "MiniDumpWriteDump", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
private static extern bool MiniDumpWriteDump(IntPtr hProcess, uint processId, SafeHandle hFile, uint dumpType, ref MiniDumpExceptionInformation expParam, IntPtr userStreamParam, IntPtr callbackParam);
|
||||
|
||||
// Overload supporting MiniDumpExceptionInformation == NULL
|
||||
[DllImport("dbghelp.dll", EntryPoint = "MiniDumpWriteDump", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
|
||||
private static extern bool MiniDumpWriteDump(IntPtr hProcess, uint processId, SafeHandle hFile, uint dumpType, IntPtr expParam, IntPtr userStreamParam, IntPtr callbackParam);
|
||||
|
||||
[DllImport("kernel32.dll", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]
|
||||
private static extern uint GetCurrentThreadId();
|
||||
|
||||
private static bool Write(SafeHandle fileHandle, Option options, bool withException = false)
|
||||
{
|
||||
var currentProcess = Process.GetCurrentProcess();
|
||||
var currentProcessHandle = currentProcess.Handle;
|
||||
var currentProcessId = (uint)currentProcess.Id;
|
||||
|
||||
MiniDumpExceptionInformation exp;
|
||||
|
||||
exp.ThreadId = GetCurrentThreadId();
|
||||
exp.ClientPointers = false;
|
||||
exp.ExceptionPointers = IntPtr.Zero;
|
||||
|
||||
if (withException)
|
||||
exp.ExceptionPointers = Marshal.GetExceptionPointers();
|
||||
|
||||
var bRet = exp.ExceptionPointers == IntPtr.Zero
|
||||
? MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint) options, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)
|
||||
: MiniDumpWriteDump(currentProcessHandle, currentProcessId, fileHandle, (uint) options, ref exp, IntPtr.Zero, IntPtr.Zero);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
public static bool Dump(Option options = Option.WithFullMemory, bool withException = false)
|
||||
{
|
||||
lock (LockO)
|
||||
{
|
||||
// work around "stack trace is not available while minidump debugging",
|
||||
// by making sure a local var (that we can inspect) contains the stack trace.
|
||||
// getting the call stack before it is unwound would require a special exception
|
||||
// filter everywhere in our code = not!
|
||||
var stacktrace = withException ? Environment.StackTrace : string.Empty;
|
||||
|
||||
var filepath = IOHelper.MapPath("~/App_Data/MiniDump");
|
||||
if (Directory.Exists(filepath) == false)
|
||||
Directory.CreateDirectory(filepath);
|
||||
|
||||
var filename = Path.Combine(filepath, string.Format("{0:yyyyMMddTHHmmss}.{1}.dmp", DateTime.UtcNow, Guid.NewGuid().ToString("N").Substring(0, 4)));
|
||||
using (var stream = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite, FileShare.Write))
|
||||
{
|
||||
return Write(stream.SafeFileHandle, options, withException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool OkToDump()
|
||||
{
|
||||
lock (LockO)
|
||||
{
|
||||
var filepath = IOHelper.MapPath("~/App_Data/MiniDump");
|
||||
if (Directory.Exists(filepath) == false) return true;
|
||||
var count = Directory.GetFiles(filepath, "*.dmp").Length;
|
||||
return count < 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,22 +295,5 @@ namespace Umbraco.Core
|
||||
return list1Groups.Count == list2Groups.Count
|
||||
&& list1Groups.All(g => g.Count() == list2Groups[g.Key].Count());
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Returns the items of the given enumerable as a pure enumerable.
|
||||
/// <remarks>
|
||||
/// When quering lists using methods such as <see cref="M:List.Where"/>, the result, despite appearing to look like and quack like an
|
||||
/// <see cref="T:Enumerable{T}"/> the type is actually an instance of <see cref="T:System.Linq.Enumerable.WhereEnumerableIterator"/>
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
///<param name="source">The item to find.</param>
|
||||
///<returns>The index of the first matching item, or -1 if the item was not found.</returns>
|
||||
internal static IEnumerable<T> Yield<T>(this IEnumerable<T> source)
|
||||
{
|
||||
foreach (var element in source)
|
||||
{
|
||||
yield return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Umbraco.Core.IO
|
||||
private long _folderCounter;
|
||||
private bool _folderCounterInitialized;
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
private static readonly Dictionary<int, string> DefaultSizes = new Dictionary<int, string>
|
||||
{
|
||||
{ 100, "thumb" },
|
||||
@@ -263,7 +264,7 @@ namespace Umbraco.Core.IO
|
||||
var filename = Path.GetFileName(sourcepath);
|
||||
var filepath = GetMediaPath(filename, content.Key, propertyType.Key);
|
||||
this.CopyFile(sourcepath, filepath);
|
||||
CopyThumbnails(sourcepath, filepath);
|
||||
|
||||
return filepath;
|
||||
}
|
||||
|
||||
@@ -312,29 +313,17 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
}
|
||||
|
||||
// sets a file for the FileUpload property editor
|
||||
// ie generates thumbnails and populates autofill properties
|
||||
/// <summary>
|
||||
/// Sets a file for the FileUpload property editor and populates autofill properties
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="property"></param>
|
||||
/// <param name="filepath"></param>
|
||||
/// <param name="filestream"></param>
|
||||
private void SetUploadFile(IContentBase content, Property property, string filepath, Stream filestream)
|
||||
{
|
||||
// check if file is an image (and supports resizing and thumbnails etc)
|
||||
var extension = Path.GetExtension(filepath);
|
||||
var isImage = IsImageFile(extension);
|
||||
|
||||
// specific stuff for images (thumbnails etc)
|
||||
if (isImage)
|
||||
{
|
||||
using (var image = Image.FromStream(filestream))
|
||||
{
|
||||
// use one image for all
|
||||
GenerateThumbnails(image, filepath, property.PropertyType);
|
||||
_uploadAutoFillProperties.Populate(content, property.Alias, filepath, filestream, image);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// will use filepath for extension, and filestream for length
|
||||
_uploadAutoFillProperties.Populate(content, property.Alias, filepath, filestream);
|
||||
}
|
||||
{
|
||||
// will use filepath for extension, and filestream for length
|
||||
_uploadAutoFillProperties.Populate(content, property.Alias, filepath, filestream);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -401,6 +390,7 @@ namespace Umbraco.Core.IO
|
||||
|
||||
// note: this does not find 'custom' thumbnails?
|
||||
// will find _thumb and _big-thumb but NOT _custom?
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public IEnumerable<string> GetThumbnails(string path)
|
||||
{
|
||||
var parentDirectory = Path.GetDirectoryName(path);
|
||||
@@ -421,12 +411,14 @@ namespace Umbraco.Core.IO
|
||||
DeleteThumbnails(path);
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public void DeleteThumbnails(string path)
|
||||
{
|
||||
GetThumbnails(path)
|
||||
.ForEach(x => base.DeleteFile(x));
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public void CopyThumbnails(string sourcePath, string targetPath)
|
||||
{
|
||||
var targetPathBase = Path.GetDirectoryName(targetPath) ?? "";
|
||||
@@ -479,6 +471,7 @@ namespace Umbraco.Core.IO
|
||||
|
||||
#region GenerateThumbnails
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public IEnumerable<ResizedImage> GenerateThumbnails(
|
||||
Image image,
|
||||
string filepath,
|
||||
@@ -500,6 +493,7 @@ namespace Umbraco.Core.IO
|
||||
return GenerateThumbnails(image, filepath, additionalSizes);
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public IEnumerable<ResizedImage> GenerateThumbnails(
|
||||
Image image,
|
||||
string filepath,
|
||||
@@ -522,6 +516,7 @@ namespace Umbraco.Core.IO
|
||||
.ToList(); // now
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public IEnumerable<ResizedImage> GenerateThumbnails(
|
||||
Stream filestream,
|
||||
string filepath,
|
||||
@@ -535,6 +530,7 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public IEnumerable<ResizedImage> GenerateThumbnails(
|
||||
Image image,
|
||||
string filepath,
|
||||
@@ -556,16 +552,19 @@ namespace Umbraco.Core.IO
|
||||
|
||||
#region GenerateResized - Generate at resized filepath derived from origin filepath
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public ResizedImage GenerateResized(Image originImage, string originFilepath, string sizeName, int maxWidthHeight)
|
||||
{
|
||||
return GenerateResized(originImage, originFilepath, sizeName, maxWidthHeight, -1, -1);
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public ResizedImage GenerateResized(Image originImage, string originFilepath, string sizeName, int fixedWidth, int fixedHeight)
|
||||
{
|
||||
return GenerateResized(originImage, originFilepath, sizeName, -1, fixedWidth, fixedHeight);
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public ResizedImage GenerateResized(Image originImage, string originFilepath, string sizeName, int maxWidthHeight, int fixedWidth, int fixedHeight)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sizeName))
|
||||
@@ -581,16 +580,19 @@ namespace Umbraco.Core.IO
|
||||
|
||||
#region GenerateResizedAt - Generate at specified resized filepath
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public ResizedImage GenerateResizedAt(Image originImage, string resizedFilepath, int maxWidthHeight)
|
||||
{
|
||||
return GenerateResizedAt(originImage, resizedFilepath, maxWidthHeight, -1, -1);
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public ResizedImage GenerateResizedAt(Image originImage, int fixedWidth, int fixedHeight, string resizedFilepath)
|
||||
{
|
||||
return GenerateResizedAt(originImage, resizedFilepath, -1, fixedWidth, fixedHeight);
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public ResizedImage GenerateResizedAt(Image originImage, string resizedFilepath, int maxWidthHeight, int fixedWidth, int fixedHeight)
|
||||
{
|
||||
// target dimensions
|
||||
@@ -699,6 +701,7 @@ namespace Umbraco.Core.IO
|
||||
|
||||
#region Inner classes
|
||||
|
||||
[Obsolete("This should no longer be used, image manipulation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public class ResizedImage
|
||||
{
|
||||
public ResizedImage()
|
||||
|
||||
@@ -7,6 +7,8 @@ using System.Threading;
|
||||
using System.Web;
|
||||
using log4net;
|
||||
using log4net.Config;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Diagnostics;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
@@ -57,23 +59,55 @@ namespace Umbraco.Core.Logging
|
||||
internal ILog LoggerFor(object getTypeFromInstance)
|
||||
{
|
||||
if (getTypeFromInstance == null) throw new ArgumentNullException("getTypeFromInstance");
|
||||
|
||||
|
||||
return LogManager.GetLogger(getTypeFromInstance.GetType());
|
||||
}
|
||||
|
||||
|
||||
public void Error(Type callingType, string message, Exception exception)
|
||||
{
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null) return;
|
||||
|
||||
var dump = false;
|
||||
|
||||
if (IsTimeoutThreadAbortException(exception))
|
||||
{
|
||||
message += "\r\nThe thread has been aborted, because the request has timed out.";
|
||||
|
||||
// dump if configured, or if stacktrace contains Monitor.ReliableEnter
|
||||
dump = UmbracoConfig.For.CoreDebug().DumpOnTimeoutThreadAbort || IsMonitorEnterThreadAbortException(exception);
|
||||
|
||||
// dump if it is ok to dump (might have a cap on number of dump...)
|
||||
dump &= MiniDump.OkToDump();
|
||||
}
|
||||
|
||||
logger.Error(message, exception);
|
||||
if (dump)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dumped = MiniDump.Dump(withException: true);
|
||||
message += dumped
|
||||
? "\r\nA minidump was created in App_Data/MiniDump"
|
||||
: "\r\nFailed to create a minidump";
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
message += string.Format("\r\nFailed to create a minidump ({0}: {1})", e.GetType().FullName, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
logger.Error(message, exception);
|
||||
}
|
||||
|
||||
private static bool IsMonitorEnterThreadAbortException(Exception exception)
|
||||
{
|
||||
var abort = exception as ThreadAbortException;
|
||||
if (abort == null) return false;
|
||||
|
||||
var stacktrace = abort.StackTrace;
|
||||
return stacktrace.Contains("System.Threading.Monitor.ReliableEnter");
|
||||
}
|
||||
|
||||
private static bool IsTimeoutThreadAbortException(Exception exception)
|
||||
{
|
||||
var abort = exception as ThreadAbortException;
|
||||
@@ -105,7 +139,7 @@ namespace Umbraco.Core.Logging
|
||||
if (showHttpTrace && HttpContext.Current != null)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn(callingType.Name, string.Format(message, formatItems.Select(x => x.Invoke()).ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
@@ -122,7 +156,7 @@ namespace Umbraco.Core.Logging
|
||||
var logger = LogManager.GetLogger(callingType);
|
||||
if (logger == null || logger.IsWarnEnabled == false) return;
|
||||
var executedParams = formatItems.Select(x => x.Invoke()).ToArray();
|
||||
logger.WarnFormat((message) + ". Exception: " + e, executedParams);
|
||||
logger.WarnFormat((message) + ". Exception: " + e, executedParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Media
|
||||
{
|
||||
public interface IImageUrlProvider
|
||||
// note: because this interface is obsolete is is *not* IDiscoverable, and in case the
|
||||
// PluginManager is asked to find types implementing this interface it will fall back
|
||||
// to a complete scan.
|
||||
|
||||
[Obsolete("IImageUrlProvider is no longer used and will be removed in future versions")]
|
||||
public interface IImageUrlProvider // IDiscoverable
|
||||
{
|
||||
string Name { get; }
|
||||
string GetImageUrlFromMedia(int mediaId, IDictionary<string, string> parameters);
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
namespace Umbraco.Core.Media
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Media
|
||||
{
|
||||
public interface IThumbnailProvider
|
||||
// note: because this interface is obsolete is is *not* IDiscoverable, and in case the
|
||||
// PluginManager is asked to find types implementing this interface it will fall back
|
||||
// to a complete scan.
|
||||
|
||||
[Obsolete("Thumbnails are generated by ImageProcessor, use that instead")]
|
||||
public interface IThumbnailProvider // : IDiscoverable
|
||||
{
|
||||
bool CanProvideThumbnail(string fileUrl);
|
||||
string GetThumbnailUrl(string fileUrl);
|
||||
|
||||
@@ -96,8 +96,7 @@ namespace Umbraco.Core.Media
|
||||
/// <param name="propertyTypeAlias">The property type alias.</param>
|
||||
/// <param name="filepath">The filesystem-relative filepath, or null to clear properties.</param>
|
||||
/// <param name="filestream">The stream containing the file data.</param>
|
||||
/// <param name="image">The file data as an image object.</param>
|
||||
public void Populate(IContentBase content, string propertyTypeAlias, string filepath, Stream filestream, Image image = null)
|
||||
public void Populate(IContentBase content, string propertyTypeAlias, string filepath, Stream filestream)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
if (propertyTypeAlias == null) throw new ArgumentNullException("propertyTypeAlias");
|
||||
@@ -110,7 +109,7 @@ namespace Umbraco.Core.Media
|
||||
if (autoFillConfig == null) return; // nothing
|
||||
|
||||
// populate
|
||||
Populate(content, autoFillConfig, filepath, filestream, image);
|
||||
Populate(content, autoFillConfig, filepath, filestream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,8 +157,7 @@ namespace Umbraco.Core.Media
|
||||
/// <param name="autoFillConfig"></param>
|
||||
/// <param name="filepath">The filesystem-relative filepath, or null to clear properties.</param>
|
||||
/// <param name="filestream">The stream containing the file data.</param>
|
||||
/// <param name="image">The file data as an image object.</param>
|
||||
public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream, Image image = null)
|
||||
public void Populate(IContentBase content, IImagingAutoFillUploadField autoFillConfig, string filepath, Stream filestream)
|
||||
{
|
||||
if (content == null) throw new ArgumentNullException("content");
|
||||
if (autoFillConfig == null) throw new ArgumentNullException("autoFillConfig");
|
||||
@@ -172,11 +170,7 @@ namespace Umbraco.Core.Media
|
||||
else
|
||||
{
|
||||
var extension = (Path.GetExtension(filepath) ?? "").TrimStart('.');
|
||||
Size? size;
|
||||
if (image == null)
|
||||
size = _mediaFileSystem.IsImageFile(extension) ? (Size?) _mediaFileSystem.GetDimensions(filestream) : null;
|
||||
else
|
||||
size = new Size(image.Width, image.Height);
|
||||
var size = _mediaFileSystem.IsImageFile(extension) ? (Size?)_mediaFileSystem.GetDimensions(filestream) : null;
|
||||
SetProperties(content, autoFillConfig, size, filestream.Length, extension);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -84,16 +86,64 @@ namespace Umbraco.Core.Models
|
||||
public string Type { get; set; }
|
||||
|
||||
private Type _runtimeType;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the CLR type based on it's assembly name stored in the config
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Type GetRuntimeType()
|
||||
{
|
||||
return _runtimeType ?? (_runtimeType = System.Type.GetType(Type));
|
||||
}
|
||||
|
||||
if (_runtimeType != null)
|
||||
return _runtimeType;
|
||||
|
||||
_runtimeType = TryGetType(Type);
|
||||
return _runtimeType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to try to get and cache the tree type
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
internal static Type TryGetType(string type)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ResolvedTypes.GetOrAdd(type, s =>
|
||||
{
|
||||
var result = System.Type.GetType(type);
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
//we need to implement a bit of a hack here due to some trees being renamed and backwards compat
|
||||
var parts = type.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
if (parts[1].Trim() == "umbraco" && parts[0].StartsWith("Umbraco.Web.Trees") && parts[0].EndsWith("Controller") == false)
|
||||
{
|
||||
//if it's one of our controllers but it's not suffixed with "Controller" then add it and try again
|
||||
var tempType = parts[0] + "Controller, umbraco";
|
||||
|
||||
result = System.Type.GetType(tempType);
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Could not resolve type");
|
||||
});
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
//swallow, this is our own exception, couldn't find the type
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<string, Type> ResolvedTypes = new ConcurrentDictionary<string, Type>();
|
||||
}
|
||||
}
|
||||
@@ -274,6 +274,9 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public bool HasPublishedVersion { get { return PublishedVersionGuid != default(Guid); } }
|
||||
|
||||
[IgnoreDataMember]
|
||||
internal DateTime PublishedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Trashed state of the content object
|
||||
/// </summary>
|
||||
|
||||
@@ -49,7 +49,10 @@ namespace Umbraco.Core.Models
|
||||
return path
|
||||
.Replace('\\', System.IO.Path.DirectorySeparatorChar)
|
||||
.Replace('/', System.IO.Path.DirectorySeparatorChar);
|
||||
//.TrimStart(System.IO.Path.DirectorySeparatorChar);
|
||||
|
||||
//Don't strip the start - this was a bug fixed in 7.3, see ScriptRepositoryTests.PathTests
|
||||
//.TrimStart(System.IO.Path.DirectorySeparatorChar)
|
||||
//.TrimStart('/');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
|
||||
if (contentType == null)
|
||||
throw new Exception(string.Format("ContentTypeService failed to find a {0} type with alias \"{1}\".",
|
||||
throw new InvalidOperationException(string.Format("ContentTypeService failed to find a {0} type with alias \"{1}\".",
|
||||
itemType.ToString().ToLower(), alias));
|
||||
|
||||
return new PublishedContentType(contentType);
|
||||
|
||||
@@ -19,5 +19,8 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
|
||||
[Column("newest")]
|
||||
public bool Newest { get; set; }
|
||||
|
||||
[Column("updateDate")]
|
||||
public DateTime VersionDate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
private readonly string _httpContextKey;
|
||||
private readonly List<Type> _instanceTypes = new List<Type>();
|
||||
private IEnumerable<TResolved> _sortedValues;
|
||||
private readonly Func<HttpContextBase> _httpContextGetter;
|
||||
|
||||
private int _defaultPluginWeight = 100;
|
||||
|
||||
@@ -42,12 +43,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
CanResolveBeforeFrozen = false;
|
||||
if (scope == ObjectLifetimeScope.HttpRequest)
|
||||
{
|
||||
if (HttpContext.Current == null)
|
||||
throw new InvalidOperationException("Use alternative constructor accepting a HttpContextBase object in order to set the lifetime scope to HttpRequest when HttpContext.Current is null");
|
||||
|
||||
CurrentHttpContext = new HttpContextWrapper(HttpContext.Current);
|
||||
}
|
||||
_httpContextGetter = () => new HttpContextWrapper(HttpContext.Current);
|
||||
|
||||
ServiceProvider = serviceProvider;
|
||||
Logger = logger;
|
||||
@@ -84,7 +80,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
LifetimeScope = ObjectLifetimeScope.HttpRequest;
|
||||
_httpContextKey = GetType().FullName;
|
||||
ServiceProvider = serviceProvider;
|
||||
CurrentHttpContext = httpContext;
|
||||
_httpContextGetter = () => httpContext;
|
||||
_instanceTypes = new List<Type>();
|
||||
|
||||
InitializeAppInstances();
|
||||
@@ -160,7 +156,16 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Gets or sets the <see cref="HttpContextBase"/> used to initialize this object, if any.
|
||||
/// </summary>
|
||||
/// <remarks>If not null, then <c>LifetimeScope</c> will be <c>ObjectLifetimeScope.HttpRequest</c>.</remarks>
|
||||
protected HttpContextBase CurrentHttpContext { get; private set; }
|
||||
protected HttpContextBase CurrentHttpContext
|
||||
{
|
||||
get
|
||||
{
|
||||
var context = _httpContextGetter == null ? null : _httpContextGetter();
|
||||
if (context == null)
|
||||
throw new InvalidOperationException("Cannot use this resolver with lifetime 'HttpRequest' when there is no current HttpContext. Either use the ctor accepting an HttpContextBase, or use the resolver from within a request exclusively.");
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the service provider used to instantiate objects
|
||||
@@ -196,7 +201,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Gets or sets the default type weight.
|
||||
/// </summary>
|
||||
/// <remarks>Determines the weight of types that do not have a <c>WeightAttribute</c> set on
|
||||
/// <remarks>Determines the weight of types that do not have a <c>WeightAttribute</c> set on
|
||||
/// them, when calling <c>GetSortedValues</c>.</remarks>
|
||||
protected virtual int DefaultPluginWeight
|
||||
{
|
||||
@@ -276,7 +281,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Removes a type.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to remove.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
|
||||
/// the type is not a valid type for the resolver.</exception>
|
||||
public virtual void RemoveType(Type value)
|
||||
{
|
||||
@@ -296,7 +301,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Removes a type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to remove.</typeparam>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
|
||||
/// the type is not a valid type for the resolver.</exception>
|
||||
public void RemoveType<T>()
|
||||
where T : TResolved
|
||||
@@ -309,7 +314,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <param name="types">The types to add.</param>
|
||||
/// <remarks>The types are appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// a type is not a valid type for the resolver, or a type is already in the collection of types.</exception>
|
||||
protected void AddTypes(IEnumerable<Type> types)
|
||||
{
|
||||
@@ -336,7 +341,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <param name="value">The type to add.</param>
|
||||
/// <remarks>The type is appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public virtual void AddType(Type value)
|
||||
{
|
||||
@@ -362,7 +367,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to add.</typeparam>
|
||||
/// <remarks>The type is appended at the end of the list.</remarks>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public void AddType<T>()
|
||||
where T : TResolved
|
||||
@@ -404,7 +409,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index at which the type should be inserted.</param>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
|
||||
public virtual void InsertType(int index, Type value)
|
||||
@@ -430,7 +435,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Inserts a type at the beginning of the list.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// the type is not a valid type for the resolver, or the type is already in the collection of types.</exception>
|
||||
public virtual void InsertType(Type value)
|
||||
{
|
||||
@@ -464,7 +469,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <param name="existingType">The existing type before which to insert.</param>
|
||||
/// <param name="value">The type to insert.</param>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
|
||||
/// or the new type is already in the collection of types.</exception>
|
||||
public virtual void InsertTypeBefore(Type existingType, Type value)
|
||||
@@ -498,7 +503,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <typeparam name="TExisting">The existing type before which to insert.</typeparam>
|
||||
/// <typeparam name="T">The type to insert.</typeparam>
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
|
||||
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
|
||||
/// or the new type is already in the collection of types.</exception>
|
||||
public void InsertTypeBefore<TExisting, T>()
|
||||
|
||||
@@ -63,49 +63,6 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE - the ugly code below exists only because of umbraco.BusinessLogic.Actions.Action.ReRegisterActionsAndHandlers
|
||||
// which wants to re-register actions and handlers instead of properly restarting the application. Don't even think
|
||||
// about using it for anything else. Also, while the backdoor is open, the resolution system is locked so nothing
|
||||
// can work properly => deadlocks. Therefore, open the backdoor, do resolution changes EXCLUSIVELY, and close the door!
|
||||
|
||||
/// <summary>
|
||||
/// Returns a disposable object that reprents dirty access to temporarily unfrozen resolution configuration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Should not be used.</para>
|
||||
/// <para>Should be used in a <c>using(Resolution.DirtyBackdoorToConfiguration) { ... }</c> mode.</para>
|
||||
/// <para>Because we just lift the frozen state, and we don't actually re-freeze, the <c>Frozen</c> event does not trigger.</para>
|
||||
/// </remarks>
|
||||
internal static IDisposable DirtyBackdoorToConfiguration
|
||||
{
|
||||
get { return new DirtyBackdoor(); }
|
||||
}
|
||||
|
||||
// keep the class here because it needs write-access to Resolution.IsFrozen
|
||||
private class DirtyBackdoor : IDisposable
|
||||
{
|
||||
|
||||
private readonly IDisposable _lock;
|
||||
private readonly bool _frozen;
|
||||
|
||||
public DirtyBackdoor()
|
||||
{
|
||||
LogHelper.Debug(typeof(DirtyBackdoor), "Creating back door for resolution");
|
||||
|
||||
_lock = new WriteLock(ConfigurationLock);
|
||||
_frozen = _isFrozen;
|
||||
_isFrozen = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LogHelper.Debug(typeof(DirtyBackdoor), "Disposing back door for resolution");
|
||||
|
||||
_isFrozen = _frozen;
|
||||
_lock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freezes resolution.
|
||||
/// </summary>
|
||||
|
||||
@@ -72,6 +72,9 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
content.PublishedVersionGuid = publishedDto == null
|
||||
? (dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId)
|
||||
: publishedDto.VersionId;
|
||||
content.PublishedDate = publishedDto == null
|
||||
? (dto.DocumentPublishedReadOnlyDto == null ? default(DateTime) : dto.DocumentPublishedReadOnlyDto.VersionDate)
|
||||
: publishedDto.VersionDate;
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
// http://issues.umbraco.org/issue/U4-1946
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Mappers
|
||||
{
|
||||
public abstract class BaseMapper
|
||||
public abstract class BaseMapper : IDiscoverable
|
||||
{
|
||||
private readonly ISqlSyntaxProvider _sqlSyntax;
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
namespace Umbraco.Core.Persistence.Migrations
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interface for database migrations
|
||||
/// </summary>
|
||||
public interface IMigration
|
||||
public interface IMigration : IDiscoverable
|
||||
{
|
||||
void Up();
|
||||
void Down();
|
||||
|
||||
@@ -513,11 +513,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
dto.DocumentPublishedReadOnlyDto = new DocumentPublishedReadOnlyDto
|
||||
{
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.UpdateDate,
|
||||
Newest = true,
|
||||
NodeId = dto.NodeId,
|
||||
Published = true
|
||||
Published = true
|
||||
};
|
||||
((Content)entity).PublishedVersionGuid = dto.VersionId;
|
||||
((Content) entity).PublishedVersionGuid = dto.VersionId;
|
||||
((Content) entity).PublishedDate = dto.UpdateDate;
|
||||
}
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
@@ -688,22 +690,26 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
dto.DocumentPublishedReadOnlyDto = new DocumentPublishedReadOnlyDto
|
||||
{
|
||||
VersionId = dto.VersionId,
|
||||
VersionDate = dto.UpdateDate,
|
||||
Newest = true,
|
||||
NodeId = dto.NodeId,
|
||||
Published = true
|
||||
};
|
||||
((Content)entity).PublishedVersionGuid = dto.VersionId;
|
||||
((Content) entity).PublishedVersionGuid = dto.VersionId;
|
||||
((Content) entity).PublishedDate = dto.UpdateDate;
|
||||
}
|
||||
else if (publishedStateChanged)
|
||||
{
|
||||
dto.DocumentPublishedReadOnlyDto = new DocumentPublishedReadOnlyDto
|
||||
{
|
||||
VersionId = default(Guid),
|
||||
VersionId = default (Guid),
|
||||
VersionDate = default (DateTime),
|
||||
Newest = false,
|
||||
NodeId = dto.NodeId,
|
||||
Published = false
|
||||
};
|
||||
((Content)entity).PublishedVersionGuid = default(Guid);
|
||||
((Content) entity).PublishedVersionGuid = default(Guid);
|
||||
((Content) entity).PublishedDate = default (DateTime);
|
||||
}
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
@@ -975,7 +981,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
|
||||
}
|
||||
|
||||
//order by update date DESC, if there is corrupted published flags we only want the latest!
|
||||
var publishedSql = new Sql(@"SELECT cmsDocument.nodeId, cmsDocument.published, cmsDocument.versionId, cmsDocument.newest
|
||||
var publishedSql = new Sql(@"SELECT cmsDocument.nodeId, cmsDocument.published, cmsDocument.versionId, cmsDocument.updateDate, cmsDocument.newest
|
||||
FROM cmsDocument INNER JOIN cmsContentVersion ON cmsContentVersion.VersionId = cmsDocument.versionId
|
||||
WHERE cmsDocument.published = 1 AND cmsDocument.nodeId IN
|
||||
(" + parsedOriginalSql + @")
|
||||
|
||||
@@ -101,7 +101,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var translator = new SqlTranslator<PropertyType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<PropertyTypeDto>(x => x.PropertyTypeGroupId, SqlSyntax);
|
||||
//must be sorted this way for the relator to work
|
||||
.OrderBy<PropertyTypeGroupDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new GroupPropertyTypeRelator().Map, sql);
|
||||
|
||||
@@ -468,7 +469,8 @@ AND umbracoNode.id <> @id",
|
||||
.LeftJoin<DataTypeDto>()
|
||||
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.DataTypeId)
|
||||
.Where<PropertyTypeGroupDto>(x => x.ContentTypeNodeId == id)
|
||||
.OrderBy<PropertyTypeGroupDto>(x => x.Id);
|
||||
//must be sorted this way for the relator to work
|
||||
.OrderBy<PropertyTypeGroupDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new GroupPropertyTypeRelator().Map, sql);
|
||||
|
||||
@@ -1250,5 +1252,19 @@ WHERE cmsContentType." + aliasColumn + @" LIKE @pattern",
|
||||
while (aliases.Contains(test = alias + i)) i++;
|
||||
return test;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given the path of a content item, this will return true if the content item exists underneath a list view content item
|
||||
/// </summary>
|
||||
/// <param name="contentPath"></param>
|
||||
/// <returns></returns>
|
||||
public bool HasContainerInPath(string contentPath)
|
||||
{
|
||||
var ids = contentPath.Split(',').Select(int.Parse);
|
||||
var sql = new Sql(@"SELECT COUNT(*) FROM cmsContentType
|
||||
INNER JOIN cmsContent ON cmsContentType.nodeId=cmsContent.contentType
|
||||
WHERE cmsContent.nodeId IN (@ids) AND cmsContentType.isContainer=@isContainer", new { ids, isContainer = true });
|
||||
return Database.ExecuteScalar<int>(sql) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,47 +276,33 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
public PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId)
|
||||
{
|
||||
var cached = IsolatedCache.GetCacheItemsByKeySearch<PreValueCollection>(GetPrefixedCacheKey(dataTypeId));
|
||||
if (cached != null && cached.Any())
|
||||
{
|
||||
//return from the cache, ensure it's a cloned result
|
||||
return (PreValueCollection)cached.First().DeepClone();
|
||||
}
|
||||
|
||||
return GetAndCachePreValueCollection(dataTypeId);
|
||||
}
|
||||
|
||||
internal static string GetCacheKeyRegex(int preValueId)
|
||||
{
|
||||
return CacheKeys.DataTypePreValuesCacheKey + @"[-\d]+-([\d]*,)*" + preValueId + @"(?!\d)[,\d$]*";
|
||||
var collection = GetCachedPreValueCollection(dataTypeId);
|
||||
return collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specific PreValue by its Id
|
||||
/// </summary>
|
||||
/// <param name="preValueId">Id of the PreValue to retrieve the value from</param>
|
||||
/// <returns>PreValue as a string</returns>
|
||||
public string GetPreValueAsString(int preValueId)
|
||||
{
|
||||
//We need to see if we can find the cached PreValueCollection based on the cache key above
|
||||
var collections = IsolatedCache.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + "_");
|
||||
|
||||
var cached = IsolatedCache.GetCacheItemsByKeyExpression<PreValueCollection>(GetCacheKeyRegex(preValueId));
|
||||
if (cached != null && cached.Any())
|
||||
{
|
||||
//return from the cache
|
||||
var collection = cached.First();
|
||||
var preVal = collection.FormatAsDictionary().Single(x => x.Value.Id == preValueId);
|
||||
return preVal.Value.Value;
|
||||
}
|
||||
var preValue = collections.SelectMany(x => x.FormatAsDictionary().Values).FirstOrDefault(x => x.Id == preValueId);
|
||||
if (preValue != null)
|
||||
return preValue.Value;
|
||||
|
||||
//go and find the data type id for the pre val id passed in
|
||||
|
||||
var dto = Database.FirstOrDefault<DataTypePreValueDto>("WHERE id = @preValueId", new { preValueId = preValueId });
|
||||
var dto = Database.FirstOrDefault<DataTypePreValueDto>("WHERE id = @preValueId", new { preValueId });
|
||||
if (dto == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
// go cache the collection
|
||||
var preVals = GetAndCachePreValueCollection(dto.DataTypeNodeId);
|
||||
|
||||
//return the single value for this id
|
||||
var pv = preVals.FormatAsDictionary().Single(x => x.Value.Id == preValueId);
|
||||
return pv.Value.Value;
|
||||
var collection = GetCachedPreValueCollection(dto.DataTypeNodeId);
|
||||
if (collection == null)
|
||||
return string.Empty;
|
||||
|
||||
preValue = collection.FormatAsDictionary().Values.FirstOrDefault(x => x.Id == preValueId);
|
||||
return preValue == null ? string.Empty : preValue.Value;
|
||||
}
|
||||
|
||||
public void AddOrUpdatePreValues(int dataTypeId, IDictionary<string, PreValue> values)
|
||||
@@ -441,40 +427,28 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
sortOrder++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string GetPrefixedCacheKey(int dataTypeId)
|
||||
private static string GetPrefixedCacheKey(int dataTypeId)
|
||||
{
|
||||
return CacheKeys.DataTypePreValuesCacheKey + dataTypeId + "-";
|
||||
return CacheKeys.DataTypePreValuesCacheKey + "_" + dataTypeId;
|
||||
}
|
||||
|
||||
private PreValueCollection GetAndCachePreValueCollection(int dataTypeId)
|
||||
private PreValueCollection GetCachedPreValueCollection(int datetypeId)
|
||||
{
|
||||
//go get the data
|
||||
var dtos = Database.Fetch<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new { Id = dataTypeId });
|
||||
var list = dtos.Select(x => new Tuple<PreValue, string, int>(new PreValue(x.Id, x.Value, x.SortOrder), x.Alias, x.SortOrder)).ToList();
|
||||
var collection = PreValueConverter.ConvertToPreValuesCollection(list);
|
||||
|
||||
//now create the cache key, this needs to include all pre-value ids so that we can use this cached item in the GetPreValuesAsString method
|
||||
//the key will be: "UmbracoPreValDATATYPEID-CSVOFPREVALIDS
|
||||
|
||||
var key = GetPrefixedCacheKey(dataTypeId)
|
||||
+ string.Join(",", collection.FormatAsDictionary().Select(x => x.Value.Id).ToArray());
|
||||
|
||||
//store into cache
|
||||
IsolatedCache.InsertCacheItem(key, () => collection,
|
||||
//30 mins
|
||||
new TimeSpan(0, 0, 30),
|
||||
//sliding is true
|
||||
true);
|
||||
|
||||
return collection;
|
||||
var key = GetPrefixedCacheKey(datetypeId);
|
||||
return IsolatedCache.GetCacheItem<PreValueCollection>(key, () =>
|
||||
{
|
||||
var dtos = Database.Fetch<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new { Id = datetypeId });
|
||||
var list = dtos.Select(x => new Tuple<PreValue, string, int>(new PreValue(x.Id, x.Value, x.SortOrder), x.Alias, x.SortOrder)).ToList();
|
||||
var collection = PreValueConverter.ConvertToPreValuesCollection(list);
|
||||
return collection;
|
||||
}, TimeSpan.FromMinutes(20), isSliding: true);
|
||||
}
|
||||
|
||||
private string EnsureUniqueNodeName(string nodeName, int id = 0)
|
||||
{
|
||||
|
||||
|
||||
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
@@ -575,7 +549,7 @@ AND umbracoNode.id <> @id",
|
||||
}
|
||||
|
||||
//NOTE: We used to check that the Alias was unique for the given DataTypeNodeId prevalues list, BUT
|
||||
// in reality there is no need to check the uniqueness of this alias because the only way that this code executes is
|
||||
// in reality there is no need to check the uniqueness of this alias because the only way that this code executes is
|
||||
// based on an IDictionary<string, PreValue> dictionary being passed to this repository and a dictionary
|
||||
// must have unique aliases by definition, so there is no need for this additional check
|
||||
|
||||
@@ -595,10 +569,10 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
throw new InvalidOperationException("Cannot update a pre value for a data type that has no identity");
|
||||
}
|
||||
|
||||
|
||||
//NOTE: We used to check that the Alias was unique for the given DataTypeNodeId prevalues list, BUT
|
||||
// this causes issues when sorting the pre-values (http://issues.umbraco.org/issue/U4-5670) but in reality
|
||||
// there is no need to check the uniqueness of this alias because the only way that this code executes is
|
||||
// there is no need to check the uniqueness of this alias because the only way that this code executes is
|
||||
// based on an IDictionary<string, PreValue> dictionary being passed to this repository and a dictionary
|
||||
// must have unique aliases by definition, so there is no need for this additional check
|
||||
|
||||
@@ -613,7 +587,7 @@ AND umbracoNode.id <> @id",
|
||||
Database.Update(dto);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
internal static class PreValueConverter
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
//must be sorted this way for the relator to work
|
||||
.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
|
||||
|
||||
var dto = Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql).FirstOrDefault();
|
||||
@@ -64,6 +65,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
sql.Where("cmsDictionary.pk in (@ids)", new { ids = ids });
|
||||
}
|
||||
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
|
||||
|
||||
return Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql)
|
||||
.Select(dto => ConvertFromDto(dto));
|
||||
}
|
||||
@@ -73,6 +77,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IDictionaryItem>(sqlClause, query);
|
||||
var sql = translator.Translate();
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
|
||||
|
||||
return Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql)
|
||||
@@ -94,9 +99,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
else
|
||||
{
|
||||
sql.Select("*")
|
||||
.From<DictionaryDto>(SqlSyntax)
|
||||
.LeftJoin<LanguageTextDto>(SqlSyntax)
|
||||
.On<DictionaryDto, LanguageTextDto>(SqlSyntax, left => left.UniqueId, right => right.UniqueId);
|
||||
.From<DictionaryDto>(SqlSyntax)
|
||||
.LeftJoin<LanguageTextDto>(SqlSyntax)
|
||||
.On<DictionaryDto, LanguageTextDto>(SqlSyntax, left => left.UniqueId, right => right.UniqueId);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
@@ -270,6 +275,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var translator = new SqlTranslator<IDictionaryItem>(sqlClause, Query<IDictionaryItem>.Builder);
|
||||
var sql = translator.Translate();
|
||||
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
|
||||
|
||||
return Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql)
|
||||
@@ -297,6 +304,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IEnumerable<DictionaryDto> PerformFetch(Sql sql)
|
||||
{
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
|
||||
|
||||
return Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql);
|
||||
}
|
||||
|
||||
@@ -349,6 +359,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IEnumerable<DictionaryDto> PerformFetch(Sql sql)
|
||||
{
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<DictionaryDto>(x => x.UniqueId, SqlSyntax);
|
||||
|
||||
return Database.Fetch<DictionaryDto, LanguageTextDto, DictionaryDto>(new DictionaryLanguageTextRelator().Map, sql);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentTypeRepository : IContentTypeCompositionRepository<IContentType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Given the path of a content item, this will return true if the content item exists underneath a list view content item
|
||||
/// </summary>
|
||||
/// <param name="contentPath"></param>
|
||||
/// <returns></returns>
|
||||
bool HasContainerInPath(string contentPath);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all entities of the specified <see cref="PropertyType"/> query
|
||||
/// </summary>
|
||||
|
||||
@@ -37,6 +37,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
private IMacro GetBySql(Sql sql)
|
||||
{
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<MacroDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
var macroDto = Database.Fetch<MacroDto, MacroPropertyDto, MacroDto>(new MacroPropertyRelator().Map, sql).FirstOrDefault();
|
||||
if (macroDto == null)
|
||||
return null;
|
||||
@@ -68,7 +71,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
private IEnumerable<IMacro> GetAllNoIds()
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
var sql = GetBaseQuery(false)
|
||||
//must be sorted this way for the relator to work
|
||||
.OrderBy<MacroDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
return ConvertFromDtos(Database.Fetch<MacroDto, MacroPropertyDto, MacroDto>(new MacroPropertyRelator().Map, sql))
|
||||
.ToArray();// we don't want to re-iterate again!
|
||||
}
|
||||
@@ -92,6 +98,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var translator = new SqlTranslator<IMacro>(sqlClause, query);
|
||||
var sql = translator.Translate();
|
||||
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<MacroDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<MacroDto, MacroPropertyDto, MacroDto>(new MacroPropertyRelator().Map, sql);
|
||||
|
||||
foreach (var dto in dtos)
|
||||
@@ -114,13 +123,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return sql;
|
||||
}
|
||||
|
||||
private static Sql GetBaseQuery()
|
||||
private Sql GetBaseQuery()
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select("*")
|
||||
.From<MacroDto>()
|
||||
.LeftJoin<MacroPropertyDto>()
|
||||
.On<MacroDto, MacroPropertyDto>(left => left.Id, right => right.Macro);
|
||||
.From<MacroDto>()
|
||||
.LeftJoin<MacroPropertyDto>()
|
||||
.On<MacroDto, MacroPropertyDto>(left => left.Id, right => right.Macro);
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.id='{0}'", x)));
|
||||
sql.Where(statement);
|
||||
}
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<MemberTypeReadOnlyDto>(x => x.UniqueId, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
@@ -62,7 +64,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var subquery = translator.Translate();
|
||||
var sql = GetBaseQuery(false)
|
||||
.Append(new Sql("WHERE umbracoNode.id IN (" + subquery.SQL + ")", subquery.Arguments))
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
//must be sorted this way for the relator to work
|
||||
.OrderBy<MemberTypeReadOnlyDto>(x => x.UniqueId, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
|
||||
@@ -40,7 +40,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
var factory = new PublicAccessEntryFactory();
|
||||
|
||||
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
|
||||
sql.OrderBy<AccessDto>(dto => dto.Id, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<AccessDto, AccessRuleDto, AccessDto>(new AccessRulesRelator().Map, sql);
|
||||
return dtos.Select(factory.BuildEntity);
|
||||
}
|
||||
@@ -52,7 +55,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = translator.Translate();
|
||||
|
||||
var factory = new PublicAccessEntryFactory();
|
||||
|
||||
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
|
||||
sql.OrderBy<AccessDto>(dto => dto.Id, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<AccessDto, AccessRuleDto, AccessDto>(new AccessRulesRelator().Map, sql);
|
||||
return dtos.Select(factory.BuildEntity);
|
||||
}
|
||||
@@ -63,9 +69,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
sql.Select("*")
|
||||
.From<AccessDto>(SqlSyntax)
|
||||
.LeftJoin<AccessRuleDto>(SqlSyntax)
|
||||
.On<AccessDto, AccessRuleDto>(SqlSyntax, left => left.Id, right => right.AccessId)
|
||||
//MUST be ordered by this GUID ID for the AccessRulesRelator to work
|
||||
.OrderBy<AccessDto>(dto => dto.Id, SqlSyntax);
|
||||
.On<AccessDto, AccessRuleDto>(SqlSyntax, left => left.Id, right => right.AccessId);
|
||||
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<UserDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
var dto = Database.Fetch<UserDto, User2AppDto, UserDto>(new UserSectionRelator().Map, sql).FirstOrDefault();
|
||||
|
||||
@@ -60,7 +62,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
sql.Where("umbracoUser.id in (@ids)", new {ids = ids});
|
||||
}
|
||||
|
||||
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<UserDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
return ConvertFromDtos(Database.Fetch<UserDto, User2AppDto, UserDto>(new UserSectionRelator().Map, sql))
|
||||
.ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching.
|
||||
}
|
||||
@@ -71,6 +76,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var translator = new SqlTranslator<IUser>(sqlClause, query);
|
||||
var sql = translator.Translate();
|
||||
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<UserDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
var dtos = Database.Fetch<UserDto, User2AppDto, UserDto>(new UserSectionRelator().Map, sql)
|
||||
.DistinctBy(x => x.Id);
|
||||
|
||||
@@ -96,13 +104,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return sql;
|
||||
}
|
||||
|
||||
private static Sql GetBaseQuery(string columns)
|
||||
private Sql GetBaseQuery(string columns)
|
||||
{
|
||||
var sql = new Sql();
|
||||
sql.Select(columns)
|
||||
.From<UserDto>()
|
||||
.LeftJoin<User2AppDto>()
|
||||
.On<UserDto, User2AppDto>(left => left.Id, right => right.UserId);
|
||||
.From<UserDto>()
|
||||
.LeftJoin<User2AppDto>()
|
||||
.On<UserDto, User2AppDto>(left => left.Id, right => right.UserId);
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -300,6 +308,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var innerSql = GetBaseQuery("umbracoUser.id");
|
||||
innerSql.Where("umbracoUser2app.app = " + SqlSyntax.GetQuotedValue(sectionAlias));
|
||||
sql.Where(string.Format("umbracoUser.id IN ({0})", innerSql.SQL));
|
||||
//must be sorted this way for the relator to work
|
||||
sql.OrderBy<UserDto>(x => x.Id, SqlSyntax);
|
||||
|
||||
return ConvertFromDtos(Database.Fetch<UserDto, User2AppDto, UserDto>(new UserSectionRelator().Map, sql));
|
||||
}
|
||||
|
||||
@@ -49,7 +49,12 @@ namespace Umbraco.Core.Persistence
|
||||
_cacheHelper.IsolatedRuntimeCache.CacheFactory = type =>
|
||||
{
|
||||
var cache = origFactory(type);
|
||||
return new DeepCloneRuntimeCacheProvider(cache);
|
||||
|
||||
//if the result is already a DeepCloneRuntimeCacheProvider then return it, otherwise
|
||||
//wrap the result with a DeepCloneRuntimeCacheProvider
|
||||
return cache is DeepCloneRuntimeCacheProvider
|
||||
? cache
|
||||
: new DeepCloneRuntimeCacheProvider(cache);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+706
-631
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
public interface IParameterEditor
|
||||
public interface IParameterEditor : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// The id of the property editor
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
@@ -7,8 +8,8 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </summary>
|
||||
// todo: drop IPropertyEditorValueConverter support (when?).
|
||||
[Obsolete("Use IPropertyValueConverter.")]
|
||||
public interface IPropertyEditorValueConverter
|
||||
{
|
||||
public interface IPropertyEditorValueConverter : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether this provider applies to the specified property.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides published content properties conversion service.
|
||||
/// </summary>
|
||||
public interface IPropertyValueConverter
|
||||
public interface IPropertyValueConverter : IDiscoverable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the converter supports a property type.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
@@ -17,11 +19,13 @@ namespace Umbraco.Core.PropertyEditors
|
||||
internal class ParameterEditorResolver : LazyManyObjectsResolverBase<ParameterEditorResolver, IParameterEditor>
|
||||
{
|
||||
private readonly ManifestBuilder _builder;
|
||||
private readonly IContentSection _contentSection;
|
||||
|
||||
public ParameterEditorResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> typeListProducerList, ManifestBuilder builder)
|
||||
: base(serviceProvider, logger, typeListProducerList, ObjectLifetimeScope.Application)
|
||||
{
|
||||
_builder = builder;
|
||||
_contentSection = UmbracoConfig.For.UmbracoSettings().Content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,20 +35,27 @@ namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
get
|
||||
{
|
||||
//This will by default include all property editors and parameter editors but we need to filter this
|
||||
//list to ensure that none of the property editors that do not have the IsParameterEditor flag set to true
|
||||
//are filtered.
|
||||
var filtered = Values.Select(x => x as PropertyEditor)
|
||||
.WhereNotNull()
|
||||
.Where(x => x.IsParameterEditor == false);
|
||||
|
||||
return Values
|
||||
//exclude the non parameter editor c# property editors
|
||||
.Except(filtered)
|
||||
//include the manifest parameter editors
|
||||
.Union(_builder.ParameterEditors)
|
||||
//include the manifest prop editors that are parameter editors
|
||||
// all property editors and parameter editors
|
||||
// except property editors where !IsParameterEditor
|
||||
var values = Values
|
||||
.Where(x => x is PropertyEditor == false || ((PropertyEditor) x).IsParameterEditor);
|
||||
|
||||
// union all manifest parameter editors
|
||||
values = values
|
||||
.Union(_builder.ParameterEditors);
|
||||
|
||||
// union all manifest property editors where IsParameterEditor
|
||||
values = values
|
||||
.Union(_builder.PropertyEditors.Where(x => x.IsParameterEditor));
|
||||
|
||||
if (_contentSection.ShowDeprecatedPropertyEditors == false)
|
||||
{
|
||||
// except deprecated property editors
|
||||
values = values
|
||||
.Where(x => x is PropertyEditor == false || ((PropertyEditor) x).IsDeprecated == false);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -88,13 +89,26 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
/// </returns>
|
||||
private bool IsRangeDataType(int dataTypeId)
|
||||
{
|
||||
// ** This must be cached (U4-8862) **
|
||||
var enableRange =
|
||||
_dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeId)
|
||||
.PreValuesAsDictionary.FirstOrDefault(
|
||||
x => string.Equals(x.Key, "enableRange", StringComparison.InvariantCultureIgnoreCase)).Value;
|
||||
// GetPreValuesCollectionByDataTypeId is cached at repository level;
|
||||
// still, the collection is deep-cloned so this is kinda expensive,
|
||||
// better to cache here + trigger refresh in DataTypeCacheRefresher
|
||||
|
||||
return enableRange != null && enableRange.Value.TryConvertTo<bool>().Result;
|
||||
return Storages.GetOrAdd(dataTypeId, id =>
|
||||
{
|
||||
var preValue = _dataTypeService.GetPreValuesCollectionByDataTypeId(id)
|
||||
.PreValuesAsDictionary
|
||||
.FirstOrDefault(x => string.Equals(x.Key, "enableRange", StringComparison.InvariantCultureIgnoreCase))
|
||||
.Value;
|
||||
|
||||
return preValue != null && preValue.Value.TryConvertTo<bool>().Result;
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<int, bool> Storages = new ConcurrentDictionary<int, bool>();
|
||||
|
||||
internal static void ClearCaches()
|
||||
{
|
||||
Storages.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
@@ -74,18 +77,26 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
/// </returns>
|
||||
private bool JsonStorageType(int dataTypeId)
|
||||
{
|
||||
// ** This must be cached (U4-8862) **
|
||||
var storageType =
|
||||
_dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeId)
|
||||
.PreValuesAsDictionary.FirstOrDefault(
|
||||
x => string.Equals(x.Key, "storageType", StringComparison.InvariantCultureIgnoreCase)).Value;
|
||||
// GetPreValuesCollectionByDataTypeId is cached at repository level;
|
||||
// still, the collection is deep-cloned so this is kinda expensive,
|
||||
// better to cache here + trigger refresh in DataTypeCacheRefresher
|
||||
|
||||
if (storageType != null && storageType.Value.InvariantEquals("Json"))
|
||||
return Storages.GetOrAdd(dataTypeId, id =>
|
||||
{
|
||||
return true;
|
||||
}
|
||||
var preValue = _dataTypeService.GetPreValuesCollectionByDataTypeId(id)
|
||||
.PreValuesAsDictionary
|
||||
.FirstOrDefault(x => string.Equals(x.Key, "storageType", StringComparison.InvariantCultureIgnoreCase))
|
||||
.Value;
|
||||
|
||||
return false;
|
||||
return preValue != null && preValue.Value.InvariantEquals("json");
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<int, bool> Storages = new ConcurrentDictionary<int, bool>();
|
||||
|
||||
internal static void ClearCaches()
|
||||
{
|
||||
Storages.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -12,7 +13,8 @@ namespace Umbraco.Core.Publishing
|
||||
{
|
||||
public PublishStatus(IContent content, PublishStatusType statusType, EventMessages eventMessages)
|
||||
: base(content, statusType, eventMessages)
|
||||
{
|
||||
{
|
||||
InvalidProperties = Enumerable.Empty<Property>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -20,8 +22,7 @@ namespace Umbraco.Core.Publishing
|
||||
/// </summary>
|
||||
public PublishStatus(IContent content, EventMessages eventMessages)
|
||||
: this(content, PublishStatusType.Success, eventMessages)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
public IContent ContentItem
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Umbraco.Core.Publishing
|
||||
/// </summary>
|
||||
/// <param name="uow"></param>
|
||||
/// <param name="content"><see cref="IContent"/> to publish</param>
|
||||
/// <param name="userId">Id of the User issueing the publish operation</param>
|
||||
/// <param name="userId">Id of the User issueing the publish operation</param>
|
||||
Attempt<PublishStatus> IPublishingStrategy2.Publish(IScopeUnitOfWork uow, IContent content, int userId)
|
||||
{
|
||||
var evtMsgs = _eventMessagesFactory.Get();
|
||||
@@ -124,26 +124,26 @@ namespace Umbraco.Core.Publishing
|
||||
/// By default this is set to true which means that it will publish any content item in the list that is completely unpublished and
|
||||
/// not visible on the front-end. If set to false, this will only publish content that is live on the front-end but has new versions
|
||||
/// that have yet to be published.
|
||||
/// </param>
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
///
|
||||
///
|
||||
/// This method becomes complex once we start to be able to cancel events or stop publishing a content item in any way because if a
|
||||
/// content item is not published then it's children shouldn't be published either. This rule will apply for the following conditions:
|
||||
/// * If a document fails to be published, do not proceed to publish it's children if:
|
||||
/// ** The document does not have a publish version
|
||||
/// ** The document does have a published version but the includeUnpublishedDocuments = false
|
||||
///
|
||||
///
|
||||
/// In order to do this, we will order the content by level and begin by publishing each item at that level, then proceed to the next
|
||||
/// level and so on. If we detect that the above rule applies when the document publishing is cancelled we'll add it to the list of
|
||||
/// level and so on. If we detect that the above rule applies when the document publishing is cancelled we'll add it to the list of
|
||||
/// parentsIdsCancelled so that it's children don't get published.
|
||||
///
|
||||
///
|
||||
/// Its important to note that all 'root' documents included in the list *will* be published regardless of the rules mentioned
|
||||
/// above (unless it is invalid)!! By 'root' documents we are referring to documents in the list with the minimum value for their 'level'.
|
||||
/// In most cases the 'root' documents will only be one document since under normal circumstance we only publish one document and
|
||||
/// above (unless it is invalid)!! By 'root' documents we are referring to documents in the list with the minimum value for their 'level'.
|
||||
/// In most cases the 'root' documents will only be one document since under normal circumstance we only publish one document and
|
||||
/// its children. The reason we have to do this is because if a user is publishing a document and it's children, it is implied that
|
||||
/// the user definitely wants to publish it even if it has never been published before.
|
||||
///
|
||||
///
|
||||
/// </remarks>
|
||||
IEnumerable<Attempt<PublishStatus>> IPublishingStrategy2.PublishWithChildren(IScopeUnitOfWork uow,
|
||||
IEnumerable<IContent> content, int userId, bool includeUnpublishedDocuments)
|
||||
@@ -157,7 +157,7 @@ namespace Umbraco.Core.Publishing
|
||||
|
||||
//group by levels and iterate over the sorted ascending level.
|
||||
//TODO: This will cause all queries to execute, they will not be lazy but I'm not really sure being lazy actually made
|
||||
// much difference because we iterate over them all anyways?? Morten?
|
||||
// much difference because we iterate over them all anyways?? Morten?
|
||||
// Because we're grouping I think this will execute all the queries anyways so need to fetch it all first.
|
||||
var fetchedContent = content.ToArray();
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Umbraco.Core.Publishing
|
||||
var levelGroups = fetchedContent.GroupBy(x => x.Level);
|
||||
foreach (var level in levelGroups.OrderBy(x => x.Key))
|
||||
{
|
||||
//set the first level flag, used to ensure that all documents at the first level will
|
||||
//set the first level flag, used to ensure that all documents at the first level will
|
||||
//be published regardless of the rules mentioned in the remarks.
|
||||
if (!firstLevel.HasValue)
|
||||
{
|
||||
@@ -224,7 +224,10 @@ namespace Umbraco.Core.Publishing
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published because some of it's content is not passing validation rules.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid, evtMsgs)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid, evtMsgs)
|
||||
{
|
||||
InvalidProperties = ((ContentBase)item).LastInvalidProperties
|
||||
}));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -296,11 +299,11 @@ namespace Umbraco.Core.Publishing
|
||||
/// <param name="includeUnpublishedDocuments"></param>
|
||||
/// <remarks>
|
||||
/// See remarks on method: PublishWithChildrenInternal
|
||||
/// </remarks>
|
||||
/// </remarks>
|
||||
private void CheckCancellingOfChildPublishing(IContent content, List<int> parentsIdsCancelled, bool includeUnpublishedDocuments)
|
||||
{
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
//TODO: We're going back to the service layer here... not sure how to avoid this? And this will add extra overhead to
|
||||
//TODO: We're going back to the service layer here... not sure how to avoid this? And this will add extra overhead to
|
||||
// any document that fails to publish...
|
||||
var hasPublishedVersion = ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
|
||||
|
||||
@@ -358,9 +358,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var applicationAlias = (string)addElement.Attribute("application");
|
||||
var type = (string)addElement.Attribute("type");
|
||||
var assembly = (string)addElement.Attribute("assembly");
|
||||
|
||||
var clrType = Type.GetType(type);
|
||||
|
||||
var clrType = ApplicationTree.TryGetType(type);
|
||||
if (clrType == null)
|
||||
{
|
||||
_logger.Warn<ApplicationTreeService>("The tree definition: " + addElement.ToString() + " could not be resolved to a .Net object type");
|
||||
|
||||
@@ -19,14 +19,15 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public class ContentTypeService : ContentTypeServiceBase, IContentTypeService
|
||||
{
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IMediaService _mediaService;
|
||||
|
||||
//Support recursive locks because some of the methods that require locking call other methods that require locking.
|
||||
//for example, the Move method needs to be locked but this calls the Save method which also needs to be locked.
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
|
||||
public ContentTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory, IContentService contentService, IMediaService mediaService)
|
||||
public ContentTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory, IContentService contentService,
|
||||
IMediaService mediaService)
|
||||
: base(provider, repositoryFactory, logger, eventMessagesFactory)
|
||||
{
|
||||
if (contentService == null) throw new ArgumentNullException("contentService");
|
||||
@@ -210,7 +211,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public IEnumerable<EntityContainer> GetMediaTypeContainers(IMediaType mediaType)
|
||||
{
|
||||
var ancestorIds = mediaType.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
var ancestorIds = mediaType.Path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x =>
|
||||
{
|
||||
var asInt = x.TryConvertTo<int>();
|
||||
@@ -297,7 +298,7 @@ namespace Umbraco.Core.Services
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
|
||||
uow.Events.Dispatch(DeletedContentTypeContainer, this, new DeleteEventArgs<EntityContainer>(container, evtMsgs));
|
||||
uow.Events.Dispatch(DeletedContentTypeContainer, this, new DeleteEventArgs<EntityContainer>(container, evtMsgs), "DeletedContentTypeContainer");
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
@@ -425,7 +426,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
clone.Name = name;
|
||||
|
||||
var compositionAliases = clone.CompositionAliases().Except(new[] { alias }).ToList();
|
||||
var compositionAliases = clone.CompositionAliases().Except(new[] {alias}).ToList();
|
||||
//remove all composition that is not it's current alias
|
||||
foreach (var a in compositionAliases)
|
||||
{
|
||||
@@ -712,7 +713,7 @@ namespace Umbraco.Core.Services
|
||||
var comparer = new DelegateEqualityComparer<IContentTypeComposition>((x, y) => x.Id == y.Id, x => x.Id);
|
||||
var dependencies = new HashSet<IContentTypeComposition>(compositions, comparer);
|
||||
var stack = new Stack<IContentTypeComposition>();
|
||||
indirectReferences.ForEach(stack.Push);//Push indirect references to a stack, so we can add recursively
|
||||
indirectReferences.ForEach(stack.Push); //Push indirect references to a stack, so we can add recursively
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var indirectReference = stack.Pop();
|
||||
@@ -770,6 +771,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
ValidateLocked(contentType); // throws if invalid
|
||||
contentType.CreatorId = userId;
|
||||
if (contentType.Description == string.Empty)
|
||||
contentType.Description = null;
|
||||
repository.AddOrUpdate(contentType);
|
||||
|
||||
uow.Commit();
|
||||
@@ -812,6 +815,8 @@ namespace Umbraco.Core.Services
|
||||
foreach (var contentType in asArray)
|
||||
{
|
||||
contentType.CreatorId = userId;
|
||||
if (contentType.Description == string.Empty)
|
||||
contentType.Description = null;
|
||||
repository.AddOrUpdate(contentType);
|
||||
}
|
||||
|
||||
@@ -1233,6 +1238,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
ValidateLocked(mediaType); // throws if invalid
|
||||
mediaType.CreatorId = userId;
|
||||
if (mediaType.Description == string.Empty)
|
||||
mediaType.Description = null;
|
||||
repository.AddOrUpdate(mediaType);
|
||||
uow.Commit();
|
||||
|
||||
@@ -1274,6 +1281,8 @@ namespace Umbraco.Core.Services
|
||||
foreach (var mediaType in asArray)
|
||||
{
|
||||
mediaType.CreatorId = userId;
|
||||
if (mediaType.Description == string.Empty)
|
||||
mediaType.Description = null;
|
||||
repository.AddOrUpdate(mediaType);
|
||||
}
|
||||
|
||||
@@ -1452,40 +1461,40 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletingContentType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletedContentType;
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletedContentType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletingMediaType;
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletingMediaType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletedMediaType;
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletedMediaType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IContentType>> SavingContentType;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IContentType>> SavingContentType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IContentType>> SavedContentType;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IContentType>> SavedContentType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavingMediaType;
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavingMediaType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavedMediaType;
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavedMediaType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Move
|
||||
|
||||
@@ -5,6 +5,7 @@ using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
@@ -74,5 +75,20 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
return Enumerable.Empty<IContentTypeBase>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given the path of a content item, this will return true if the content item exists underneath a list view content item
|
||||
/// </summary>
|
||||
/// <param name="contentPath"></param>
|
||||
/// <returns></returns>
|
||||
public bool HasContainerInPath(string contentPath)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
// can use same repo for both content and media
|
||||
var repository = RepositoryFactory.CreateContentTypeRepository(uow);
|
||||
return repository.HasContainerInPath(contentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var result = _runtimeCache.GetCacheItem<int?>(CacheKeys.IdToKeyCacheKey + key, () =>
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
switch (umbracoObjectType)
|
||||
{
|
||||
@@ -92,7 +92,6 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
case UmbracoObjectTypes.DocumentTypeContainer:
|
||||
uow.Commit();
|
||||
return uow.Database.ExecuteScalar<int?>(new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.UniqueId == key));
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
@@ -119,7 +118,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var result = _runtimeCache.GetCacheItem<Guid?>(CacheKeys.KeyToIdCacheKey + id, () =>
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
switch (umbracoObjectType)
|
||||
{
|
||||
@@ -131,7 +130,6 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.DocumentType:
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
uow.Commit();
|
||||
return uow.Database.ExecuteScalar<Guid?>(new Sql().Select("uniqueID").From<NodeDto>().Where<NodeDto>(dto => dto.NodeId == id));
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
@@ -185,11 +183,10 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if (loadBaseType)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var ret = repository.Get(id);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -207,11 +204,10 @@ namespace Umbraco.Core.Services
|
||||
if (loadBaseType)
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var ret = repository.GetByKey(key, objectTypeId);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -241,11 +237,10 @@ namespace Umbraco.Core.Services
|
||||
if (loadBaseType)
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var ret = repository.Get(id, objectTypeId);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -276,11 +271,10 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if (loadBaseType)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var ret = repository.Get(id);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -303,7 +297,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An <see cref="IUmbracoEntity"/></returns>
|
||||
public virtual IUmbracoEntity GetParent(int id)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var entity = repository.Get(id);
|
||||
@@ -311,7 +305,6 @@ namespace Umbraco.Core.Services
|
||||
if (entity.ParentId == -1 || entity.ParentId == -20 || entity.ParentId == -21)
|
||||
return null;
|
||||
var ret = repository.Get(entity.ParentId);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -324,7 +317,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An <see cref="IUmbracoEntity"/></returns>
|
||||
public virtual IUmbracoEntity GetParent(int id, UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var entity = repository.Get(id);
|
||||
@@ -334,7 +327,6 @@ namespace Umbraco.Core.Services
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
|
||||
var ret = repository.Get(entity.ParentId, objectTypeId);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -346,13 +338,12 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
public virtual IEnumerable<IUmbracoEntity> GetChildren(int parentId)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == parentId);
|
||||
|
||||
var contents = repository.GetByQuery(query);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -366,13 +357,12 @@ namespace Umbraco.Core.Services
|
||||
public virtual IEnumerable<IUmbracoEntity> GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == parentId);
|
||||
|
||||
var contents = repository.GetByQuery(query, objectTypeId);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -393,7 +383,7 @@ namespace Umbraco.Core.Services
|
||||
string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.ParentId == parentId && x.Trashed == false);
|
||||
@@ -405,7 +395,6 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -426,7 +415,7 @@ namespace Umbraco.Core.Services
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
|
||||
@@ -442,7 +431,6 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -463,7 +451,7 @@ namespace Umbraco.Core.Services
|
||||
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true)
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
|
||||
@@ -481,7 +469,6 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
var contents = repository.GetPagedResultsByQuery(query, objectTypeId, pageIndex, pageSize, out totalRecords, orderBy, orderDirection, filterQuery);
|
||||
uow.Commit();
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
@@ -493,7 +480,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
public virtual IEnumerable<IUmbracoEntity> GetDescendents(int id)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var entity = repository.Get(id);
|
||||
@@ -501,7 +488,6 @@ namespace Umbraco.Core.Services
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.Path.StartsWith(pathMatch) && x.Id != id);
|
||||
|
||||
var entities = repository.GetByQuery(query);
|
||||
uow.Commit();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
@@ -515,14 +501,13 @@ namespace Umbraco.Core.Services
|
||||
public virtual IEnumerable<IUmbracoEntity> GetDescendents(int id, UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var entity = repository.Get(id);
|
||||
var query = Query<IUmbracoEntity>.Builder.Where(x => x.Path.StartsWith(entity.Path) && x.Id != id);
|
||||
|
||||
var entities = repository.GetByQuery(query, objectTypeId);
|
||||
uow.Commit();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
@@ -541,11 +526,10 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var entities = repository.GetByQuery(_rootEntityQuery, objectTypeId);
|
||||
uow.Commit();
|
||||
return entities;
|
||||
}
|
||||
}
|
||||
@@ -585,11 +569,10 @@ namespace Umbraco.Core.Services
|
||||
});
|
||||
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var ret = repository.GetAll(objectTypeId, ids);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -605,11 +588,10 @@ namespace Umbraco.Core.Services
|
||||
});
|
||||
|
||||
var objectTypeId = umbracoObjectType.GetGuid();
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var ret = repository.GetAll(objectTypeId, keys);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -631,11 +613,10 @@ namespace Umbraco.Core.Services
|
||||
("The passed in type is not supported");
|
||||
});
|
||||
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var ret = repository.GetAll(objectTypeId, ids);
|
||||
uow.Commit();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -721,22 +702,20 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public bool Exists(Guid key)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var exists = repository.Exists(key);
|
||||
uow.Commit();
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Exists(int id)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateEntityRepository(uow);
|
||||
var exists = repository.Exists(id);
|
||||
uow.Commit();
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,7 +868,7 @@ namespace Umbraco.Core.Services
|
||||
if (partialView == null)
|
||||
{
|
||||
uow.Commit();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uow.Events.DispatchCancelable(DeletingPartialView, this, new DeleteEventArgs<IPartialView>(partialView)))
|
||||
|
||||
@@ -11,6 +11,13 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IContentTypeService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// Given the path of a content item, this will return true if the content item exists underneath a list view content item
|
||||
/// </summary>
|
||||
/// <param name="contentPath"></param>
|
||||
/// <returns></returns>
|
||||
bool HasContainerInPath(string contentPath);
|
||||
|
||||
int CountContentTypes();
|
||||
int CountMediaTypes();
|
||||
|
||||
|
||||
@@ -468,12 +468,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="filepath">The filesystem path to the media.</param>
|
||||
void DeleteMediaFile(string filepath);
|
||||
|
||||
/// <summary>
|
||||
/// Generates thumbnails.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem-relative path to the original image.</param>
|
||||
/// <param name="propertyType">The property type.</param>
|
||||
/// <remarks>This should be obsoleted, we should not generate thumbnails.</remarks>
|
||||
[Obsolete("This should no longer be used, thumbnail generation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
void GenerateThumbnails(string filepath, PropertyType propertyType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1431,6 +1431,7 @@ namespace Umbraco.Core.Services
|
||||
_mediaFileSystem.DeleteFile(filepath, true);
|
||||
}
|
||||
|
||||
[Obsolete("This should no longer be used, thumbnail generation should be done via ImageProcessor, Umbraco no longer generates '_thumb' files for media")]
|
||||
public void GenerateThumbnails(string filepath, PropertyType propertyType)
|
||||
{
|
||||
using (var filestream = _mediaFileSystem.OpenFile(filepath))
|
||||
|
||||
@@ -93,6 +93,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = RepositoryFactory.CreateMemberTypeRepository(uow);
|
||||
memberType.CreatorId = userId;
|
||||
if (memberType.Description == string.Empty)
|
||||
memberType.Description = null;
|
||||
repository.AddOrUpdate(memberType);
|
||||
uow.Commit(); // flush, so that the db contains the saved value
|
||||
|
||||
@@ -121,6 +123,8 @@ namespace Umbraco.Core.Services
|
||||
foreach (var memberType in asArray)
|
||||
{
|
||||
memberType.CreatorId = userId;
|
||||
if (memberType.Description == string.Empty)
|
||||
memberType.Description = null;
|
||||
repository.AddOrUpdate(memberType);
|
||||
}
|
||||
uow.Commit(); // flush, so that the db contains the saved values
|
||||
|
||||
+118
-225
@@ -1,32 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
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 volatile HashSet<Assembly> _localFilteredAssemblyCache = null;
|
||||
private static volatile HashSet<Assembly> _localFilteredAssemblyCache;
|
||||
private static readonly object LocalFilteredAssemblyCacheLocker = new object();
|
||||
|
||||
/// <summary>
|
||||
@@ -63,7 +55,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
if ((e.InnerException is SecurityException) == false)
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -99,7 +91,7 @@ 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())
|
||||
if (assemblies.Any() == false)
|
||||
{
|
||||
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
@@ -111,12 +103,12 @@ namespace Umbraco.Core
|
||||
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())))
|
||||
if (appCodeFolder.Exists && fileExtensions.Any(x => appCodeFolder.GetFiles("*" + x).Any()))
|
||||
{
|
||||
try
|
||||
{
|
||||
var appCodeAssembly = Assembly.Load("App_Code");
|
||||
if (!assemblies.Contains(appCodeAssembly)) // BuildManager will find App_Code already
|
||||
if (assemblies.Contains(appCodeAssembly) == false) // BuildManager will find App_Code already
|
||||
assemblies.Add(appCodeAssembly);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
@@ -128,7 +120,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
if (!(e.InnerException is SecurityException))
|
||||
if (e.InnerException is SecurityException == false)
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -145,23 +137,15 @@ namespace Umbraco.Core
|
||||
internal static HashSet<Assembly> GetAssembliesWithKnownExclusions(
|
||||
IEnumerable<Assembly> excludeFromResults = null)
|
||||
{
|
||||
if (_localFilteredAssemblyCache == null)
|
||||
lock (LocalFilteredAssemblyCacheLocker)
|
||||
{
|
||||
lock (LocalFilteredAssemblyCacheLocker)
|
||||
{
|
||||
//double check
|
||||
if (_localFilteredAssemblyCache == null)
|
||||
{
|
||||
_localFilteredAssemblyCache = new HashSet<Assembly>();
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
foreach (var a in assemblies)
|
||||
{
|
||||
_localFilteredAssemblyCache.Add(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_localFilteredAssemblyCache != null)
|
||||
return _localFilteredAssemblyCache;
|
||||
|
||||
var assemblies = GetFilteredAssemblies(excludeFromResults, KnownAssemblyExclusionFilter);
|
||||
_localFilteredAssemblyCache = new HashSet<Assembly>(assemblies);
|
||||
return _localFilteredAssemblyCache;
|
||||
}
|
||||
return _localFilteredAssemblyCache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -180,9 +164,9 @@ namespace Umbraco.Core
|
||||
exclusionFilter = new string[] { };
|
||||
|
||||
return GetAllAssemblies()
|
||||
.Where(x => !excludeFromResults.Contains(x)
|
||||
&& !x.GlobalAssemblyCache
|
||||
&& !exclusionFilter.Any(f => x.FullName.StartsWith(f)));
|
||||
.Where(x => excludeFromResults.Contains(x) == false
|
||||
&& x.GlobalAssemblyCache == false
|
||||
&& exclusionFilter.Any(f => x.FullName.StartsWith(f)) == false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -298,7 +282,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(assignTypeFrom, assemblies, onlyConcreteClasses,
|
||||
return GetClassesWithBaseType(assignTypeFrom, assemblies, onlyConcreteClasses,
|
||||
//the additional filter will ensure that any found types also have the attribute applied.
|
||||
t => t.GetCustomAttributes<TAttribute>(false).Any());
|
||||
}
|
||||
@@ -324,7 +308,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
if (assemblies == null) throw new ArgumentNullException("assemblies");
|
||||
|
||||
return GetClasses(typeof(T), assemblies, onlyConcreteClasses);
|
||||
return GetClassesWithBaseType(typeof(T), assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -363,105 +347,9 @@ namespace Umbraco.Core
|
||||
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");
|
||||
|
||||
var foundAttributedTypes = new HashSet<Type>();
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
//find all assembly references that are referencing the attribute type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain a class that has this attribute.
|
||||
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(attributeType, assemblyList);
|
||||
|
||||
//get a list of non-referenced assemblies (we'll use this when we recurse below)
|
||||
var otherAssemblies = assemblyList.Where(x => referencedAssemblies.Contains(x) == false).ToArray();
|
||||
|
||||
//loop through the referenced assemblies
|
||||
foreach (var a in referencedAssemblies)
|
||||
{
|
||||
//get all types in this assembly
|
||||
var allTypes = GetTypesWithFormattedException(a)
|
||||
.ToArray();
|
||||
|
||||
var attributedTypes = new Type[] { };
|
||||
try
|
||||
{
|
||||
//now filter the types based on the onlyConcreteClasses flag, not interfaces, not static classes but have
|
||||
//the specified attribute
|
||||
attributedTypes = allTypes
|
||||
.Where(t => (TypeHelper.IsNonStaticClass(t)
|
||||
&& (onlyConcreteClasses == false || t.IsAbstract == false))
|
||||
//the type must have this attribute
|
||||
&& t.GetCustomAttributes(attributeType, false).Any())
|
||||
.ToArray();
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
LogHelper.Error(typeof(TypeFinder), string.Format("Could not query types on {0} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", a), ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
//add the types to our list to return
|
||||
foreach (var t in attributedTypes)
|
||||
{
|
||||
foundAttributedTypes.Add(t);
|
||||
}
|
||||
|
||||
//get all attributes of the type being searched for
|
||||
var allAttributeTypes = allTypes.Where(attributeType.IsAssignableFrom);
|
||||
|
||||
//now we need to include types that may be inheriting from sub classes of the attribute type being searched for
|
||||
//so we will search in assemblies that reference those types too.
|
||||
foreach (var subTypesInAssembly in allAttributeTypes.GroupBy(x => x.Assembly))
|
||||
{
|
||||
|
||||
//So that we are not scanning too much, we need to group the sub types:
|
||||
// * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type.
|
||||
// * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class
|
||||
// * We should not search for sub types if the type is static since you cannot inherit from them.
|
||||
var subTypeList = subTypesInAssembly
|
||||
.Where(t => t.IsSealed == false && TypeHelper.IsStaticClass(t) == false)
|
||||
.ToArray();
|
||||
|
||||
var baseClassAttempt = TypeHelper.GetLowestBaseType(subTypeList);
|
||||
|
||||
//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 HashSet<Type>();
|
||||
if (baseClassAttempt.Success)
|
||||
{
|
||||
subTypesToSearch.Add(baseClassAttempt.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
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 = FindClassesWithAttribute(typeToSearch, otherAssemblies, onlyConcreteClasses);
|
||||
|
||||
foreach (var f in foundTypes)
|
||||
{
|
||||
foundAttributedTypes.Add(f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return foundAttributedTypes;
|
||||
return GetClassesWithAttribute(attributeType, assemblies, onlyConcreteClasses);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds the classes with attribute.
|
||||
/// </summary>
|
||||
@@ -485,122 +373,129 @@ namespace Umbraco.Core
|
||||
return FindClassesWithAttribute<T>(GetAssembliesWithKnownExclusions());
|
||||
}
|
||||
|
||||
|
||||
#region Private methods
|
||||
|
||||
private static IEnumerable<Type> GetClassesWithAttribute(
|
||||
Type attributeType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses)
|
||||
{
|
||||
if (typeof(Attribute).IsAssignableFrom(attributeType) == false)
|
||||
throw new ArgumentException("Type " + attributeType + " is not an Attribute type.");
|
||||
|
||||
var candidateAssemblies = new HashSet<Assembly>(assemblies);
|
||||
var attributeAssemblyIsCandidate = candidateAssemblies.Contains(attributeType.Assembly);
|
||||
candidateAssemblies.Remove(attributeType.Assembly);
|
||||
var types = new List<Type>();
|
||||
|
||||
var stack = new Stack<Assembly>();
|
||||
stack.Push(attributeType.Assembly);
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var assembly = stack.Pop();
|
||||
|
||||
Type[] assemblyTypes = null;
|
||||
if (assembly != attributeType.Assembly || attributeAssemblyIsCandidate)
|
||||
{
|
||||
// get all assembly types that can be assigned to baseType
|
||||
try
|
||||
{
|
||||
assemblyTypes = GetTypesWithFormattedException(assembly)
|
||||
.ToArray(); // in try block
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
LogHelper.Error(typeof(TypeFinder), string.Format("Could not query types on {0} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly), ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
types.AddRange(assemblyTypes.Where(x =>
|
||||
x.IsClass // only classes
|
||||
&& (x.IsAbstract == false || x.IsSealed == false) // ie non-static, static is abstract and sealed
|
||||
&& x.IsNestedPrivate == false // exclude nested private
|
||||
&& (onlyConcreteClasses == false || x.IsAbstract == false) // exclude abstract
|
||||
&& x.GetCustomAttribute<HideFromTypeFinderAttribute>() == null // exclude hidden
|
||||
&& x.GetCustomAttributes(attributeType, false).Any())); // marked with the attribute
|
||||
}
|
||||
|
||||
if (assembly != attributeType.Assembly && assemblyTypes.Where(attributeType.IsAssignableFrom).Any() == false)
|
||||
continue;
|
||||
|
||||
foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
|
||||
{
|
||||
candidateAssemblies.Remove(referencing);
|
||||
stack.Push(referencing);
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
/// <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="baseType"></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,
|
||||
private static IEnumerable<Type> GetClassesWithBaseType(
|
||||
Type baseType,
|
||||
IEnumerable<Assembly> assemblies,
|
||||
bool onlyConcreteClasses,
|
||||
Func<Type, bool> additionalFilter = null)
|
||||
{
|
||||
//the default filter will always return true.
|
||||
if (additionalFilter == null)
|
||||
var candidateAssemblies = new HashSet<Assembly>(assemblies);
|
||||
var baseTypeAssemblyIsCandidate = candidateAssemblies.Contains(baseType.Assembly);
|
||||
candidateAssemblies.Remove(baseType.Assembly);
|
||||
var types = new List<Type>();
|
||||
|
||||
var stack = new Stack<Assembly>();
|
||||
stack.Push(baseType.Assembly);
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
additionalFilter = type => true;
|
||||
}
|
||||
var assembly = stack.Pop();
|
||||
|
||||
var foundAssignableTypes = new HashSet<Type>();
|
||||
|
||||
var assemblyList = assemblies.ToArray();
|
||||
|
||||
//find all assembly references that are referencing the current type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain sub type's of the one we're currently looking for
|
||||
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(assignTypeFrom, assemblyList);
|
||||
|
||||
//get a list of non-referenced assemblies (we'll use this when we recurse below)
|
||||
var otherAssemblies = assemblyList.Where(x => referencedAssemblies.Contains(x) == false).ToArray();
|
||||
|
||||
//loop through the referenced assemblies
|
||||
foreach (var a in referencedAssemblies)
|
||||
{
|
||||
//get all types in the assembly that are sub types of the current type
|
||||
var allSubTypes = GetTypesWithFormattedException(a)
|
||||
.Where(assignTypeFrom.IsAssignableFrom)
|
||||
.ToArray();
|
||||
|
||||
var filteredTypes = new Type[] { };
|
||||
try
|
||||
// get all assembly types that can be assigned to baseType
|
||||
Type[] assemblyTypes = null;
|
||||
if (assembly != baseType.Assembly || baseTypeAssemblyIsCandidate)
|
||||
{
|
||||
//now filter the types based on the onlyConcreteClasses flag, not interfaces, not static classes
|
||||
filteredTypes = allSubTypes
|
||||
.Where(t => (TypeHelper.IsNonStaticClass(t)
|
||||
//Do not include nested private classes - since we are in full trust now this will find those too!
|
||||
&& t.IsNestedPrivate == false
|
||||
&& (onlyConcreteClasses == false || t.IsAbstract == false)
|
||||
//Do not include classes that are flagged to hide from the type finder
|
||||
&& t.GetCustomAttribute<HideFromTypeFinderAttribute>() == null
|
||||
&& additionalFilter(t)))
|
||||
.ToArray();
|
||||
try
|
||||
{
|
||||
assemblyTypes = GetTypesWithFormattedException(assembly)
|
||||
.Where(baseType.IsAssignableFrom)
|
||||
.ToArray(); // in try block
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
LogHelper.Error(typeof(TypeFinder), string.Format("Could not query types on {0} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", assembly), ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
types.AddRange(assemblyTypes.Where(x =>
|
||||
x.IsClass // only classes
|
||||
&& (x.IsAbstract == false || x.IsSealed == false) // ie non-static, static is abstract and sealed
|
||||
&& x.IsNestedPrivate == false // exclude nested private
|
||||
&& (onlyConcreteClasses == false || x.IsAbstract == false) // exclude abstract
|
||||
&& x.GetCustomAttribute<HideFromTypeFinderAttribute>() == null // exclude hidden
|
||||
&& (additionalFilter == null || additionalFilter(x)))); // filter
|
||||
}
|
||||
catch (TypeLoadException ex)
|
||||
{
|
||||
LogHelper.Error(typeof(TypeFinder), string.Format("Could not query types on {0} assembly, this is most likely due to this assembly not being compatible with the current Umbraco version", a), ex);
|
||||
|
||||
if (assembly != baseType.Assembly && assemblyTypes.All(x => x.IsSealed))
|
||||
continue;
|
||||
}
|
||||
|
||||
//add the types to our list to return
|
||||
foreach (var t in filteredTypes)
|
||||
foreach (var referencing in TypeHelper.GetReferencingAssemblies(assembly, candidateAssemblies))
|
||||
{
|
||||
foundAssignableTypes.Add(t);
|
||||
candidateAssemblies.Remove(referencing);
|
||||
stack.Push(referencing);
|
||||
}
|
||||
|
||||
//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))
|
||||
{
|
||||
|
||||
//So that we are not scanning too much, we need to group the sub types:
|
||||
// * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type.
|
||||
// * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class
|
||||
// * We should not search for sub types if the type is static since you cannot inherit from them.
|
||||
var subTypeList = subTypesInAssembly
|
||||
.Where(t => t.IsSealed == false && TypeHelper.IsStaticClass(t) == false)
|
||||
.ToArray();
|
||||
|
||||
var baseClassAttempt = TypeHelper.GetLowestBaseType(subTypeList);
|
||||
|
||||
//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 HashSet<Type>();
|
||||
if (baseClassAttempt.Success)
|
||||
{
|
||||
subTypesToSearch.Add(baseClassAttempt.Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
|
||||
foreach (var f in foundTypes)
|
||||
{
|
||||
foundAssignableTypes.Add(f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return foundAssignableTypes;
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
internal static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
|
||||
@@ -666,7 +561,6 @@ namespace Umbraco.Core
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static Type GetTypeByName(string typeName)
|
||||
{
|
||||
var type = BuildManager.GetType(typeName, false);
|
||||
@@ -684,6 +578,5 @@ namespace Umbraco.Core
|
||||
.Select(x => x.GetType(typeName))
|
||||
.FirstOrDefault(x => x != null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,12 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
internal static class TypeHelper
|
||||
{
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, FieldInfo[]> GetFieldsCache = new ConcurrentDictionary<Type, FieldInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]> GetPropertiesCache = new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]> GetPropertiesCache
|
||||
= new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Type, FieldInfo[]> GetFieldsCache
|
||||
= new ConcurrentDictionary<Type, FieldInfo[]>();
|
||||
|
||||
private static readonly Assembly[] EmptyAssemblies = new Assembly[0];
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the method is actually overriding a base method
|
||||
@@ -30,44 +33,40 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Find all assembly references that are referencing the assignTypeFrom Type's assembly found in the assemblyList
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <param name="assembly">The referenced assembly.</param>
|
||||
/// <param name="assemblies">A list of assemblies.</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// If the assembly of the assignTypeFrom Type is in the App_Code assembly, then we return nothing since things cannot
|
||||
/// reference that assembly, same with the global.asax assembly.
|
||||
/// </remarks>
|
||||
public static Assembly[] GetReferencedAssemblies(Type assignTypeFrom, IEnumerable<Assembly> assemblies)
|
||||
public static Assembly[] GetReferencingAssemblies(Assembly assembly, IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
//check if it is the app_code assembly.
|
||||
//check if it is App_global.asax assembly
|
||||
if (assignTypeFrom.Assembly.IsAppCodeAssembly() || assignTypeFrom.Assembly.IsGlobalAsaxAssembly())
|
||||
{
|
||||
return Enumerable.Empty<Assembly>().ToArray();
|
||||
}
|
||||
if (assembly.IsAppCodeAssembly() || assembly.IsGlobalAsaxAssembly())
|
||||
return EmptyAssemblies;
|
||||
|
||||
|
||||
//find all assembly references that are referencing the current type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain sub type's of the one we're currently looking for
|
||||
return assemblies
|
||||
.Where(assembly =>
|
||||
assembly == assignTypeFrom.Assembly
|
||||
|| HasReferenceToAssemblyWithName(assembly, assignTypeFrom.Assembly.GetName().Name))
|
||||
.ToArray();
|
||||
// find all assembly references that are referencing the current type's assembly since we
|
||||
// should only be scanning those assemblies because any other assembly will definitely not
|
||||
// contain sub type's of the one we're currently looking for
|
||||
var name = assembly.GetName().Name;
|
||||
return assemblies.Where(x => x == assembly || HasReference(x, name)).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// checks if the assembly has a reference with the same name as the expected assembly name.
|
||||
/// Determines if an assembly references another assembly.
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="expectedAssemblyName"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName)
|
||||
{
|
||||
return assembly
|
||||
.GetReferencedAssemblies()
|
||||
.Select(a => a.Name)
|
||||
.Contains(expectedAssemblyName, StringComparer.Ordinal);
|
||||
public static bool HasReference(Assembly assembly, string name)
|
||||
{
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery - no!
|
||||
foreach (var a in assembly.GetReferencedAssemblies())
|
||||
{
|
||||
if (string.Equals(a.Name, name, StringComparison.Ordinal)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,13 +105,10 @@ namespace Umbraco.Core
|
||||
public static Attempt<Type> GetLowestBaseType(params Type[] types)
|
||||
{
|
||||
if (types.Length == 0)
|
||||
{
|
||||
return Attempt<Type>.Fail();
|
||||
}
|
||||
if (types.Length == 1)
|
||||
{
|
||||
|
||||
if (types.Length == 1)
|
||||
return Attempt.Succeed(types[0]);
|
||||
}
|
||||
|
||||
foreach (var curr in types)
|
||||
{
|
||||
@@ -196,20 +192,15 @@ namespace Umbraco.Core
|
||||
/// <param name="includeIndexed"></param>
|
||||
/// <param name="caseSensitive"> </param>
|
||||
/// <returns></returns>
|
||||
public static PropertyInfo GetProperty(Type type, string name,
|
||||
bool mustRead = true,
|
||||
bool mustWrite = true,
|
||||
public static PropertyInfo GetProperty(Type type, string name,
|
||||
bool mustRead = true,
|
||||
bool mustWrite = true,
|
||||
bool includeIndexed = false,
|
||||
bool caseSensitive = true)
|
||||
{
|
||||
return CachedDiscoverableProperties(type, mustRead, mustWrite, includeIndexed)
|
||||
.FirstOrDefault(x =>
|
||||
{
|
||||
if (caseSensitive)
|
||||
return x.Name == name;
|
||||
return x.Name.InvariantEquals(name);
|
||||
});
|
||||
}
|
||||
return CachedDiscoverableProperties(type, mustRead, mustWrite, includeIndexed)
|
||||
.FirstOrDefault(x => caseSensitive ? (x.Name == name) : x.Name.InvariantEquals(name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and caches) <see cref="FieldInfo"/> discoverable in the current <see cref="AppDomain"/> for a given <paramref name="type"/>.
|
||||
@@ -222,7 +213,7 @@ namespace Umbraco.Core
|
||||
type,
|
||||
x => type
|
||||
.GetFields(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(y => !y.IsInitOnly)
|
||||
.Where(y => y.IsInitOnly == false)
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
@@ -240,13 +231,12 @@ namespace Umbraco.Core
|
||||
new Tuple<Type, bool, bool, bool>(type, mustRead, mustWrite, includeIndexed),
|
||||
x => type
|
||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(y => (!mustRead || y.CanRead)
|
||||
&& (!mustWrite || y.CanWrite)
|
||||
&& (includeIndexed || !y.GetIndexParameters().Any()))
|
||||
.Where(y => (mustRead == false || y.CanRead)
|
||||
&& (mustWrite == false || y.CanWrite)
|
||||
&& (includeIndexed || y.GetIndexParameters().Any() == false))
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
|
||||
#region Match Type
|
||||
|
||||
//TODO: Need to determine if these methods should replace/combine/merge etc with IsTypeAssignableFrom, IsAssignableFromGeneric
|
||||
@@ -337,9 +327,9 @@ namespace Umbraco.Core
|
||||
|
||||
// not a generic type, not a generic parameter
|
||||
// so normal class or interface
|
||||
// fixme structs? enums? array types?
|
||||
// about primitive types, value types, etc:
|
||||
// http://stackoverflow.com/questions/1827425/how-to-check-programatically-if-a-type-is-a-struct-or-a-class
|
||||
// if it's a primitive type... it needs to be ==
|
||||
|
||||
if (implementation == contract) return true;
|
||||
if (contract.IsClass && implementation.IsClass && implementation.IsSubclassOf(contract)) return true;
|
||||
|
||||
@@ -199,6 +199,7 @@
|
||||
<Compile Include="Configuration\BaseRest\ExtensionElementCollection.cs" />
|
||||
<Compile Include="Configuration\BaseRest\MethodElement.cs" />
|
||||
<Compile Include="Configuration\ContentXmlStorage.cs" />
|
||||
<Compile Include="Configuration\CoreDebug.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AccessElement.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AccessItem.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AccessType.cs" />
|
||||
@@ -219,7 +220,6 @@
|
||||
<Compile Include="Configuration\Dashboard\SectionElement.cs" />
|
||||
<Compile Include="Configuration\Dashboard\TabCollection.cs" />
|
||||
<Compile Include="Configuration\Dashboard\TabElement.cs" />
|
||||
<Compile Include="Configuration\CoreDebug.cs" />
|
||||
<Compile Include="Configuration\FileSystemProviderElement.cs" />
|
||||
<Compile Include="Configuration\FileSystemProviderElementCollection.cs" />
|
||||
<Compile Include="Configuration\FileSystemProvidersSection.cs" />
|
||||
@@ -323,6 +323,7 @@
|
||||
<Compile Include="DateTimeExtensions.cs" />
|
||||
<Compile Include="DecimalExtensions.cs" />
|
||||
<Compile Include="DelegateExtensions.cs" />
|
||||
<Compile Include="Diagnostics\MiniDump.cs" />
|
||||
<Compile Include="Deploy\ArtifactBase.cs" />
|
||||
<Compile Include="Deploy\ArtifactDependency.cs" />
|
||||
<Compile Include="Deploy\ArtifactDependencyCollection.cs" />
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Tests.CodeFirst
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -84,10 +84,7 @@ namespace Umbraco.Tests.CodeFirst
|
||||
var foundTypes = _pluginManager.ResolveContentTypeBaseTypes();
|
||||
|
||||
Assert.That(foundTypes.Count(), Is.EqualTo(15));
|
||||
Assert.AreEqual(1,
|
||||
_pluginManager.GetTypeLists()
|
||||
.Count(x => x.IsTypeList<ContentTypeBase>(PluginManager.TypeResolutionKind.FindAllTypes)));
|
||||
Assert.AreEqual(1, _pluginManager.TypeLists.Count(x => x.BaseType == typeof (ContentTypeBase) && x.AttributeType == null));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -46,23 +46,6 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
return new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), SqlSyntax, Constants.ObjectTypes.DataTypeContainerGuid);
|
||||
}
|
||||
|
||||
[TestCase("UmbracoPreVal87-21,3,48", 3, true)]
|
||||
[TestCase("UmbracoPreVal87-21,33,48", 3, false)]
|
||||
[TestCase("UmbracoPreVal87-21,33,48", 33, true)]
|
||||
[TestCase("UmbracoPreVal87-21,3,48", 33, false)]
|
||||
[TestCase("UmbracoPreVal87-21,3,48", 21, true)]
|
||||
[TestCase("UmbracoPreVal87-21,3,48", 48, true)]
|
||||
[TestCase("UmbracoPreVal87-22,33,48", 2, false)]
|
||||
[TestCase("UmbracoPreVal87-22,33,48", 22, true)]
|
||||
[TestCase("UmbracoPreVal87-22,33,44", 4, false)]
|
||||
[TestCase("UmbracoPreVal87-22,33,44", 44, true)]
|
||||
[TestCase("UmbracoPreVal87-22,333,44", 33, false)]
|
||||
[TestCase("UmbracoPreVal87-22,333,44", 333, true)]
|
||||
public void Pre_Value_Cache_Key_Tests(string cacheKey, int preValueId, bool outcome)
|
||||
{
|
||||
Assert.AreEqual(outcome, Regex.IsMatch(cacheKey, DataTypeDefinitionRepository.GetCacheKeyRegex(preValueId)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Move()
|
||||
{
|
||||
@@ -537,7 +520,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
|
||||
var cached = cache.IsolatedRuntimeCache.GetCache<IDataTypeDefinition>().Result
|
||||
.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-");
|
||||
.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + "_" + dtd.Id);
|
||||
|
||||
Assert.IsNotNull(cached);
|
||||
Assert.AreEqual(1, cached.Count());
|
||||
@@ -581,7 +564,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
|
||||
var cached = cache.IsolatedRuntimeCache.GetCache<IDataTypeDefinition>().Result
|
||||
.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-");
|
||||
.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + "_" + dtd.Id);
|
||||
|
||||
Assert.IsNotNull(cached);
|
||||
Assert.AreEqual(1, cached.Count());
|
||||
|
||||
@@ -237,6 +237,14 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.AreEqual("test-path-1.js", script.Path);
|
||||
Assert.AreEqual("/scripts/test-path-1.js", script.VirtualPath);
|
||||
|
||||
//ensure you can prefix the same path as the root path name
|
||||
script = new Script("scripts/path-2/test-path-2.js") { Content = "// script" };
|
||||
repository.AddOrUpdate(script);
|
||||
unitOfWork.Commit();
|
||||
Assert.IsTrue(_fileSystem.FileExists("scripts/path-2/test-path-2.js"));
|
||||
Assert.AreEqual("scripts\\path-2\\test-path-2.js", script.Path);
|
||||
Assert.AreEqual("/scripts/scripts/path-2/test-path-2.js", script.VirtualPath);
|
||||
|
||||
script = new Script("path-2/test-path-2.js") { Content = "// script" };
|
||||
repository.AddOrUpdate(script);
|
||||
unitOfWork.Commit();
|
||||
|
||||
@@ -18,6 +18,7 @@ using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using umbraco.DataLayer;
|
||||
using umbraco.editorControls;
|
||||
using umbraco.interfaces;
|
||||
using umbraco.MacroEngines;
|
||||
using umbraco.uicontrols;
|
||||
using Umbraco.Web;
|
||||
@@ -34,14 +35,14 @@ namespace Umbraco.Tests.Plugins
|
||||
public void Initialize()
|
||||
{
|
||||
//this ensures its reset
|
||||
_manager = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(),
|
||||
_manager = new PluginManager(new ActivatorServiceProvider(), new NullCacheProvider(),
|
||||
new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
|
||||
//for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
|
||||
//TODO: Should probably update this so it only searches this assembly and add custom types to be found
|
||||
_manager.AssembliesToScan = new[]
|
||||
{
|
||||
this.GetType().Assembly,
|
||||
this.GetType().Assembly,
|
||||
typeof(ApplicationStartupHandler).Assembly,
|
||||
typeof(SqlCEHelper).Assembly,
|
||||
typeof(CMSNode).Assembly,
|
||||
@@ -160,7 +161,7 @@ namespace Umbraco.Tests.Plugins
|
||||
public void Detect_Legacy_Plugin_File_List()
|
||||
{
|
||||
var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache");
|
||||
|
||||
|
||||
var filePath= Path.Combine(tempFolder, string.Format("umbraco-plugins.{0}.list", NetworkHelper.FileSafeMachineName));
|
||||
|
||||
File.WriteAllText(filePath, @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
@@ -169,12 +170,11 @@ namespace Umbraco.Tests.Plugins
|
||||
<add type=""umbraco.macroCacheRefresh, umbraco, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null"" />
|
||||
</baseType>
|
||||
</plugins>");
|
||||
|
||||
Assert.IsTrue(_manager.DetectLegacyPluginListFile());
|
||||
|
||||
Assert.IsEmpty(_manager.ReadCache()); // uber-legacy cannot be read
|
||||
|
||||
File.Delete(filePath);
|
||||
|
||||
//now create a valid one
|
||||
File.WriteAllText(filePath, @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<plugins>
|
||||
<baseType type=""umbraco.interfaces.ICacheRefresher"" resolutionType=""FindAllTypes"">
|
||||
@@ -182,19 +182,32 @@ namespace Umbraco.Tests.Plugins
|
||||
</baseType>
|
||||
</plugins>");
|
||||
|
||||
Assert.IsFalse(_manager.DetectLegacyPluginListFile());
|
||||
Assert.IsEmpty(_manager.ReadCache()); // legacy cannot be read
|
||||
|
||||
File.Delete(filePath);
|
||||
|
||||
File.WriteAllText(filePath, @"IContentFinder
|
||||
|
||||
MyContentFinder
|
||||
AnotherContentFinder
|
||||
|
||||
");
|
||||
|
||||
Assert.IsNotNull(_manager.ReadCache()); // works
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Create_Cached_Plugin_File()
|
||||
{
|
||||
var types = new[] { typeof(PluginManager), typeof(PluginManagerTests), typeof(UmbracoContext) };
|
||||
var types = new[] { typeof (PluginManager), typeof (PluginManagerTests), typeof (UmbracoContext) };
|
||||
|
||||
//yes this is silly, none of these types inherit from string, but this is just to test the xml file format
|
||||
_manager.UpdateCachedPluginsFile<string>(types, PluginManager.TypeResolutionKind.FindAllTypes);
|
||||
var typeList1 = new PluginManager.TypeList(typeof (object), null);
|
||||
foreach (var type in types) typeList1.Add(type);
|
||||
_manager.AddTypeList(typeList1);
|
||||
_manager.WriteCache();
|
||||
|
||||
var plugins = _manager.TryGetCachedPluginsFromFile<string>(PluginManager.TypeResolutionKind.FindAllTypes);
|
||||
var diffType = _manager.TryGetCachedPluginsFromFile<string>(PluginManager.TypeResolutionKind.FindAttributedTypes);
|
||||
var plugins = _manager.TryGetCached(typeof (object), null);
|
||||
var diffType = _manager.TryGetCached(typeof (object), typeof (ObsoleteAttribute));
|
||||
|
||||
Assert.IsTrue(plugins.Success);
|
||||
//this will be false since there is no cache of that type resolution kind
|
||||
@@ -210,7 +223,7 @@ namespace Umbraco.Tests.Plugins
|
||||
public void PluginHash_From_String()
|
||||
{
|
||||
var s = "hello my name is someone".GetHashCode().ToString("x", CultureInfo.InvariantCulture);
|
||||
var output = PluginManager.ConvertPluginsHashFromHex(s);
|
||||
var output = PluginManager.ConvertHashToInt64(s);
|
||||
Assert.AreNotEqual(0, output);
|
||||
}
|
||||
|
||||
@@ -240,7 +253,7 @@ namespace Umbraco.Tests.Plugins
|
||||
var list1 = new[] { f1, f2, f3, f4, f5, f6 };
|
||||
var list2 = new[] { f1, f3, f5 };
|
||||
var list3 = new[] { f1, f3, f5, f7 };
|
||||
|
||||
|
||||
//Act
|
||||
var hash1 = PluginManager.GetFileHash(list1, new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
var hash2 = PluginManager.GetFileHash(list2, new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
@@ -259,9 +272,7 @@ namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
var foundTypes1 = _manager.ResolveFindMeTypes();
|
||||
var foundTypes2 = _manager.ResolveFindMeTypes();
|
||||
Assert.AreEqual(1,
|
||||
_manager.GetTypeLists()
|
||||
.Count(x => x.IsTypeList<IFindMe>(PluginManager.TypeResolutionKind.FindAllTypes)));
|
||||
Assert.AreEqual(1, _manager.TypeLists.Count(x => x.BaseType == typeof(IFindMe) && x.AttributeType == null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -344,20 +355,20 @@ namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
var types = new HashSet<PluginManager.TypeList>();
|
||||
|
||||
var propEditors = new PluginManager.TypeList<PropertyEditor>(PluginManager.TypeResolutionKind.FindAllTypes);
|
||||
propEditors.AddType(typeof(LabelPropertyEditor));
|
||||
var propEditors = new PluginManager.TypeList(typeof (PropertyEditor), null);
|
||||
propEditors.Add(typeof(LabelPropertyEditor));
|
||||
types.Add(propEditors);
|
||||
|
||||
var found = types.SingleOrDefault(x => x.IsTypeList<PropertyEditor>(PluginManager.TypeResolutionKind.FindAllTypes));
|
||||
var found = types.SingleOrDefault(x => x.BaseType == typeof (PropertyEditor) && x.AttributeType == null);
|
||||
|
||||
Assert.IsNotNull(found);
|
||||
|
||||
//This should not find a type list of this type
|
||||
var shouldNotFind = types.SingleOrDefault(x => x.IsTypeList<IParameterEditor>(PluginManager.TypeResolutionKind.FindAllTypes));
|
||||
var shouldNotFind = types.SingleOrDefault(x => x.BaseType == typeof (IParameterEditor) && x.AttributeType == null);
|
||||
|
||||
Assert.IsNull(shouldNotFind);
|
||||
}
|
||||
|
||||
|
||||
[XsltExtension("Blah.Blah")]
|
||||
public class MyXsltExtension
|
||||
{
|
||||
@@ -371,7 +382,7 @@ namespace Umbraco.Tests.Plugins
|
||||
|
||||
}
|
||||
|
||||
public interface IFindMe
|
||||
public interface IFindMe : IDiscoverable
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ using Umbraco.Web.BaseRest;
|
||||
|
||||
namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tests for typefinder
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
[TestFixture]
|
||||
public class TypeFinderTests
|
||||
{
|
||||
/// <summary>
|
||||
@@ -43,7 +43,7 @@ namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
_assemblies = new[]
|
||||
{
|
||||
this.GetType().Assembly,
|
||||
this.GetType().Assembly,
|
||||
typeof(ApplicationStartupHandler).Assembly,
|
||||
typeof(SqlCEHelper).Assembly,
|
||||
typeof(CMSNode).Assembly,
|
||||
@@ -75,7 +75,7 @@ namespace Umbraco.Tests.Plugins
|
||||
[Test]
|
||||
public void Find_Classes_Of_Type()
|
||||
{
|
||||
var typesFound = TypeFinder.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
|
||||
var typesFound = TypeFinder.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
|
||||
var originalTypesFound = TypeFinderOriginal.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
|
||||
|
||||
Assert.AreEqual(originalTypesFound.Count(), typesFound.Count());
|
||||
@@ -118,7 +118,7 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
@@ -149,7 +149,7 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class MyTag : ITag
|
||||
@@ -161,7 +161,7 @@ namespace Umbraco.Tests.Plugins
|
||||
|
||||
public class MySuperTag : MyTag
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
|
||||
@@ -203,7 +203,7 @@ namespace Umbraco.Tests.Plugins
|
||||
/// 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
|
||||
/// 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
|
||||
@@ -329,8 +329,8 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
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
|
||||
//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.
|
||||
}
|
||||
}
|
||||
@@ -347,9 +347,9 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
catch (SecurityException)
|
||||
{
|
||||
//we will just ignore this because if we are trying to do a call to:
|
||||
//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
|
||||
//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.
|
||||
}
|
||||
}
|
||||
@@ -361,7 +361,7 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
|
||||
/// 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>
|
||||
@@ -429,7 +429,7 @@ namespace Umbraco.Tests.Plugins
|
||||
"RouteDebugger,",
|
||||
"SqlCE4Umbraco,",
|
||||
"umbraco.datalayer,",
|
||||
"umbraco.interfaces,",
|
||||
"umbraco.interfaces,",
|
||||
"umbraco.providers,",
|
||||
"Umbraco.Web.UI,",
|
||||
"umbraco.webservices",
|
||||
@@ -631,5 +631,5 @@ namespace Umbraco.Tests.Plugins
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Runtime.Remoting;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -9,7 +8,6 @@ using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.CodeFirst.TestModels.Composition;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
|
||||
@@ -1644,6 +1642,38 @@ namespace Umbraco.Tests.Services
|
||||
Assert.That(descriptionPropertyTypeReloaded.PropertyGroupId.IsValueCreated, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Empty_Description_Is_Always_Null_After_Saving_Content_Type()
|
||||
{
|
||||
var service = ServiceContext.ContentTypeService;
|
||||
var contentType = MockedContentTypes.CreateBasicContentType();
|
||||
contentType.Description = null;
|
||||
service.Save(contentType);
|
||||
|
||||
var contentType2 = MockedContentTypes.CreateBasicContentType("basePage2", "Base Page 2");
|
||||
contentType2.Description = string.Empty;
|
||||
service.Save(contentType2);
|
||||
|
||||
Assert.IsNull(contentType.Description);
|
||||
Assert.IsNull(contentType2.Description);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Empty_Description_Is_Always_Null_After_Saving_Media_Type()
|
||||
{
|
||||
var service = ServiceContext.ContentTypeService;
|
||||
var mediaType = MockedContentTypes.CreateSimpleMediaType("mediaType", "Media Type");
|
||||
mediaType.Description = null;
|
||||
service.Save(mediaType);
|
||||
|
||||
var mediaType2 = MockedContentTypes.CreateSimpleMediaType("mediaType2", "Media Type 2");
|
||||
mediaType2.Description = string.Empty;
|
||||
service.Save(mediaType2);
|
||||
|
||||
Assert.IsNull(mediaType.Description);
|
||||
Assert.IsNull(mediaType2.Description);
|
||||
}
|
||||
|
||||
private ContentType CreateComponent()
|
||||
{
|
||||
var component = new ContentType(-1)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using umbraco.cms.presentation.create.controls;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
@@ -183,6 +181,22 @@ namespace Umbraco.Tests.Services
|
||||
Assert.Throws<ArgumentException>(() => ServiceContext.MemberTypeService.Save(memberType));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Empty_Description_Is_Always_Null_After_Saving_Member_Type()
|
||||
{
|
||||
var service = ServiceContext.MemberTypeService;
|
||||
var memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
memberType.Description = null;
|
||||
service.Save(memberType);
|
||||
|
||||
var memberType2 = MockedContentTypes.CreateSimpleMemberType("memberType2", "Member Type 2");
|
||||
memberType2.Description = string.Empty;
|
||||
service.Save(memberType2);
|
||||
|
||||
Assert.IsNull(memberType.Description);
|
||||
Assert.IsNull(memberType2.Description);
|
||||
}
|
||||
|
||||
//[Test]
|
||||
//public void Can_Save_MemberType_Structure_And_Create_A_Member_Based_On_It()
|
||||
//{
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
|
||||
// reset settings
|
||||
SettingsForTests.Reset();
|
||||
UmbracoContext.Current = null;
|
||||
@@ -119,7 +119,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// By default this returns false which means the plugin manager will not be reset so it doesn't need to re-scan
|
||||
/// By default this returns false which means the plugin manager will not be reset so it doesn't need to re-scan
|
||||
/// all of the assemblies. Inheritors can override this if plugin manager resetting is required, generally needs
|
||||
/// to be set to true if the SetupPluginManager has been overridden.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.81.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.81\lib\net45\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.82.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.82\lib\net45\Examine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.81" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.82" targetFramework="net45" />
|
||||
<package id="log4net" version="2.0.5" targetFramework="net45" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
|
||||
|
||||
@@ -191,27 +191,34 @@ tinymce.PluginManager.add('umbracolink', function(editor) {
|
||||
callback: function (data) {
|
||||
if (data) {
|
||||
var href = data.url;
|
||||
|
||||
// We want to use the Udi. If it is set, we use it, else fallback to id, and finally to null
|
||||
var hasUdi = data.udi ? true : false;
|
||||
var id = hasUdi ? data.udi : (data.id ? data.id : null);
|
||||
|
||||
//Create a json obj used to create the attributes for the tag
|
||||
function createElemAttributes() {
|
||||
var a = {
|
||||
href: href,
|
||||
title: data.name,
|
||||
target: data.target ? data.target : null,
|
||||
rel: data.rel ? data.rel : null
|
||||
};
|
||||
if (hasUdi) {
|
||||
a["data-udi"] = data.udi;
|
||||
}
|
||||
else if (data.id) {
|
||||
a["data-id"] = data.id;
|
||||
}
|
||||
}
|
||||
|
||||
function insertLink() {
|
||||
if (anchorElm) {
|
||||
dom.setAttribs(anchorElm, {
|
||||
href: href,
|
||||
title: data.name,
|
||||
target: data.target ? data.target : null,
|
||||
rel: data.rel ? data.rel : null,
|
||||
'data-id': data.id ? data.id : null
|
||||
});
|
||||
dom.setAttribs(anchorElm, createElemAttributes());
|
||||
|
||||
selection.select(anchorElm);
|
||||
editor.execCommand('mceEndTyping');
|
||||
} else {
|
||||
editor.execCommand('mceInsertLink', false, {
|
||||
href: href,
|
||||
title: data.name,
|
||||
target: data.target ? data.target : null,
|
||||
rel: data.rel ? data.rel : null,
|
||||
'data-id': data.id ? data.id : null
|
||||
});
|
||||
editor.execCommand('mceInsertLink', false, createElemAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,15 +228,11 @@ tinymce.PluginManager.add('umbracolink', function(editor) {
|
||||
}
|
||||
|
||||
//if we have an id, it must be a locallink:id, aslong as the isMedia flag is not set
|
||||
if(data.id && (angular.isUndefined(data.isMedia) || !data.isMedia)){
|
||||
if (target.udi) {
|
||||
href = "/{localLink:" + target.udi + "}";
|
||||
}
|
||||
else {
|
||||
//This shouldn't happen! but just in case we'll leave this here
|
||||
href = "/{localLink:" + target.id + "}";
|
||||
}
|
||||
insertLink();
|
||||
if (id && (angular.isUndefined(data.isMedia) || !data.isMedia)){
|
||||
|
||||
href = "/{localLink:" + id + "}";
|
||||
|
||||
insertLink();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -163,13 +163,13 @@ angular.module('umbraco.directives')
|
||||
}
|
||||
|
||||
// ignore clicks on dialog from old dialog service
|
||||
var oldDialog = $(el).parents("#old-dialog-service");
|
||||
var oldDialog = $(event.target).parents("#old-dialog-service");
|
||||
if (oldDialog.length === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore clicks in tinyMCE dropdown(floatpanel)
|
||||
var floatpanel = $(el).parents(".mce-floatpanel");
|
||||
var floatpanel = $(event.target).closest(".mce-floatpanel");
|
||||
if (floatpanel.length === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
+4
-2
@@ -108,8 +108,10 @@ angular.module("umbraco.directives")
|
||||
$image.load(function(){
|
||||
$timeout(function(){
|
||||
setDimensions();
|
||||
scope.loaded = true;
|
||||
scope.onImageLoaded();
|
||||
scope.loaded = true;
|
||||
if (scope.onImageLoaded) {
|
||||
scope.onImageLoaded();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+3
-2
@@ -17,6 +17,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
hideheader: '@',
|
||||
cachekey: '@',
|
||||
isdialog: '@',
|
||||
onlyinitialized: '@',
|
||||
//Custom query string arguments to pass in to the tree as a string, example: "startnodeid=123&something=value"
|
||||
customtreeparams: '@',
|
||||
eventhandler: '=',
|
||||
@@ -252,7 +253,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
deleteAnimations = false;
|
||||
|
||||
//default args
|
||||
var args = { section: scope.section, tree: scope.treealias, cacheKey: scope.cachekey, isDialog: scope.isdialog ? scope.isdialog : false };
|
||||
var args = { section: scope.section, tree: scope.treealias, cacheKey: scope.cachekey, isDialog: scope.isdialog ? scope.isdialog : false, onlyinitialized: scope.onlyinitialized };
|
||||
|
||||
//add the extra query string params if specified
|
||||
if (scope.customtreeparams) {
|
||||
@@ -305,7 +306,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
scope.selectEnabledNodeClass = function (node) {
|
||||
return node ?
|
||||
node.selected ?
|
||||
'icon umb-tree-icon sprTree icon-check blue temporary' :
|
||||
'icon umb-tree-icon sprTree icon-check green temporary' :
|
||||
'' :
|
||||
'';
|
||||
};
|
||||
|
||||
+2
-1
@@ -87,7 +87,8 @@ Use this directive to generate a list of folders presented as a flexbox grid.
|
||||
|
||||
scope.clickFolder = function(folder, $event, $index) {
|
||||
if(scope.onClick) {
|
||||
scope.onClick(folder, $event, $index);
|
||||
scope.onClick(folder, $event, $index);
|
||||
$event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -247,6 +247,7 @@ Use this directive to generate a thumbnail grid of media items.
|
||||
scope.clickItem = function(item, $event, $index) {
|
||||
if (scope.onClick) {
|
||||
scope.onClick(item, $event, $index);
|
||||
$event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+11
-1
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MiniListViewDirective(entityResource) {
|
||||
function MiniListViewDirective(entityResource, iconHelper) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
|
||||
function open(node) {
|
||||
|
||||
// convert legacy icon for node
|
||||
if(node && node.icon) {
|
||||
node.icon = iconHelper.convertFromLegacyIcon(node.icon);
|
||||
}
|
||||
|
||||
goingForward = true;
|
||||
|
||||
var miniListView = {
|
||||
@@ -58,6 +63,11 @@
|
||||
// update children
|
||||
miniListView.children = data.items;
|
||||
_.each(miniListView.children, function(c) {
|
||||
// convert legacy icon for node
|
||||
if(c.icon) {
|
||||
c.icon = iconHelper.convertFromLegacyIcon(c.icon);
|
||||
}
|
||||
// set published state for content
|
||||
if (c.metaData) {
|
||||
c.hasChildren = c.metaData.HasChildren;
|
||||
if(scope.entityType === "Document") {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function TableDirective() {
|
||||
function TableDirective(iconHelper) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
}
|
||||
};
|
||||
|
||||
scope.getIcon = function (entry) {
|
||||
return iconHelper.convertFromLegacyIcon(entry.icon);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
|
||||
+10
-8
@@ -9,7 +9,7 @@ function valServerField(serverValidationManager) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
link: function (scope, element, attr, ngModel) {
|
||||
|
||||
var fieldName = null;
|
||||
var eventBindings = [];
|
||||
@@ -23,23 +23,25 @@ function valServerField(serverValidationManager) {
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
eventBindings.push(scope.$watch('ngModel', function(newValue){
|
||||
if (ctrl.$invalid) {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
eventBindings.push(scope.$watch(function() {
|
||||
return ngModel.$modelValue;
|
||||
}, function(newValue){
|
||||
if (ngModel.$invalid) {
|
||||
ngModel.$setValidity('valServerField', true);
|
||||
}
|
||||
}));
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
ctrl.$setValidity('valServerField', false);
|
||||
ngModel.$setValidity('valServerField', false);
|
||||
//assign an error msg property to the current validator
|
||||
ctrl.errorMsg = fieldErrors[0].errorMsg;
|
||||
ngModel.errorMsg = fieldErrors[0].errorMsg;
|
||||
}
|
||||
else {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
ngModel.$setValidity('valServerField', true);
|
||||
//reset the error message
|
||||
ctrl.errorMsg = "";
|
||||
ngModel.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -343,8 +343,13 @@ angular.module('umbraco.mocks').
|
||||
{
|
||||
results.push(decodeURIComponent(match[1].replace(/\+/g, " ")));
|
||||
}
|
||||
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
getObjectPropertyFromJsonString: function(data, name) {
|
||||
var obj = JSON.parse(data);
|
||||
return obj[name];
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -21,8 +21,27 @@ angular.module('umbraco.mocks').
|
||||
if (!mocksUtils.checkAuth()) {
|
||||
return [401, null, null];
|
||||
}
|
||||
|
||||
|
||||
var ids = mocksUtils.getParametersByName(data, "ids") || [1234, 23324, 2323, 23424];
|
||||
|
||||
var nodes = [];
|
||||
|
||||
$(ids).each(function (i, id) {
|
||||
var _id = parseInt(id, 10);
|
||||
nodes.push(mocksUtils.getMockEntity(_id));
|
||||
});
|
||||
|
||||
return [200, nodes, null];
|
||||
}
|
||||
|
||||
function returnEntitybyIdsPost(method, url, data, headers) {
|
||||
|
||||
if (!mocksUtils.checkAuth()) {
|
||||
return [401, null, null];
|
||||
}
|
||||
|
||||
var ids = mocksUtils.getObjectPropertyFromJsonString(data, "ids") || [1234, 23324, 2323, 23424];
|
||||
|
||||
var nodes = [];
|
||||
|
||||
$(ids).each(function (i, id) {
|
||||
@@ -50,6 +69,10 @@ angular.module('umbraco.mocks').
|
||||
.whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetByIds'))
|
||||
.respond(returnEntitybyIds);
|
||||
|
||||
$httpBackend
|
||||
.whenPOST(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetByIds'))
|
||||
.respond(returnEntitybyIdsPost);
|
||||
|
||||
$httpBackend
|
||||
.whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetAncestors'))
|
||||
.respond(returnEntitybyIds);
|
||||
|
||||
@@ -199,11 +199,17 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*/
|
||||
|
||||
getScaffold: function (type, id, snippetName) {
|
||||
|
||||
var queryString = "?type=" + type + "&id=" + id;
|
||||
if (snippetName) {
|
||||
queryString += "&snippetName=" + snippetName;
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"GetScaffold?type=" + type + "&id=" + id + "&snippetName=" + snippetName)),
|
||||
"codeFileApiBaseUrl",
|
||||
"GetScaffold" + queryString)),
|
||||
"Failed to get scaffold for" + type);
|
||||
},
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
* @ngdoc service
|
||||
* @name umbraco.resources.macroResource
|
||||
* @description Deals with data for macros
|
||||
*
|
||||
*
|
||||
**/
|
||||
function macroResource($q, $http, umbRequestHelper) {
|
||||
|
||||
//the factory object returned
|
||||
return {
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.macroResource#getMacroParameters
|
||||
@@ -20,7 +20,7 @@ function macroResource($q, $http, umbRequestHelper) {
|
||||
* @param {int} macroId The macro id to get parameters for
|
||||
*
|
||||
*/
|
||||
getMacroParameters: function (macroId) {
|
||||
getMacroParameters: function (macroId) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -29,7 +29,7 @@ function macroResource($q, $http, umbRequestHelper) {
|
||||
[{ macroId: macroId }])),
|
||||
'Failed to retrieve macro parameters for macro with id ' + macroId);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.macroResource#getMacroResult
|
||||
@@ -55,6 +55,27 @@ function macroResource($q, $http, umbRequestHelper) {
|
||||
macroParams: macroParamDictionary
|
||||
}),
|
||||
'Failed to retrieve macro result for macro with alias ' + macroAlias);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {} filename
|
||||
* @returns {}
|
||||
*/
|
||||
createPartialViewMacroWithFile: function(virtualPath, filename) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"macroApiBaseUrl",
|
||||
"CreatePartialViewMacroWithFile"), {
|
||||
virtualPath: virtualPath,
|
||||
filename: filename
|
||||
}
|
||||
),
|
||||
'Failed to create macro "' + filename + '"'
|
||||
);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -51,10 +51,15 @@ function treeResource($q, $http, umbRequestHelper) {
|
||||
if (!options.isDialog) {
|
||||
options.isDialog = false;
|
||||
}
|
||||
|
||||
|
||||
//create the query string for the tree request, these are the mandatory options:
|
||||
var query = "application=" + options.section + "&tree=" + options.tree + "&isDialog=" + options.isDialog;
|
||||
|
||||
//if you need to load a not initialized tree set this value to false - default is true
|
||||
if (options.onlyinitialized) {
|
||||
query += "&onlyInitialized=" + options.onlyinitialized;
|
||||
}
|
||||
|
||||
//the options can contain extra query string parameters
|
||||
if (options.queryString) {
|
||||
query += "&" + options.queryString;
|
||||
|
||||
@@ -522,6 +522,26 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.services.contentEditingHelper#redirectToRenamedContent
|
||||
* @methodOf umbraco.services.contentEditingHelper
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* For some editors like scripts or entites that have names as ids, these names can change and we need to redirect
|
||||
* to their new paths, this is helper method to do that.
|
||||
*/
|
||||
redirectToRenamedContent: function (id) {
|
||||
//clear the query strings
|
||||
$location.search("");
|
||||
//change to new path
|
||||
$location.path("/" + $routeParams.section + "/" + $routeParams.tree + "/" + $routeParams.method + "/" + id);
|
||||
//don't add a browser history for this
|
||||
$location.replace();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function entityHelper() {
|
||||
|
||||
function getEntityTypeFromSection(section) {
|
||||
if (section === "member") {
|
||||
return "Member";
|
||||
}
|
||||
else if (section === "media") {
|
||||
return "Media";
|
||||
} else {
|
||||
return "Document";
|
||||
}
|
||||
}
|
||||
|
||||
////////////
|
||||
|
||||
var service = {
|
||||
getEntityTypeFromSection: getEntityTypeFromSection
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.services').factory('entityHelper', entityHelper);
|
||||
|
||||
})();
|
||||
@@ -21,7 +21,9 @@ function mediaTypeHelper(mediaTypeResource, $q) {
|
||||
},
|
||||
|
||||
getAllowedImagetypes: function (mediaId){
|
||||
|
||||
|
||||
//TODO: This is horribly inneficient - why make one request per type!?
|
||||
|
||||
// Get All allowedTypes
|
||||
return mediaTypeResource.getAllowedTypes(mediaId)
|
||||
.then(function(types){
|
||||
|
||||
@@ -8,8 +8,15 @@
|
||||
return "@Umbraco.GetDictionaryValue(\"" + nodeName + "\")";
|
||||
}
|
||||
|
||||
function getInsertPartialSnippet(nodeName) {
|
||||
return "@Html.Partial(\"" + nodeName + "\")";
|
||||
function getInsertPartialSnippet(parentId, nodeName) {
|
||||
|
||||
var partialViewName = nodeName.replace(".cshtml", "");
|
||||
|
||||
if(parentId) {
|
||||
partialViewName = parentId + "/" + partialViewName;
|
||||
}
|
||||
|
||||
return "@Html.Partial(\"" + partialViewName + "\")";
|
||||
}
|
||||
|
||||
function getQuerySnippet(queryExpression) {
|
||||
|
||||
@@ -95,11 +95,20 @@ function tinyMceService(dialogService, $log, imageHelper, $http, $timeout, macro
|
||||
|
||||
if(selectedElm.nodeName === 'IMG'){
|
||||
var img = $(selectedElm);
|
||||
|
||||
var hasUdi = img.attr("data-udi") ? true : false;
|
||||
|
||||
currentTarget = {
|
||||
altText: img.attr("alt"),
|
||||
url: img.attr("src"),
|
||||
id: img.attr("rel")
|
||||
url: img.attr("src")
|
||||
};
|
||||
|
||||
if (hasUdi) {
|
||||
currentTarget["udi"] = img.attr("data-udi");
|
||||
}
|
||||
else {
|
||||
currentTarget["id"] = img.attr("rel");
|
||||
}
|
||||
}
|
||||
|
||||
userService.getCurrentUser().then(function(userData) {
|
||||
@@ -115,13 +124,23 @@ function tinyMceService(dialogService, $log, imageHelper, $http, $timeout, macro
|
||||
insertMediaInEditor: function(editor, img) {
|
||||
if(img) {
|
||||
|
||||
var hasUdi = img.udi ? true : false;
|
||||
|
||||
var data = {
|
||||
alt: img.altText || "",
|
||||
src: (img.url) ? img.url : "nothing.jpg",
|
||||
rel: img.id,
|
||||
'data-id': img.id,
|
||||
src: (img.url) ? img.url : "nothing.jpg",
|
||||
id: '__mcenew'
|
||||
};
|
||||
};
|
||||
|
||||
if (hasUdi) {
|
||||
data["data-udi"] = img.udi;
|
||||
}
|
||||
else {
|
||||
//Considering these fixed because UDI will now be used and thus
|
||||
// we have no need for rel http://issues.umbraco.org/issue/U4-6228, http://issues.umbraco.org/issue/U4-6595
|
||||
data["rel"] = img.id;
|
||||
data["data-id"] = img.id;
|
||||
}
|
||||
|
||||
editor.insertContent(editor.dom.createHTML('img', data));
|
||||
|
||||
@@ -725,27 +744,36 @@ function tinyMceService(dialogService, $log, imageHelper, $http, $timeout, macro
|
||||
insertLinkInEditor: function(editor, target, anchorElm) {
|
||||
|
||||
var href = target.url;
|
||||
// We want to use the Udi. If it is set, we use it, else fallback to id, and finally to null
|
||||
var hasUdi = target.udi ? true : false;
|
||||
var id = hasUdi ? target.udi : (target.id ? target.id : null);
|
||||
|
||||
//Create a json obj used to create the attributes for the tag
|
||||
function createElemAttributes() {
|
||||
var a = {
|
||||
href: href,
|
||||
title: target.name,
|
||||
target: target.target ? target.target : null,
|
||||
rel: target.rel ? target.rel : null
|
||||
};
|
||||
if (hasUdi) {
|
||||
a["data-udi"] = target.udi;
|
||||
}
|
||||
else if (target.id) {
|
||||
a["data-id"] = target.id;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
function insertLink() {
|
||||
if (anchorElm) {
|
||||
editor.dom.setAttribs(anchorElm, {
|
||||
href: href,
|
||||
title: target.name,
|
||||
target: target.target ? target.target : null,
|
||||
rel: target.rel ? target.rel : null,
|
||||
'data-id': target.id ? target.id : null
|
||||
});
|
||||
editor.dom.setAttribs(anchorElm, createElemAttributes());
|
||||
|
||||
editor.selection.select(anchorElm);
|
||||
editor.execCommand('mceEndTyping');
|
||||
} else {
|
||||
editor.execCommand('mceInsertLink', false, {
|
||||
href: href,
|
||||
title: target.name,
|
||||
target: target.target ? target.target : null,
|
||||
rel: target.rel ? target.rel : null,
|
||||
'data-id': target.id ? target.id : null
|
||||
});
|
||||
}
|
||||
else {
|
||||
editor.execCommand('mceInsertLink', false, createElemAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,14 +783,9 @@ function tinyMceService(dialogService, $log, imageHelper, $http, $timeout, macro
|
||||
}
|
||||
|
||||
//if we have an id, it must be a locallink:id, aslong as the isMedia flag is not set
|
||||
if(target.id && (angular.isUndefined(target.isMedia) || !target.isMedia)){
|
||||
if (target.udi) {
|
||||
href = "/{localLink:" + target.udi + "}";
|
||||
}
|
||||
else {
|
||||
//This shouldn't happen! but just in case we'll leave this here
|
||||
href = "/{localLink:" + target.id + "}";
|
||||
}
|
||||
if(id && (angular.isUndefined(target.isMedia) || !target.isMedia)){
|
||||
|
||||
href = "/{localLink:" + id + "}";
|
||||
|
||||
insertLink();
|
||||
return;
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
//page specific styles
|
||||
@import "pages/document-type-editor.less";
|
||||
@import "pages/login.less";
|
||||
@import "pages/welcome-dashboard.less";
|
||||
|
||||
|
||||
//used for property editors
|
||||
|
||||
@@ -65,12 +65,6 @@
|
||||
-webkit-box-shadow:none;
|
||||
}
|
||||
|
||||
.btn-group > .btn:first-child,
|
||||
.btn-group > .btn:last-child,
|
||||
.btn-group > .dropdown-toggle {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Button Sizes
|
||||
|
||||
@@ -138,16 +138,6 @@ input.umb-group-builder__group-title-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
input.umb-group-builder__group-sort-value {
|
||||
font-size: 12px;
|
||||
padding: 0px 0 0px 5px;
|
||||
width: 40px;
|
||||
margin-bottom: 0;
|
||||
border-color: @gray-8;
|
||||
}
|
||||
|
||||
/* ---------- PROPERTIES ---------- */
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
border-radius: 3px;
|
||||
padding: 10px;
|
||||
img {
|
||||
max-width: 50vw;
|
||||
max-height: 70vh;
|
||||
max-width: 80vw;
|
||||
max-height: 80vh;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.forms-install-button {
|
||||
.btn {
|
||||
padding: 14px 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.installer-top {
|
||||
overflow: hidden;
|
||||
margin: 0 auto 30px;
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
.login-overlay {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: @gray-1 url(../img/application/logo.png) no-repeat 25px 30px fixed !important;
|
||||
background-size: 30px 30px !important;
|
||||
color: @white;
|
||||
position: absolute;
|
||||
z-index: 10000;
|
||||
top: 0;
|
||||
@@ -16,34 +13,24 @@
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
overflow-y: auto;
|
||||
background-color: @purple-d2;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
|
||||
only screen and (min-resolution: 144dpi)
|
||||
{
|
||||
.login-overlay {
|
||||
background-image: url(../img/application/logo@2x.png) !important;
|
||||
}
|
||||
.login-overlay__background-image {
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
opacity: 0.05;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2),
|
||||
only screen and (min-resolution: 192dpi)
|
||||
{
|
||||
.login-overlay {
|
||||
background-image: url(../img/application/logo@2x.png) !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 3),
|
||||
only screen and (min-resolution: 3dppx),
|
||||
only screen and (min-resolution: 350dpi)
|
||||
{
|
||||
.login-overlay {
|
||||
background-image: url(../img/application/logo@3x.png) !important;
|
||||
}
|
||||
.login-overlay__logo {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
left: 25px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.login-overlay .umb-modalcolumn {
|
||||
@@ -51,21 +38,56 @@
|
||||
border: none;
|
||||
}
|
||||
|
||||
.login-overlay .umb-login-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 565px) {
|
||||
// making sure we don't crash into the logo
|
||||
.login-overlay .umb-login-container {
|
||||
padding-top: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-overlay .form {
|
||||
position:relative;
|
||||
display: block;
|
||||
top: 100px;
|
||||
left: 165px;
|
||||
width: 370px;
|
||||
text-align: right;
|
||||
background: @white;
|
||||
padding: 25px;
|
||||
width: 500px;
|
||||
margin-left: 25px;
|
||||
margin-right: 25px;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.login-overlay .form input[type="text"],
|
||||
.login-overlay .form input[type="password"] {
|
||||
height: 36px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.login-overlay .btn-success {
|
||||
padding: 12px 24px;
|
||||
}
|
||||
|
||||
.login-overlay .form label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.login-overlay h1 {
|
||||
display: block;
|
||||
text-align: right;
|
||||
color: @white;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
color: @black;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-overlay .alert {
|
||||
@@ -76,62 +98,19 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-overlay .switch-view {
|
||||
margin-top: 10px;
|
||||
.login-overlay .external-logins form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) and (max-height: 420px) and (orientation: landscape) {
|
||||
// Move form closer to top on narrow screen sizes
|
||||
.login-overlay .form {
|
||||
top: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 565px) {
|
||||
// Remove padding on login-form on smaller devices
|
||||
.login-overlay .form {
|
||||
top: 60px;
|
||||
right: 25px;
|
||||
left: inherit;
|
||||
padding-left: 25px;
|
||||
padding-right:25px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 339px) {
|
||||
.login-overlay .form {
|
||||
input[type="text"], input[type="password"] {
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#hrOr {
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
#hrOr hr {
|
||||
.login-overlay .btn-social {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: @gray-3;
|
||||
height: 1px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#hrOr div {
|
||||
background-color: @black;
|
||||
position: relative;
|
||||
top: -16px;
|
||||
border: 1px solid @gray-3;
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: auto;
|
||||
color: @gray-8;
|
||||
.login-overlay .btn-social>:first-child {
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.login-overlay .text-error,
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
// Title
|
||||
.welcome-dashboard__intro {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.welcome-dashboard__title {
|
||||
font-size: 30px;
|
||||
color: @gray-2;
|
||||
line-height: 1.3em;
|
||||
text-align: center;
|
||||
max-width: 750px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.welcome-dashboard__intro-text {
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
max-width: 750px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
// Info box
|
||||
.welcome-dashboard__info-box-boxes {
|
||||
display: flex;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.welcome-dashboard__info-box {
|
||||
background-color: @turquoise-washed;
|
||||
border-radius: 3px;
|
||||
border: 2px solid transparent;
|
||||
padding: 25px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.welcome-dashboard__info-box:hover {
|
||||
border: 2px solid @turquoise;
|
||||
cursor: pointer;
|
||||
transition: border-color 150ms ease-in-out;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.welcome-dashboard__info-box:active,
|
||||
.welcome-dashboard__info-box:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
.welcome-dashboard__info-box-title {
|
||||
color: @turquoise-d1;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.welcome-dashboard__info-box-description {
|
||||
text-align: center;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
// Articles
|
||||
.welcome-dashboard__cards {
|
||||
display: flex;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.welcome-dashboard__card {
|
||||
background-color: @gray-10;
|
||||
border-radius: 3px;
|
||||
margin: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.welcome-dashboard__card-image-wrapper {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
max-height: 225px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.welcome-dashboard__card-image {
|
||||
cursor: pointer;
|
||||
border-radius: 3px 3px 0 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.welcome-dashboard__card-image-wrapper + .welcome-dashboard__card-content {
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.welcome-dashboard__card-content {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.welcome-dashboard__card-title {
|
||||
color: @gray-2;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
.welcome-dashboard__card-teaser {
|
||||
font-size: 14px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
.umb-editor-tiny {
|
||||
width: 50px;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.umb-editor-small {
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
@turquoise-l3: #C0F0ED;
|
||||
@turquoise-washed: #F3FDFC;
|
||||
|
||||
@purple-d2: #1D1333;
|
||||
@purple-d1: #2E2246;
|
||||
@purple: #413659;
|
||||
@purple-l1: #675E7A;
|
||||
@@ -141,9 +142,9 @@
|
||||
|
||||
|
||||
// Disabled this to keep consistency throughout the backoffice UI. Untill a better solution is thought up, this will do.
|
||||
@baseBorderRadius: 0px; // 2px;
|
||||
@borderRadiusLarge: 0px; // 6px;
|
||||
@borderRadiusSmall: 0px; // 3px;
|
||||
@baseBorderRadius: 3px; // 2px;
|
||||
@borderRadiusLarge: 3px; // 6px;
|
||||
@borderRadiusSmall: 3px; // 3px;
|
||||
|
||||
|
||||
// Tables
|
||||
@@ -185,7 +186,7 @@
|
||||
// -------------------------
|
||||
@inputBackground: @white;
|
||||
@inputBorder: @gray-7;
|
||||
@inputBorderRadius: @baseBorderRadius;
|
||||
@inputBorderRadius: 0;
|
||||
@inputDisabledBackground: @gray-10;
|
||||
@formActionsBackground: @gray-9;
|
||||
@inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border
|
||||
@@ -195,7 +196,7 @@
|
||||
// Tabs
|
||||
// -------------------------
|
||||
|
||||
@tabsBorderRadius: 0px;
|
||||
@tabsBorderRadius: @baseBorderRadius;
|
||||
|
||||
// Dropdowns
|
||||
// -------------------------
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user