mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-27 04:19:04 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
@@ -48,7 +48,8 @@
|
||||
<MSBuild
|
||||
Projects="$(SrcFolder)\Orchard.Azure\Orchard.Azure.CloudService.sln"
|
||||
Targets="Build"
|
||||
Properties="Configuration=Release;OutputPath=$(CompileFolder);PlatformTarget=x64" />
|
||||
Properties="Configuration=Release;OutputPath=$(CompileFolder);PlatformTarget=x64;DefineConstants=AZURE"
|
||||
/>
|
||||
|
||||
<MSBuild
|
||||
Projects="$(SrcFolder)\Orchard.Azure.sln"
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Orchard.Azure.Tests.FileSystems.Media {
|
||||
|
||||
Assert.AreEqual(".txt", storageFile.GetFileType());
|
||||
Assert.AreEqual("foo.txt", storageFile.GetName());
|
||||
Assert.That(storageFile.GetPath().EndsWith("/default/foo.txt"), Is.True);
|
||||
Assert.AreEqual("foo.txt", storageFile.GetPath());
|
||||
Assert.AreEqual(0, storageFile.GetSize());
|
||||
}
|
||||
|
||||
@@ -71,7 +71,8 @@ namespace Orchard.Azure.Tests.FileSystems.Media {
|
||||
var files = _azureBlobStorageProvider.ListFiles("");
|
||||
|
||||
Assert.AreEqual(1, files.Count());
|
||||
Assert.That(files.First().GetPath().EndsWith("foo2.txt"), Is.True);
|
||||
Assert.That(files.First().GetPath().Equals("foo2.txt"), Is.True);
|
||||
Assert.That(files.First().GetName().Equals("foo2.txt"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -82,17 +83,28 @@ namespace Orchard.Azure.Tests.FileSystems.Media {
|
||||
|
||||
Assert.AreEqual(1, _azureBlobStorageProvider.ListFiles("").Count());
|
||||
Assert.AreEqual(1, _azureBlobStorageProvider.ListFiles("folder").Count());
|
||||
Assert.AreEqual("folder/foo.txt", _azureBlobStorageProvider.ListFiles("folder").First().GetPath());
|
||||
Assert.AreEqual("foo.txt", _azureBlobStorageProvider.ListFiles("folder").First().GetName());
|
||||
Assert.AreEqual(1, _azureBlobStorageProvider.ListFiles("folder/folder").Count());
|
||||
Assert.AreEqual("folder/folder/foo.txt", _azureBlobStorageProvider.ListFiles("folder/folder").First().GetPath());
|
||||
Assert.AreEqual("foo.txt", _azureBlobStorageProvider.ListFiles("folder/folder").First().GetName());
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentException))]
|
||||
public void CreateFolderThatExistsShouldThrow() {
|
||||
// sebros: In Azure, the folder concept is just about checking files prefix. So until a file exists, a folder is nothing
|
||||
_azureBlobStorageProvider.CreateFile("folder/foo.txt");
|
||||
_azureBlobStorageProvider.CreateFolder("folder");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ListFolderShouldAcceptNullPath() {
|
||||
_azureBlobStorageProvider.CreateFolder("folder");
|
||||
Assert.AreEqual(1, _azureBlobStorageProvider.ListFolders(null).Count());
|
||||
Assert.AreEqual("folder", _azureBlobStorageProvider.ListFolders(null).First().GetName());
|
||||
Assert.AreEqual("folder", _azureBlobStorageProvider.ListFolders(null).First().GetPath());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeleteFolderShouldDeleteFilesAlso() {
|
||||
_azureBlobStorageProvider.CreateFile("folder/foo1.txt");
|
||||
|
||||
@@ -8,11 +8,15 @@ using Microsoft.WindowsAzure.StorageClient;
|
||||
using Orchard.FileSystems.Media;
|
||||
|
||||
namespace Orchard.Azure {
|
||||
public class AzureFileSystem {
|
||||
public class AzureFileSystem
|
||||
{
|
||||
private const string FolderEntry = "$$$ORCHARD$$$.$$$";
|
||||
|
||||
public string ContainerName { get; protected set; }
|
||||
|
||||
private readonly CloudStorageAccount _storageAccount;
|
||||
private readonly string _root;
|
||||
private readonly string _absoluteRoot;
|
||||
public CloudBlobClient BlobClient { get; private set; }
|
||||
public CloudBlobContainer Container { get; private set; }
|
||||
|
||||
@@ -25,6 +29,7 @@ namespace Orchard.Azure {
|
||||
_storageAccount = storageAccount;
|
||||
ContainerName = containerName;
|
||||
_root = String.IsNullOrEmpty(root) || root == "/" ? String.Empty : root + "/";
|
||||
_absoluteRoot = _storageAccount.BlobEndpoint.AbsoluteUri + containerName + "/" + root + "/";
|
||||
|
||||
using ( new HttpContextWeaver() ) {
|
||||
|
||||
@@ -46,66 +51,65 @@ namespace Orchard.Azure {
|
||||
}
|
||||
|
||||
private static void EnsurePathIsRelative(string path) {
|
||||
if ( path.StartsWith("/") || path.StartsWith("http://"))
|
||||
if (path.StartsWith("/") || path.StartsWith("http://"))
|
||||
throw new ArgumentException("Path must be relative");
|
||||
}
|
||||
|
||||
public IStorageFile GetFile(string path) {
|
||||
EnsurePathIsRelative(path);
|
||||
path = String.Concat(_root, path);
|
||||
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
Container.EnsureBlobExists(path);
|
||||
return new AzureBlobFileStorage(Container.GetBlockBlobReference(path));
|
||||
using ( new HttpContextWeaver() ) {
|
||||
Container.EnsureBlobExists(String.Concat(_root, path));
|
||||
return new AzureBlobFileStorage(Container.GetBlockBlobReference(path), _absoluteRoot);
|
||||
}
|
||||
}
|
||||
|
||||
public bool FileExists(string path) {
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
path = String.Concat(_root, path);
|
||||
return Container.BlobExists(path);
|
||||
using ( new HttpContextWeaver() ) {
|
||||
return Container.BlobExists(String.Concat(_root, path));
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IStorageFile> ListFiles(string path) {
|
||||
path = path ?? String.Empty;
|
||||
|
||||
EnsurePathIsRelative(path);
|
||||
|
||||
string prefix = String.Concat(Container.Name, "/", _root, path);
|
||||
|
||||
if ( !prefix.EndsWith("/") )
|
||||
prefix += "/";
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
foreach (var blobItem in BlobClient.ListBlobsWithPrefix(prefix).OfType<CloudBlockBlob>())
|
||||
{
|
||||
yield return new AzureBlobFileStorage(blobItem);
|
||||
|
||||
using ( new HttpContextWeaver() ) {
|
||||
foreach (var blobItem in BlobClient.ListBlobsWithPrefix(prefix).OfType<CloudBlockBlob>()) {
|
||||
// ignore directory entries
|
||||
if(blobItem.Uri.AbsoluteUri.EndsWith(FolderEntry))
|
||||
continue;
|
||||
|
||||
yield return new AzureBlobFileStorage(blobItem, _absoluteRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IStorageFolder> ListFolders(string path) {
|
||||
path = path ?? String.Empty;
|
||||
|
||||
EnsurePathIsRelative(path);
|
||||
path = String.Concat(_root, path);
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
if (!Container.DirectoryExists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
CreateFolder(path);
|
||||
using ( new HttpContextWeaver() ) {
|
||||
if ( !Container.DirectoryExists(String.Concat(_root, path)) ) {
|
||||
try {
|
||||
CreateFolder(String.Concat(_root, path));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
catch ( Exception ex ) {
|
||||
throw new ArgumentException(string.Format("The folder could not be created at path: {0}. {1}",
|
||||
path, ex));
|
||||
}
|
||||
}
|
||||
|
||||
return Container.GetDirectoryReference(path)
|
||||
return Container.GetDirectoryReference(String.Concat(_root, path))
|
||||
.ListBlobs()
|
||||
.OfType<CloudBlobDirectory>()
|
||||
.Select<CloudBlobDirectory, IStorageFolder>(d => new AzureBlobFolderStorage(d))
|
||||
.Select<CloudBlobDirectory, IStorageFolder>(d => new AzureBlobFolderStorage(d, _absoluteRoot))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
@@ -113,23 +117,20 @@ namespace Orchard.Azure {
|
||||
public void CreateFolder(string path)
|
||||
{
|
||||
EnsurePathIsRelative(path);
|
||||
path = String.Concat(_root, path);
|
||||
using (new HttpContextWeaver())
|
||||
{
|
||||
Container.EnsureDirectoryDoesNotExist(path);
|
||||
Container.GetDirectoryReference(path);
|
||||
using (new HttpContextWeaver()) {
|
||||
Container.EnsureDirectoryDoesNotExist(String.Concat(_root, path));
|
||||
|
||||
// Creating a virtually hidden file to make the directory an existing concept
|
||||
CreateFile(path + "/" + FolderEntry);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteFolder(string path) {
|
||||
EnsurePathIsRelative(path);
|
||||
path = String.Concat(_root, path);
|
||||
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
Container.EnsureDirectoryExists(path);
|
||||
foreach (var blob in Container.GetDirectoryReference(path).ListBlobs())
|
||||
{
|
||||
using ( new HttpContextWeaver() ) {
|
||||
Container.EnsureDirectoryExists(String.Concat(_root, path));
|
||||
foreach ( var blob in Container.GetDirectoryReference(String.Concat(_root, path)).ListBlobs() ) {
|
||||
if (blob is CloudBlob)
|
||||
((CloudBlob) blob).Delete();
|
||||
|
||||
@@ -141,7 +142,6 @@ namespace Orchard.Azure {
|
||||
|
||||
public void RenameFolder(string path, string newPath) {
|
||||
EnsurePathIsRelative(path);
|
||||
|
||||
EnsurePathIsRelative(newPath);
|
||||
|
||||
if ( !path.EndsWith("/") )
|
||||
@@ -149,20 +149,16 @@ namespace Orchard.Azure {
|
||||
|
||||
if ( !newPath.EndsWith("/") )
|
||||
newPath += "/";
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
foreach (var blob in Container.GetDirectoryReference(_root + path).ListBlobs())
|
||||
{
|
||||
if (blob is CloudBlob)
|
||||
{
|
||||
using ( new HttpContextWeaver() ) {
|
||||
foreach (var blob in Container.GetDirectoryReference(_root + path).ListBlobs()) {
|
||||
if (blob is CloudBlob) {
|
||||
string filename = Path.GetFileName(blob.Uri.ToString());
|
||||
string source = String.Concat(path, filename);
|
||||
string destination = String.Concat(newPath, filename);
|
||||
RenameFile(source, destination);
|
||||
}
|
||||
|
||||
if (blob is CloudBlobDirectory)
|
||||
{
|
||||
if (blob is CloudBlobDirectory) {
|
||||
string foldername = blob.Uri.Segments.Last();
|
||||
string source = String.Concat(path, foldername);
|
||||
string destination = String.Concat(newPath, foldername);
|
||||
@@ -174,29 +170,24 @@ namespace Orchard.Azure {
|
||||
|
||||
public void DeleteFile(string path) {
|
||||
EnsurePathIsRelative(path);
|
||||
path = String.Concat(_root, path);
|
||||
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
|
||||
using ( new HttpContextWeaver() ) {
|
||||
Container.EnsureBlobExists(path);
|
||||
var blob = Container.GetBlockBlobReference(path);
|
||||
var blob = Container.GetBlockBlobReference(String.Concat(_root, path));
|
||||
blob.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void RenameFile(string path, string newPath) {
|
||||
EnsurePathIsRelative(path);
|
||||
path = String.Concat(_root, path);
|
||||
|
||||
EnsurePathIsRelative(newPath);
|
||||
newPath = String.Concat(_root, newPath);
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
Container.EnsureBlobExists(path);
|
||||
Container.EnsureBlobDoesNotExist(newPath);
|
||||
|
||||
var blob = Container.GetBlockBlobReference(path);
|
||||
var newBlob = Container.GetBlockBlobReference(newPath);
|
||||
using ( new HttpContextWeaver() ) {
|
||||
Container.EnsureBlobExists(String.Concat(_root, path));
|
||||
Container.EnsureBlobDoesNotExist(String.Concat(_root, newPath));
|
||||
|
||||
var blob = Container.GetBlockBlobReference(String.Concat(_root, path));
|
||||
var newBlob = Container.GetBlockBlobReference(String.Concat(_root, newPath));
|
||||
newBlob.CopyFromBlob(blob);
|
||||
blob.Delete();
|
||||
}
|
||||
@@ -204,36 +195,36 @@ namespace Orchard.Azure {
|
||||
|
||||
public IStorageFile CreateFile(string path) {
|
||||
EnsurePathIsRelative(path);
|
||||
path = String.Concat(_root, path);
|
||||
|
||||
if ( Container.BlobExists(path) ) {
|
||||
if ( Container.BlobExists(String.Concat(_root, path)) ) {
|
||||
throw new ArgumentException("File " + path + " already exists");
|
||||
}
|
||||
|
||||
var blob = Container.GetBlockBlobReference(path);
|
||||
var blob = Container.GetBlockBlobReference(String.Concat(_root, path));
|
||||
blob.OpenWrite().Dispose(); // force file creation
|
||||
return new AzureBlobFileStorage(blob);
|
||||
return new AzureBlobFileStorage(blob, _absoluteRoot);
|
||||
}
|
||||
|
||||
public string GetPublicUrl(string path) {
|
||||
EnsurePathIsRelative(path);
|
||||
path = String.Concat(_root, path);
|
||||
using ( new HttpContextWeaver() )
|
||||
{
|
||||
Container.EnsureBlobExists(path);
|
||||
return Container.GetBlockBlobReference(path).Uri.ToString();
|
||||
|
||||
using ( new HttpContextWeaver() ) {
|
||||
Container.EnsureBlobExists(String.Concat(_root, path));
|
||||
return Container.GetBlockBlobReference(String.Concat(_root, path)).Uri.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private class AzureBlobFileStorage : IStorageFile {
|
||||
private readonly CloudBlockBlob _blob;
|
||||
private readonly string _rootPath;
|
||||
|
||||
public AzureBlobFileStorage(CloudBlockBlob blob) {
|
||||
public AzureBlobFileStorage(CloudBlockBlob blob, string rootPath) {
|
||||
_blob = blob;
|
||||
_rootPath = rootPath;
|
||||
}
|
||||
|
||||
public string GetPath() {
|
||||
return _blob.Uri.ToString();
|
||||
return _blob.Uri.ToString().Substring(_rootPath.Length+1);
|
||||
}
|
||||
|
||||
public string GetName() {
|
||||
@@ -264,17 +255,19 @@ namespace Orchard.Azure {
|
||||
|
||||
private class AzureBlobFolderStorage : IStorageFolder {
|
||||
private readonly CloudBlobDirectory _blob;
|
||||
private readonly string _rootPath;
|
||||
|
||||
public AzureBlobFolderStorage(CloudBlobDirectory blob) {
|
||||
public AzureBlobFolderStorage(CloudBlobDirectory blob, string rootPath) {
|
||||
_blob = blob;
|
||||
_rootPath = rootPath;
|
||||
}
|
||||
|
||||
public string GetName() {
|
||||
return Path.GetDirectoryName(_blob.Uri.ToString());
|
||||
return Path.GetDirectoryName(GetPath() + "/");
|
||||
}
|
||||
|
||||
public string GetPath() {
|
||||
return _blob.Uri.ToString();
|
||||
return _blob.Uri.ToString().Substring(_rootPath.Length + 1).TrimEnd('/');
|
||||
}
|
||||
|
||||
public long GetSize() {
|
||||
@@ -287,7 +280,7 @@ namespace Orchard.Azure {
|
||||
|
||||
public IStorageFolder GetParent() {
|
||||
if ( _blob.Parent != null ) {
|
||||
return new AzureBlobFolderStorage(_blob.Parent);
|
||||
return new AzureBlobFolderStorage(_blob.Parent, _rootPath);
|
||||
}
|
||||
throw new ArgumentException("Directory " + _blob.Uri + " does not have a parent directory");
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@ namespace Orchard.Azure.Web {
|
||||
public override bool OnStart() {
|
||||
DiagnosticMonitor.Start("DiagnosticsConnectionString");
|
||||
|
||||
CloudStorageAccount.SetConfigurationSettingPublisher(
|
||||
(configName, configSetter) =>
|
||||
configSetter(RoleEnvironment.GetConfigurationSettingValue(configName))
|
||||
);
|
||||
|
||||
// For information on handling configuration changes
|
||||
// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
|
||||
RoleEnvironment.Changing += RoleEnvironmentChanging;
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Orchard.Tests.DataMigration {
|
||||
private string _tempFolder;
|
||||
private SchemaBuilder _schemaBuilder;
|
||||
private DefaultDataMigrationInterpreter _interpreter;
|
||||
private ISession _session;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() {
|
||||
@@ -38,7 +39,7 @@ namespace Orchard.Tests.DataMigration {
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
|
||||
var session = _sessionFactory.OpenSession();
|
||||
_session = _sessionFactory.OpenSession();
|
||||
builder.RegisterInstance(appDataFolder).As<IAppDataFolder>();
|
||||
builder.RegisterType<SqlCeDataServicesProvider>().As<IDataServicesProvider>();
|
||||
builder.RegisterType<DataServicesProviderFactory>().As<IDataServicesProviderFactory>();
|
||||
@@ -46,7 +47,7 @@ namespace Orchard.Tests.DataMigration {
|
||||
builder.RegisterType<DefaultDataMigrationInterpreter>().As<IDataMigrationInterpreter>();
|
||||
builder.RegisterType<SessionConfigurationCache>().As<ISessionConfigurationCache>();
|
||||
builder.RegisterType<SessionFactoryHolder>().As<ISessionFactoryHolder>();
|
||||
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(session)).As<ISessionLocator>();
|
||||
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
|
||||
builder.RegisterInstance(new ShellBlueprint { Records = Enumerable.Empty<RecordBlueprint>() }).As<ShellBlueprint>();
|
||||
builder.RegisterInstance(new ShellSettings { Name = "temp", DataProvider = "SqlCe", DataTablePrefix = "TEST" }).As<ShellSettings>();
|
||||
builder.RegisterModule(new DataModule());
|
||||
@@ -133,10 +134,24 @@ namespace Orchard.Tests.DataMigration {
|
||||
.AlterTable("User", table => table
|
||||
.AddColumn("Age", DbType.Int32))
|
||||
.AlterTable("User", table => table
|
||||
.AlterColumn("Lastname", column => column.WithDefault("John")))
|
||||
.AlterColumn("Lastname", column => column.WithDefault("Doe")))
|
||||
.AlterTable("User", table => table
|
||||
.DropColumn("Firstname")
|
||||
);
|
||||
|
||||
// creating a new row should assign a default value to Firstname and Age
|
||||
_schemaBuilder
|
||||
.ExecuteSql("insert into TEST_User VALUES (DEFAULT, DEFAULT)");
|
||||
|
||||
// ensure wehave one record woth the default value
|
||||
var command = _session.Connection.CreateCommand();
|
||||
command.CommandText = "SELECT count(*) FROM TEST_User WHERE Lastname = 'Doe'";
|
||||
Assert.That(command.ExecuteScalar(), Is.EqualTo(1));
|
||||
|
||||
// ensure this is not a false positive
|
||||
command = _session.Connection.CreateCommand();
|
||||
command.CommandText = "SELECT count(*) FROM TEST_User WHERE Lastname = 'Foo'";
|
||||
Assert.That(command.ExecuteScalar(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Parts_Localization_ContentTranslations_SummaryAdmin
|
||||
-->
|
||||
<!-- edit shape just gets default placement -->
|
||||
<Place Parts_Localization_ContentTranslations_Edit="Content:before.1"/>
|
||||
<Place Parts_Localization_ContentTranslations_Edit="Content:0"/>
|
||||
<Match DisplayType="Detail">
|
||||
<Place Parts_Localization_ContentTranslations="Content:2"/>
|
||||
</Match>
|
||||
|
||||
@@ -298,7 +298,6 @@
|
||||
<Content Include="Shapes\Views\HeadPreload.cshtml" />
|
||||
<Content Include="Shapes\Views\Message.cshtml" />
|
||||
<Content Include="Shapes\Views\NotFound.cshtml" />
|
||||
<Content Include="Shapes\Views\UI\Switchable.cshtml" />
|
||||
<Content Include="Web.config" />
|
||||
<Content Include="XmlRpc\Module.txt" />
|
||||
<Content Include="Settings\Views\EditorTemplates\Parts\Settings.SiteSettingsPart.cshtml" />
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Orchard.UI.Resources;
|
||||
|
||||
namespace Orchard.Core.Shapes {
|
||||
@@ -11,6 +7,11 @@ namespace Orchard.Core.Shapes {
|
||||
manifest.DefineScript("ShapesBase").SetUrl("base.js").SetDependencies("jQuery");
|
||||
manifest.DefineStyle("Shapes").SetUrl("site.css"); // todo: missing
|
||||
manifest.DefineStyle("ShapesSpecial").SetUrl("special.css");
|
||||
|
||||
manifest.DefineScript("Switchable").SetUrl("jquery.switchable.js")
|
||||
.SetDependencies("jQuery")
|
||||
.SetDependencies("ShapesBase");
|
||||
manifest.DefineStyle("Switchable").SetUrl("jquery.switchable.css");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
@{
|
||||
Style.Require("Switchable");
|
||||
Script.Require("Switchable");
|
||||
}
|
||||
@string.Format("{0} switchable", Model)
|
||||
@@ -3,10 +3,13 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Media.Models;
|
||||
using Orchard.Media.Services;
|
||||
using Orchard.Media.ViewModels;
|
||||
using Orchard.Settings;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
@@ -153,6 +156,15 @@ namespace Orchard.Media.Controllers {
|
||||
if (!ModelState.IsValid)
|
||||
return View(viewModel);
|
||||
|
||||
// first validate them all
|
||||
foreach (string fileName in Request.Files) {
|
||||
HttpPostedFileBase file = Request.Files[fileName];
|
||||
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);
|
||||
@@ -195,10 +207,11 @@ namespace Orchard.Media.Controllers {
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult EditMedia(string name, string caption, DateTime lastUpdated, long size, string folderName, string mediaPath) {
|
||||
public ActionResult EditMedia(string name, DateTime lastUpdated, long size, string folderName, string mediaPath) {
|
||||
var model = new MediaItemEditViewModel();
|
||||
model.Name = name;
|
||||
model.Caption = caption ?? String.Empty;
|
||||
// todo: reimplement
|
||||
//model.Caption = caption ?? String.Empty;
|
||||
model.LastUpdated = lastUpdated;
|
||||
model.Size = size;
|
||||
model.FolderName = folderName;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Data;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Media.Models;
|
||||
|
||||
namespace Orchard.Media.Handlers {
|
||||
[UsedImplicitly]
|
||||
public class MediaSettingsPartHandler : ContentHandler {
|
||||
public MediaSettingsPartHandler(IRepository<MediaSettingsPartRecord> repository) {
|
||||
Filters.Add(new ActivatingFilter<MediaSettingsPart>("Site"));
|
||||
Filters.Add(StorageFilter.For(repository));
|
||||
Filters.Add(new TemplateFilterForRecord<MediaSettingsPartRecord>("MediaSettings", "Parts/Media.MediaSettings"));
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Orchard.Web/Modules/Orchard.Media/Migrations.cs
Normal file
16
src/Orchard.Web/Modules/Orchard.Media/Migrations.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Orchard.Data.Migration;
|
||||
using Orchard.Media.Models;
|
||||
|
||||
namespace Orchard.Media {
|
||||
public class MediaDataMigration : DataMigrationImpl {
|
||||
public int Create() {
|
||||
SchemaBuilder.CreateTable("MediaSettingsPartRecord",
|
||||
table => table
|
||||
.ContentPartRecord()
|
||||
.Column<string>("UploadAllowedFileTypeWhitelist", c => c.WithDefault(MediaSettingsPartRecord.DefaultWhitelist).WithLength(255))
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Orchard.ContentManagement;
|
||||
using System;
|
||||
|
||||
namespace Orchard.Media.Models {
|
||||
public class MediaSettingsPart : ContentPart<MediaSettingsPartRecord> {
|
||||
public string UploadAllowedFileTypeWhitelist {
|
||||
get { return Record.UploadAllowedFileTypeWhitelist; }
|
||||
set { Record.UploadAllowedFileTypeWhitelist = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Net.Mail;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Orchard.Media.Models {
|
||||
public class MediaSettingsPartRecord : ContentPartRecord {
|
||||
internal const string DefaultWhitelist = "jpg jpeg gif png txt doc docx xls xlsx pdf ppt pptx pps ppsx odt ods odp";
|
||||
private string _whitelist = DefaultWhitelist;
|
||||
|
||||
public virtual string UploadAllowedFileTypeWhitelist {
|
||||
get { return _whitelist; }
|
||||
set { _whitelist = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,10 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Handlers\MediaSettingsPartHandler.cs" />
|
||||
<Compile Include="Migrations.cs" />
|
||||
<Compile Include="Models\MediaSettingsPart.cs" />
|
||||
<Compile Include="Models\MediaSettingsPartRecord.cs" />
|
||||
<Compile Include="ResourceManifest.cs" />
|
||||
<Compile Include="Helpers\MediaHelpers.cs" />
|
||||
<Compile Include="Permissions.cs" />
|
||||
@@ -114,6 +118,7 @@
|
||||
<Content Include="Views\Admin\Index.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\EditorTemplates\Parts\Media.MediaSettings.cshtml" />
|
||||
<Content Include="Content\Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
|
||||
@@ -13,5 +13,6 @@ namespace Orchard.Media.Services {
|
||||
void DeleteFile(string name, string folderName);
|
||||
void RenameFile(string name, string newName, string folderName);
|
||||
string UploadMediaFile(string folderName, HttpPostedFileBase postedFile);
|
||||
bool FileAllowed(HttpPostedFileBase postedFile);
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,12 @@ using System.Text;
|
||||
using System.Web;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.FileSystems.Media;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Media.Models;
|
||||
using Orchard.Security;
|
||||
using Orchard.Settings;
|
||||
|
||||
namespace Orchard.Media.Services {
|
||||
[UsedImplicitly]
|
||||
@@ -21,6 +24,9 @@ namespace Orchard.Media.Services {
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; }
|
||||
protected virtual IUser CurrentUser { get; [UsedImplicitly] private set; }
|
||||
|
||||
|
||||
public string GetPublicUrl(string path) {
|
||||
return _storageProvider.GetPublicUrl(path);
|
||||
@@ -82,18 +88,18 @@ namespace Orchard.Media.Services {
|
||||
}
|
||||
|
||||
public void RenameFile(string name, string newName, string folderName) {
|
||||
_storageProvider.RenameFile(folderName + "\\" + name, folderName + "\\" + newName);
|
||||
if (FileAllowed(newName, false)) {
|
||||
_storageProvider.RenameFile(folderName + "\\" + name, folderName + "\\" + newName);
|
||||
}
|
||||
}
|
||||
|
||||
public string UploadMediaFile(string folderName, HttpPostedFileBase postedFile) {
|
||||
|
||||
if (postedFile.FileName.EndsWith(".zip")) {
|
||||
UnzipMediaFileArchive(folderName, postedFile);
|
||||
// Don't save the zip file.
|
||||
return _storageProvider.GetPublicUrl(folderName);
|
||||
}
|
||||
|
||||
if (postedFile.ContentLength > 0) {
|
||||
if (FileAllowed(postedFile) && postedFile.ContentLength > 0) {
|
||||
var filePath = Path.Combine(folderName, Path.GetFileName(postedFile.FileName));
|
||||
var inputStream = postedFile.InputStream;
|
||||
|
||||
@@ -104,6 +110,41 @@ namespace Orchard.Media.Services {
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool FileAllowed(string name, bool allowZip) {
|
||||
if (string.IsNullOrWhiteSpace(name)) {
|
||||
return false;
|
||||
}
|
||||
var mediaSettings = CurrentSite.As<MediaSettingsPart>();
|
||||
var allowedExtensions = mediaSettings.UploadAllowedFileTypeWhitelist.ToLowerInvariant().Split(' ');
|
||||
var ext = (Path.GetExtension(name) ?? "").TrimStart('.').ToLowerInvariant();
|
||||
if (string.IsNullOrWhiteSpace(ext)) {
|
||||
return false;
|
||||
}
|
||||
// whitelist does not apply to the superuser
|
||||
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
|
||||
if (Array.IndexOf(allowedExtensions, ext) == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// blacklist always applies
|
||||
if (string.Equals(name.Trim(), "web.config", StringComparison.OrdinalIgnoreCase)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool FileAllowed(HttpPostedFileBase postedFile) {
|
||||
if (postedFile == null) {
|
||||
return false;
|
||||
}
|
||||
return FileAllowed(postedFile.FileName, true);
|
||||
}
|
||||
|
||||
private void SaveStream(string filePath, Stream inputStream) {
|
||||
var file = _storageProvider.CreateFile(filePath);
|
||||
var outputStream = file.OpenWrite();
|
||||
@@ -139,12 +180,17 @@ namespace Orchard.Media.Services {
|
||||
var entryName = Path.Combine(targetFolder, entry.Name);
|
||||
var directoryName = Path.GetDirectoryName(entryName);
|
||||
|
||||
try { _storageProvider.CreateFolder(directoryName); }
|
||||
catch {
|
||||
// no handling needed - this is to force the folder to exist if it doesn't
|
||||
}
|
||||
// skip disallowed files
|
||||
if (FileAllowed(entry.Name, false)) {
|
||||
try {
|
||||
_storageProvider.CreateFolder(directoryName);
|
||||
}
|
||||
catch {
|
||||
// no handling needed - this is to force the folder to exist if it doesn't
|
||||
}
|
||||
|
||||
SaveStream(entryName, fileInflater);
|
||||
SaveStream(entryName, fileInflater);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Orchard.Media.ViewModels {
|
||||
using Orchard.Media.Models;
|
||||
|
||||
namespace Orchard.Media.ViewModels {
|
||||
public class MediaItemAddViewModel {
|
||||
public string FolderName { get; set; }
|
||||
public string MediaPath { get; set; }
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
@Html.ValidationSummary()
|
||||
<div class="primary">
|
||||
<div>
|
||||
<img src="@Model.PublicUrl" class="previewImage" alt="@Model.Caption" />
|
||||
<img src="@Model.PublicUrl" class="previewImage"/>
|
||||
</div>
|
||||
<fieldset>
|
||||
@* todo: make these real (including markup) *@
|
||||
@@ -32,7 +32,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<label for="embedPath">@T("Embed:")</label>
|
||||
<input id="embedPath" class="textMedium" name="embedPath" type="text" readonly="readonly" value="<img src="@Href("~/Media/" + Model.RelativePath + "/" + Model.Name)" @* width="500" height="375" *@ alt="@Model.Caption" />" />
|
||||
<input id="embedPath" class="textMedium" name="embedPath" type="text" readonly="readonly" value="<img src="@Model.PublicUrl" @* width="500" height="375" *@ />" />
|
||||
<span class="hint">@T("Copy this html to add this image to your site.")</span>
|
||||
</div>
|
||||
|
||||
@@ -42,9 +42,6 @@
|
||||
<input id="NewName" class="textMedium" name="NewName" type="text" value="@Model.Name"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Caption">@T("Caption")</label>
|
||||
<input id="Caption" class="textMedium" name="Caption" type="text" value="@Model.Caption"/>
|
||||
<span class="hint">@T("This will be used for the image alt tag.")</span>
|
||||
<input type="hidden" id="LastUpdated" name="LastUpdated" value="@Model.LastUpdated"/>
|
||||
<input type="hidden" id="Size" name="Size" value="@Model.Size"/>
|
||||
<input type="hidden" id="FolderName" name="FolderName" value="@Model.FolderName"/>
|
||||
@@ -58,7 +55,7 @@
|
||||
@*
|
||||
<div class="secondary" style="border:1px solid #ff0000;">
|
||||
<h2>@T("Preview")</h2>
|
||||
<div><img src="@Href("~/Media/" + Html.Encode(Model.RelativePath + "/" + Model.Name))" class="previewImage" alt="@Model.Caption" /></div>
|
||||
<div><img src="@Href("~/Media/" + Html.Encode(Model.RelativePath + "/" + Model.Name))" class="previewImage" /></div>
|
||||
<ul>
|
||||
@// todo: make these real (including markup)
|
||||
<li><label>@T("Dimensions: <span>500 x 375 pixels</span>")</label></li>
|
||||
@@ -66,7 +63,7 @@
|
||||
<li><label>@T("Added on: <span>{0} by Orchard User</span>", Model.LastUpdated)</label></li>
|
||||
<li>
|
||||
<label for="embedPath">@T("Embed:")</label>
|
||||
<input id="embedPath" class="text" name="embedPath" type="text" readonly="readonly" value="@T("<img src=\"{0}\" width=\"{1}\" height=\"{2}\" alt=\"{3}\" />", ResolveUrl("~/Media/" + Model.RelativePath + "/" + Model.Name), 500, 375, Model.Caption)" />
|
||||
<input id="embedPath" class="text" name="embedPath" type="text" readonly="readonly" value="@T("<img src=\"{0}\" width=\"{1}\" height=\"{2}\" />", ResolveUrl("~/Media/" + Model.RelativePath + "/" + Model.Name), 500, 375)" />
|
||||
<span class="hint">@T("Copy this html to add this image to your site.")</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@model Orchard.Media.Models.MediaSettingsPartRecord
|
||||
|
||||
<fieldset>
|
||||
<legend>@T("Media Settings")</legend>
|
||||
<div>
|
||||
@Html.LabelFor(m => m.UploadAllowedFileTypeWhitelist, T("Upload allowed file types (list of extensions separated by spaces)"))
|
||||
@Html.TextBoxFor(m => m.UploadAllowedFileTypeWhitelist, new { @class = "textMedium" })
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -4,14 +4,15 @@
|
||||
@using Orchard.Modules.ViewModels;
|
||||
@using Orchard.Utility.Extensions;
|
||||
@using Orchard.Modules.Models;
|
||||
|
||||
@{
|
||||
Style.Require("ModulesAdmin");
|
||||
Style.Require("Switchable");
|
||||
Script.Require("Switchable");
|
||||
}
|
||||
|
||||
<h1>@Html.TitleForPage(T("Manage Features").ToString())</h1>
|
||||
@if (Model.Features.Count() > 0) {
|
||||
<ul class="features summary-view">@{
|
||||
<ul class="features summary-view switchable">@{
|
||||
var featureGroups = Model.Features.OrderBy(f => f.Descriptor.Category, new DoghouseComparer("Core")).GroupBy(f => f.Descriptor.Category);
|
||||
foreach (var featureGroup in featureGroups) {
|
||||
var categoryName = LocalizedString.TextOrDefault(featureGroup.First().Descriptor.Category, T("Uncategorized"));
|
||||
|
||||
@@ -6,9 +6,6 @@ namespace Orchard.Themes {
|
||||
public void BuildManifests(ResourceManifestBuilder builder) {
|
||||
var manifest = builder.Add();
|
||||
manifest.DefineStyle("ThemesAdmin").SetUrl("admin.css");
|
||||
// todo: used by core\shapes -- move it?
|
||||
manifest.DefineScript("Switchable").SetUrl("jquery.switchable.js").SetDependencies("jQuery");
|
||||
manifest.DefineStyle("Switchable").SetUrl("jquery.switchable.css");
|
||||
|
||||
// todo: include and define the min.js version too
|
||||
// todo: move EasySlider to common location, although it does not appear to be used anywhere right now
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Autofac.Features.OwnedInstances;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc.ModelBinders;
|
||||
using Orchard.Mvc.Routes;
|
||||
@@ -17,21 +14,18 @@ namespace Orchard.Environment {
|
||||
private readonly IRoutePublisher _routePublisher;
|
||||
private readonly IEnumerable<IModelBinderProvider> _modelBinderProviders;
|
||||
private readonly IModelBinderPublisher _modelBinderPublisher;
|
||||
private readonly ViewEngineCollection _viewEngines;
|
||||
|
||||
public DefaultOrchardShell(
|
||||
Func<Owned<IOrchardShellEvents>> eventsFactory,
|
||||
IEnumerable<IRouteProvider> routeProviders,
|
||||
IRoutePublisher routePublisher,
|
||||
IEnumerable<IModelBinderProvider> modelBinderProviders,
|
||||
IModelBinderPublisher modelBinderPublisher,
|
||||
ViewEngineCollection viewEngines) {
|
||||
IModelBinderPublisher modelBinderPublisher) {
|
||||
_eventsFactory = eventsFactory;
|
||||
_routeProviders = routeProviders;
|
||||
_routePublisher = routePublisher;
|
||||
_modelBinderProviders = modelBinderProviders;
|
||||
_modelBinderPublisher = modelBinderPublisher;
|
||||
_viewEngines = viewEngines;
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
@@ -42,8 +36,6 @@ namespace Orchard.Environment {
|
||||
_routePublisher.Publish(_routeProviders.SelectMany(provider => provider.GetRoutes()));
|
||||
_modelBinderPublisher.Publish(_modelBinderProviders.SelectMany(provider => provider.GetModelBinders()));
|
||||
|
||||
//AddOrchardLocationsFormats();
|
||||
|
||||
using (var events = _eventsFactory()) {
|
||||
events.Value.Activated();
|
||||
}
|
||||
@@ -54,62 +46,5 @@ namespace Orchard.Environment {
|
||||
events.Value.Terminating();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds view locations formats for non-themed views in custom orchard modules.
|
||||
/// </summary>
|
||||
private void AddOrchardLocationsFormats() {
|
||||
|
||||
IEnumerable<string> orchardMasterLocationFormats = new[] {
|
||||
"~/Modules/{2}/Views/{1}/{0}.master",
|
||||
"~/Modules/{2}/Views/Shared/{0}.master",
|
||||
"~/Themes/{2}/Views/{1}/{0}.master",
|
||||
"~/Themes/{2}/Views/Shared/{0}.master",
|
||||
"~/Core/{2}/Views/{1}/{0}.master",
|
||||
"~/Core/{2}/Views/Shared/{0}.master",
|
||||
"~/Areas/{2}/Views/{1}/{0}.master",
|
||||
"~/Areas/{2}/Views/Shared/{0}.master",
|
||||
};
|
||||
|
||||
IEnumerable<string> orchardLocationFormats = new[] {
|
||||
"~/Modules/{2}/Views/{1}/{0}.aspx",
|
||||
"~/Modules/{2}/Views/{1}/{0}.ascx",
|
||||
"~/Modules/{2}/Views/Shared/{0}.aspx",
|
||||
"~/Modules/{2}/Views/Shared/{0}.ascx",
|
||||
"~/Themes/{2}/Views/{1}/{0}.aspx",
|
||||
"~/Themes/{2}/Views/{1}/{0}.ascx",
|
||||
"~/Themes/{2}/Views/Shared/{0}.aspx",
|
||||
"~/Themes/{2}/Views/Shared/{0}.ascx",
|
||||
"~/Core/{2}/Views/{1}/{0}.aspx",
|
||||
"~/Core/{2}/Views/{1}/{0}.ascx",
|
||||
"~/Core/{2}/Views/Shared/{0}.aspx",
|
||||
"~/Core/{2}/Views/Shared/{0}.ascx",
|
||||
"~/Areas/{2}/Views/{1}/{0}.aspx",
|
||||
"~/Areas/{2}/Views/{1}/{0}.ascx",
|
||||
"~/Areas/{2}/Views/Shared/{0}.aspx",
|
||||
"~/Areas/{2}/Views/Shared/{0}.ascx",
|
||||
};
|
||||
|
||||
var viewEngine = _viewEngines.OfType<VirtualPathProviderViewEngine>().Single();
|
||||
viewEngine.AreaMasterLocationFormats = orchardMasterLocationFormats
|
||||
.Concat(viewEngine.AreaMasterLocationFormats)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
viewEngine.AreaViewLocationFormats = orchardLocationFormats
|
||||
.Concat(viewEngine.AreaViewLocationFormats)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
viewEngine.AreaPartialViewLocationFormats = orchardLocationFormats
|
||||
.Concat(viewEngine.AreaPartialViewLocationFormats)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static string ModelsLocationFormat(ExtensionDescriptor descriptor) {
|
||||
return Path.Combine(Path.Combine(descriptor.Location, descriptor.Name), "Views/Shared/{0}.ascx");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using Orchard.Services;
|
||||
@@ -36,7 +37,7 @@ namespace Orchard.Environment {
|
||||
}
|
||||
|
||||
public bool IsAssemblyLoaded(string name) {
|
||||
return AppDomain.CurrentDomain.GetAssemblies().Any(a => a.FullName.Contains(name));
|
||||
return AppDomain.CurrentDomain.GetAssemblies().Any(assembly => new AssemblyName(assembly.FullName).Name == name);
|
||||
}
|
||||
|
||||
public void RestartAppDomain() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#if !AZURE
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -45,7 +46,7 @@ namespace Orchard.FileSystems.Media {
|
||||
|
||||
public string GetPublicUrl(string path) {
|
||||
|
||||
return _publicPath + path.Replace(Path.DirectorySeparatorChar, '/');
|
||||
return Map(_publicPath + path.Replace(Path.DirectorySeparatorChar, '/'));
|
||||
}
|
||||
|
||||
public IStorageFile GetFile(string path) {
|
||||
@@ -248,4 +249,5 @@ namespace Orchard.FileSystems.Media {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2,21 +2,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Routing;
|
||||
using Autofac;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
|
||||
namespace Orchard.Mvc.Routes {
|
||||
public class RoutePublisher : IRoutePublisher {
|
||||
private readonly RouteCollection _routeCollection;
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly Func<RouteBase, ShellRoute> _shellRouteFactory;
|
||||
private readonly ILifetimeScope _shellLifetimeScope;
|
||||
private readonly IRunningShellTable _runningShellTable;
|
||||
|
||||
public RoutePublisher(
|
||||
RouteCollection routeCollection,
|
||||
ShellSettings shellSettings,
|
||||
Func<RouteBase, ShellRoute> shellRouteFactory) {
|
||||
ILifetimeScope shellLifetimeScope,
|
||||
IRunningShellTable runningShellTable) {
|
||||
_routeCollection = routeCollection;
|
||||
_shellSettings = shellSettings;
|
||||
_shellRouteFactory = shellRouteFactory;
|
||||
_shellLifetimeScope = shellLifetimeScope;
|
||||
_runningShellTable = runningShellTable;
|
||||
}
|
||||
|
||||
public void Publish(IEnumerable<RouteDescriptor> routes) {
|
||||
@@ -41,8 +46,8 @@ namespace Orchard.Mvc.Routes {
|
||||
|
||||
// new routes are added
|
||||
foreach (var routeDescriptor in routesArray) {
|
||||
//_routeCollection.Add(route.Name, _shellRouteFactory(_shellSettings.Name, route.Route));
|
||||
_routeCollection.Add(routeDescriptor.Name, _shellRouteFactory(routeDescriptor.Route));
|
||||
ShellRoute shellRoute = new ShellRoute(routeDescriptor.Route, _shellSettings, _shellLifetimeScope, _runningShellTable);
|
||||
_routeCollection.Add(routeDescriptor.Name, shellRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ using PackageIndexReferenceImplementation.Services;
|
||||
namespace PackageIndexReferenceImplementation.Controllers {
|
||||
[HandleError]
|
||||
public class FeedController : Controller {
|
||||
private const string VersionTag = "Version";
|
||||
private const string ExtensionsNamespace = "http://orchardproject.net";
|
||||
|
||||
private readonly FeedStorage _feedStorage;
|
||||
private readonly MediaStorage _mediaStorage;
|
||||
|
||||
@@ -104,7 +107,12 @@ namespace PackageIndexReferenceImplementation.Controllers {
|
||||
}
|
||||
|
||||
if ( !string.IsNullOrEmpty(packageProperties.Version) ) {
|
||||
item.ElementExtensions.Add("Version", "http://orchardproject.net", packageProperties.Version);
|
||||
var versionExtensions = item.ElementExtensions.Where(e => e.OuterName == VersionTag && e.OuterNamespace == ExtensionsNamespace);
|
||||
foreach(var versionExtension in versionExtensions) {
|
||||
item.ElementExtensions.Remove(versionExtension);
|
||||
}
|
||||
|
||||
item.ElementExtensions.Add(VersionTag, ExtensionsNamespace, packageProperties.Version);
|
||||
}
|
||||
|
||||
var mediaIdentifier = packageProperties.Identifier + "-" + packageProperties.Version + ".zip";
|
||||
|
||||
Reference in New Issue
Block a user