mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-24 05:23:33 +08:00
@@ -17,8 +17,17 @@ Scenario: Creating a folder
|
|||||||
And I fill in
|
And I fill in
|
||||||
| name | value |
|
| name | value |
|
||||||
| Name | Hello World |
|
| Name | Hello World |
|
||||||
And I hit "Save"
|
And I hit "Save"
|
||||||
And I am redirected
|
And I am redirected
|
||||||
Then I should see "Manage Media Folders"
|
Then I should see "Manage Media Folders"
|
||||||
And I should see "Hello World"
|
And I should see "Hello World"
|
||||||
And the status should be 200 "OK"
|
And the status should be 200 "OK"
|
||||||
|
|
||||||
|
Scenario: Limited access
|
||||||
|
Given I have installed Orchard
|
||||||
|
And I have installed "Orchard.Media"
|
||||||
|
When I go to "admin/media/edit?name=..\..\bin&mediaPath=..\..\bin"
|
||||||
|
And I am redirected
|
||||||
|
Then I should see "Manage Media Folders"
|
||||||
|
And I should see "Editing failed: Invalid path"
|
||||||
|
And the status should be 200 "OK"
|
||||||
|
59
src/Orchard.Specs/Media.feature.cs
generated
59
src/Orchard.Specs/Media.feature.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||||
// SpecFlow Version:1.3.2.0
|
// SpecFlow Version:1.5.0.0
|
||||||
// Runtime Version:4.0.30319.1
|
// Runtime Version:4.0.30319.1
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
@@ -14,7 +14,7 @@ namespace Orchard.Specs
|
|||||||
using TechTalk.SpecFlow;
|
using TechTalk.SpecFlow;
|
||||||
|
|
||||||
|
|
||||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.3.2.0")]
|
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.5.0.0")]
|
||||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[NUnit.Framework.TestFixtureAttribute()]
|
[NUnit.Framework.TestFixtureAttribute()]
|
||||||
[NUnit.Framework.DescriptionAttribute("Media management")]
|
[NUnit.Framework.DescriptionAttribute("Media management")]
|
||||||
@@ -31,7 +31,7 @@ namespace Orchard.Specs
|
|||||||
{
|
{
|
||||||
testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner();
|
testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner();
|
||||||
TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Media management", "In order to reference images and such from content\r\nAs an author\r\nI want to uploa" +
|
TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Media management", "In order to reference images and such from content\r\nAs an author\r\nI want to uploa" +
|
||||||
"d and manage files in a media folder", ((string[])(null)));
|
"d and manage files in a media folder", GenerationTargetLanguage.CSharp, ((string[])(null)));
|
||||||
testRunner.OnFeatureStart(featureInfo);
|
testRunner.OnFeatureStart(featureInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,15 +61,15 @@ namespace Orchard.Specs
|
|||||||
#line 6
|
#line 6
|
||||||
this.ScenarioSetup(scenarioInfo);
|
this.ScenarioSetup(scenarioInfo);
|
||||||
#line 7
|
#line 7
|
||||||
testRunner.Given("I have installed Orchard");
|
testRunner.Given("I have installed Orchard");
|
||||||
#line 8
|
#line 8
|
||||||
testRunner.And("I have installed \"Orchard.Media\"");
|
testRunner.And("I have installed \"Orchard.Media\"");
|
||||||
#line 9
|
#line 9
|
||||||
testRunner.When("I go to \"admin/media\"");
|
testRunner.When("I go to \"admin/media\"");
|
||||||
#line 10
|
#line 10
|
||||||
testRunner.Then("I should see \"Manage Media Folders\"");
|
testRunner.Then("I should see \"Manage Media Folders\"");
|
||||||
#line 11
|
#line 11
|
||||||
testRunner.And("the status should be 200 \"OK\"");
|
testRunner.And("the status should be 200 \"OK\"");
|
||||||
#line hidden
|
#line hidden
|
||||||
testRunner.CollectScenarioErrors();
|
testRunner.CollectScenarioErrors();
|
||||||
}
|
}
|
||||||
@@ -82,11 +82,11 @@ testRunner.And("the status should be 200 \"OK\"");
|
|||||||
#line 13
|
#line 13
|
||||||
this.ScenarioSetup(scenarioInfo);
|
this.ScenarioSetup(scenarioInfo);
|
||||||
#line 14
|
#line 14
|
||||||
testRunner.Given("I have installed Orchard");
|
testRunner.Given("I have installed Orchard");
|
||||||
#line 15
|
#line 15
|
||||||
testRunner.And("I have installed \"Orchard.Media\"");
|
testRunner.And("I have installed \"Orchard.Media\"");
|
||||||
#line 16
|
#line 16
|
||||||
testRunner.When("I go to \"admin/media/create\"");
|
testRunner.When("I go to \"admin/media/create\"");
|
||||||
#line hidden
|
#line hidden
|
||||||
TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] {
|
TechTalk.SpecFlow.Table table1 = new TechTalk.SpecFlow.Table(new string[] {
|
||||||
"name",
|
"name",
|
||||||
@@ -95,17 +95,42 @@ testRunner.When("I go to \"admin/media/create\"");
|
|||||||
"Name",
|
"Name",
|
||||||
"Hello World"});
|
"Hello World"});
|
||||||
#line 17
|
#line 17
|
||||||
testRunner.And("I fill in", ((string)(null)), table1);
|
testRunner.And("I fill in", ((string)(null)), table1);
|
||||||
#line 20
|
#line 20
|
||||||
testRunner.And("I hit \"Save\"");
|
testRunner.And("I hit \"Save\"");
|
||||||
#line 21
|
#line 21
|
||||||
testRunner.And("I am redirected");
|
testRunner.And("I am redirected");
|
||||||
#line 22
|
#line 22
|
||||||
testRunner.Then("I should see \"Manage Media Folders\"");
|
testRunner.Then("I should see \"Manage Media Folders\"");
|
||||||
#line 23
|
#line 23
|
||||||
testRunner.And("I should see \"Hello World\"");
|
testRunner.And("I should see \"Hello World\"");
|
||||||
#line 24
|
#line 24
|
||||||
testRunner.And("the status should be 200 \"OK\"");
|
testRunner.And("the status should be 200 \"OK\"");
|
||||||
|
#line hidden
|
||||||
|
testRunner.CollectScenarioErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
[NUnit.Framework.TestAttribute()]
|
||||||
|
[NUnit.Framework.DescriptionAttribute("Limited access")]
|
||||||
|
public virtual void LimitedAccess()
|
||||||
|
{
|
||||||
|
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Limited access", ((string[])(null)));
|
||||||
|
#line 26
|
||||||
|
this.ScenarioSetup(scenarioInfo);
|
||||||
|
#line 27
|
||||||
|
testRunner.Given("I have installed Orchard");
|
||||||
|
#line 28
|
||||||
|
testRunner.And("I have installed \"Orchard.Media\"");
|
||||||
|
#line 29
|
||||||
|
testRunner.When("I go to \"admin/media/edit?name=..\\..\\bin&mediaPath=..\\..\\bin\"");
|
||||||
|
#line 30
|
||||||
|
testRunner.And("I am redirected");
|
||||||
|
#line 31
|
||||||
|
testRunner.Then("I should see \"Manage Media Folders\"");
|
||||||
|
#line 32
|
||||||
|
testRunner.And("I should see \"Editing failed: Invalid path\"");
|
||||||
|
#line 33
|
||||||
|
testRunner.And("the status should be 200 \"OK\"");
|
||||||
#line hidden
|
#line hidden
|
||||||
testRunner.CollectScenarioErrors();
|
testRunner.CollectScenarioErrors();
|
||||||
}
|
}
|
||||||
|
297
src/Orchard.Tests.Modules/Media/Services/MediaServiceTests.cs
Normal file
297
src/Orchard.Tests.Modules/Media/Services/MediaServiceTests.cs
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Orchard.Environment.Configuration;
|
||||||
|
using Orchard.FileSystems.Media;
|
||||||
|
using Orchard.Media.Models;
|
||||||
|
using Orchard.Media.Services;
|
||||||
|
using Orchard.Tests.Stubs;
|
||||||
|
using Orchard.Tests.UI.Navigation;
|
||||||
|
|
||||||
|
namespace Orchard.Tests.Modules.Media.Services {
|
||||||
|
[TestFixture]
|
||||||
|
public class MediaServiceTests {
|
||||||
|
private const string FolderName1 = "Folder1";
|
||||||
|
private const string FolderName2 = "Folder2";
|
||||||
|
private const string FolderName3 = "Folder3";
|
||||||
|
|
||||||
|
private const string InnerDirectory = "MyDir";
|
||||||
|
|
||||||
|
private const string TextFileName = "File1.txt";
|
||||||
|
private const string PaddedTextFileName = " File2.txt";
|
||||||
|
private const string FinalDottedTextFileName = "file2.txt.";
|
||||||
|
private const string WebconfigFileName = "web.config";
|
||||||
|
private const string PaddedWebconfigFileName = " web.config";
|
||||||
|
private const string FinalDottedWebconfigFileName = "web.config.";
|
||||||
|
private const string DllFileName = "test.dll";
|
||||||
|
private const string ZipFileName = "test.zip";
|
||||||
|
private const string NoExtensionFileName = "test";
|
||||||
|
|
||||||
|
private const string MediaFolder = "Media";
|
||||||
|
private const string ShellSettingsName = "Default";
|
||||||
|
|
||||||
|
private StubOrchardServices OrchardServices { get; set; }
|
||||||
|
private StubStorageProvider StorageProvider { get; set; }
|
||||||
|
private MediaServiceAccessor MediaService { get; set; }
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup() {
|
||||||
|
OrchardServices = new StubOrchardServices();
|
||||||
|
StorageProvider = new StubStorageProvider(new ShellSettings { Name = ShellSettingsName });
|
||||||
|
MediaService = new MediaServiceAccessor(StorageProvider, OrchardServices);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetPublicUrlTests() {
|
||||||
|
Assert.That(() => MediaService.GetPublicUrl(null), Throws.InstanceOf(typeof(ArgumentException)), "null relative path is invalid");
|
||||||
|
Assert.That(MediaService.GetPublicUrl(TextFileName), Is.EqualTo(string.Format("/{0}/{1}/{2}", MediaFolder, ShellSettingsName, TextFileName)), "base path file");
|
||||||
|
Assert.That(MediaService.GetPublicUrl(string.Format("{0}/{1}", InnerDirectory, TextFileName)), Is.EqualTo(string.Format("/{0}/{1}/{2}/{3}", MediaFolder, ShellSettingsName, InnerDirectory, TextFileName)), "file within directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetMediaFoldersTest() {
|
||||||
|
StorageProvider.ListFoldersPredicate = path => {
|
||||||
|
return string.IsNullOrEmpty(path)
|
||||||
|
? new[] {new StubStorageFolder(FolderName1)}
|
||||||
|
: string.Equals(path, FolderName1)
|
||||||
|
? new[] {new StubStorageFolder(FolderName2), new StubStorageFolder(FolderName3)}
|
||||||
|
: new StubStorageFolder[] {};
|
||||||
|
};
|
||||||
|
|
||||||
|
IEnumerable<MediaFolder> mediaFolders = MediaService.GetMediaFolders(null);
|
||||||
|
Assert.That(mediaFolders.Count(), Is.EqualTo(1), "Root path only has 1 sub directory");
|
||||||
|
Assert.That(mediaFolders.FirstOrDefault(mediaFolder => mediaFolder.Name.Equals(FolderName1)), Is.Not.Null, "Correct sub directory in root path");
|
||||||
|
|
||||||
|
mediaFolders = MediaService.GetMediaFolders(FolderName3);
|
||||||
|
Assert.That(mediaFolders.Count(), Is.EqualTo(0), "Invalid folder path has 0 sub directories");
|
||||||
|
|
||||||
|
mediaFolders = MediaService.GetMediaFolders(FolderName1);
|
||||||
|
Assert.That(mediaFolders.Count(), Is.EqualTo(2), "Folder1 has 2 sub directories");
|
||||||
|
Assert.That(mediaFolders.FirstOrDefault(mediaFolder => mediaFolder.Name.Equals(FolderName2)), Is.Not.Null, "Correct sub directory in root path");
|
||||||
|
Assert.That(mediaFolders.FirstOrDefault(mediaFolder => mediaFolder.Name.Equals(FolderName3)), Is.Not.Null, "Correct sub directory in root path");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UnzipMediaFileArchiveNotNullParametersTest() {
|
||||||
|
// Test basic parameter validation
|
||||||
|
Assert.That(() => MediaService.UnzipMediaFileArchiveAccessor(null, new MemoryStream()), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => MediaService.UnzipMediaFileArchiveAccessor(FolderName1, null), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UnzipMediaFileArchiveAdministratorTest() {
|
||||||
|
// Test unzip some valid and invalid files as an administrator user
|
||||||
|
StorageProvider.SavedStreams.Clear();
|
||||||
|
StubWorkContextAccessor.WorkContextImpl.StubSite.DefaultSuperUser = OrchardServices.WorkContext.CurrentUser.UserName;
|
||||||
|
|
||||||
|
MediaService.UnzipMediaFileArchiveAccessor(FolderName1, CreateZipMemoryStream());
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, TextFileName)), Is.True, "text files are allowed for super users");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, PaddedTextFileName)), Is.True, "padded text files are allowed for super users");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, DllFileName)), Is.True, "dll files are allowed for super users");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, ZipFileName)), Is.False, "Recursive zip archive files are not allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, WebconfigFileName)), Is.False, "web.config files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, NoExtensionFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, FinalDottedWebconfigFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, PaddedWebconfigFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, FinalDottedTextFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Count, Is.EqualTo(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UnzipMediaFileArchiveNonAdministratorNoWhitelistTest() {
|
||||||
|
// Test unzip some files as a non administrator user and without a white list (everything should be rejected by default)
|
||||||
|
StorageProvider.SavedStreams.Clear();
|
||||||
|
StubWorkContextAccessor.WorkContextImpl.StubSite.DefaultSuperUser = "myuser";
|
||||||
|
|
||||||
|
MediaService.UnzipMediaFileArchiveAccessor(FolderName1, CreateZipMemoryStream());
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, TextFileName)), Is.False, "text files are not allowed by default for non super users");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, DllFileName)), Is.False, "dll files are not allowed by default for non super users");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, ZipFileName)), Is.False, "Recursive zip archive files are not allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, WebconfigFileName)), Is.False, "web.config files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, NoExtensionFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, FinalDottedWebconfigFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, PaddedWebconfigFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Count, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UnzipMediaFileArchiveNonAdministratorWhitelistTest() {
|
||||||
|
// Test unzip some files as a non administrator user but with a white list
|
||||||
|
StorageProvider.SavedStreams.Clear();
|
||||||
|
StubWorkContextAccessor.WorkContextImpl.StubSite.DefaultSuperUser = "myuser";
|
||||||
|
|
||||||
|
MediaSettingsPart mediaSettingsPart = new MediaSettingsPart {
|
||||||
|
Record = new MediaSettingsPartRecord { UploadAllowedFileTypeWhitelist = "txt dll config" }
|
||||||
|
};
|
||||||
|
|
||||||
|
StubWorkContextAccessor.WorkContextImpl.InitMethod = workContext => {
|
||||||
|
workContext.CurrentSite.ContentItem.Weld(mediaSettingsPart);
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaService.UnzipMediaFileArchiveAccessor(FolderName1, CreateZipMemoryStream());
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, TextFileName)), Is.True, "text files are allowed by the white list for non super users");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, PaddedTextFileName)), Is.True, "padded text files are allowed for super users");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, DllFileName)), Is.True, "dll files are allowed by the white list for non super users");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, ZipFileName)), Is.False, "Recursive zip archive files are not allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, WebconfigFileName)), Is.False, "web.config files are never allowed even if config extensions are");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, NoExtensionFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, FinalDottedWebconfigFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, FinalDottedTextFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Contains(StorageProvider.Combine(FolderName1, PaddedWebconfigFileName)), Is.False, "no extension files are never allowed");
|
||||||
|
Assert.That(StorageProvider.SavedStreams.Count, Is.EqualTo(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemoryStream CreateZipMemoryStream() {
|
||||||
|
// Setup memory stream with zip archive for more complex scenarios
|
||||||
|
MemoryStream memoryStream = new MemoryStream();
|
||||||
|
ZipOutputStream zipOut = new ZipOutputStream(memoryStream);
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(TextFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x01 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(WebconfigFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x02 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(DllFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x03 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(ZipFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x04 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(NoExtensionFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x05 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(PaddedWebconfigFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x06 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(FinalDottedWebconfigFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x07 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(PaddedTextFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x08 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.PutNextEntry(new ZipEntry(FinalDottedTextFileName));
|
||||||
|
zipOut.Write(new byte[] { 0x09 }, 0, 1);
|
||||||
|
zipOut.CloseEntry();
|
||||||
|
|
||||||
|
zipOut.Close();
|
||||||
|
|
||||||
|
return new MemoryStream(memoryStream.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MediaServiceAccessor : MediaService {
|
||||||
|
public MediaServiceAccessor(IStorageProvider storageProvider, IOrchardServices orchardServices)
|
||||||
|
: base (storageProvider, orchardServices) {}
|
||||||
|
|
||||||
|
public void UnzipMediaFileArchiveAccessor(string targetFolder, Stream zipStream) {
|
||||||
|
UnzipMediaFileArchive(targetFolder, zipStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StubStorageProvider : IStorageProvider {
|
||||||
|
private FileSystemStorageProvider FileSystemStorageProvider { get; set; }
|
||||||
|
public Func<string, IEnumerable<IStorageFolder>> ListFoldersPredicate { get; set; }
|
||||||
|
public List<string> SavedStreams { get; set; }
|
||||||
|
|
||||||
|
public StubStorageProvider(ShellSettings settings) {
|
||||||
|
FileSystemStorageProvider = new FileSystemStorageProvider(settings);
|
||||||
|
SavedStreams = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetPublicUrl(string path) {
|
||||||
|
return FileSystemStorageProvider.GetPublicUrl(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IStorageFile GetFile(string path) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IStorageFile> ListFiles(string path) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IStorageFolder> ListFolders(string path) {
|
||||||
|
return ListFoldersPredicate(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryCreateFolder(string path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateFolder(string path) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteFolder(string path) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenameFolder(string path, string newPath) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteFile(string path) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenameFile(string path, string newPath) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public IStorageFile CreateFile(string path) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Combine(string path1, string path2) {
|
||||||
|
return FileSystemStorageProvider.Combine(path1, path2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TrySaveStream(string path, Stream inputStream) {
|
||||||
|
try { SaveStream(path, inputStream); }
|
||||||
|
catch { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveStream(string path, Stream inputStream) {
|
||||||
|
SavedStreams.Add(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StubStorageFolder : IStorageFolder {
|
||||||
|
public string Path { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public StubStorageFolder(string name) {
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetPath() {
|
||||||
|
return Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetName() {
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long GetSize() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime GetLastUpdated() {
|
||||||
|
return DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IStorageFolder GetParent() {
|
||||||
|
return new StubStorageFolder("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -72,6 +72,10 @@
|
|||||||
<Reference Include="FluentPath">
|
<Reference Include="FluentPath">
|
||||||
<HintPath>..\..\lib\fluentpath\FluentPath.dll</HintPath>
|
<HintPath>..\..\lib\fluentpath\FluentPath.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="ICSharpCode.SharpZipLib, Version=0.85.5.452, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\..\lib\sharpziplib\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="IronRuby, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="IronRuby, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\lib\dlr\IronRuby.dll</HintPath>
|
<HintPath>..\..\lib\dlr\IronRuby.dll</HintPath>
|
||||||
@@ -138,6 +142,7 @@
|
|||||||
<Compile Include="Comments\Services\CommentServiceTests.cs" />
|
<Compile Include="Comments\Services\CommentServiceTests.cs" />
|
||||||
<Compile Include="Indexing\LuceneIndexProviderTests.cs" />
|
<Compile Include="Indexing\LuceneIndexProviderTests.cs" />
|
||||||
<Compile Include="Indexing\LuceneSearchBuilderTests.cs" />
|
<Compile Include="Indexing\LuceneSearchBuilderTests.cs" />
|
||||||
|
<Compile Include="Media\Services\MediaServiceTests.cs" />
|
||||||
<Compile Include="Scripting.Dlr\EvaluatorTests.cs" />
|
<Compile Include="Scripting.Dlr\EvaluatorTests.cs" />
|
||||||
<Compile Include="Scripting\EvaluatorTestsBase.cs" />
|
<Compile Include="Scripting\EvaluatorTestsBase.cs" />
|
||||||
<Compile Include="Scripting\EvaluatorTests.cs" />
|
<Compile Include="Scripting\EvaluatorTests.cs" />
|
||||||
|
@@ -253,6 +253,7 @@
|
|||||||
<Compile Include="Mvc\Routes\UrlPrefixTests.cs" />
|
<Compile Include="Mvc\Routes\UrlPrefixTests.cs" />
|
||||||
<Compile Include="Records\BigRecord.cs" />
|
<Compile Include="Records\BigRecord.cs" />
|
||||||
<Compile Include="Security\DefaultEncryptionServiceTests.cs" />
|
<Compile Include="Security\DefaultEncryptionServiceTests.cs" />
|
||||||
|
<Compile Include="Storage\FileSystemStorageProviderTests.cs" />
|
||||||
<Compile Include="Stubs\InMemoryWebSiteFolder.cs" />
|
<Compile Include="Stubs\InMemoryWebSiteFolder.cs" />
|
||||||
<Compile Include="Stubs\StubHttpContextAccessor.cs" />
|
<Compile Include="Stubs\StubHttpContextAccessor.cs" />
|
||||||
<Compile Include="Stubs\StubWorkContextAccessor.cs" />
|
<Compile Include="Stubs\StubWorkContextAccessor.cs" />
|
||||||
@@ -285,7 +286,6 @@
|
|||||||
<Compile Include="UI\Notify\NotifierTests.cs" />
|
<Compile Include="UI\Notify\NotifierTests.cs" />
|
||||||
<Compile Include="UI\Notify\NotifyFilterTests.cs" />
|
<Compile Include="UI\Notify\NotifyFilterTests.cs" />
|
||||||
<Compile Include="Services\ClockTests.cs" />
|
<Compile Include="Services\ClockTests.cs" />
|
||||||
<Compile Include="Storage\FileSystemStorageProviderTests.cs" />
|
|
||||||
<Compile Include="Stubs\StubClock.cs" />
|
<Compile Include="Stubs\StubClock.cs" />
|
||||||
<Compile Include="Stubs\StubContainerProvider.cs" />
|
<Compile Include="Stubs\StubContainerProvider.cs" />
|
||||||
<Compile Include="FakeTests.cs" />
|
<Compile Include="FakeTests.cs" />
|
||||||
|
@@ -15,6 +15,10 @@ namespace Orchard.Tests.Storage {
|
|||||||
_folderPath = Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Media"), "Default");
|
_folderPath = Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Media"), "Default");
|
||||||
_filePath = _folderPath + "\\testfile.txt";
|
_filePath = _folderPath + "\\testfile.txt";
|
||||||
|
|
||||||
|
if (Directory.Exists(_folderPath)) {
|
||||||
|
Directory.Delete(_folderPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(_folderPath);
|
Directory.CreateDirectory(_folderPath);
|
||||||
File.WriteAllText(_filePath, "testfile contents");
|
File.WriteAllText(_filePath, "testfile contents");
|
||||||
|
|
||||||
@@ -165,8 +169,149 @@ namespace Orchard.Tests.Storage {
|
|||||||
Assert.That(GetFile(Path.Combine("SubFolder1", "testfile4.txt")), Is.Null);
|
Assert.That(GetFile(Path.Combine("SubFolder1", "testfile4.txt")), Is.Null);
|
||||||
Assert.That(GetFile(Path.Combine("SubFolder1", "testfile5.txt")), Is.Not.Null);
|
Assert.That(GetFile(Path.Combine("SubFolder1", "testfile5.txt")), Is.Not.Null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetFileFailsInInvalidPath() {
|
||||||
|
Assert.That(() => _storageProvider.GetFile(@"../InvalidFile.txt"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.GetFile(@"../../InvalidFile.txt"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid get one level up within the storage provider domain
|
||||||
|
_storageProvider.CreateFile(@"test.txt");
|
||||||
|
Assert.That(_storageProvider.GetFile(@"test.txt"), Is.Not.Null);
|
||||||
|
Assert.That(_storageProvider.GetFile(@"SubFolder1\..\test.txt"), Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ListFilesFailsInInvalidPath() {
|
||||||
|
Assert.That(() => _storageProvider.ListFiles(@"../InvalidFolder"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.ListFiles(@"../../InvalidFolder"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid get one level up within the storage provider domain
|
||||||
|
Assert.That(_storageProvider.ListFiles(@"SubFolder1"), Is.Not.Null);
|
||||||
|
Assert.That(_storageProvider.ListFiles(@"SubFolder1\.."), Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ListFoldersFailsInInvalidPath() {
|
||||||
|
Assert.That(() => _storageProvider.ListFolders(@"../InvalidFolder"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.ListFolders(@"../../InvalidFolder"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid get one level up within the storage provider domain
|
||||||
|
Assert.That(_storageProvider.ListFolders(@"SubFolder1"), Is.Not.Null);
|
||||||
|
Assert.That(_storageProvider.ListFolders(@"SubFolder1\.."), Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TryCreateFolderFailsInInvalidPath() {
|
||||||
|
Assert.That(_storageProvider.TryCreateFolder(@"../InvalidFolder1"), Is.False);
|
||||||
|
Assert.That(_storageProvider.TryCreateFolder(@"../../InvalidFolder1"), Is.False);
|
||||||
|
|
||||||
|
// Valid create one level up within the storage provider domain
|
||||||
|
Assert.That(_storageProvider.TryCreateFolder(@"SubFolder1\..\ValidFolder1"), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CreateFolderFailsInInvalidPath() {
|
||||||
|
Assert.That(() => _storageProvider.CreateFolder(@"../InvalidFolder1"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.CreateFolder(@"../../InvalidFolder1"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid create one level up within the storage provider domain
|
||||||
|
_storageProvider.CreateFolder(@"SubFolder1\..\ValidFolder1");
|
||||||
|
Assert.That(GetFolder("ValidFolder1"), Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DeleteFolderFailsInInvalidPath() {
|
||||||
|
Assert.That(() => _storageProvider.DeleteFolder(@"../InvalidFolder1"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.DeleteFolder(@"../../InvalidFolder1"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid create one level up within the storage provider domain
|
||||||
|
Assert.That(GetFolder("SubFolder1"), Is.Not.Null);
|
||||||
|
_storageProvider.DeleteFolder(@"SubFolder1\..\SubFolder1");
|
||||||
|
Assert.That(GetFolder("SubFolder1"), Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RenameFolderFailsInInvalidPath() {
|
||||||
|
Assert.That(GetFolder(@"SubFolder1/SubSubFolder1"), Is.Not.Null);
|
||||||
|
Assert.That(() => _storageProvider.RenameFolder(@"SubFolder1", @"../SubSubFolder1"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.RenameFolder(@"SubFolder1", @"../../SubSubFolder1"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid move one level up within the storage provider domain
|
||||||
|
_storageProvider.RenameFolder(@"SubFolder1\SubSubFolder1", @"SubFolder1\..\SubSubFolder1");
|
||||||
|
Assert.That(GetFolder("SubSubFolder1"), Is.Not.Null);
|
||||||
|
|
||||||
|
_storageProvider.CreateFolder(@"SubFolder1\SubSubFolder1\SubSubSubFolder1");
|
||||||
|
_storageProvider.RenameFolder(@"SubFolder1\SubSubFolder1\SubSubSubFolder1", @"SubFolder1\SubSubFolder1\..\SubSubSubFolder1");
|
||||||
|
Assert.That(GetFolder(@"SubFolder1\SubSubSubFolder1"), Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DeleteFileFailsInInvalidPath() {
|
||||||
|
Assert.That(() => _storageProvider.DeleteFile(@"../test.txt"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.DeleteFile(@"../test.txt"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid move one level up within the storage provider domain
|
||||||
|
_storageProvider.CreateFile(@"test.txt");
|
||||||
|
Assert.That(GetFile("test.txt"), Is.Not.Null);
|
||||||
|
_storageProvider.DeleteFile(@"test.txt");
|
||||||
|
Assert.That(GetFile("test.txt"), Is.Null);
|
||||||
|
|
||||||
|
_storageProvider.CreateFile(@"test.txt");
|
||||||
|
Assert.That(GetFile("test.txt"), Is.Not.Null);
|
||||||
|
_storageProvider.DeleteFile(@"SubFolder1\..\test.txt");
|
||||||
|
Assert.That(GetFile("test.txt"), Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RenameFileFailsInInvalidPath() {
|
||||||
|
Assert.That(() => _storageProvider.RenameFile(@"../test.txt", "invalid.txt"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.RenameFile(@"../test.txt", "invalid.txt"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid move one level up within the storage provider domain
|
||||||
|
_storageProvider.CreateFile(@"test.txt");
|
||||||
|
Assert.That(GetFile("test.txt"), Is.Not.Null);
|
||||||
|
_storageProvider.RenameFile(@"test.txt", "newName.txt");
|
||||||
|
Assert.That(GetFile("newName.txt"), Is.Not.Null);
|
||||||
|
_storageProvider.RenameFile(@"SubFolder1\..\newName.txt", "newNewName.txt");
|
||||||
|
Assert.That(GetFile("newNewName.txt"), Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CreateFileFailsInInvalidPath() {
|
||||||
|
Assert.That(() => _storageProvider.CreateFile(@"../InvalidFolder1.txt"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.CreateFile(@"../../InvalidFolder1.txt"), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid create one level up within the storage provider domain
|
||||||
|
_storageProvider.CreateFile(@"SubFolder1\..\ValidFolder1.txt");
|
||||||
|
Assert.That(GetFile("ValidFolder1.txt"), Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SaveStreamFailsInInvalidPath() {
|
||||||
|
_storageProvider.CreateFile(@"test.txt");
|
||||||
|
|
||||||
|
using (Stream stream = GetFile("test.txt").OpenRead()) {
|
||||||
|
Assert.That(() => _storageProvider.SaveStream(@"../newTest.txt", stream), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
Assert.That(() => _storageProvider.SaveStream(@"../../newTest.txt", stream), Throws.InstanceOf(typeof(ArgumentException)));
|
||||||
|
|
||||||
|
// Valid create one level up within the storage provider domain
|
||||||
|
_storageProvider.SaveStream(@"SubFolder1\..\newTest.txt", stream);
|
||||||
|
Assert.That(GetFile("newTest.txt"), Is.Not.Null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TrySaveStreamFailsInInvalidPath() {
|
||||||
|
_storageProvider.CreateFile(@"test.txt");
|
||||||
|
|
||||||
|
using (Stream stream = GetFile("test.txt").OpenRead()) {
|
||||||
|
Assert.That(_storageProvider.TrySaveStream(@"../newTest.txt", stream), Is.False);
|
||||||
|
Assert.That(_storageProvider.TrySaveStream(@"../../newTest.txt", stream), Is.False);
|
||||||
|
|
||||||
|
// Valid create one level up within the storage provider domain
|
||||||
|
Assert.That(_storageProvider.TrySaveStream(@"SubFolder1\..\newTest.txt", stream), Is.True);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -19,6 +19,8 @@ namespace Orchard.Tests.Stubs {
|
|||||||
public class WorkContextImpl : WorkContext {
|
public class WorkContextImpl : WorkContext {
|
||||||
private readonly ILifetimeScope _lifetimeScope;
|
private readonly ILifetimeScope _lifetimeScope;
|
||||||
private Dictionary<string, object> _contextDictonary;
|
private Dictionary<string, object> _contextDictonary;
|
||||||
|
public delegate void MyInitMethod(WorkContextImpl workContextImpl);
|
||||||
|
public static MyInitMethod InitMethod;
|
||||||
|
|
||||||
public WorkContextImpl(ILifetimeScope lifetimeScope) {
|
public WorkContextImpl(ILifetimeScope lifetimeScope) {
|
||||||
_contextDictonary = new Dictionary<string, object>();
|
_contextDictonary = new Dictionary<string, object>();
|
||||||
@@ -27,9 +29,15 @@ namespace Orchard.Tests.Stubs {
|
|||||||
ci.Weld(new StubSite());
|
ci.Weld(new StubSite());
|
||||||
CurrentSite = ci.As<ISite>();
|
CurrentSite = ci.As<ISite>();
|
||||||
_lifetimeScope = lifetimeScope;
|
_lifetimeScope = lifetimeScope;
|
||||||
|
|
||||||
|
if (InitMethod != null) {
|
||||||
|
InitMethod(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StubSite : ContentPart, ISite {
|
public class StubSite : ContentPart, ISite {
|
||||||
|
public static string DefaultSuperUser;
|
||||||
|
|
||||||
public string PageTitleSeparator {
|
public string PageTitleSeparator {
|
||||||
get { throw new NotImplementedException(); }
|
get { throw new NotImplementedException(); }
|
||||||
}
|
}
|
||||||
@@ -43,7 +51,7 @@ namespace Orchard.Tests.Stubs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string SuperUser {
|
public string SuperUser {
|
||||||
get { throw new NotImplementedException(); }
|
get { return DefaultSuperUser; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public string HomePage {
|
public string HomePage {
|
||||||
|
@@ -74,10 +74,16 @@ namespace Orchard.Media.Controllers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult Edit(string name, string mediaPath) {
|
public ActionResult Edit(string name, string mediaPath) {
|
||||||
IEnumerable<MediaFile> mediaFiles = _mediaService.GetMediaFiles(mediaPath);
|
try {
|
||||||
IEnumerable<MediaFolder> mediaFolders = _mediaService.GetMediaFolders(mediaPath);
|
IEnumerable<MediaFile> mediaFiles = _mediaService.GetMediaFiles(mediaPath);
|
||||||
var model = new MediaFolderEditViewModel { FolderName = name, MediaFiles = mediaFiles, MediaFolders = mediaFolders, MediaPath = mediaPath };
|
IEnumerable<MediaFolder> mediaFolders = _mediaService.GetMediaFolders(mediaPath);
|
||||||
return View(model);
|
var model = new MediaFolderEditViewModel { FolderName = name, MediaFiles = mediaFiles, MediaFolders = mediaFolders, MediaPath = mediaPath };
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
catch (Exception exception) {
|
||||||
|
Services.Notifier.Error(T("Editing failed: {0}", exception.Message));
|
||||||
|
return RedirectToAction("Index");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@@ -178,18 +184,8 @@ namespace Orchard.Media.Controllers {
|
|||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return View(viewModel);
|
return View(viewModel);
|
||||||
|
|
||||||
// first validate them all
|
|
||||||
foreach (string fileName in Request.Files) {
|
foreach (string fileName in Request.Files) {
|
||||||
HttpPostedFileBase file = Request.Files[fileName];
|
_mediaService.UploadMediaFile(viewModel.MediaPath, Request.Files[fileName], viewModel.ExtractZip);
|
||||||
if (!_mediaService.FileAllowed(file)) {
|
|
||||||
ModelState.AddModelError("File", T("That file type is not allowed.").ToString());
|
|
||||||
return View(viewModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// then save them
|
|
||||||
foreach (string fileName in Request.Files) {
|
|
||||||
HttpPostedFileBase file = Request.Files[fileName];
|
|
||||||
_mediaService.UploadMediaFile(viewModel.MediaPath, file, viewModel.ExtractZip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Services.Notifier.Information(T("Media file(s) uploaded"));
|
Services.Notifier.Information(T("Media file(s) uploaded"));
|
||||||
|
@@ -114,6 +114,7 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
@@ -1,19 +1,96 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Orchard.Media.Models;
|
using Orchard.Media.Models;
|
||||||
|
|
||||||
namespace Orchard.Media.Services {
|
namespace Orchard.Media.Services {
|
||||||
public interface IMediaService : IDependency {
|
public interface IMediaService : IDependency {
|
||||||
string GetPublicUrl(string path);
|
/// <summary>
|
||||||
IEnumerable<MediaFolder> GetMediaFolders(string path);
|
/// Retrieves the public path based on the relative path within the media directory.
|
||||||
IEnumerable<MediaFile> GetMediaFiles(string path);
|
/// </summary>
|
||||||
void CreateFolder(string path, string name);
|
/// <example>
|
||||||
void DeleteFolder(string name);
|
/// "/Media/Default/InnerDirectory/Test.txt" based on the input "InnerDirectory/Test.txt"
|
||||||
void RenameFolder(string path, string newName);
|
/// </example>
|
||||||
void DeleteFile(string name, string folderName);
|
/// <param name="relativePath">The relative path within the media directory.</param>
|
||||||
void RenameFile(string name, string newName, string folderName);
|
/// <returns>The public path relative to the application url.</returns>
|
||||||
string UploadMediaFile(string folderName, string fileName, byte[] bytes, bool extractZip);
|
string GetPublicUrl(string relativePath);
|
||||||
string UploadMediaFile(string folderName, HttpPostedFileBase postedFile, bool extractZip);
|
|
||||||
bool FileAllowed(HttpPostedFileBase postedFile);
|
/// <summary>
|
||||||
|
/// Retrieves the media folders within a given relative path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relativePath">The path where to retrieve the media folder from. null means root.</param>
|
||||||
|
/// <returns>The media folder in the given path.</returns>
|
||||||
|
IEnumerable<MediaFolder> GetMediaFolders(string relativePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the media files within a given relative path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relativePath">The path where to retrieve the media files from. null means root.</param>
|
||||||
|
/// <returns>The media files in the given path.</returns>
|
||||||
|
IEnumerable<MediaFile> GetMediaFiles(string relativePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a media folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relativePath">The path where to create the new folder. null means root.</param>
|
||||||
|
/// <param name="folderName">The name of the folder to be created.</param>
|
||||||
|
void CreateFolder(string relativePath, string folderName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a media folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the folder to be deleted.</param>
|
||||||
|
void DeleteFolder(string folderPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renames a media folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the folder to be renamed.</param>
|
||||||
|
/// <param name="newFolderName">The new folder name.</param>
|
||||||
|
void RenameFolder(string folderPath, string newFolderName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a media file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The folder path.</param>
|
||||||
|
/// <param name="fileName">The file name.</param>
|
||||||
|
void DeleteFile(string folderPath, string fileName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renames a media file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the file's parent folder.</param>
|
||||||
|
/// <param name="currentFileName">The current file name.</param>
|
||||||
|
/// <param name="newFileName">The new file name.</param>
|
||||||
|
void RenameFile(string folderPath, string currentFileName, string newFileName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uploads a media file based on a posted file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the folder where to upload the file.</param>
|
||||||
|
/// <param name="postedFile">The file to upload.</param>
|
||||||
|
/// <param name="extractZip">Boolean value indicating weather zip files should be extracted.</param>
|
||||||
|
/// <returns>The path to the uploaded file.</returns>
|
||||||
|
string UploadMediaFile(string folderPath, HttpPostedFileBase postedFile, bool extractZip);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uploads a media file based on an array of bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the folder where to upload the file.</param>
|
||||||
|
/// <param name="fileName">The file name.</param>
|
||||||
|
/// <param name="bytes">The array of bytes with the file's contents.</param>
|
||||||
|
/// <param name="extractZip">Boolean value indicating weather zip files should be extracted.</param>
|
||||||
|
/// <returns>The path to the uploaded file.</returns>
|
||||||
|
string UploadMediaFile(string folderPath, string fileName, byte[] bytes, bool extractZip);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uploads a media file based on a stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The folder path to where to upload the file.</param>
|
||||||
|
/// <param name="fileName">The file name.</param>
|
||||||
|
/// <param name="inputStream">The stream with the file's contents.</param>
|
||||||
|
/// <param name="extractZip">Boolean value indicating weather zip files should be extracted.</param>
|
||||||
|
/// <returns>The path to the uploaded file.</returns>
|
||||||
|
string UploadMediaFile(string folderPath, string fileName, Stream inputStream, bool extractZip);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using ICSharpCode.SharpZipLib.Zip;
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -8,13 +9,26 @@ using Orchard.ContentManagement;
|
|||||||
using Orchard.FileSystems.Media;
|
using Orchard.FileSystems.Media;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
using Orchard.Media.Models;
|
using Orchard.Media.Models;
|
||||||
|
using Orchard.Security;
|
||||||
|
using Orchard.Settings;
|
||||||
|
using Orchard.Validation;
|
||||||
|
|
||||||
namespace Orchard.Media.Services {
|
namespace Orchard.Media.Services {
|
||||||
|
/// <summary>
|
||||||
|
/// The MediaService class provides the services o manipulate media entities (files / folders).
|
||||||
|
/// Among other things it provides filtering functionalities on file types.
|
||||||
|
/// The actual manipulation of the files is, however, delegated to the IStorageProvider.
|
||||||
|
/// </summary>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class MediaService : IMediaService {
|
public class MediaService : IMediaService {
|
||||||
private readonly IStorageProvider _storageProvider;
|
private readonly IStorageProvider _storageProvider;
|
||||||
private readonly IOrchardServices _orchardServices;
|
private readonly IOrchardServices _orchardServices;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the MediaService class with a given IStorageProvider and IOrchardServices.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="storageProvider">The storage provider.</param>
|
||||||
|
/// <param name="orchardServices">The orchard services provider.</param>
|
||||||
public MediaService(IStorageProvider storageProvider, IOrchardServices orchardServices) {
|
public MediaService(IStorageProvider storageProvider, IOrchardServices orchardServices) {
|
||||||
_storageProvider = storageProvider;
|
_storageProvider = storageProvider;
|
||||||
_orchardServices = orchardServices;
|
_orchardServices = orchardServices;
|
||||||
@@ -24,96 +38,167 @@ namespace Orchard.Media.Services {
|
|||||||
|
|
||||||
public Localizer T { get; set; }
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
public string GetPublicUrl(string path) {
|
/// <summary>
|
||||||
return _storageProvider.GetPublicUrl(path);
|
/// Retrieves the public path based on the relative path within the media directory.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <example>
|
||||||
|
/// "/Media/Default/InnerDirectory/Test.txt" based on the input "InnerDirectory/Test.txt"
|
||||||
|
/// </example>
|
||||||
|
/// <param name="relativePath">The relative path within the media directory.</param>
|
||||||
|
/// <returns>The public path relative to the application url.</returns>
|
||||||
|
public string GetPublicUrl(string relativePath) {
|
||||||
|
Argument.ThrowIfNullOrEmpty(relativePath, "relativePath");
|
||||||
|
|
||||||
public IEnumerable<MediaFolder> GetMediaFolders(string path) {
|
return _storageProvider.GetPublicUrl(relativePath);
|
||||||
var mediaFolders = new List<MediaFolder>();
|
}
|
||||||
var folders = _storageProvider.ListFolders(path);
|
|
||||||
|
|
||||||
foreach (var folder in folders) {
|
/// <summary>
|
||||||
var mediaFolder = new MediaFolder {
|
/// Retrieves the media folders within a given relative path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relativePath">The path where to retrieve the media folder from. null means root.</param>
|
||||||
|
/// <returns>The media folder in the given path.</returns>
|
||||||
|
public IEnumerable<MediaFolder> GetMediaFolders(string relativePath) {
|
||||||
|
return _storageProvider.ListFolders(relativePath).Select(folder =>
|
||||||
|
new MediaFolder {
|
||||||
Name = folder.GetName(),
|
Name = folder.GetName(),
|
||||||
Size = folder.GetSize(),
|
Size = folder.GetSize(),
|
||||||
LastUpdated = folder.GetLastUpdated(),
|
LastUpdated = folder.GetLastUpdated(),
|
||||||
MediaPath = folder.GetPath()
|
MediaPath = folder.GetPath()
|
||||||
};
|
});
|
||||||
mediaFolders.Add(mediaFolder);
|
|
||||||
}
|
|
||||||
return mediaFolders;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<MediaFile> GetMediaFiles(string path) {
|
/// <summary>
|
||||||
var mediaFiles = new List<MediaFile>();
|
/// Retrieves the media files within a given relative path.
|
||||||
|
/// </summary>
|
||||||
var files = _storageProvider.ListFiles(path);
|
/// <param name="relativePath">The path where to retrieve the media files from. null means root.</param>
|
||||||
foreach (var file in files) {
|
/// <returns>The media files in the given path.</returns>
|
||||||
var mediaFile = new MediaFile {
|
public IEnumerable<MediaFile> GetMediaFiles(string relativePath) {
|
||||||
|
return _storageProvider.ListFiles(relativePath).Select(file =>
|
||||||
|
new MediaFile {
|
||||||
Name = file.GetName(),
|
Name = file.GetName(),
|
||||||
Size = file.GetSize(),
|
Size = file.GetSize(),
|
||||||
LastUpdated = file.GetLastUpdated(),
|
LastUpdated = file.GetLastUpdated(),
|
||||||
Type = file.GetFileType(),
|
Type = file.GetFileType(),
|
||||||
FolderName = path
|
FolderName = relativePath
|
||||||
};
|
});
|
||||||
mediaFiles.Add(mediaFile);
|
|
||||||
}
|
|
||||||
return mediaFiles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Use Path.Combine.
|
/// <summary>
|
||||||
public void CreateFolder(string mediaPath, string name) {
|
/// Creates a media folder.
|
||||||
if (String.IsNullOrEmpty(mediaPath)) {
|
/// </summary>
|
||||||
_storageProvider.CreateFolder(name);
|
/// <param name="relativePath">The path where to create the new folder. null means root.</param>
|
||||||
return;
|
/// <param name="folderName">The name of the folder to be created.</param>
|
||||||
}
|
public void CreateFolder(string relativePath, string folderName) {
|
||||||
_storageProvider.CreateFolder(_storageProvider.Combine(mediaPath, name));
|
Argument.ThrowIfNullOrEmpty(folderName, "folderName");
|
||||||
|
|
||||||
|
_storageProvider.CreateFolder(relativePath == null ? folderName : _storageProvider.Combine(relativePath, folderName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteFolder(string name) {
|
/// <summary>
|
||||||
_storageProvider.DeleteFolder(name);
|
/// Deletes a media folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the folder to be deleted.</param>
|
||||||
|
public void DeleteFolder(string folderPath) {
|
||||||
|
Argument.ThrowIfNullOrEmpty(folderPath, "folderPath");
|
||||||
|
|
||||||
|
_storageProvider.DeleteFolder(folderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenameFolder(string path, string newName) {
|
/// <summary>
|
||||||
var newPath = RenameFolderPath(path, newName);
|
/// Renames a media folder.
|
||||||
_storageProvider.RenameFolder(path, newPath);
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the folder to be renamed.</param>
|
||||||
|
/// <param name="newFolderName">The new folder name.</param>
|
||||||
|
public void RenameFolder(string folderPath, string newFolderName) {
|
||||||
|
Argument.ThrowIfNullOrEmpty(folderPath, "folderPath");
|
||||||
|
Argument.ThrowIfNullOrEmpty(newFolderName, "newFolderName");
|
||||||
|
|
||||||
|
_storageProvider.RenameFolder(folderPath, _storageProvider.Combine(Path.GetDirectoryName(folderPath), newFolderName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteFile(string name, string folderName) {
|
/// <summary>
|
||||||
_storageProvider.DeleteFile(_storageProvider.Combine(folderName, name));
|
/// Deletes a media file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The folder path.</param>
|
||||||
|
/// <param name="fileName">The file name.</param>
|
||||||
|
public void DeleteFile(string folderPath, string fileName) {
|
||||||
|
Argument.ThrowIfNullOrEmpty(folderPath, "folderPath");
|
||||||
|
Argument.ThrowIfNullOrEmpty(fileName, "fileName");
|
||||||
|
|
||||||
|
_storageProvider.DeleteFile(_storageProvider.Combine(folderPath, fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenameFile(string name, string newName, string folderName) {
|
/// <summary>
|
||||||
if (!FileAllowed(newName, false)) {
|
/// Renames a media file.
|
||||||
throw new ArgumentException(T("New file name {0} not allowed", newName).ToString());
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the file's parent folder.</param>
|
||||||
|
/// <param name="currentFileName">The current file name.</param>
|
||||||
|
/// <param name="newFileName">The new file name.</param>
|
||||||
|
public void RenameFile(string folderPath, string currentFileName, string newFileName) {
|
||||||
|
Argument.ThrowIfNullOrEmpty(folderPath, "folderPath");
|
||||||
|
Argument.ThrowIfNullOrEmpty(currentFileName, "currentFileName");
|
||||||
|
Argument.ThrowIfNullOrEmpty(newFileName, "newFileName");
|
||||||
|
|
||||||
|
if (!FileAllowed(newFileName, false)) {
|
||||||
|
throw new ArgumentException(T("New file name {0} is not allowed", newFileName).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
_storageProvider.RenameFile(_storageProvider.Combine(folderName, name), _storageProvider.Combine(folderName, newName));
|
_storageProvider.RenameFile(_storageProvider.Combine(folderPath, currentFileName), _storageProvider.Combine(Path.GetDirectoryName(folderPath), newFileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string UploadMediaFile(string folderName, HttpPostedFileBase postedFile, bool extractZip) {
|
/// <summary>
|
||||||
var postedFileLength = postedFile.ContentLength;
|
/// Uploads a media file based on a posted file.
|
||||||
var postedFileStream = postedFile.InputStream;
|
/// </summary>
|
||||||
var postedFileData = new byte[postedFileLength];
|
/// <param name="folderPath">The path to the folder where to upload the file.</param>
|
||||||
postedFileStream.Read(postedFileData, 0, postedFileLength);
|
/// <param name="postedFile">The file to upload.</param>
|
||||||
|
/// <param name="extractZip">Boolean value indicating weather zip files should be extracted.</param>
|
||||||
|
/// <returns>The path to the uploaded file.</returns>
|
||||||
|
public string UploadMediaFile(string folderPath, HttpPostedFileBase postedFile, bool extractZip) {
|
||||||
|
Argument.ThrowIfNullOrEmpty(folderPath, "folderPath");
|
||||||
|
Argument.ThrowIfNull(postedFile, "postedFile");
|
||||||
|
|
||||||
return UploadMediaFile(folderName, postedFile.FileName, postedFileData, extractZip);
|
return UploadMediaFile(folderPath, postedFile.FileName, postedFile.InputStream, extractZip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uploads a media file based on an array of bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The path to the folder where to upload the file.</param>
|
||||||
|
/// <param name="fileName">The file name.</param>
|
||||||
|
/// <param name="bytes">The array of bytes with the file's contents.</param>
|
||||||
|
/// <param name="extractZip">Boolean value indicating weather zip files should be extracted.</param>
|
||||||
|
/// <returns>The path to the uploaded file.</returns>
|
||||||
public string UploadMediaFile(string folderPath, string fileName, byte [] bytes, bool extractZip) {
|
public string UploadMediaFile(string folderPath, string fileName, byte [] bytes, bool extractZip) {
|
||||||
if (extractZip && fileName.EndsWith(".zip")) {
|
Argument.ThrowIfNullOrEmpty(folderPath, "folderPath");
|
||||||
UnzipMediaFileArchive(folderPath, bytes);
|
Argument.ThrowIfNullOrEmpty(fileName, "fileName");
|
||||||
|
Argument.ThrowIfNull(bytes, "bytes");
|
||||||
|
|
||||||
|
return UploadMediaFile(folderPath, fileName, new MemoryStream(bytes), extractZip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uploads a media file based on a stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folderPath">The folder path to where to upload the file.</param>
|
||||||
|
/// <param name="fileName">The file name.</param>
|
||||||
|
/// <param name="inputStream">The stream with the file's contents.</param>
|
||||||
|
/// <param name="extractZip">Boolean value indicating weather zip files should be extracted.</param>
|
||||||
|
/// <returns>The path to the uploaded file.</returns>
|
||||||
|
public string UploadMediaFile(string folderPath, string fileName, Stream inputStream, bool extractZip) {
|
||||||
|
Argument.ThrowIfNullOrEmpty(folderPath, "folderPath");
|
||||||
|
Argument.ThrowIfNullOrEmpty(fileName, "fileName");
|
||||||
|
Argument.ThrowIfNull(inputStream, "inputStream");
|
||||||
|
|
||||||
|
if (extractZip && IsZipFile(Path.GetExtension(fileName))) {
|
||||||
|
UnzipMediaFileArchive(folderPath, inputStream);
|
||||||
|
|
||||||
// Don't save the zip file.
|
// Don't save the zip file.
|
||||||
return _storageProvider.GetPublicUrl(folderPath);
|
return _storageProvider.GetPublicUrl(folderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileAllowed(fileName, true) && bytes.Length > 0) {
|
if (FileAllowed(fileName, true)) {
|
||||||
string filePath = Path.Combine(folderPath, Path.GetFileName(fileName));
|
string filePath = _storageProvider.Combine(folderPath, fileName);
|
||||||
_storageProvider.TryCreateFolder(folderPath);
|
_storageProvider.SaveStream(filePath, inputStream);
|
||||||
IStorageFile file = _storageProvider.CreateFile(filePath);
|
|
||||||
using(var stream = file.OpenWrite()) {
|
|
||||||
stream.Write(bytes, 0, bytes.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _storageProvider.GetPublicUrl(filePath);
|
return _storageProvider.GetPublicUrl(filePath);
|
||||||
}
|
}
|
||||||
@@ -121,100 +206,90 @@ namespace Orchard.Media.Services {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool FileAllowed(HttpPostedFileBase postedFile) {
|
/// <summary>
|
||||||
if (postedFile == null) {
|
/// Verifies if a file is allowed based on its name and the policies defined by the black / white lists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">The file name of the file to validate.</param>
|
||||||
|
/// <param name="allowZip">Boolean value indicating weather zip files are allowed.</param>
|
||||||
|
/// <returns>True if the file is allowed; false if otherwise.</returns>
|
||||||
|
protected bool FileAllowed(string fileName, bool allowZip) {
|
||||||
|
string localFileName = GetFileName(fileName);
|
||||||
|
string extension = GetExtension(localFileName);
|
||||||
|
if (string.IsNullOrEmpty(localFileName) || string.IsNullOrEmpty(extension)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return FileAllowed(postedFile.FileName, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool FileAllowed(string name, bool allowZip) {
|
ISite currentSite = _orchardServices.WorkContext.CurrentSite;
|
||||||
if (string.IsNullOrWhiteSpace(name)) {
|
IUser currentUser = _orchardServices.WorkContext.CurrentUser;
|
||||||
return false;
|
|
||||||
}
|
// zip files at the top level are allowed since this is how you upload multiple files at once.
|
||||||
var currentSite = _orchardServices.WorkContext.CurrentSite;
|
if (IsZipFile(extension)) {
|
||||||
var mediaSettings = currentSite.As<MediaSettingsPart>();
|
return allowZip;
|
||||||
var allowedExtensions = mediaSettings.UploadAllowedFileTypeWhitelist.ToUpperInvariant().Split(' ');
|
|
||||||
var ext = (Path.GetExtension(name) ?? "").TrimStart('.').ToUpperInvariant();
|
|
||||||
if (string.IsNullOrWhiteSpace(ext)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// whitelist does not apply to the superuser
|
// whitelist does not apply to the superuser
|
||||||
var currentUser = _orchardServices.WorkContext.CurrentUser;
|
|
||||||
if (currentUser == null || !currentSite.SuperUser.Equals(currentUser.UserName, StringComparison.Ordinal)) {
|
if (currentUser == null || !currentSite.SuperUser.Equals(currentUser.UserName, StringComparison.Ordinal)) {
|
||||||
// zip files at the top level are allowed since this is how you upload multiple files at once.
|
|
||||||
if (allowZip && ext.Equals("zip", StringComparison.OrdinalIgnoreCase)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// must be in the whitelist
|
// must be in the whitelist
|
||||||
if (Array.IndexOf(allowedExtensions, ext) == -1) {
|
MediaSettingsPart mediaSettings = currentSite.As<MediaSettingsPart>();
|
||||||
|
if (mediaSettings == null ||
|
||||||
|
!mediaSettings.UploadAllowedFileTypeWhitelist.ToUpperInvariant().Split(' ').Contains(extension.ToUpperInvariant())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// blacklist always applies
|
// blacklist always applies
|
||||||
if (string.Equals(name.Trim(), "web.config", StringComparison.OrdinalIgnoreCase)) {
|
if (string.Equals(localFileName, "web.config", StringComparison.OrdinalIgnoreCase)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveStream(string filePath, Stream inputStream) {
|
/// <summary>
|
||||||
var file = _storageProvider.CreateFile(filePath);
|
/// Unzips a media archive file.
|
||||||
var outputStream = file.OpenWrite();
|
/// </summary>
|
||||||
var buffer = new byte[8192];
|
/// <param name="targetFolder">The folder where to unzip the file.</param>
|
||||||
for (; ; ) {
|
/// <param name="zipStream">The archive file stream.</param>
|
||||||
|
protected void UnzipMediaFileArchive(string targetFolder, Stream zipStream) {
|
||||||
|
Argument.ThrowIfNullOrEmpty(targetFolder, "targetFolder");
|
||||||
|
Argument.ThrowIfNull(zipStream, "zipStream");
|
||||||
|
|
||||||
var length = inputStream.Read(buffer, 0, buffer.Length);
|
var fileInflater = new ZipInputStream(zipStream);
|
||||||
if (length <= 0)
|
ZipEntry entry;
|
||||||
break;
|
// We want to preserve whatever directory structure the zip file contained instead
|
||||||
outputStream.Write(buffer, 0, length);
|
// of flattening it.
|
||||||
}
|
// The API below doesn't necessarily return the entries in the zip file in any order.
|
||||||
outputStream.Dispose();
|
// That means the files in subdirectories can be returned as entries from the stream
|
||||||
}
|
// before the directories that contain them, so we create directories as soon as first
|
||||||
|
// file below their path is encountered.
|
||||||
|
while ((entry = fileInflater.GetNextEntry()) != null) {
|
||||||
|
if (!entry.IsDirectory && !string.IsNullOrEmpty(entry.Name)) {
|
||||||
|
|
||||||
private void UnzipMediaFileArchive(string targetFolder, HttpPostedFileBase postedFile) {
|
// skip disallowed files
|
||||||
var postedFileLength = postedFile.ContentLength;
|
if (FileAllowed(entry.Name, false)) {
|
||||||
var postedFileStream = postedFile.InputStream;
|
string fullFileName = _storageProvider.Combine(targetFolder, entry.Name);
|
||||||
var postedFileData = new byte[postedFileLength];
|
_storageProvider.TrySaveStream(fullFileName, fileInflater);
|
||||||
postedFileStream.Read(postedFileData, 0, postedFileLength);
|
|
||||||
|
|
||||||
UnzipMediaFileArchive(targetFolder, postedFileData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UnzipMediaFileArchive(string targetFolder, byte [] postedFileData) {
|
|
||||||
using (var memoryStream = new MemoryStream(postedFileData)) {
|
|
||||||
var fileInflater = new ZipInputStream(memoryStream);
|
|
||||||
ZipEntry entry;
|
|
||||||
// We want to preserve whatever directory structure the zip file contained instead
|
|
||||||
// of flattening it.
|
|
||||||
// The API below doesn't necessarily return the entries in the zip file in any order.
|
|
||||||
// That means the files in subdirectories can be returned as entries from the stream
|
|
||||||
// before the directories that contain them, so we create directories as soon as first
|
|
||||||
// file below their path is encountered.
|
|
||||||
while ((entry = fileInflater.GetNextEntry()) != null) {
|
|
||||||
|
|
||||||
if (!entry.IsDirectory && entry.Name.Length > 0) {
|
|
||||||
var entryName = Path.Combine(targetFolder, entry.Name);
|
|
||||||
var directoryName = Path.GetDirectoryName(entryName);
|
|
||||||
|
|
||||||
// skip disallowed files
|
|
||||||
if (FileAllowed(entry.Name, false)) {
|
|
||||||
_storageProvider.TryCreateFolder(directoryName);
|
|
||||||
SaveStream(entryName, fileInflater);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RenameFolderPath(string path, string newName) {
|
/// <summary>
|
||||||
var lastIndex = Math.Max(path.LastIndexOf(Path.DirectorySeparatorChar), path.LastIndexOf(Path.AltDirectorySeparatorChar));
|
/// Determines if a file is a Zip Archive based on its extension.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="extension">The extension of the file to analyze.</param>
|
||||||
|
/// <returns>True if the file is a Zip archive; false otherwise.</returns>
|
||||||
|
private static bool IsZipFile(string extension) {
|
||||||
|
return string.Equals(extension.TrimStart('.'), "zip", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
if (lastIndex == -1) {
|
private static string GetFileName(string fileName) {
|
||||||
return newName;
|
return Path.GetFileName(fileName).Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _storageProvider.Combine(path.Substring(0, lastIndex), newName);
|
private static string GetExtension(string fileName) {
|
||||||
|
return Path.GetExtension(fileName).Trim().TrimStart('.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ using Orchard.Caching;
|
|||||||
using Orchard.FileSystems.VirtualPath;
|
using Orchard.FileSystems.VirtualPath;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
|
using Orchard.Validation;
|
||||||
|
|
||||||
namespace Orchard.FileSystems.AppData {
|
namespace Orchard.FileSystems.AppData {
|
||||||
public class AppDataFolder : IAppDataFolder {
|
public class AppDataFolder : IAppDataFolder {
|
||||||
@@ -79,8 +80,7 @@ namespace Orchard.FileSystems.AppData {
|
|||||||
/// starting with "_basePath".
|
/// starting with "_basePath".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string CombineToPhysicalPath(params string[] paths) {
|
private string CombineToPhysicalPath(params string[] paths) {
|
||||||
return Path.Combine(RootFolder, Path.Combine(paths))
|
return PathValidation.ValidatePath(RootFolder, Path.Combine(RootFolder, Path.Combine(paths)).Replace('/', Path.DirectorySeparatorChar));
|
||||||
.Replace('/', Path.DirectorySeparatorChar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#if !AZURE
|
#if !AZURE
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Web.Hosting;
|
using System.Web.Hosting;
|
||||||
using Orchard.Environment.Configuration;
|
using Orchard.Environment.Configuration;
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
|
using Orchard.Validation;
|
||||||
|
|
||||||
namespace Orchard.FileSystems.Media {
|
namespace Orchard.FileSystems.Media {
|
||||||
public class FileSystemStorageProvider : IStorageProvider {
|
public class FileSystemStorageProvider : IStorageProvider {
|
||||||
@@ -16,7 +17,7 @@ namespace Orchard.FileSystems.Media {
|
|||||||
var mediaPath = HostingEnvironment.IsHosted
|
var mediaPath = HostingEnvironment.IsHosted
|
||||||
? HostingEnvironment.MapPath("~/Media/") ?? ""
|
? HostingEnvironment.MapPath("~/Media/") ?? ""
|
||||||
: Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Media");
|
: Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Media");
|
||||||
|
|
||||||
_storagePath = Path.Combine(mediaPath, settings.Name);
|
_storagePath = Path.Combine(mediaPath, settings.Name);
|
||||||
|
|
||||||
var appPath = "";
|
var appPath = "";
|
||||||
@@ -35,11 +36,26 @@ namespace Orchard.FileSystems.Media {
|
|||||||
|
|
||||||
public Localizer T { get; set; }
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
string Map(string path) {
|
/// <summary>
|
||||||
return string.IsNullOrEmpty(path) ? _storagePath : Path.Combine(_storagePath, path);
|
/// Maps a relative path into the storage path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to be mapped.</param>
|
||||||
|
/// <returns>The relative path combined with the storage path.</returns>
|
||||||
|
private string MapStorage(string path) {
|
||||||
|
string mappedPath = string.IsNullOrEmpty(path) ? _storagePath : Path.Combine(_storagePath, path);
|
||||||
|
return PathValidation.ValidatePath(_storagePath, mappedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string Fix(string path) {
|
/// <summary>
|
||||||
|
/// Maps a relative path into the public path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to be mapped.</param>
|
||||||
|
/// <returns>The relative path combined with the public path in an URL friendly format ('/' character for directory separator).</returns>
|
||||||
|
private string MapPublic(string path) {
|
||||||
|
return string.IsNullOrEmpty(path) ? _publicPath : Path.Combine(_publicPath, path).Replace(Path.DirectorySeparatorChar, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Fix(string path) {
|
||||||
return string.IsNullOrEmpty(path)
|
return string.IsNullOrEmpty(path)
|
||||||
? ""
|
? ""
|
||||||
: Path.DirectorySeparatorChar != '/'
|
: Path.DirectorySeparatorChar != '/'
|
||||||
@@ -49,118 +65,230 @@ namespace Orchard.FileSystems.Media {
|
|||||||
|
|
||||||
#region Implementation of IStorageProvider
|
#region Implementation of IStorageProvider
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the public URL for a given file within the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path within the storage provider.</param>
|
||||||
|
/// <returns>The public URL.</returns>
|
||||||
public string GetPublicUrl(string path) {
|
public string GetPublicUrl(string path) {
|
||||||
|
return MapPublic(path);
|
||||||
return Map(_publicPath + path.Replace(Path.DirectorySeparatorChar, '/'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a file within the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the file within the storage provider.</param>
|
||||||
|
/// <returns>The file.</returns>
|
||||||
|
/// <exception cref="ArgumentException">If the file is not found.</exception>
|
||||||
public IStorageFile GetFile(string path) {
|
public IStorageFile GetFile(string path) {
|
||||||
if (!File.Exists(Map(path))) {
|
FileInfo fileInfo = new FileInfo(MapStorage(path));
|
||||||
|
if (!fileInfo.Exists) {
|
||||||
throw new ArgumentException(T("File {0} does not exist", path).ToString());
|
throw new ArgumentException(T("File {0} does not exist", path).ToString());
|
||||||
}
|
}
|
||||||
return new FileSystemStorageFile(Fix(path), new FileInfo(Map(path)));
|
|
||||||
|
return new FileSystemStorageFile(Fix(path), fileInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lists the files within a storage provider's path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder which files to list.</param>
|
||||||
|
/// <returns>The list of files in the folder.</returns>
|
||||||
public IEnumerable<IStorageFile> ListFiles(string path) {
|
public IEnumerable<IStorageFile> ListFiles(string path) {
|
||||||
if (!Directory.Exists(Map(path))) {
|
DirectoryInfo directoryInfo = new DirectoryInfo(MapStorage(path));
|
||||||
|
if (!directoryInfo.Exists) {
|
||||||
throw new ArgumentException(T("Directory {0} does not exist", path).ToString());
|
throw new ArgumentException(T("Directory {0} does not exist", path).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DirectoryInfo(Map(path))
|
return directoryInfo
|
||||||
.GetFiles()
|
.GetFiles()
|
||||||
.Where(fi => !IsHidden(fi))
|
.Where(fi => !IsHidden(fi))
|
||||||
.Select<FileInfo, IStorageFile>(fi => new FileSystemStorageFile(Path.Combine(Fix(path), fi.Name), fi))
|
.Select<FileInfo, IStorageFile>(fi => new FileSystemStorageFile(Path.Combine(Fix(path), fi.Name), fi))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lists the folders within a storage provider's path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder which folders to list.</param>
|
||||||
|
/// <returns>The list of folders in the folder.</returns>
|
||||||
public IEnumerable<IStorageFolder> ListFolders(string path) {
|
public IEnumerable<IStorageFolder> ListFolders(string path) {
|
||||||
if (!Directory.Exists(Map(path))) {
|
DirectoryInfo directoryInfo = new DirectoryInfo(MapStorage(path));
|
||||||
|
if (!directoryInfo.Exists) {
|
||||||
try {
|
try {
|
||||||
Directory.CreateDirectory(Map(path));
|
directoryInfo.Create();
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new ArgumentException(T("The folder could not be created at path: {0}. {1}", path, ex).ToString());
|
throw new ArgumentException(T("The folder could not be created at path: {0}. {1}", path, ex).ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DirectoryInfo(Map(path))
|
return directoryInfo
|
||||||
.GetDirectories()
|
.GetDirectories()
|
||||||
.Where(di => !IsHidden(di))
|
.Where(di => !IsHidden(di))
|
||||||
.Select<DirectoryInfo, IStorageFolder>(di => new FileSystemStorageFolder(Path.Combine(Fix(path), di.Name), di))
|
.Select<DirectoryInfo, IStorageFolder>(di => new FileSystemStorageFolder(Path.Combine(Fix(path), di.Name), di))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsHidden(FileSystemInfo di) {
|
/// <summary>
|
||||||
return (di.Attributes & FileAttributes.Hidden) != 0;
|
/// Tries to create a folder in the storage provider.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder to be created.</param>
|
||||||
public void TryCreateFolder(string path) {
|
/// <returns>True if success; False otherwise.</returns>
|
||||||
Directory.CreateDirectory(Map(path));
|
public bool TryCreateFolder(string path) {
|
||||||
|
try { CreateFolder(path); }
|
||||||
|
catch { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a folder in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder to be created.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the folder already exists.</exception>
|
||||||
public void CreateFolder(string path) {
|
public void CreateFolder(string path) {
|
||||||
if (Directory.Exists(Map(path))) {
|
DirectoryInfo directoryInfo = new DirectoryInfo(MapStorage(path));
|
||||||
|
if (directoryInfo.Exists) {
|
||||||
throw new ArgumentException(T("Directory {0} already exists", path).ToString());
|
throw new ArgumentException(T("Directory {0} already exists", path).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TryCreateFolder(Map(path));
|
Directory.CreateDirectory(directoryInfo.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a folder in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder to be deleted.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the folder doesn't exist.</exception>
|
||||||
public void DeleteFolder(string path) {
|
public void DeleteFolder(string path) {
|
||||||
if (!Directory.Exists(Map(path))) {
|
DirectoryInfo directoryInfo = new DirectoryInfo(MapStorage(path));
|
||||||
|
if (!directoryInfo.Exists) {
|
||||||
throw new ArgumentException(T("Directory {0} does not exist", path).ToString());
|
throw new ArgumentException(T("Directory {0} does not exist", path).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.Delete(Map(path), true);
|
directoryInfo.Delete(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenameFolder(string path, string newPath) {
|
/// <summary>
|
||||||
if (!Directory.Exists(Map(path))) {
|
/// Renames a folder in the storage provider.
|
||||||
throw new ArgumentException(T("Directory {0} does not exist", path).ToString());
|
/// </summary>
|
||||||
|
/// <param name="oldPath">The relative path to the folder to be renamed.</param>
|
||||||
|
/// <param name="newPath">The relative path to the new folder.</param>
|
||||||
|
public void RenameFolder(string oldPath, string newPath) {
|
||||||
|
DirectoryInfo sourceDirectory = new DirectoryInfo(MapStorage(oldPath));
|
||||||
|
if (!sourceDirectory.Exists) {
|
||||||
|
throw new ArgumentException(T("Directory {0} does not exist", oldPath).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.Exists(Map(newPath))) {
|
DirectoryInfo targetDirectory = new DirectoryInfo(MapStorage(newPath));
|
||||||
|
if (targetDirectory.Exists) {
|
||||||
throw new ArgumentException(T("Directory {0} already exists", newPath).ToString());
|
throw new ArgumentException(T("Directory {0} already exists", newPath).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.Move(Map(path), Map(newPath));
|
Directory.Move(sourceDirectory.FullName, targetDirectory.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorageFile CreateFile(string path) {
|
/// <summary>
|
||||||
if (File.Exists(Map(path))) {
|
/// Deletes a file in the storage provider.
|
||||||
throw new ArgumentException(T("File {0} already exists", path).ToString());
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the file to be deleted.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the file doesn't exist.</exception>
|
||||||
|
public void DeleteFile(string path) {
|
||||||
|
FileInfo fileInfo = new FileInfo(MapStorage(path));
|
||||||
|
if (!fileInfo.Exists) {
|
||||||
|
throw new ArgumentException(T("File {0} does not exist", path).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileInfo = new FileInfo(Map(path));
|
fileInfo.Delete();
|
||||||
File.WriteAllBytes(Map(path), new byte[0]);
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renames a file in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="oldPath">The relative path to the file to be renamed.</param>
|
||||||
|
/// <param name="newPath">The relative path to the new file.</param>
|
||||||
|
public void RenameFile(string oldPath, string newPath) {
|
||||||
|
FileInfo sourceFileInfo = new FileInfo(MapStorage(oldPath));
|
||||||
|
if (!sourceFileInfo.Exists) {
|
||||||
|
throw new ArgumentException(T("File {0} does not exist", oldPath).ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInfo targetFileInfo = new FileInfo(MapStorage(newPath));
|
||||||
|
if (targetFileInfo.Exists) {
|
||||||
|
throw new ArgumentException(T("File {0} already exists", newPath).ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
File.Move(sourceFileInfo.FullName, targetFileInfo.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a file in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the file to be created.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the file already exists.</exception>
|
||||||
|
/// <returns>The created file.</returns>
|
||||||
|
public IStorageFile CreateFile(string path) {
|
||||||
|
FileInfo fileInfo = new FileInfo(MapStorage(path));
|
||||||
|
if (fileInfo.Exists) {
|
||||||
|
throw new ArgumentException(T("File {0} already exists", fileInfo.Name).ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllBytes(fileInfo.FullName, new byte[0]);
|
||||||
|
|
||||||
return new FileSystemStorageFile(Fix(path), fileInfo);
|
return new FileSystemStorageFile(Fix(path), fileInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteFile(string path) {
|
/// <summary>
|
||||||
if (!File.Exists(Map(path))) {
|
/// Tries to save a stream in the storage provider.
|
||||||
throw new ArgumentException(T("File {0} does not exist", path).ToString());
|
/// </summary>
|
||||||
}
|
/// <param name="path">The relative path to the file to be created.</param>
|
||||||
|
/// <param name="inputStream">The stream to be saved.</param>
|
||||||
|
/// <returns>True if success; False otherwise.</returns>
|
||||||
|
public bool TrySaveStream(string path, Stream inputStream) {
|
||||||
|
try { SaveStream(path, inputStream); }
|
||||||
|
catch { return false; }
|
||||||
|
|
||||||
File.Delete(Map(path));
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RenameFile(string path, string newPath) {
|
/// <summary>
|
||||||
if (!File.Exists(Map(path))) {
|
/// Saves a stream in the storage provider.
|
||||||
throw new ArgumentException(T("File {0} does not exist", path).ToString());
|
/// </summary>
|
||||||
}
|
/// <param name="path">The relative path to the file to be created.</param>
|
||||||
|
/// <param name="inputStream">The stream to be saved.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the stream can't be saved due to access permissions.</exception>
|
||||||
|
public void SaveStream(string path, Stream inputStream) {
|
||||||
|
// Create the file.
|
||||||
|
// The CreateFile method will map the still relative path
|
||||||
|
var file = CreateFile(path);
|
||||||
|
|
||||||
if (File.Exists(Map(newPath))) {
|
var outputStream = file.OpenWrite();
|
||||||
throw new ArgumentException(T("File {0} already exists", newPath).ToString());
|
var buffer = new byte[8192];
|
||||||
}
|
for (;;) {
|
||||||
|
|
||||||
File.Move(Map(path), Map(newPath));
|
var length = inputStream.Read(buffer, 0, buffer.Length);
|
||||||
|
if (length <= 0)
|
||||||
|
break;
|
||||||
|
outputStream.Write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
outputStream.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Combines to paths.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path1">The parent path.</param>
|
||||||
|
/// <param name="path2">The child path.</param>
|
||||||
|
/// <returns>The combined path.</returns>
|
||||||
public string Combine(string path1, string path2) {
|
public string Combine(string path1, string path2) {
|
||||||
return Path.Combine(path1, path2);
|
return Path.Combine(path1, path2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsHidden(FileSystemInfo di) {
|
||||||
|
return (di.Attributes & FileAttributes.Hidden) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private class FileSystemStorageFile : IStorageFile {
|
private class FileSystemStorageFile : IStorageFile {
|
||||||
@@ -264,7 +392,6 @@ namespace Orchard.FileSystems.Media {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,18 +1,110 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Orchard.FileSystems.Media {
|
namespace Orchard.FileSystems.Media {
|
||||||
public interface IStorageProvider : IDependency {
|
public interface IStorageProvider : IDependency {
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the public URL for a given file within the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path within the storage provider.</param>
|
||||||
|
/// <returns>The public URL.</returns>
|
||||||
string GetPublicUrl(string path);
|
string GetPublicUrl(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a file within the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the file within the storage provider.</param>
|
||||||
|
/// <returns>The file.</returns>
|
||||||
|
/// <exception cref="ArgumentException">If the file is not found.</exception>
|
||||||
IStorageFile GetFile(string path);
|
IStorageFile GetFile(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lists the files within a storage provider's path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder which files to list.</param>
|
||||||
|
/// <returns>The list of files in the folder.</returns>
|
||||||
IEnumerable<IStorageFile> ListFiles(string path);
|
IEnumerable<IStorageFile> ListFiles(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lists the folders within a storage provider's path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder which folders to list.</param>
|
||||||
|
/// <returns>The list of folders in the folder.</returns>
|
||||||
IEnumerable<IStorageFolder> ListFolders(string path);
|
IEnumerable<IStorageFolder> ListFolders(string path);
|
||||||
void TryCreateFolder(string path);
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to create a folder in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder to be created.</param>
|
||||||
|
/// <returns>True if success; False otherwise.</returns>
|
||||||
|
bool TryCreateFolder(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a folder in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder to be created.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the folder already exists.</exception>
|
||||||
void CreateFolder(string path);
|
void CreateFolder(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a folder in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the folder to be deleted.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the folder doesn't exist.</exception>
|
||||||
void DeleteFolder(string path);
|
void DeleteFolder(string path);
|
||||||
void RenameFolder(string path, string newPath);
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renames a folder in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="oldPath">The relative path to the folder to be renamed.</param>
|
||||||
|
/// <param name="newPath">The relative path to the new folder.</param>
|
||||||
|
void RenameFolder(string oldPath, string newPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a file in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the file to be deleted.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the file doesn't exist.</exception>
|
||||||
void DeleteFile(string path);
|
void DeleteFile(string path);
|
||||||
void RenameFile(string path, string newPath);
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renames a file in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="oldPath">The relative path to the file to be renamed.</param>
|
||||||
|
/// <param name="newPath">The relative path to the new file.</param>
|
||||||
|
void RenameFile(string oldPath, string newPath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a file in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the file to be created.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the file already exists.</exception>
|
||||||
|
/// <returns>The created file.</returns>
|
||||||
IStorageFile CreateFile(string path);
|
IStorageFile CreateFile(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to save a stream in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the file to be created.</param>
|
||||||
|
/// <param name="inputStream">The stream to be saved.</param>
|
||||||
|
/// <returns>True if success; False otherwise.</returns>
|
||||||
|
bool TrySaveStream(string path, Stream inputStream);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves a stream in the storage provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The relative path to the file to be created.</param>
|
||||||
|
/// <param name="inputStream">The stream to be saved.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the stream can't be saved due to access permissions.</exception>
|
||||||
|
void SaveStream(string path, Stream inputStream);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Combines to paths.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path1">The parent path.</param>
|
||||||
|
/// <param name="path2">The child path.</param>
|
||||||
|
/// <returns>The combined path.</returns>
|
||||||
string Combine(string path1, string path2);
|
string Combine(string path1, string path2);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -181,6 +181,7 @@
|
|||||||
<Compile Include="Environment\WorkContextImplementation.cs" />
|
<Compile Include="Environment\WorkContextImplementation.cs" />
|
||||||
<Compile Include="Environment\WorkContextModule.cs" />
|
<Compile Include="Environment\WorkContextModule.cs" />
|
||||||
<Compile Include="Environment\WorkContextProperty.cs" />
|
<Compile Include="Environment\WorkContextProperty.cs" />
|
||||||
|
<Compile Include="FileSystems\Media\FileSystemStorageProvider.cs" />
|
||||||
<Compile Include="Localization\Services\CurrentCultureWorkContext.cs" />
|
<Compile Include="Localization\Services\CurrentCultureWorkContext.cs" />
|
||||||
<Compile Include="Localization\Services\DefaultLocalizedStringManager.cs" />
|
<Compile Include="Localization\Services\DefaultLocalizedStringManager.cs" />
|
||||||
<Compile Include="Localization\Services\ILocalizedStringManager.cs" />
|
<Compile Include="Localization\Services\ILocalizedStringManager.cs" />
|
||||||
@@ -459,6 +460,7 @@
|
|||||||
<Compile Include="Messaging\Services\IMessageManager.cs" />
|
<Compile Include="Messaging\Services\IMessageManager.cs" />
|
||||||
<Compile Include="Messaging\Services\IMessagingChannel.cs" />
|
<Compile Include="Messaging\Services\IMessagingChannel.cs" />
|
||||||
<Compile Include="IWorkContextAccessor.cs" />
|
<Compile Include="IWorkContextAccessor.cs" />
|
||||||
|
<Compile Include="Validation\PathValidation.cs" />
|
||||||
<Compile Include="WorkContextExtensions.cs" />
|
<Compile Include="WorkContextExtensions.cs" />
|
||||||
<Compile Include="Mvc\ViewEngines\Razor\RazorCompilationEventsShim.cs" />
|
<Compile Include="Mvc\ViewEngines\Razor\RazorCompilationEventsShim.cs" />
|
||||||
<Compile Include="Mvc\ViewEngines\Razor\RazorViewEngineProvider.cs" />
|
<Compile Include="Mvc\ViewEngines\Razor\RazorViewEngineProvider.cs" />
|
||||||
@@ -799,7 +801,6 @@
|
|||||||
<Compile Include="Security\Permissions\Permission.cs" />
|
<Compile Include="Security\Permissions\Permission.cs" />
|
||||||
<Compile Include="Security\Providers\OrchardRoleProvider.cs" />
|
<Compile Include="Security\Providers\OrchardRoleProvider.cs" />
|
||||||
<Compile Include="Services\Clock.cs" />
|
<Compile Include="Services\Clock.cs" />
|
||||||
<Compile Include="FileSystems\Media\FileSystemStorageProvider.cs" />
|
|
||||||
<Compile Include="FileSystems\Media\IStorageFile.cs" />
|
<Compile Include="FileSystems\Media\IStorageFile.cs" />
|
||||||
<Compile Include="FileSystems\Media\IStorageFolder.cs" />
|
<Compile Include="FileSystems\Media\IStorageFolder.cs" />
|
||||||
<Compile Include="FileSystems\Media\IStorageProvider.cs" />
|
<Compile Include="FileSystems\Media\IStorageProvider.cs" />
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Orchard.Validation {
|
namespace Orchard.Validation {
|
||||||
class Argument {
|
public class Argument {
|
||||||
[AssertionMethod]
|
[AssertionMethod]
|
||||||
public static void Validate([AssertionCondition(AssertionConditionType.IS_TRUE)] bool condition, [InvokerParameterName]string name) {
|
public static void Validate([AssertionCondition(AssertionConditionType.IS_TRUE)] bool condition, [InvokerParameterName]string name) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
|
35
src/Orchard/Validation/PathValidation.cs
Normal file
35
src/Orchard/Validation/PathValidation.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Orchard.Validation {
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods to validate paths.
|
||||||
|
/// </summary>
|
||||||
|
public static class PathValidation {
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if a path lies within the base path boundaries.
|
||||||
|
/// If not, an exception is thrown.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="basePath">The base path which boundaries are not to be transposed.</param>
|
||||||
|
/// <param name="mappedPath">The path to determine.</param>
|
||||||
|
/// <rereturns>The mapped path if valid.</rereturns>
|
||||||
|
/// <exception cref="ArgumentException">If the path is invalid.</exception>
|
||||||
|
public static string ValidatePath(string basePath, string mappedPath) {
|
||||||
|
bool valid = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check that we are indeed within the storage directory boundaries
|
||||||
|
valid = Path.GetFullPath(mappedPath).StartsWith(Path.GetFullPath(basePath), StringComparison.OrdinalIgnoreCase);
|
||||||
|
} catch {
|
||||||
|
// Make sure that if invalid for medium trust we give a proper exception
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
throw new ArgumentException("Invalid path");
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappedPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user