diff --git a/build/Build.proj b/build/Build.proj
deleted file mode 100644
index 498637ccd4..0000000000
--- a/build/Build.proj
+++ /dev/null
@@ -1,179 +0,0 @@
-
-
-
-
-
- ..\MSBuildCommunityTasks
- ..\UmbracoMSBuildTasks
-
-
-
-
-
-
-
-
-
- .$(BUILD_NUMBER)
-
-
-
- Release
- _BuildOutput\
- UmbracoCms$(DECIMAL_BUILD_NUMBER).zip
- UmbracoCms.AllBinaries$(DECIMAL_BUILD_NUMBER).zip
- UmbracoCms.WebPI$(DECIMAL_BUILD_NUMBER).zip
- False
- ..\..\build\$(BuildFolder)
- $(MSBuildProjectDirectory)\$(BuildFolder)
- $(BuildFolder)bin\
- $(BuildFolder)WebApp\
- $(BuildFolder)WebPi\
- $(BuildFolderRelativeToProjects)bin\
- $(BuildFolderAbsolutePath)bin\
- $(BuildFolderRelativeToProjects)WebApp\
- $(BuildFolderAbsolutePath)WebApp\
- $(BuildFolderRelativeToProjects)WebPi\
- $(BuildFolderAbsolutePath)WebPi\
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/FileSystemProviderElement.cs b/src/Umbraco.Core/Configuration/FileSystemProviderElement.cs
new file mode 100644
index 0000000000..c0773e64e3
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/FileSystemProviderElement.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Text;
+
+namespace Umbraco.Core.Configuration
+{
+ public class FileSystemProviderElement : ConfigurationElement
+ {
+ private const string ALIAS_KEY = "alias";
+ private const string TYPE_KEY = "type";
+ private const string PARAMETERS_KEY = "Parameters";
+
+ [ConfigurationProperty(ALIAS_KEY, IsKey = true, IsRequired = true)]
+ public string Alias
+ {
+ get
+ {
+ return ((string)(base[ALIAS_KEY]));
+ }
+ }
+
+ [ConfigurationProperty(TYPE_KEY, IsKey = false, IsRequired = true)]
+ public string Type
+ {
+ get
+ {
+ return ((string)(base[TYPE_KEY]));
+ }
+ }
+
+ [ConfigurationProperty(PARAMETERS_KEY, IsDefaultCollection = true, IsRequired = false)]
+ public KeyValueConfigurationCollection Parameters
+ {
+ get
+ {
+ return ((KeyValueConfigurationCollection)(base[PARAMETERS_KEY]));
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/FileSystemProviderElementCollection.cs b/src/Umbraco.Core/Configuration/FileSystemProviderElementCollection.cs
new file mode 100644
index 0000000000..0604560939
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/FileSystemProviderElementCollection.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Text;
+
+namespace Umbraco.Core.Configuration
+{
+ [ConfigurationCollection(typeof(FileSystemProviderElement), AddItemName = "Provider")]
+ public class FileSystemProviderElementCollection : ConfigurationElementCollection
+ {
+ protected override ConfigurationElement CreateNewElement()
+ {
+ return new FileSystemProviderElement();
+ }
+
+ protected override object GetElementKey(ConfigurationElement element)
+ {
+ return ((FileSystemProviderElement)(element)).Alias;
+ }
+
+ new public FileSystemProviderElement this[string key]
+ {
+ get
+ {
+ return (FileSystemProviderElement)BaseGet(key);
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Configuration/FileSystemProvidersSection.cs b/src/Umbraco.Core/Configuration/FileSystemProvidersSection.cs
new file mode 100644
index 0000000000..a893d541a6
--- /dev/null
+++ b/src/Umbraco.Core/Configuration/FileSystemProvidersSection.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Text;
+
+namespace Umbraco.Core.Configuration
+{
+ public class FileSystemProvidersSection : ConfigurationSection
+ {
+ private const string PROVIDERS_KEY = "providers";
+
+ [ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
+ public FileSystemProviderElementCollection Providers
+ {
+ get { return ((FileSystemProviderElementCollection)(base[""])); }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/IO/AbstractFileSystem.cs b/src/Umbraco.Core/IO/AbstractFileSystem.cs
new file mode 100644
index 0000000000..3e49742c03
--- /dev/null
+++ b/src/Umbraco.Core/IO/AbstractFileSystem.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Umbraco.Core.IO
+{
+ public abstract class AbstractFileSystem : IFileSystem
+ {
+ public abstract IEnumerable GetDirectories(string path);
+
+ public abstract void DeleteDirectory(string path);
+
+ public abstract void DeleteDirectory(string path, bool recursive);
+
+ public abstract bool DirectoryExists(string path);
+
+ public abstract void AddFile(string path, Stream stream);
+
+ public abstract void AddFile(string path, Stream stream, bool overrideIfExists);
+
+ public abstract IEnumerable GetFiles(string path);
+
+ public abstract IEnumerable GetFiles(string path, string filter);
+
+ public abstract Stream OpenFile(string path);
+
+ public abstract void DeleteFile(string path);
+
+ public abstract bool FileExists(string path);
+
+ public abstract string GetRelativePath(string fullPathOrUrl);
+
+ public abstract string GetFullPath(string path);
+
+ public abstract string GetUrl(string path);
+
+ public virtual long GetSize(string path)
+ {
+ var s = OpenFile(path);
+ var size = s.Length;
+ s.Close();
+
+ return size;
+ }
+
+ public abstract DateTimeOffset GetLastModified(string path);
+
+ public abstract DateTimeOffset GetCreated(string path);
+ }
+}
diff --git a/src/Umbraco.Core/IO/FileSystemProvider.cs b/src/Umbraco.Core/IO/FileSystemProvider.cs
new file mode 100644
index 0000000000..31f767f28e
--- /dev/null
+++ b/src/Umbraco.Core/IO/FileSystemProvider.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Umbraco.Core.IO
+{
+ internal class FileSystemProvider
+ {
+ public const string Media = "media";
+ }
+}
diff --git a/src/Umbraco.Core/IO/FileSystemProviderManager.cs b/src/Umbraco.Core/IO/FileSystemProviderManager.cs
new file mode 100644
index 0000000000..da4a1e8dec
--- /dev/null
+++ b/src/Umbraco.Core/IO/FileSystemProviderManager.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Linq;
+using System.Text;
+using Umbraco.Core.Configuration;
+
+namespace Umbraco.Core.IO
+{
+ internal class FileSystemProviderManager
+ {
+ private readonly FileSystemProvidersSection _config;
+
+ #region Singleton
+
+ private static readonly FileSystemProviderManager Instance = new FileSystemProviderManager();
+
+ public static FileSystemProviderManager Current
+ {
+ get { return Instance; }
+ }
+
+ #endregion
+
+ #region Constructors
+
+ public FileSystemProviderManager()
+ {
+ _config = (FileSystemProvidersSection)ConfigurationManager.GetSection("FileSystemProviders");
+ }
+
+ #endregion
+
+ public IFileSystem GetFileSystemProvider(string alias)
+ {
+ var providerConfig = _config.Providers[alias];
+ if(providerConfig == null)
+ throw new ArgumentException(string.Format("No provider found with the alias '{0}'", alias));
+
+ var providerType = Type.GetType(providerConfig.Type);
+ if(providerType == null)
+ throw new InvalidOperationException(string.Format("Could not find type '{0}'", providerConfig.Type));
+
+ if (providerType.IsAssignableFrom(typeof(IFileSystem)))
+ throw new InvalidOperationException(string.Format("The type '{0}' does not implement IFileSystem", providerConfig.Type));
+
+ var paramCount = providerConfig.Parameters != null ? providerConfig.Parameters.Count : 0;
+ var constructor = providerType.GetConstructors()
+ .SingleOrDefault(x => x.GetParameters().Count() == paramCount
+ && x.GetParameters().All(y => providerConfig.Parameters.AllKeys.Contains(y.Name)));
+ if(constructor == null)
+ throw new InvalidOperationException(string.Format("Could not find constructor for type '{0}' which accepts {1} parameters", providerConfig.Type, paramCount));
+
+ var parameters = new object[paramCount];
+ for(var i = 0; i < paramCount; i++)
+ parameters[i] = providerConfig.Parameters[providerConfig.Parameters.AllKeys[i]].Value;
+
+ return (IFileSystem) constructor.Invoke(parameters);
+ }
+ }
+}
diff --git a/src/Umbraco.Core/IO/IFileSystem.cs b/src/Umbraco.Core/IO/IFileSystem.cs
new file mode 100644
index 0000000000..0bb11527ea
--- /dev/null
+++ b/src/Umbraco.Core/IO/IFileSystem.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Umbraco.Core.IO
+{
+ internal interface IFileSystem
+ {
+ IEnumerable GetDirectories(string path);
+
+ void DeleteDirectory(string path);
+
+ void DeleteDirectory(string path, bool recursive);
+
+ bool DirectoryExists(string path);
+
+
+ void AddFile(string path, Stream stream);
+
+ void AddFile(string path, Stream stream, bool overrideIfExists);
+
+ IEnumerable GetFiles(string path);
+
+ IEnumerable GetFiles(string path, string filter);
+
+ Stream OpenFile(string path);
+
+ void DeleteFile(string path);
+
+ bool FileExists(string path);
+
+ string GetRelativePath(string fullPathOrUrl);
+
+ string GetFullPath(string path);
+
+ string GetUrl(string path);
+
+ long GetSize(string path);
+
+ DateTimeOffset GetLastModified(string path);
+
+ DateTimeOffset GetCreated(string path);
+ }
+}
diff --git a/src/Umbraco.Core/IO/PhysicalFileSystem.cs b/src/Umbraco.Core/IO/PhysicalFileSystem.cs
new file mode 100644
index 0000000000..5b2cbd7db5
--- /dev/null
+++ b/src/Umbraco.Core/IO/PhysicalFileSystem.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Web;
+
+namespace Umbraco.Core.IO
+{
+ internal class PhysicalFileSystem : AbstractFileSystem
+ {
+ private readonly string _rootPath;
+ private readonly string _rootUrl;
+
+ public PhysicalFileSystem(string virtualRoot)
+ {
+ if(HttpContext.Current == null)
+ throw new InvalidOperationException("The single parameter constructor can only be accessed when there is a valid HttpContext");
+
+ _rootPath = HttpContext.Current.Server.MapPath(virtualRoot);
+ _rootUrl = VirtualPathUtility.ToAbsolute(virtualRoot);
+ }
+
+ public PhysicalFileSystem(string rootPath, string rootUrl)
+ {
+ if (string.IsNullOrEmpty(rootPath))
+ throw new ArgumentException("The argument 'rootPath' cannot be null or empty.");
+
+ if (string.IsNullOrEmpty(rootUrl))
+ throw new ArgumentException("The argument 'rootUrl' cannot be null or empty.");
+
+ _rootPath = rootPath;
+ _rootUrl = rootUrl;
+ }
+
+ public override IEnumerable GetDirectories(string path)
+ {
+ path = EnsureTrailingSeparator(GetFullPath(path));
+
+ try
+ {
+ if (Directory.Exists(path))
+ return Directory.EnumerateDirectories(path).Select(GetRelativePath);
+ }
+ catch (UnauthorizedAccessException ex)
+ { }
+ catch (DirectoryNotFoundException ex)
+ { }
+
+ return Enumerable.Empty();
+ }
+
+ public override void DeleteDirectory(string path)
+ {
+ DeleteDirectory(path, false);
+ }
+
+ public override void DeleteDirectory(string path, bool recursive)
+ {
+ if (!DirectoryExists(path))
+ return;
+
+ try
+ {
+ Directory.Delete(GetFullPath(path), recursive);
+ }
+ catch (DirectoryNotFoundException ex)
+ { }
+ }
+
+ public override bool DirectoryExists(string path)
+ {
+ return Directory.Exists(GetFullPath(path));
+ }
+
+ public override void AddFile(string path, Stream stream)
+ {
+ AddFile(path, stream, true);
+ }
+
+ public override void AddFile(string path, Stream stream, bool overrideIfExists)
+ {
+ if (FileExists(path) && !overrideIfExists)
+ throw new InvalidOperationException(string.Format("A file at path '{0}' already exists",
+ path));
+
+ EnsureDirectory(Path.GetDirectoryName(path));
+
+ using (var destination = (Stream)File.Create(GetFullPath(path)))
+ stream.CopyTo(destination);
+ }
+
+ public override IEnumerable GetFiles(string path)
+ {
+ return GetFiles(path, "*.*");
+ }
+
+ public override IEnumerable GetFiles(string path, string filter)
+ {
+ path = EnsureTrailingSeparator(GetFullPath(path));
+
+ try
+ {
+ if (Directory.Exists(path))
+ return Directory.EnumerateFiles(path, filter).Select(GetRelativePath);
+ }
+ catch (UnauthorizedAccessException ex)
+ { }
+ catch (DirectoryNotFoundException ex)
+ { }
+
+ return Enumerable.Empty();
+ }
+
+ public override Stream OpenFile(string path)
+ {
+ return File.OpenRead(GetFullPath(path));
+ }
+
+ public override void DeleteFile(string path)
+ {
+ if (!FileExists(path))
+ return;
+
+ try
+ {
+ File.Delete(GetFullPath(path));
+ }
+ catch (FileNotFoundException ex)
+ { }
+ }
+
+ public override bool FileExists(string path)
+ {
+ return File.Exists(GetFullPath(path));
+ }
+
+ public override string GetRelativePath(string fullPathOrUrl)
+ {
+ var relativePath = fullPathOrUrl
+ .TrimStart(_rootUrl)
+ .Replace('/', Path.DirectorySeparatorChar)
+ .TrimStart(_rootPath)
+ .TrimStart(Path.DirectorySeparatorChar);
+
+ return relativePath;
+ }
+
+ public override string GetFullPath(string path)
+ {
+ return !path.StartsWith(_rootPath)
+ ? Path.Combine(_rootPath, path)
+ : path;
+ }
+
+ public override string GetUrl(string path)
+ {
+ return _rootUrl.TrimEnd("/") + "/" + path
+ .TrimStart(Path.DirectorySeparatorChar)
+ .Replace(Path.DirectorySeparatorChar, '/');
+ }
+
+ public override DateTimeOffset GetLastModified(string path)
+ {
+ return DirectoryExists(path)
+ ? new DirectoryInfo(GetFullPath(path)).LastWriteTimeUtc
+ : new FileInfo(GetFullPath(path)).LastWriteTimeUtc;
+ }
+
+ public override DateTimeOffset GetCreated(string path)
+ {
+ return DirectoryExists(path)
+ ? Directory.GetCreationTimeUtc(GetFullPath(path))
+ : File.GetCreationTimeUtc(GetFullPath(path));
+ }
+
+ #region Helper Methods
+
+ protected virtual void EnsureDirectory(string path)
+ {
+ path = GetFullPath(path);
+ Directory.CreateDirectory(path);
+ }
+
+ protected string EnsureTrailingSeparator(string path)
+ {
+ if (!path.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
+ path = path + Path.DirectorySeparatorChar;
+
+ return path;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Umbraco.Core/Properties/AssemblyInfo.cs b/src/Umbraco.Core/Properties/AssemblyInfo.cs
index 66467357e9..8b45c29f7f 100644
--- a/src/Umbraco.Core/Properties/AssemblyInfo.cs
+++ b/src/Umbraco.Core/Properties/AssemblyInfo.cs
@@ -26,3 +26,8 @@ using System.Runtime.InteropServices;
[assembly: InternalsVisibleTo("cms")]
[assembly: InternalsVisibleTo("umbraco.editorControls")]
[assembly: InternalsVisibleTo("umbraco.MacroEngines")]
+
+[assembly: InternalsVisibleTo("umbraco.editorControls")]
+[assembly: InternalsVisibleTo("Umbraco.Tests")]
+
+[assembly: InternalsVisibleTo("Our.Umbraco.AmazonS3FileSystem")]
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 96ac25111b..725875506c 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -35,7 +35,7 @@
..\packages\log4net.2.0.0\lib\net40-full\log4net.dll
-
+
@@ -51,6 +51,9 @@
+
+
+
@@ -95,6 +98,11 @@
+
+
+
+
+
diff --git a/src/Umbraco.Tests/IO/AbstractFileSystemTests.cs b/src/Umbraco.Tests/IO/AbstractFileSystemTests.cs
new file mode 100644
index 0000000000..5379dcd059
--- /dev/null
+++ b/src/Umbraco.Tests/IO/AbstractFileSystemTests.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Umbraco.Core.IO;
+using Umbraco.Tests.BusinessLogic;
+
+namespace Umbraco.Tests.IO
+{
+ [TestFixture]
+ internal abstract class AbstractFileSystemTests
+ {
+ protected IFileSystem _fileSystem;
+
+ protected AbstractFileSystemTests(IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ }
+
+ [Test]
+ public void Can_Create_And_Delete_Files()
+ {
+ _fileSystem.AddFile("test.txt", CreateStream());
+
+ Assert.IsTrue(_fileSystem.FileExists("test.txt"));
+
+ _fileSystem.DeleteFile("test.txt");
+
+ Assert.IsFalse(_fileSystem.FileExists("test.txt"));
+ }
+
+ [Test]
+ public void Can_Overwrite_File()
+ {
+ _fileSystem.AddFile("test/test.txt", CreateStream());
+ _fileSystem.AddFile("test/test.txt", CreateStream());
+
+ var files = _fileSystem.GetFiles("test");
+
+ Assert.AreEqual(1, files.Count());
+
+ _fileSystem.DeleteDirectory("test", true);
+ }
+
+ [Test]
+ [ExpectedException(typeof(InvalidOperationException))]
+ public void Cant_Overwrite_File()
+ {
+ _fileSystem.AddFile("test.txt", CreateStream());
+ _fileSystem.AddFile("test.txt", CreateStream(), false);
+
+ _fileSystem.DeleteFile("test.txt");
+ }
+
+ [Test]
+ public void Can_Get_Files()
+ {
+ _fileSystem.AddFile("test/test1.txt", CreateStream());
+ _fileSystem.AddFile("test/test2.txt", CreateStream());
+ _fileSystem.AddFile("test/test3.txt", CreateStream());
+ _fileSystem.AddFile("test/test4.bak", CreateStream());
+
+ var files = _fileSystem.GetFiles("test");
+
+ Assert.AreEqual(4, files.Count());
+
+ files = _fileSystem.GetFiles("test", "*.txt");
+
+ Assert.AreEqual(3, files.Count());
+
+ _fileSystem.DeleteDirectory("test", true);
+ }
+
+ [Test]
+ public void Can_Read_File()
+ {
+ _fileSystem.AddFile("test.txt", CreateStream("hello world"));
+
+ var stream = _fileSystem.OpenFile("test.txt");
+ var reader = new StreamReader(stream);
+ var contents = reader.ReadToEnd();
+ reader.Close();
+
+ Assert.AreEqual("hello world", contents);
+
+ _fileSystem.DeleteFile("test.txt");
+ }
+
+ [Test]
+ public void Can_Get_Directories()
+ {
+ _fileSystem.AddFile("test/sub1/test.txt", CreateStream());
+ _fileSystem.AddFile("test/sub2/test.txt", CreateStream());
+ _fileSystem.AddFile("test/sub3/test.txt", CreateStream());
+
+ var dirs = _fileSystem.GetDirectories("test");
+
+ Assert.AreEqual(3, dirs.Count());
+ Assert.IsTrue(_fileSystem.DirectoryExists("test/sub1"));
+ Assert.IsTrue(_fileSystem.DirectoryExists("test/sub2"));
+ Assert.IsTrue(_fileSystem.DirectoryExists("test/sub3"));
+
+ _fileSystem.DeleteDirectory("test", true);
+ }
+
+ [Test]
+ public void Can_Get_File_Dates()
+ {
+ _fileSystem.AddFile("test.txt", CreateStream());
+
+ var created = _fileSystem.GetCreated("test.txt");
+ var modified = _fileSystem.GetLastModified("test.txt");
+
+ Assert.AreEqual(DateTime.Today.Year, created.Year);
+ Assert.AreEqual(DateTime.Today.Month, created.Month);
+ Assert.AreEqual(DateTime.Today.Date, created.Date);
+
+ Assert.AreEqual(DateTime.Today.Year, modified.Year);
+ Assert.AreEqual(DateTime.Today.Month, modified.Month);
+ Assert.AreEqual(DateTime.Today.Date, modified.Date);
+
+ _fileSystem.DeleteFile("test.txt");
+ }
+
+ [Test]
+ public void Can_Get_File_Url()
+ {
+ _fileSystem.AddFile("test.txt", CreateStream());
+
+ var url = _fileSystem.GetUrl("test.txt");
+
+ Assert.AreEqual(ConstructUrl("test.txt"), url);
+
+ _fileSystem.DeleteFile("test.txt");
+ }
+
+ [Test]
+ public void Can_Convert_Full_Path_And_Url_To_Relative_Path()
+ {
+ _fileSystem.AddFile("test.txt", CreateStream());
+
+ var url = _fileSystem.GetUrl("test.txt");
+ var fullPath = _fileSystem.GetFullPath("test.txt");
+
+ Assert.AreNotEqual("test.txt", url);
+ Assert.AreNotEqual("test.txt", fullPath);
+
+ Assert.AreEqual("test.txt", _fileSystem.GetRelativePath(url));
+ Assert.AreEqual("test.txt", _fileSystem.GetRelativePath(fullPath));
+
+ _fileSystem.DeleteFile("test.txt");
+ }
+
+ [Test]
+ public void Can_Get_Size()
+ {
+ var stream = CreateStream();
+ var streamLength = stream.Length;
+ _fileSystem.AddFile("test.txt", stream);
+
+ Assert.AreEqual(streamLength, _fileSystem.GetSize("test.txt"));
+
+ _fileSystem.DeleteFile("test.txt");
+ }
+
+ #region Helper Methods
+
+ protected Stream CreateStream(string contents = null)
+ {
+ if(string.IsNullOrEmpty(contents))
+ contents = "test";
+
+ var bytes = Encoding.UTF8.GetBytes(contents);
+ var stream = new MemoryStream(bytes);
+
+ return stream;
+ }
+
+ protected abstract string ConstructUrl(string path);
+
+ #endregion
+ }
+}
diff --git a/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs b/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs
new file mode 100644
index 0000000000..dc79f82620
--- /dev/null
+++ b/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Umbraco.Core.IO;
+using Umbraco.Tests.BusinessLogic;
+
+namespace Umbraco.Tests.IO
+{
+ [TestFixture]
+ internal class PhysicalFileSystemTests : AbstractFileSystemTests
+ {
+ public PhysicalFileSystemTests()
+ : base(new PhysicalFileSystem(AppDomain.CurrentDomain.BaseDirectory,
+ "/Media/"))
+ { }
+
+ protected override string ConstructUrl(string path)
+ {
+ return "/Media/" + path;
+ }
+ }
+}
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 1ed1e7d4b3..6ff3fc2256 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -79,6 +79,8 @@
+
+
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index 76be138a12..d86101b920 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -271,6 +271,9 @@
log4net.config
+
+
+ FileSystemProviders.config
xsltExtensions.config
diff --git a/src/Umbraco.Web.UI/config/FileSystemProviders.Release.config b/src/Umbraco.Web.UI/config/FileSystemProviders.Release.config
new file mode 100644
index 0000000000..cffbc4e802
--- /dev/null
+++ b/src/Umbraco.Web.UI/config/FileSystemProviders.Release.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI/config/FileSystemProviders.config b/src/Umbraco.Web.UI/config/FileSystemProviders.config
new file mode 100644
index 0000000000..cffbc4e802
--- /dev/null
+++ b/src/Umbraco.Web.UI/config/FileSystemProviders.config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config
index 9384fc2c05..dae69d2df4 100644
--- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config
+++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config
@@ -114,7 +114,6 @@
star
- -
ae
oe
aa
@@ -125,8 +124,6 @@
ae
oe
-
- false
diff --git a/src/Umbraco.Web.UI/umbraco/plugins/TheOutfield/DesktopMediaUploader/dmu.ashx b/src/Umbraco.Web.UI/umbraco/plugins/TheOutfield/DesktopMediaUploader/dmu.ashx
new file mode 100644
index 0000000000..3dab7a3f91
--- /dev/null
+++ b/src/Umbraco.Web.UI/umbraco/plugins/TheOutfield/DesktopMediaUploader/dmu.ashx
@@ -0,0 +1 @@
+<%@ WebHandler Language="C#" CodeBehind="MediaUploader.ashx.cs" Class="umbraco.presentation.umbraco.webservices.MediaUploader" %>
diff --git a/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Js/folderbrowser.js b/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Js/folderbrowser.js
index cb380ba028..cdad318d0f 100644
--- a/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Js/folderbrowser.js
+++ b/src/Umbraco.Web.UI/umbraco_client/FolderBrowser/Js/folderbrowser.js
@@ -4,7 +4,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
(function ($, Base, window, document, undefined) {
var itemMappingOptions = {
- 'create': function(o) {
+ 'create': function (o) {
var item = ko.mapping.fromJS(o.data);
item.selected = ko.observable(false);
item.toggleSelected = function (itm, e) {
@@ -115,6 +115,14 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
items: ko.observableArray([]),
queued: ko.observableArray([])
});
+
+ self._viewModel.filtered = ko.computed(function () {
+ return self._viewModel.items();
+ return ko.utils.arrayFilter(this.items(), function (item) {
+ return item.Name().toLowerCase().indexOf(self._viewModel.filterTerm()) > -1 ||
+ item.Tags().toLowerCase().indexOf(self._viewModel.filterTerm()) > -1;
+ });
+ }, self._viewModel);
self._viewModel.selected = ko.computed(function() {
return ko.utils.arrayFilter(this.items(), function(item) {
@@ -162,10 +170,10 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
var overlay = $("" +
"
" +
instructions +
- "
" +
"
" +
"
" +
- "
" +
- "
" +
+ "
" +
+ "
" +
"
Cancel" +
"
" +
"
");
@@ -226,6 +234,9 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
},
onProgress: function (data) {
data.context.progress(data.progress);
+ },
+ onDoneAll: function () {
+ self._getChildNodes();
}
});
@@ -235,8 +246,8 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
$("#fileupload").fileUploader("uploadAll");
});
- $(".upload-overlay #overwriteExisting").click(function() {
- $("input[name=overwriteExisting]").val($(this).is(":checked"));
+ $(".upload-overlay #replaceExisting").click(function() {
+ $("input[name=replaceExisting]").val($(this).is(":checked"));
});
$(".upload-overlay .cancel").click(function (e) {
@@ -301,15 +312,16 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
start: function (e, ui) {
// Add dragging class to container
$(".umbFolderBrowser .items").addClass("ui-sortable-dragging");
-
- $(".umbFolderBrowser .items .ui-sortable-helper span").removeAttr("data-bind").text("Moving 1 item");
},
- update: function (e, ui) {
+ update: function (e, ui)
+ {
+ // Can't sort when filtered so just return
+ if (self._viewModel.filterTerm().length > 0)
+ return;
+
//var oldIndex = self._viewModel.items.indexOf(self._viewModel.tempItem());
var newIndex = ui.item.index();
- //TODO: Don't allow sorting on a filtered view
-
$(".umbFolderBrowser .items .selected").sort(function (a,b) {
return parseInt($(a).data("order")) > parseInt($(b).data("order")) ? 1 : -1;
}).each(function(idx, itm) {
@@ -327,7 +339,15 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
stop: function (e, ui) {
// Remove dragging class from container
$(".umbFolderBrowser .items").removeClass("ui-sortable-dragging");
- //TODO: Update on server
+
+ if (self._viewModel.filterTerm().length > 0) {
+ $(this).sortable("cancel");
+ alert("Can't sort items which have been filtered");
+ }
+ else
+ {
+ //TODO: Update on server
+ }
}
});
},
diff --git a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracocontextmenu/editor_plugin_src.js b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracocontextmenu/editor_plugin_src.js
index da22f21a87..f3074ef21f 100644
--- a/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracocontextmenu/editor_plugin_src.js
+++ b/src/Umbraco.Web.UI/umbraco_client/tinymce3/plugins/umbracocontextmenu/editor_plugin_src.js
@@ -26,7 +26,7 @@
* @param {string} url Absolute URL to where the plugin is located.
*/
init: function (ed) {
- var t = this;
+ if (ed.plugins.contextmenu) {
ed.plugins.contextmenu.onContextMenu.add(function (th, menu, event) {
@@ -61,7 +61,7 @@
});
}
-
+ }
});
// Register plugin
diff --git a/src/Umbraco.Web.UI/web.Template.UMBRACOELISE.Debug.config b/src/Umbraco.Web.UI/web.Template.UMBRACOELISE.Debug.config
index 4b2e4bb8da..124bf94e8e 100644
--- a/src/Umbraco.Web.UI/web.Template.UMBRACOELISE.Debug.config
+++ b/src/Umbraco.Web.UI/web.Template.UMBRACOELISE.Debug.config
@@ -17,9 +17,9 @@
+ value="server=.\sqlexpress;database=481;user id=DBUSER;password=DBPASSWORD"/>
+ value="4.8.1"/>
diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config
index 0d9235e222..e3644f256d 100644
--- a/src/Umbraco.Web.UI/web.Template.config
+++ b/src/Umbraco.Web.UI/web.Template.config
@@ -13,6 +13,7 @@
+
@@ -29,6 +30,7 @@
+
diff --git a/src/Umbraco.Web/Media/ThumbnailProviders/ImageThumbnailProvider.cs b/src/Umbraco.Web/Media/ThumbnailProviders/ImageThumbnailProvider.cs
index 4e5ddbb489..5d117f1040 100644
--- a/src/Umbraco.Web/Media/ThumbnailProviders/ImageThumbnailProvider.cs
+++ b/src/Umbraco.Web/Media/ThumbnailProviders/ImageThumbnailProvider.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Text;
using Umbraco.Core;
+using Umbraco.Core.IO;
using umbraco.IO;
namespace Umbraco.Web.Media.ThumbnailProviders
@@ -36,8 +37,19 @@ namespace Umbraco.Web.Media.ThumbnailProviders
// Make sure the thumbnail exists
var tmpThumbUrl = fileUrl.Replace(ext, "_thumb.jpg");
- if (!File.Exists(IOHelper.MapPath(tmpThumbUrl)))
+
+ try
+ {
+ var fs = FileSystemProviderManager.Current.GetFileSystemProvider(FileSystemProvider.Media);
+ var relativeThumbPath = fs.GetRelativePath(tmpThumbUrl);
+ if (!fs.FileExists(relativeThumbPath))
+ return false;
+ }
+ catch (Exception)
+ {
+ // If something odd happens, just return false and move on
return false;
+ }
// We've got this far, so thumbnail must exist
thumbUrl = tmpThumbUrl;
diff --git a/src/Umbraco.Web/UI/Controls/FolderBrowser.cs b/src/Umbraco.Web/UI/Controls/FolderBrowser.cs
index 272d83c8bb..3b6db75e7b 100644
--- a/src/Umbraco.Web/UI/Controls/FolderBrowser.cs
+++ b/src/Umbraco.Web/UI/Controls/FolderBrowser.cs
@@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
+using System.Web;
+using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using ClientDependency.Core;
using umbraco.BasePages;
+using umbraco.BusinessLogic;
using umbraco.IO;
using umbraco.cms.businesslogic.media;
@@ -113,7 +116,7 @@ namespace Umbraco.Web.UI.Controls
sb.Append("Filter:
");
// Create thumbnails container
- sb.Append("" +
+ sb.Append("");
diff --git a/src/Umbraco.Web/WebServices/FolderBrowserService.cs b/src/Umbraco.Web/WebServices/FolderBrowserService.cs
index 2c02c3dca0..3535b66894 100644
--- a/src/Umbraco.Web/WebServices/FolderBrowserService.cs
+++ b/src/Umbraco.Web/WebServices/FolderBrowserService.cs
@@ -45,19 +45,21 @@ namespace Umbraco.Web.WebServices
var fileUrl = fileProp != null ? fileProp.Value.ToString() : "";
var thumbUrl = ThumbnailProvidersResolver.Current.GetThumbnailUrl(fileUrl);
-
- data.Add(new
+ var item = new
{
Id = child.Id,
Path = child.Path,
Name = child.Text,
+ Tags = string.Join(",", Tag.GetTags(child.Id).Select(x => x.TagCaption)),
MediaTypeAlias = child.ContentType.Alias,
EditUrl = string.Format("editMedia.aspx?id={0}", child.Id),
FileUrl = fileUrl,
- ThumbnailUrl = !string.IsNullOrEmpty(thumbUrl)
- ? thumbUrl
+ ThumbnailUrl = !string.IsNullOrEmpty(thumbUrl)
+ ? thumbUrl
: IOHelper.ResolveUrl(SystemDirectories.Umbraco + "/images/thumbnails/" + child.ContentType.Thumbnail)
- });
+ };
+
+ data.Add(item);
}
return new JavaScriptSerializer().Serialize(data);
@@ -84,14 +86,6 @@ namespace Umbraco.Web.WebServices
});
}
- [RestExtensionMethod(returnXml = false)]
- public static string Upload(int parentId)
- {
- return new JavaScriptSerializer().Serialize(new {
- success = true
- });
- }
-
[RestExtensionMethod(returnXml = false)]
public static string UpdateSortOrder(int parentId, IDictionary map)
{
diff --git a/src/Umbraco.Web/umbraco.presentation/default.aspx.cs b/src/Umbraco.Web/umbraco.presentation/default.aspx.cs
index 0695c7c162..f5d8698001 100644
--- a/src/Umbraco.Web/umbraco.presentation/default.aspx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/default.aspx.cs
@@ -8,6 +8,8 @@ using System.Xml;
using System.Text.RegularExpressions;
using Umbraco.Web;
using Umbraco.Web.Routing;
+using Umbraco.Core.Configuration;
+using Umbraco.Core.IO;
using umbraco.cms.businesslogic.web;
using umbraco.cms.businesslogic;
@@ -171,7 +173,6 @@ namespace umbraco
if (ValidateRequest)
Request.ValidateInput();
-
// handle the infamous umbDebugShowTrace, etc
Page.Trace.IsEnabled &= GlobalSettings.DebugMode && !String.IsNullOrWhiteSpace(Request["umbDebugShowTrace"]);
}
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadRelationTypes.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadRelationTypes.cs
index c33e843b17..4e19a87947 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadRelationTypes.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadRelationTypes.cs
@@ -16,7 +16,7 @@ namespace umbraco
///
/// RelationTypes tree for developer section
///
- //[Tree("developer", "relationTypes", "Relation Types", sortOrder: 4)]
+ [Tree("developer", "relationTypes", "Relation Types", sortOrder: 4)]
public class loadRelationTypes : BaseTree
{
///
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/MediaUploader.ashx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/MediaUploader.ashx.cs
index 8c23e383a6..e2dc9302e3 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/MediaUploader.ashx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/MediaUploader.ashx.cs
@@ -6,8 +6,10 @@ using System.Linq;
using System.Text;
using System.Web;
using System.Web.Configuration;
+using System.Web.Script.Serialization;
using System.Web.Security;
using System.Xml;
+using System.Xml.Serialization;
using umbraco.BusinessLogic;
using umbraco.businesslogic.Exceptions;
using umbraco.cms.businesslogic.media;
@@ -25,75 +27,100 @@ namespace umbraco.presentation.umbraco.webservices
public void ProcessRequest(HttpContext context)
{
- context.Response.Clear();
- context.Response.ContentType = @"text\xml";
- context.Response.Charset = "UTF-8";
- context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
- context.Response.Cache.SetAllowResponseInBrowserHistory(true);
+ MediaResponse response = null;
- var xmlTextWriter = new XmlTextWriter(context.Response.OutputStream, Encoding.UTF8);
- xmlTextWriter.WriteStartDocument();
- xmlTextWriter.WriteStartElement("response");
+ var action = context.Request["action"];
- string action = context.Request["action"];
-
- if (IsValidRequest(context, xmlTextWriter) && !string.IsNullOrEmpty(action))
+ if (IsValidRequest(context) && !string.IsNullOrEmpty(action))
{
switch (action.ToLower())
{
case "config":
- ProcessConfigRequest(context, xmlTextWriter);
+ response = ProcessConfigRequest(context);
break;
case "folderlist":
- ProcessFolderListRequest(context, xmlTextWriter);
+ response = ProcessFolderListRequest(context);
break;
case "upload":
- ProcessUploadRequest(context, xmlTextWriter);
+ response = ProcessUploadRequest(context);
break;
}
}
- xmlTextWriter.WriteEndElement();
- xmlTextWriter.WriteEndDocument();
- xmlTextWriter.Flush();
- xmlTextWriter.Close();
+ // Set success flag
+ if (response != null)
+ response.success = true;
+ else
+ response = new MediaResponse { success = false };
+
+ context.Response.Clear();
+ context.Response.Charset = "UTF-8";
+ context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
+ context.Response.Cache.SetAllowResponseInBrowserHistory(true);
+
+ var format = context.Request["format"];
+ switch (format)
+ {
+ case "json":
+ // Format as JSON
+ context.Response.ContentType = @"application/json";
+
+ context.Response.Write(new JavaScriptSerializer().Serialize(response));
+
+ break;
+ default:
+ // Format as XML
+ context.Response.ContentType = @"text/xml";
+
+ var serializer = new XmlSerializer(response.GetType());
+ serializer.Serialize(context.Response.OutputStream, response);
+
+ break;
+ }
+
context.Response.End();
}
- public void ProcessConfigRequest(HttpContext context, XmlTextWriter xmlTextWriter)
+ public ConfigResponse ProcessConfigRequest(HttpContext context)
{
- xmlTextWriter.WriteElementString("displayName", new User(context.Request["username"]).Name);
- xmlTextWriter.WriteElementString("umbracoPath", VirtualPathUtility.ToAbsolute(GlobalSettings.Path));
- xmlTextWriter.WriteElementString("maxRequestLength", GetMaxRequestLength().ToString());
+ return new ConfigResponse
+ {
+ displayName = new User(context.Request["username"]).Name,
+ umbracoPath = VirtualPathUtility.ToAbsolute(GlobalSettings.Path),
+ maxRequestLength = GetMaxRequestLength()
+ };
}
- public void ProcessFolderListRequest(HttpContext context, XmlTextWriter xmlTextWriter)
+ public FolderListResponse ProcessFolderListRequest(HttpContext context)
{
- xmlTextWriter.WriteStartElement("folder");
+ var response = new FolderListResponse
+ {
+ folder = new FolderListItem()
+ };
var startMediaId = AuthenticatedUser.StartMediaId;
if (startMediaId < 1)
{
- xmlTextWriter.WriteAttributeString("id", "-1");
- xmlTextWriter.WriteAttributeString("name", "Media");
+ response.folder.id = -1;
+ response.folder.name = "Media";
- CreateMediaTree(Media.GetRootMedias(), xmlTextWriter);
+ CreateMediaTree(Media.GetRootMedias(), response.folder);
}
else
{
var root = new Media(startMediaId);
- xmlTextWriter.WriteAttributeString("id", root.Id.ToString());
- xmlTextWriter.WriteAttributeString("name", root.Text);
+ response.folder.id = root.Id;
+ response.folder.name = root.Text;
- CreateMediaTree(root.Children, xmlTextWriter);
+ CreateMediaTree(root.Children, response.folder);
}
- xmlTextWriter.WriteEndElement();
+ return response;
}
- public void ProcessUploadRequest(HttpContext context, XmlTextWriter xmlTextWriter)
+ public UploadResponse ProcessUploadRequest(HttpContext context)
{
int parentNodeId;
if (int.TryParse(context.Request["parentNodeId"], out parentNodeId) && context.Request.Files.Count > 0)
@@ -117,7 +144,8 @@ namespace umbraco.presentation.umbraco.webservices
}
// Check whether to replace existing
- bool replaceExisting = (context.Request["replaceExisting"] == "1");
+ var parsed = false;
+ bool replaceExisting = (context.Request["replaceExisting"] == "1" || (bool.TryParse(context.Request["replaceExisting"], out parsed) && parsed));
// loop through uploaded files
for (var j = 0; j < context.Request.Files.Count; j++)
@@ -131,16 +159,18 @@ namespace umbraco.presentation.umbraco.webservices
var postedMediaFile = new PostedMediaFile
{
FileName = uploadFile.FileName,
+ DisplayName = context.Request["name"],
ContentType = uploadFile.ContentType,
ContentLength = uploadFile.ContentLength,
- InputStream = uploadFile.InputStream
+ InputStream = uploadFile.InputStream,
+ ReplaceExisting = replaceExisting
};
// Get concrete MediaFactory
var factory = MediaFactory.GetMediaFactory(parentNodeId, postedMediaFile, AuthenticatedUser);
// Handle media Item
- var media = factory.HandleMedia(parentNodeId, postedMediaFile, AuthenticatedUser, replaceExisting);
+ var media = factory.HandleMedia(parentNodeId, postedMediaFile, AuthenticatedUser);
}
}
@@ -158,11 +188,13 @@ namespace umbraco.presentation.umbraco.webservices
// log error
Log.Add(LogTypes.Error, -1, "Parent node id is in incorrect format");
}
+
+ return new UploadResponse();
}
#region Helper Methods
- private bool IsValidRequest(HttpContext context, XmlTextWriter xmlTextWriter)
+ private bool IsValidRequest(HttpContext context)
{
// check for secure connection
if (GlobalSettings.UseSSL && !context.Request.IsSecureConnection)
@@ -195,26 +227,31 @@ namespace umbraco.presentation.umbraco.webservices
if (isValid)
AuthenticatedUser = user;
}
-
- xmlTextWriter.WriteAttributeString("success", isValid.ToString().ToLower());
+ else if (User.GetCurrent() != null)
+ {
+ isValid = true;
+ AuthenticatedUser = User.GetCurrent();
+ }
return isValid;
}
- private void CreateMediaTree(IEnumerable nodes, XmlWriter xmlTextWriter)
+ private void CreateMediaTree(IEnumerable nodes, FolderListItem folder)
{
foreach (var media in nodes.Where(media => media != null && media.ContentType != null && media.ContentType.Alias == "Folder"))
{
- xmlTextWriter.WriteStartElement("folder");
- xmlTextWriter.WriteAttributeString("id", media.Id.ToString());
- xmlTextWriter.WriteAttributeString("name", media.Text);
+ var subFolder = new FolderListItem
+ {
+ id = media.Id,
+ name = media.Text
+ };
if (media.HasChildren)
{
- CreateMediaTree(media.Children, xmlTextWriter);
+ CreateMediaTree(media.Children, subFolder);
}
- xmlTextWriter.WriteEndElement();
+ folder.folders.Add(subFolder);
}
}
@@ -266,4 +303,46 @@ namespace umbraco.presentation.umbraco.webservices
#endregion
}
+
+ public class MediaResponse
+ {
+ [XmlAttribute]
+ public bool success { get; set; }
+ }
+
+ [XmlRoot("response")]
+ public class ConfigResponse : MediaResponse
+ {
+ public string displayName { get; set; }
+ public string umbracoPath { get; set; }
+ public int maxRequestLength { get; set; }
+ }
+
+ [XmlRoot("response")]
+ public class FolderListResponse : MediaResponse
+ {
+ public FolderListItem folder { get; set; }
+ }
+
+ [XmlType("folder")]
+ public class FolderListItem
+ {
+ [XmlAttribute]
+ public int id { get; set; }
+
+ [XmlAttribute]
+ public string name { get; set; }
+
+ [XmlElement("folder")]
+ public List folders { get; set; }
+
+ public FolderListItem()
+ {
+ folders = new List();
+ }
+ }
+
+ [XmlRoot("response")]
+ public class UploadResponse : MediaResponse
+ { }
}
\ No newline at end of file
diff --git a/src/umbraco.MacroEngines/RazorCore/RazorMacroEngine.cs b/src/umbraco.MacroEngines/RazorCore/RazorMacroEngine.cs
index b8f46be9b2..7ea5cc9928 100644
--- a/src/umbraco.MacroEngines/RazorCore/RazorMacroEngine.cs
+++ b/src/umbraco.MacroEngines/RazorCore/RazorMacroEngine.cs
@@ -77,12 +77,19 @@ namespace umbraco.MacroEngines
var contextWrapper = new HttpContextWrapper(context);
//inject http context - for request response
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Loading Macro Script Context (file: {0})", macro.Name));
razorWebPage.Context = contextWrapper;
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Done Loading Macro Script Context (file: {0})", macro.Name));
//Inject Macro Model And Parameters
if (razorWebPage is IMacroContext) {
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Boxing Macro Script MacroContext (file: {0})", macro.Name));
var razorMacro = (IMacroContext)razorWebPage;
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Done Boxing Macro Script MacroContext (file: {0})", macro.Name));
+
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Loading Macro Script Model (file: {0})", macro.Name));
razorMacro.SetMembers(macro, currentPage);
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Done Loading Macro Script Model (file: {0})", macro.Name));
}
}
@@ -106,11 +113,16 @@ namespace umbraco.MacroEngines
return String.Empty; //No File Location
var razorWebPage = CompileAndInstantiate(fileLocation);
+
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Loading Macro Script Context (file: {0})", macro.Name));
InjectContext(razorWebPage, macro, currentPage);
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Done Loading Macro Script Context (file: {0})", macro.Name));
//Output Razor To String
var output = new StringWriter();
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Executing Macro Script (file: {0})", macro.Name));
razorWebPage.ExecutePageHierarchy(new WebPageContext(contextWrapper, razorWebPage, null), output);
+ HttpContext.Current.Trace.Write("umbracoMacro", string.Format("Done Executing Macro Script (file: {0})", macro.Name));
return output.ToString();
}
diff --git a/src/umbraco.businesslogic/BasePages/BasePage.cs b/src/umbraco.businesslogic/BasePages/BasePage.cs
index a50c7a9aeb..ab555a587a 100644
--- a/src/umbraco.businesslogic/BasePages/BasePage.cs
+++ b/src/umbraco.businesslogic/BasePages/BasePage.cs
@@ -2,6 +2,7 @@ using System;
using System.Data;
using System.Web;
using System.Linq;
+using System.Web.Security;
using umbraco.BusinessLogic;
using umbraco.DataLayer;
using umbraco.IO;
@@ -227,7 +228,26 @@ namespace umbraco.BasePages
if (StateHelper.Cookies.HasCookies && StateHelper.Cookies.UserContext.HasValue)
return StateHelper.Cookies.UserContext.GetValue();
else
- return "";
+ {
+ try
+ {
+ string encTicket = StateHelper.Cookies.UserContext.GetValue();
+ if (!String.IsNullOrEmpty(encTicket))
+ return FormsAuthentication.Decrypt(encTicket).UserData;
+ }
+ catch (HttpException ex)
+ {
+ // we swallow this type of exception as it happens if a legacy (pre 4.8.1) cookie is set
+ }
+ catch (ArgumentException ex)
+ {
+ // we swallow this one because it's 99.99% certaincy is legacy based. We'll still log it, though
+ Log.Instance.AddException(ex);
+
+ }
+ }
+
+ return "";
}
set
{
@@ -238,8 +258,28 @@ namespace umbraco.BasePages
if (StateHelper.Cookies.UserContext.HasValue)
StateHelper.Cookies.ClearAll();
- // Create new cookie.
+ if (!String.IsNullOrEmpty(value))
+ {
+ FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
+ value,
+ DateTime.Now,
+ DateTime.Now.AddDays(1),
+ false,
+ value,
+ FormsAuthentication.FormsCookiePath);
+
+ // Encrypt the ticket.
+ string encTicket = FormsAuthentication.Encrypt(ticket);
+
+
+ // Create new cookie.
StateHelper.Cookies.UserContext.SetValue(value, 1);
+
+
+ } else
+ {
+ StateHelper.Cookies.UserContext.Clear();
+ }
}
}
}
diff --git a/src/umbraco.businesslogic/StateHelper.cs b/src/umbraco.businesslogic/StateHelper.cs
index 607a729634..9bf45c0cfa 100644
--- a/src/umbraco.businesslogic/StateHelper.cs
+++ b/src/umbraco.businesslogic/StateHelper.cs
@@ -431,6 +431,8 @@ namespace umbraco.BusinessLogic
public void SetValue(string value)
{
HttpCookie cookie = new HttpCookie(_key, value);
+ if (GlobalSettings.UseSSL)
+ cookie.Secure = true;
if (!TimeSpan.Zero.Equals(_expires))
cookie.Expires = DateTime.Now + _expires;
ResponseCookie = cookie;
@@ -455,7 +457,9 @@ namespace umbraco.BusinessLogic
public void SetValue(string value, DateTime expires)
{
HttpCookie cookie = new HttpCookie(_key, value);
- cookie.Expires = expires;
+ if (GlobalSettings.UseSSL)
+ cookie.Secure = true;
+ cookie.Expires = expires;
ResponseCookie = cookie;
// original Umbraco code also does this
diff --git a/src/umbraco.cms/businesslogic/Content.cs b/src/umbraco.cms/businesslogic/Content.cs
index a94b6e45dc..fe7d5fdb25 100644
--- a/src/umbraco.cms/businesslogic/Content.cs
+++ b/src/umbraco.cms/businesslogic/Content.cs
@@ -512,6 +512,9 @@ namespace umbraco.cms.businesslogic
Guid newVersion = Guid.NewGuid();
bool tempHasVersion = hasVersion();
+
+ // we need to ensure that a version in the db exist before we add related data
+ SqlHelper.ExecuteNonQuery("Insert into cmsContentVersion (ContentId,versionId) values (" + this.Id + ",'" + newVersion + "')");
foreach (propertytype.PropertyType pt in this.ContentType.PropertyTypes)
{
object oldValue = "";
@@ -526,7 +529,6 @@ namespace umbraco.cms.businesslogic
property.Property p = this.addProperty(pt, newVersion);
if (oldValue != null && oldValue.ToString() != "") p.Value = oldValue;
}
- SqlHelper.ExecuteNonQuery("Insert into cmsContentVersion (ContentId,versionId) values (" + this.Id + ",'" + newVersion + "')");
this.Version = newVersion;
return newVersion;
}
diff --git a/src/umbraco.cms/businesslogic/Files/IFile.cs b/src/umbraco.cms/businesslogic/Files/IFile.cs
index 7bfb4490f5..ccf858fb02 100644
--- a/src/umbraco.cms/businesslogic/Files/IFile.cs
+++ b/src/umbraco.cms/businesslogic/Files/IFile.cs
@@ -9,7 +9,10 @@ namespace umbraco.cms.businesslogic.Files
{
string Filename { get; }
string Extension { get; }
+ [Obsolete("LocalName is obsolete, please use URL instead", false)]
string LocalName { get; }
+ string Path { get; }
+ string Url { get; }
bool SupportsResizing { get; }
string GetFriendlyName();
System.Tuple GetDimensions();
diff --git a/src/umbraco.cms/businesslogic/Files/UmbracoFile.cs b/src/umbraco.cms/businesslogic/Files/UmbracoFile.cs
index 1328eb9892..a8f65839a2 100644
--- a/src/umbraco.cms/businesslogic/Files/UmbracoFile.cs
+++ b/src/umbraco.cms/businesslogic/Files/UmbracoFile.cs
@@ -6,109 +6,89 @@ using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Web;
+using Umbraco.Core.IO;
using Encoder = System.Text.Encoder;
namespace umbraco.cms.businesslogic.Files
{
public class UmbracoFile : IFile
{
- private string _fullFilePath;
+ private string _path;
private string _fileName;
- private string _directoryName;
private string _extension;
- private string _localName;
+ private string _url;
private long _length;
+ private IFileSystem _fs;
+
+ #region Constructors
+
public UmbracoFile()
{
-
+ _fs = FileSystemProviderManager.Current.GetFileSystemProvider(FileSystemProvider.Media);
}
- public UmbracoFile(string fullFilePath)
+ public UmbracoFile(string path)
{
- _fullFilePath = fullFilePath;
+ _fs = FileSystemProviderManager.Current.GetFileSystemProvider(FileSystemProvider.Media);
+
+ _path = path;
+
initialize();
}
+
+ #endregion
- public static UmbracoFile Save(HttpPostedFile file, string fullFileName)
+ #region Static Methods
+
+ //MB: Do we really need all these overloads? looking through the code, only one of them is actually used
+
+ public static UmbracoFile Save(HttpPostedFile file, string path)
{
- byte[] fileData = null;
- using (var binaryReader = new BinaryReader(file.InputStream))
- {
- fileData = binaryReader.ReadBytes(file.ContentLength);
- }
-
- return Save(fileData, fullFileName);
+ return Save(file.InputStream, path);
}
- public static UmbracoFile Save(HttpPostedFileBase file, string fullFileName)
+ public static UmbracoFile Save(HttpPostedFileBase file, string path)
{
- byte[] fileData = null;
- using (var binaryReader = new BinaryReader(file.InputStream))
- {
- fileData = binaryReader.ReadBytes(file.ContentLength);
- }
-
- return Save(fileData, fullFileName);
+ return Save(file.InputStream, path);
}
- public static UmbracoFile Save(Stream inputStream, string fullFileName){
-
- byte[] fileData = null;
- using (var binaryReader = new BinaryReader(inputStream))
- {
- fileData = binaryReader.ReadBytes((int)inputStream.Length);
- }
+ public static UmbracoFile Save(Stream inputStream, string path)
+ {
+ var fs = FileSystemProviderManager.Current.GetFileSystemProvider(FileSystemProvider.Media);
+ fs.AddFile(path, inputStream);
- return Save(fileData, fullFileName);
+ return new UmbracoFile(path);
}
- public static UmbracoFile Save(byte[] file, string fullFileName)
+ public static UmbracoFile Save(byte[] file, string relativePath)
{
- string fullFilePath = IO.IOHelper.MapPath(fullFileName);
-
- // create directories
- DirectoryInfo di = new DirectoryInfo(IO.IOHelper.MapPath(fullFilePath.Substring(0, fullFilePath.LastIndexOf(Path.DirectorySeparatorChar))));
- if (!di.Exists)
- {
- var currentDir = IO.IOHelper.MapPath(IO.SystemDirectories.Root);
- var rootDir = IO.IOHelper.MapPath(IO.SystemDirectories.Root);
- foreach (var dir in di.FullName.Substring(rootDir.Length).Split(Path.DirectorySeparatorChar))
- {
- currentDir = Path.Combine(currentDir, dir);
- if (!new DirectoryInfo(currentDir).Exists)
- {
- Directory.CreateDirectory(currentDir);
- }
- }
- }
-
- File.WriteAllBytes(fullFilePath, file);
- return new UmbracoFile(fullFilePath);
+ return Save(new MemoryStream(file), relativePath);
}
public static UmbracoFile Save(HttpPostedFile file)
{
- string tempDir = Path.Combine(IO.SystemDirectories.Media, "uploads", Guid.NewGuid().ToString());
- return Save(file, tempDir);
- }
- //filebase overload...
- public static UmbracoFile Save(HttpPostedFileBase file)
- {
- string tempDir = Path.Combine(IO.SystemDirectories.Media, "uploads", Guid.NewGuid().ToString());
+ string tempDir = System.IO.Path.Combine(IO.SystemDirectories.Media, "uploads", Guid.NewGuid().ToString());
return Save(file, tempDir);
}
+ //filebase overload...
+ public static UmbracoFile Save(HttpPostedFileBase file)
+ {
+ string tempDir = System.IO.Path.Combine(IO.SystemDirectories.Media, "uploads", Guid.NewGuid().ToString());
+ return Save(file, tempDir);
+ }
+
+ #endregion
+
private void initialize()
{
- var fi = new FileInfo(_fullFilePath);
- _fileName = fi.Name;
- _length = fi.Length;
- _directoryName = fi.DirectoryName;
- _extension = fi.Extension.Substring(1).ToLowerInvariant();
- _localName =
- "/" + fi.FullName.Substring(IO.IOHelper.MapPath(IO.SystemDirectories.Root).Length).Replace(
- Path.DirectorySeparatorChar.ToString(), "/");
+ _fileName = System.IO.Path.GetFileName(_path);
+ _length = _fs.GetSize(_path);
+ _extension = System.IO.Path.GetExtension(_path) != null
+ ? System.IO.Path.GetExtension(_path).Substring(1).ToLowerInvariant()
+ : "";
+ _url = _fs.GetUrl(_path);
}
#region IFile Members
@@ -124,9 +104,20 @@ namespace umbraco.cms.businesslogic.Files
get { return _extension; }
}
+ [Obsolete("LocalName is obsolete, please use Url instead", false)]
public string LocalName
{
- get { return _localName; }
+ get { return Url; }
+ }
+
+ public string Path
+ {
+ get { return _path; }
+ }
+
+ public string Url
+ {
+ get { return _url; }
}
public long Length
@@ -155,11 +146,8 @@ namespace umbraco.cms.businesslogic.Files
{
throwNotAnImageException();
-
- FileStream fs = new FileStream(_fullFilePath,
- FileMode.Open, FileAccess.Read, FileShare.Read);
-
- Image image = Image.FromStream(fs);
+ var fs = _fs.OpenFile(_path);
+ var image = Image.FromStream(fs);
var fileWidth = image.Width;
var fileHeight = image.Height;
fs.Close();
@@ -172,42 +160,43 @@ namespace umbraco.cms.businesslogic.Files
{
throwNotAnImageException();
- string fileNameThumb = DoResize(width, height, 0, String.Empty);
+ var fileNameThumb = DoResize(width, height, 0, String.Empty);
- return fileNameThumb.Substring(IO.IOHelper.MapPath(IO.SystemDirectories.Root).Length);
+ return _fs.GetUrl(fileNameThumb);
}
public string Resize(int maxWidthHeight, string fileNameAddition)
{
throwNotAnImageException();
- string fileNameThumb = DoResize(GetDimensions().Item1, GetDimensions().Item2, maxWidthHeight, fileNameAddition);
+ var fileNameThumb = DoResize(GetDimensions().Item1, GetDimensions().Item2, maxWidthHeight, fileNameAddition);
- return fileNameThumb.Substring(IO.IOHelper.MapPath(IO.SystemDirectories.Root).Length);
+ return _fs.GetUrl(fileNameThumb);
}
private string DoResize(int width, int height, int maxWidthHeight, string fileNameAddition)
{
-
- FileStream fs = new FileStream(_fullFilePath,
- FileMode.Open, FileAccess.Read, FileShare.Read);
- Image image = Image.FromStream(fs);
+ var fs = _fs.OpenFile(_path);
+ var image = Image.FromStream(fs);
fs.Close();
string fileNameThumb = String.IsNullOrEmpty(fileNameAddition) ?
- string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", _fullFilePath.Substring(0, _fullFilePath.LastIndexOf("."))) :
- string.Format("{0}_{1}.jpg", _fullFilePath.Substring(0, _fullFilePath.LastIndexOf(".")), fileNameAddition);
- generateThumbnail(
+ string.Format("{0}_UMBRACOSYSTHUMBNAIL.jpg", _path.Substring(0, _path.LastIndexOf("."))) :
+ string.Format("{0}_{1}.jpg", _path.Substring(0, _path.LastIndexOf(".")), fileNameAddition);
+
+ fileNameThumb = generateThumbnail(
image,
maxWidthHeight,
width,
height,
- _fullFilePath,
+ _path,
_extension,
fileNameThumb,
maxWidthHeight == 0
- );
+ ).FileName;
+
image.Dispose();
+
return fileNameThumb;
}
@@ -220,7 +209,7 @@ namespace umbraco.cms.businesslogic.Files
}
- private System.Tuple generateThumbnail(System.Drawing.Image image, int maxWidthHeight, int fileWidth, int fileHeight, string fullFilePath, string ext, string thumbnailFileName, bool useFixedDimensions)
+ private ResizedImage generateThumbnail(System.Drawing.Image image, int maxWidthHeight, int fileWidth, int fileHeight, string fullFilePath, string ext, string thumbnailFileName, bool useFixedDimensions)
{
// Generate thumbnail
float f = 1;
@@ -267,14 +256,41 @@ namespace umbraco.cms.businesslogic.Files
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 90L);
// Save the new image using the dimensions of the image
- bp.Save(thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL", string.Format("{0}x{1}", widthTh, heightTh)), codec, ep);
+ string newFileName = thumbnailFileName.Replace("UMBRACOSYSTHUMBNAIL",
+ string.Format("{0}x{1}", widthTh, heightTh));
+ var ms = new MemoryStream();
+ bp.Save(ms, codec, ep);
+ ms.Seek(0, 0);
+
+ _fs.AddFile(newFileName, ms);
+
+ ms.Close();
bp.Dispose();
g.Dispose();
- return new System.Tuple(widthTh, heightTh);
+ return new ResizedImage(widthTh, heightTh, newFileName);
}
}
+
+ internal class ResizedImage
+ {
+ public ResizedImage()
+ {
+
+ }
+
+ public ResizedImage(int width, int height, string fileName)
+ {
+ Width = width;
+ Height = height;
+ FileName = fileName;
+ }
+
+ public int Width { get; set; }
+ public int Height { get; set; }
+ public string FileName { get; set; }
+ }
}
diff --git a/src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs b/src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs
index 5f2262cb6e..f399f9600b 100644
--- a/src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs
+++ b/src/umbraco.cms/businesslogic/datatype/FileHandlerData.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using umbraco.cms.businesslogic.Files;
@@ -32,13 +33,13 @@ namespace umbraco.cms.businesslogic.datatype
if (value is HttpPostedFile)
{
var file = value as HttpPostedFile;
- name = file.FileName;
+ name = SafeFileName(file.FileName.Substring(file.FileName.LastIndexOf(IOHelper.DirSepChar) + 1, file.FileName.Length - file.FileName.LastIndexOf(IOHelper.DirSepChar) - 1).ToLower());
fileStream = file.InputStream;
}
else if (value is HttpPostedFileBase)
{
var file = value as HttpPostedFileBase;
- name = file.FileName;
+ name = SafeFileName(file.FileName.Substring(file.FileName.LastIndexOf(IOHelper.DirSepChar) + 1, file.FileName.Length - file.FileName.LastIndexOf(IOHelper.DirSepChar) - 1).ToLower());
fileStream = file.InputStream;
}
else if (value is HttpPostedFileWrapper)
@@ -57,7 +58,7 @@ namespace umbraco.cms.businesslogic.datatype
? Path.Combine(PropertyId.ToString(), name)
: PropertyId + "-" + name;
- fileName = Path.Combine(SystemDirectories.Media, fileName);
+ //fileName = Path.Combine(SystemDirectories.Media, fileName);
um = UmbracoFile.Save(fileStream, fileName);
if (um.SupportsResizing)
@@ -83,31 +84,34 @@ namespace umbraco.cms.businesslogic.datatype
// check for auto fill of other properties (width, height, extension and filesize)
string propertyTypeAlias = new Property(PropertyId).PropertyType.Alias;
- XmlNode uploadFieldConfigNode =
- UmbracoSettings.ImageAutoFillImageProperties.SelectSingleNode(
- string.Format("uploadField [@alias = \"{0}\"]", propertyTypeAlias));
- if (uploadFieldConfigNode != null)
+ if (UmbracoSettings.ImageAutoFillImageProperties != null)
{
- // get the current document
- Content content = Content.GetContentFromVersion(Version);
- // only add dimensions to web images
- if (um.SupportsResizing)
+ XmlNode uploadFieldConfigNode =
+ UmbracoSettings.ImageAutoFillImageProperties.SelectSingleNode(
+ string.Format("uploadField [@alias = \"{0}\"]", propertyTypeAlias));
+ if (uploadFieldConfigNode != null)
{
- updateContentProperty(uploadFieldConfigNode, content, "widthFieldAlias",
- um.GetDimensions().Item1);
- updateContentProperty(uploadFieldConfigNode, content, "heightFieldAlias",
- um.GetDimensions().Item2);
+ // get the current document
+ Content content = Content.GetContentFromVersion(Version);
+ // only add dimensions to web images
+ if (um.SupportsResizing)
+ {
+ updateContentProperty(uploadFieldConfigNode, content, "widthFieldAlias",
+ um.GetDimensions().Item1);
+ updateContentProperty(uploadFieldConfigNode, content, "heightFieldAlias",
+ um.GetDimensions().Item2);
+ }
+ else
+ {
+ updateContentProperty(uploadFieldConfigNode, content, "widthFieldAlias", String.Empty);
+ updateContentProperty(uploadFieldConfigNode, content, "heightFieldAlias", String.Empty);
+ }
+ updateContentProperty(uploadFieldConfigNode, content, "lengthFieldAlias", um.Length);
+ updateContentProperty(uploadFieldConfigNode, content, "extensionFieldAlias", um.Extension);
}
- else
- {
- updateContentProperty(uploadFieldConfigNode, content, "widthFieldAlias", String.Empty);
- updateContentProperty(uploadFieldConfigNode, content, "heightFieldAlias", String.Empty);
- }
- updateContentProperty(uploadFieldConfigNode, content, "lengthFieldAlias", um.Length);
- updateContentProperty(uploadFieldConfigNode, content, "extensionFieldAlias", um.Extension);
}
- base.Value = um.LocalName;
+ base.Value = um.Url;
}
else
{
@@ -126,21 +130,36 @@ namespace umbraco.cms.businesslogic.datatype
}
}
+ ///
+ /// Check to see if filename passed has any special chars in it and strips them to create a safe filename. Used to overcome an issue when Umbraco is used in IE in an intranet environment.
+ ///
+ /// The filename passed to the file handler from the upload field.
+ /// A safe filename without any path specific chars.
+ private string SafeFileName(string filePath)
+ {
+ if (!String.IsNullOrEmpty(filePath))
+ return Regex.Replace(filePath, @"[^a-zA-Z0-9\-\.\/\:]{1}", "_");
+ return String.Empty;
+ }
+
private void clearRelatedValues()
{
string propertyTypeAlias = new Property(PropertyId).PropertyType.Alias;
- XmlNode uploadFieldConfigNode =
- UmbracoSettings.ImageAutoFillImageProperties.SelectSingleNode(
- string.Format("uploadField [@alias = \"{0}\"]", propertyTypeAlias));
- if (uploadFieldConfigNode != null)
+ if (UmbracoSettings.ImageAutoFillImageProperties != null)
{
- // get the current document
- Content content = Content.GetContentFromVersion(Version);
- // only add dimensions to web images
- updateContentProperty(uploadFieldConfigNode, content, "widthFieldAlias", String.Empty);
- updateContentProperty(uploadFieldConfigNode, content, "heightFieldAlias", String.Empty);
- updateContentProperty(uploadFieldConfigNode, content, "lengthFieldAlias", String.Empty);
- updateContentProperty(uploadFieldConfigNode, content, "extensionFieldAlias", String.Empty);
+ XmlNode uploadFieldConfigNode =
+ UmbracoSettings.ImageAutoFillImageProperties.SelectSingleNode(
+ string.Format("uploadField [@alias = \"{0}\"]", propertyTypeAlias));
+ if (uploadFieldConfigNode != null)
+ {
+ // get the current document
+ Content content = Content.GetContentFromVersion(Version);
+ // only add dimensions to web images
+ updateContentProperty(uploadFieldConfigNode, content, "widthFieldAlias", String.Empty);
+ updateContentProperty(uploadFieldConfigNode, content, "heightFieldAlias", String.Empty);
+ updateContentProperty(uploadFieldConfigNode, content, "lengthFieldAlias", String.Empty);
+ updateContentProperty(uploadFieldConfigNode, content, "extensionFieldAlias", String.Empty);
+ }
}
}
diff --git a/src/umbraco.cms/businesslogic/media/IMediaFactory.cs b/src/umbraco.cms/businesslogic/media/IMediaFactory.cs
index f3eb25d3e1..50c589765f 100644
--- a/src/umbraco.cms/businesslogic/media/IMediaFactory.cs
+++ b/src/umbraco.cms/businesslogic/media/IMediaFactory.cs
@@ -14,6 +14,8 @@ namespace umbraco.cms.businesslogic.media
bool CanHandleMedia(int parentNodeId, PostedMediaFile postedFile, User user);
Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user);
+
+ [Obsolete("Use HandleMedia(int, PostedMediaFile, User) and set the ReplaceExisting property on PostedMediaFile instead")]
Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user, bool replaceExisting);
}
}
diff --git a/src/umbraco.cms/businesslogic/media/MediaFactory.cs b/src/umbraco.cms/businesslogic/media/MediaFactory.cs
index e4d583e1e8..a24a221fab 100644
--- a/src/umbraco.cms/businesslogic/media/MediaFactory.cs
+++ b/src/umbraco.cms/businesslogic/media/MediaFactory.cs
@@ -52,9 +52,11 @@ namespace umbraco.cms.businesslogic.media
public class PostedMediaFile
{
public string FileName { get; set; }
+ public string DisplayName { get; set; }
public string ContentType { get; set; }
public int ContentLength { get; set; }
public Stream InputStream { get; set; }
+ public bool ReplaceExisting { get; set; }
public void SaveAs(string filename)
{
diff --git a/src/umbraco.cms/businesslogic/media/UmbracoMediaFactory.cs b/src/umbraco.cms/businesslogic/media/UmbracoMediaFactory.cs
index b7f4560a99..bf916336fc 100644
--- a/src/umbraco.cms/businesslogic/media/UmbracoMediaFactory.cs
+++ b/src/umbraco.cms/businesslogic/media/UmbracoMediaFactory.cs
@@ -31,17 +31,14 @@ namespace umbraco.cms.businesslogic.media
}
public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user)
- {
- return HandleMedia(parentNodeId, postedFile, user, false);
- }
-
- public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user, bool replaceExisting)
{
// Check to see if a file exists
Media media;
- string mediaName = extractTitleFromFileName(postedFile.FileName);
+ string mediaName = !string.IsNullOrEmpty(postedFile.DisplayName)
+ ? postedFile.DisplayName
+ : extractTitleFromFileName(postedFile.FileName);
- if (replaceExisting && TryFindExistingMedia(parentNodeId, postedFile.FileName, out media))
+ if (postedFile.ReplaceExisting && TryFindExistingMedia(parentNodeId, postedFile.FileName, out media))
{
// Do nothing as existing media is returned
}
@@ -61,6 +58,14 @@ namespace umbraco.cms.businesslogic.media
return media;
}
+ [Obsolete("Use HandleMedia(int, PostedMediaFile, User) and set the ReplaceExisting property on PostedMediaFile instead")]
+ public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user, bool replaceExisting)
+ {
+ postedFile.ReplaceExisting = replaceExisting;
+
+ return HandleMedia(parentNodeId, postedFile, user);
+ }
+
public abstract void DoHandleMedia(Media media, PostedMediaFile uploadedFile, User user);
#region Helper Methods
diff --git a/src/umbraco.cms/businesslogic/relation/Relation.cs b/src/umbraco.cms/businesslogic/relation/Relation.cs
index 66d95cab93..b0f6576f21 100644
--- a/src/umbraco.cms/businesslogic/relation/Relation.cs
+++ b/src/umbraco.cms/businesslogic/relation/Relation.cs
@@ -105,7 +105,7 @@ namespace umbraco.cms.businesslogic.relation
public void Delete()
{
- SqlHelper.ExecuteNonQuery("delete from umbracoRelation where id = @id", SqlHelper.CreateParameter("@id", this.Id));
+ SqlHelper.ExecuteNonQuery("DELETE FROM umbracoRelation WHERE id = @id", SqlHelper.CreateParameter("@id", this.Id));
}
[MethodImpl(MethodImplOptions.Synchronized)]
diff --git a/src/umbraco.cms/businesslogic/relation/RelationType.cs b/src/umbraco.cms/businesslogic/relation/RelationType.cs
index c331235672..b31c6c6837 100644
--- a/src/umbraco.cms/businesslogic/relation/RelationType.cs
+++ b/src/umbraco.cms/businesslogic/relation/RelationType.cs
@@ -41,7 +41,7 @@ namespace umbraco.cms.businesslogic.relation
public RelationType(int id)
{
using (IRecordsReader dr = SqlHelper.ExecuteReader(
- "select id, dual, name, alias from umbracoRelationType where id = @id", SqlHelper.CreateParameter("@id", id)))
+ "SELECT id, [dual], name, alias FROM umbracoRelationType WHERE id = @id", SqlHelper.CreateParameter("@id", id)))
{
if (dr.Read())
{
@@ -70,7 +70,7 @@ namespace umbraco.cms.businesslogic.relation
{
_name = value;
SqlHelper.ExecuteNonQuery(
- "update umbracoRelationType set name = @name where id = " + this.Id.ToString(), SqlHelper.CreateParameter("@name", value));
+ "UPDATE umbracoRelationType SET name = @name WHERE id = " + this.Id.ToString(), SqlHelper.CreateParameter("@name", value));
this.InvalidateCache();
}
}
@@ -82,7 +82,7 @@ namespace umbraco.cms.businesslogic.relation
{
_alias = value;
SqlHelper.ExecuteNonQuery(
- "update umbracoRelationType set alias = @alias where id = " + this.Id.ToString(), SqlHelper.CreateParameter("@alias", value));
+ "UPDATE umbracoRelationType SET alias = @alias WHERE id = " + this.Id.ToString(), SqlHelper.CreateParameter("@alias", value));
this.InvalidateCache();
}
}
@@ -94,7 +94,7 @@ namespace umbraco.cms.businesslogic.relation
{
_dual = value;
SqlHelper.ExecuteNonQuery(
- "update umbracoRelationType set [dual] = @dual where id = " + this.Id.ToString(), SqlHelper.CreateParameter("@dual", value));
+ "UPDATE umbracoRelationType SET [dual] = @dual WHERE id = " + this.Id.ToString(), SqlHelper.CreateParameter("@dual", value));
this.InvalidateCache();
}
}
@@ -128,7 +128,7 @@ namespace umbraco.cms.businesslogic.relation
{
var relationTypes = new List();
- using (IRecordsReader dr = SqlHelper.ExecuteReader("select id, dual, name, alias from umbracoRelationType"))
+ using (IRecordsReader dr = SqlHelper.ExecuteReader("SELECT id, [dual], name, alias FROM umbracoRelationType"))
{
while (dr.Read())
{
diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs
index 93e7d122ca..79352d52cd 100644
--- a/src/umbraco.cms/businesslogic/web/Document.cs
+++ b/src/umbraco.cms/businesslogic/web/Document.cs
@@ -646,7 +646,7 @@ namespace umbraco.cms.businesslogic.web
{
ArrayList docs = new ArrayList();
IRecordsReader dr =
- SqlHelper.ExecuteReader("select distinct nodeId from cmsDocument where newest = 1 and not expireDate is null and expireDate <= @today",
+ SqlHelper.ExecuteReader("select distinct nodeId from cmsDocument where published = 1 and not expireDate is null and expireDate <= @today",
SqlHelper.CreateParameter("@today", DateTime.Now));
while (dr.Read())
docs.Add(dr.GetInt("nodeId"));
diff --git a/src/umbraco.datalayer/SqlHelpers/MySql/MySqlHelper.cs b/src/umbraco.datalayer/SqlHelpers/MySql/MySqlHelper.cs
index d9b7861634..4b3fab9d0f 100644
--- a/src/umbraco.datalayer/SqlHelpers/MySql/MySqlHelper.cs
+++ b/src/umbraco.datalayer/SqlHelpers/MySql/MySqlHelper.cs
@@ -93,6 +93,7 @@ namespace umbraco.DataLayer.SqlHelpers.MySql
switch (typeof(T).FullName)
{
case "System.Boolean": return (T)(object)((1).Equals(scalar));
+ case "System.Guid": return (T)(object)(Guid.Parse(scalar.ToString()));
default: return base.ConvertScalar(scalar);
}
}
diff --git a/src/umbraco.datalayer/Utility/Installer/DefaultInstallerUtility.cs b/src/umbraco.datalayer/Utility/Installer/DefaultInstallerUtility.cs
index 816fc94a8d..882dbe19fa 100644
--- a/src/umbraco.datalayer/Utility/Installer/DefaultInstallerUtility.cs
+++ b/src/umbraco.datalayer/Utility/Installer/DefaultInstallerUtility.cs
@@ -171,7 +171,6 @@ namespace umbraco.DataLayer.Utility.Installer
#endregion
#region Protected Methods
-
protected virtual void NewInstall(string sql)
{
diff --git a/src/umbraco.datalayer/umbraco.datalayer.csproj b/src/umbraco.datalayer/umbraco.datalayer.csproj
index b840213a13..34eccea3a4 100644
--- a/src/umbraco.datalayer/umbraco.datalayer.csproj
+++ b/src/umbraco.datalayer/umbraco.datalayer.csproj
@@ -23,7 +23,7 @@
3.5
- v3.5
+ v4.0
publish\
true
Disk
@@ -39,6 +39,7 @@
false
false
true
+
true
diff --git a/src/umbraco.editorControls/tinyMCE3/webcontrol/TinyMCEWebControl.cs b/src/umbraco.editorControls/tinyMCE3/webcontrol/TinyMCEWebControl.cs
index 770239a15e..b386ef6a51 100644
--- a/src/umbraco.editorControls/tinyMCE3/webcontrol/TinyMCEWebControl.cs
+++ b/src/umbraco.editorControls/tinyMCE3/webcontrol/TinyMCEWebControl.cs
@@ -326,10 +326,9 @@ namespace umbraco.editorControls.tinyMCE3.webcontrol
tempTag += " " + ide.Key.ToString() + "=\"" + ide.Value.ToString() + "\"";
// Find the original filename, by removing the might added width and height
+ // NH, 4.8.1 - above replaced by loading the right media file from the db later!
orgSrc =
- IOHelper.ResolveUrl(orgSrc.Replace(
- "_" + helper.FindAttribute(ht, "width") + "x" + helper.FindAttribute(ht, "height"), "").
- Replace("%20", " "));
+ IOHelper.ResolveUrl(orgSrc.Replace("%20", " "));
// Check for either id or guid from media
string mediaId = getIdFromSource(orgSrc, localMediaPath);
@@ -358,15 +357,10 @@ namespace umbraco.editorControls.tinyMCE3.webcontrol
{
try
{
- // Check extention
- if (imageMedia.getProperty("umbracoExtension").Value.ToString() != orgSrc.Substring(orgSrc.LastIndexOf(".") + 1, orgSrc.Length - orgSrc.LastIndexOf(".") - 1))
- orgSrc = orgSrc.Substring(0, orgSrc.LastIndexOf(".") + 1) +
- imageMedia.getProperty("umbracoExtension").Value.ToString();
-
// Format the tag
tempTag = tempTag + " rel=\"" +
imageMedia.getProperty("umbracoWidth").Value.ToString() + "," +
- imageMedia.getProperty("umbracoHeight").Value.ToString() + "\" src=\"" + orgSrc +
+ imageMedia.getProperty("umbracoHeight").Value.ToString() + "\" src=\"" + IOHelper.ResolveUrl(imageMedia.getProperty("umbracoFile").Value.ToString()) +
"\"";
tempTag += "/>";
diff --git a/src/umbraco.editorControls/umbraco.editorControls.csproj b/src/umbraco.editorControls/umbraco.editorControls.csproj
index 3d3a8faace..b531d399af 100644
--- a/src/umbraco.editorControls/umbraco.editorControls.csproj
+++ b/src/umbraco.editorControls/umbraco.editorControls.csproj
@@ -102,6 +102,10 @@
AllRules.ruleset
+
+ {31785bc3-256c-4613-b2f5-a1b0bdded8c1}
+ Umbraco.Core
+
{651E1350-91B6-44B7-BD60-7207006D7003}
Umbraco.Web
@@ -176,6 +180,11 @@
+
+
+
+
+
Code
diff --git a/src/umbraco.editorControls/uploadfield/uploadField.cs b/src/umbraco.editorControls/uploadfield/uploadField.cs
index f974bc4787..dbd0d6f46e 100644
--- a/src/umbraco.editorControls/uploadfield/uploadField.cs
+++ b/src/umbraco.editorControls/uploadfield/uploadField.cs
@@ -4,6 +4,7 @@ using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
+using Umbraco.Core.IO;
using umbraco.interfaces;
using umbraco.IO;
using Content = umbraco.cms.businesslogic.Content;
@@ -18,8 +19,11 @@ namespace umbraco.editorControls
private readonly String _thumbnails;
private String _text;
+ private IFileSystem _fs;
+
public uploadField(IData Data, string ThumbnailSizes)
{
+ _fs = FileSystemProviderManager.Current.GetFileSystemProvider(FileSystemProvider.Media);
_data = (cms.businesslogic.datatype.DefaultData) Data;
_thumbnails = ThumbnailSizes;
}
@@ -107,8 +111,6 @@ namespace umbraco.editorControls
// we update additional properties post image upload
if (_data.Value != DBNull.Value && !string.IsNullOrEmpty(_data.Value.ToString()))
{
- string fullFilePath = IOHelper.MapPath(_data.Value.ToString());
-
Content content = Content.GetContentFromVersion(_data.Version);
// update extension in UI
@@ -161,6 +163,7 @@ namespace umbraco.editorControls
#endregion
+ [Obsolete("This method is now obsolete due to a change in the way that files are handled. If you need to check if a URL for an uploaded file is safe you should implement your own as this method will be removed in a future version", false)]
public string SafeUrl(string url)
{
if (!String.IsNullOrEmpty(url))
@@ -176,27 +179,29 @@ namespace umbraco.editorControls
Text = _data.Value.ToString();
}
- private void deleteFile(string file)
+ private void deleteFile(string fileUrl)
{
- if (file.Length > 0)
+ if (fileUrl.Length > 0)
{
- // delete old file
- if (File.Exists(IOHelper.MapPath(file)))
- File.Delete(IOHelper.MapPath(file));
+ var relativeFilePath = _fs.GetRelativePath(fileUrl);
- string extension = (file.Substring(file.LastIndexOf(".") + 1, file.Length - file.LastIndexOf(".") - 1));
+ // delete old file
+ if (_fs.FileExists(relativeFilePath))
+ _fs.DeleteFile(relativeFilePath);
+
+ string extension = (relativeFilePath.Substring(relativeFilePath.LastIndexOf(".") + 1, relativeFilePath.Length - relativeFilePath.LastIndexOf(".") - 1));
extension = extension.ToLower();
//check for thumbnails
if (",jpeg,jpg,gif,bmp,png,tiff,tif,".IndexOf("," + extension + ",") > -1)
{
//delete thumbnails
- string thumbnailfile = file.Replace("." + extension, "_thumb");
+ string relativeThumbFilePath = relativeFilePath.Replace("." + extension, "_thumb");
try
{
- if (File.Exists(IOHelper.MapPath(thumbnailfile + _thumbnailext)))
- File.Delete(IOHelper.MapPath(thumbnailfile + _thumbnailext));
+ if (_fs.FileExists(relativeThumbFilePath + _thumbnailext))
+ _fs.DeleteFile(relativeThumbFilePath + _thumbnailext);
}
catch
{
@@ -209,12 +214,12 @@ namespace umbraco.editorControls
{
if (thumb != "")
{
- string thumbnailextra = thumbnailfile + "_" + thumb + _thumbnailext;
+ string relativeExtraThumbFilePath = relativeThumbFilePath + "_" + thumb + _thumbnailext;
try
{
- if (File.Exists(IOHelper.MapPath(thumbnailextra)))
- File.Delete(IOHelper.MapPath(thumbnailextra));
+ if (_fs.FileExists(relativeExtraThumbFilePath))
+ _fs.DeleteFile(relativeExtraThumbFilePath);
}
catch
{
@@ -268,17 +273,18 @@ namespace umbraco.editorControls
{
if (!string.IsNullOrEmpty(Text))
{
- string ext = _text.Substring(_text.LastIndexOf(".") + 1, _text.Length - _text.LastIndexOf(".") - 1);
- string fileNameThumb = _text.Replace("." + ext, "_thumb.jpg");
- bool hasThumb = false;
+ var relativeFilePath = _fs.GetRelativePath(_text);
+ var ext = relativeFilePath.Substring(relativeFilePath.LastIndexOf(".") + 1, relativeFilePath.Length - relativeFilePath.LastIndexOf(".") - 1);
+ var relativeThumbFilePath = relativeFilePath.Replace("." + ext, "_thumb.jpg");
+ var hasThumb = false;
try
{
- hasThumb = File.Exists(IOHelper.MapPath(IOHelper.FindFile(fileNameThumb)));
+ hasThumb = _fs.FileExists(relativeThumbFilePath);
// 4.8.0 added support for png thumbnails (but for legacy it might have been jpg - hence the check before)
if (!hasThumb && (ext == "gif" || ext == "png"))
{
- fileNameThumb = _text.Replace("." + ext, "_thumb.png");
- hasThumb = File.Exists(IOHelper.MapPath(IOHelper.FindFile(fileNameThumb)));
+ relativeThumbFilePath = relativeFilePath.Replace("." + ext, "_thumb.png");
+ hasThumb = _fs.FileExists(relativeThumbFilePath);
}
}
catch
@@ -286,17 +292,19 @@ namespace umbraco.editorControls
}
if (hasThumb)
{
- var thumb = new Image();
- thumb.ImageUrl = fileNameThumb;
- thumb.BorderStyle = BorderStyle.None;
+ var thumb = new Image
+ {
+ ImageUrl = _fs.GetUrl(relativeThumbFilePath),
+ BorderStyle = BorderStyle.None
+ };
- output.WriteLine("");
+ output.WriteLine("");
thumb.RenderControl(output);
output.WriteLine("
");
}
else
- output.WriteLine("" +
- IOHelper.FindFile(Text) + "
");
+ output.WriteLine("" +
+ _fs.GetUrl(relativeFilePath) + "
");
output.WriteLine("