mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
@@ -77,7 +77,10 @@ namespace Orchard.Tests.Environment {
|
|||||||
return Enumerable.Empty<ExtensionEntry>();
|
return Enumerable.Empty<ExtensionEntry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShellTopology_Obsolete GetExtensionsTopology() {
|
public IEnumerable<Type> LoadFeature(string featureName) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Autofac;
|
using Autofac;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.Extensions;
|
using Orchard.Extensions;
|
||||||
|
using Orchard.Extensions.Loaders;
|
||||||
|
using Orchard.Tests.Extensions.ExtensionTypes;
|
||||||
using Yaml.Grammar;
|
using Yaml.Grammar;
|
||||||
|
|
||||||
namespace Orchard.Tests.Extensions {
|
namespace Orchard.Tests.Extensions {
|
||||||
@@ -48,6 +51,20 @@ namespace Orchard.Tests.Extensions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class StubLoaders : IExtensionLoader {
|
||||||
|
#region Implementation of IExtensionLoader
|
||||||
|
|
||||||
|
public int Order {
|
||||||
|
get { return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExtensionEntry Load(ExtensionDescriptor descriptor) {
|
||||||
|
return new ExtensionEntry { Descriptor = descriptor, ExportedTypes = new[] { typeof(Alpha), typeof(Beta), typeof(Phi) } };
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void AvailableExtensionsShouldFollowCatalogLocations() {
|
public void AvailableExtensionsShouldFollowCatalogLocations() {
|
||||||
@@ -190,5 +207,78 @@ features:
|
|||||||
Assert.That(!type.IsAbstract);
|
Assert.That(!type.IsAbstract);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ExtensionManagerShouldThrowIfFeatureDoesNotExist() {
|
||||||
|
Assert.Throws<ArgumentException>(() => _manager.LoadFeature("NoSuchFeature"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ExtensionManagerTestFeatureAttribute() {
|
||||||
|
var extensionManager = new Moq.Mock<IExtensionManager>();
|
||||||
|
extensionManager.Setup(x => x.ActiveExtensions()).Returns(new[] {
|
||||||
|
new ExtensionEntry {
|
||||||
|
Descriptor = new ExtensionDescriptor {
|
||||||
|
Name = "Module",
|
||||||
|
Features = new[] {
|
||||||
|
new FeatureDescriptor { Name = "Module", ExtensionName = "Module" },
|
||||||
|
new FeatureDescriptor { Name = "TestFeature", ExtensionName = "Module" }
|
||||||
|
}},
|
||||||
|
ExportedTypes = new[] { typeof(Alpha), typeof(Beta), typeof(Phi) }
|
||||||
|
}});
|
||||||
|
|
||||||
|
foreach (var type in extensionManager.Object.ActiveExtensions().SelectMany(x => x.ExportedTypes)) {
|
||||||
|
foreach (OrchardFeatureAttribute featureAttribute in type.GetCustomAttributes(typeof(OrchardFeatureAttribute), false)) {
|
||||||
|
Assert.That(featureAttribute.FeatureName, Is.EqualTo("TestFeature"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ExtensionManagerLoadFeatureReturnsTypesFromSpecificFeaturesWithFeatureAttribute() {
|
||||||
|
var extensionLoader = new StubLoaders();
|
||||||
|
var extensionFolder = new StubFolders();
|
||||||
|
|
||||||
|
extensionFolder.Manifests.Add("TestModule", @"
|
||||||
|
name: TestModule
|
||||||
|
version: 1.0.3
|
||||||
|
orchardversion: 1
|
||||||
|
features:
|
||||||
|
TestModule:
|
||||||
|
Description: My test module for Orchard.
|
||||||
|
TestFeature:
|
||||||
|
Description: Contains the Phi type.
|
||||||
|
");
|
||||||
|
|
||||||
|
ExtensionManager extensionManager = new ExtensionManager(new []{extensionFolder}, new [] {extensionLoader});
|
||||||
|
|
||||||
|
foreach (var type in extensionManager.LoadFeature("TestFeature")) {
|
||||||
|
Assert.That(type == typeof(Phi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ExtensionManagerLoadFeatureDoesNotReturnTypesFromNonMatchingFeatures() {
|
||||||
|
var extensionLoader = new StubLoaders();
|
||||||
|
var extensionFolder = new StubFolders();
|
||||||
|
|
||||||
|
extensionFolder.Manifests.Add("TestModule", @"
|
||||||
|
name: TestModule
|
||||||
|
version: 1.0.3
|
||||||
|
orchardversion: 1
|
||||||
|
features:
|
||||||
|
TestModule:
|
||||||
|
Description: My test module for Orchard.
|
||||||
|
TestFeature:
|
||||||
|
Description: Contains the Phi type.
|
||||||
|
");
|
||||||
|
|
||||||
|
ExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader });
|
||||||
|
|
||||||
|
foreach (var type in extensionManager.LoadFeature("TestModule")) {
|
||||||
|
Assert.That(type != typeof(Phi));
|
||||||
|
Assert.That((type == typeof(Alpha) || (type == typeof(Beta))));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/Orchard.Tests/Extensions/ExtensionTypes/StubTypes.cs
Normal file
13
src/Orchard.Tests/Extensions/ExtensionTypes/StubTypes.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Orchard.Extensions;
|
||||||
|
|
||||||
|
namespace Orchard.Tests.Extensions.ExtensionTypes {
|
||||||
|
public class Alpha {
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Beta {
|
||||||
|
}
|
||||||
|
|
||||||
|
[OrchardFeature("TestFeature")]
|
||||||
|
public class Phi {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,7 +54,10 @@ namespace Orchard.Tests.Mvc.Routes {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShellTopology_Obsolete GetExtensionsTopology() {
|
public IEnumerable<Type> LoadFeature(string featureName) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,7 @@
|
|||||||
<Compile Include="EventsTests.cs" />
|
<Compile Include="EventsTests.cs" />
|
||||||
<Compile Include="Extensions\ExtensionFoldersTests.cs" />
|
<Compile Include="Extensions\ExtensionFoldersTests.cs" />
|
||||||
<Compile Include="Extensions\ExtensionManagerTests.cs" />
|
<Compile Include="Extensions\ExtensionManagerTests.cs" />
|
||||||
|
<Compile Include="Extensions\ExtensionTypes\StubTypes.cs" />
|
||||||
<Compile Include="Localization\NullLocalizerTests.cs" />
|
<Compile Include="Localization\NullLocalizerTests.cs" />
|
||||||
<Compile Include="Logging\LoggingModuleTests.cs" />
|
<Compile Include="Logging\LoggingModuleTests.cs" />
|
||||||
<Compile Include="Mvc\ModelBinders\KeyedListModelBinderTests.cs" />
|
<Compile Include="Mvc\ModelBinders\KeyedListModelBinderTests.cs" />
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ namespace Orchard.Extensions {
|
|||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method does not load extension types, simply parses extension manifests from
|
||||||
|
// the filesystem.
|
||||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||||
var availableExtensions = new List<ExtensionDescriptor>();
|
var availableExtensions = new List<ExtensionDescriptor>();
|
||||||
foreach (var folder in _folders) {
|
foreach (var folder in _folders) {
|
||||||
@@ -44,6 +45,14 @@ namespace Orchard.Extensions {
|
|||||||
return availableExtensions;
|
return availableExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method loads types from extensions into the ExtensionEntry array.
|
||||||
|
public IEnumerable<ExtensionEntry> ActiveExtensions() {
|
||||||
|
if (_activeExtensions == null) {
|
||||||
|
_activeExtensions = BuildActiveExtensions().ToList();
|
||||||
|
}
|
||||||
|
return _activeExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
private static ExtensionDescriptor GetDescriptorForExtension(string name, IExtensionFolders folder) {
|
private static ExtensionDescriptor GetDescriptorForExtension(string name, IExtensionFolders folder) {
|
||||||
string extensionType = folder is ThemeFolders ? "Theme" : "Module";
|
string extensionType = folder is ThemeFolders ? "Theme" : "Module";
|
||||||
var parseResult = folder.ParseManifest(name);
|
var parseResult = folder.ParseManifest(name);
|
||||||
@@ -94,17 +103,50 @@ namespace Orchard.Extensions {
|
|||||||
return featureDescriptors;
|
return featureDescriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ExtensionEntry> ActiveExtensions() {
|
public ShellTopology GetExtensionsTopology() {
|
||||||
if (_activeExtensions == null) {
|
|
||||||
_activeExtensions = BuildActiveExtensions().ToList();
|
|
||||||
}
|
|
||||||
return _activeExtensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShellTopology_Obsolete GetExtensionsTopology() {
|
|
||||||
var types = ActiveExtensions().SelectMany(x => x.ExportedTypes);
|
var types = ActiveExtensions().SelectMany(x => x.ExportedTypes);
|
||||||
types = types.Concat(typeof(IOrchardHost).Assembly.GetExportedTypes());
|
types = types.Concat(typeof(IOrchardHost).Assembly.GetExportedTypes());
|
||||||
return new ShellTopology_Obsolete { Types = types.Where(t => t.IsClass && !t.IsAbstract) };
|
return new ShellTopology { Types = types.Where(t => t.IsClass && !t.IsAbstract) };
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Type> LoadFeature(string featureName) {
|
||||||
|
string extensionName = GetExtensionForFeature(featureName);
|
||||||
|
if (extensionName == null) throw new ArgumentException(T("Feature ") + featureName + T(" was not found in any of the installed extensions"));
|
||||||
|
var extension = ActiveExtensions().Where(x => x.Descriptor.Name == extensionName).FirstOrDefault();
|
||||||
|
if (extension == null) throw new InvalidOperationException(T("Extension ") + extensionName + T(" is not active"));
|
||||||
|
|
||||||
|
var extensionTypes = extension.ExportedTypes.Where(t => t.IsClass && !t.IsAbstract);
|
||||||
|
var featureTypes = new List<Type>();
|
||||||
|
|
||||||
|
foreach (var type in extensionTypes) {
|
||||||
|
string sourceFeature = GetSourceFeatureNameForType(type, extensionName);
|
||||||
|
if (String.Equals(sourceFeature, featureName, StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
featureTypes.Add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return featureTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetSourceFeatureNameForType(Type type, string extensionName) {
|
||||||
|
foreach (OrchardFeatureAttribute featureAttribute in type.GetCustomAttributes(typeof(OrchardFeatureAttribute), false)) {
|
||||||
|
return featureAttribute.FeatureName;
|
||||||
|
}
|
||||||
|
return extensionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetExtensionForFeature(string featureName) {
|
||||||
|
foreach (var extensionDescriptor in AvailableExtensions()) {
|
||||||
|
if (String.Equals(extensionDescriptor.Name, featureName, StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
return extensionDescriptor.Name;
|
||||||
|
}
|
||||||
|
foreach (var feature in extensionDescriptor.Features) {
|
||||||
|
if (String.Equals(feature.Name, featureName, StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
return extensionDescriptor.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle) {
|
public void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle) {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
|
||||||
namespace Orchard.Extensions {
|
namespace Orchard.Extensions {
|
||||||
public interface IExtensionManager {
|
public interface IExtensionManager {
|
||||||
IEnumerable<ExtensionDescriptor> AvailableExtensions();
|
IEnumerable<ExtensionDescriptor> AvailableExtensions();
|
||||||
IEnumerable<ExtensionEntry> ActiveExtensions();
|
IEnumerable<ExtensionEntry> ActiveExtensions();
|
||||||
ShellTopology_Obsolete GetExtensionsTopology();
|
IEnumerable<Type> LoadFeature(string featureName);
|
||||||
void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle);
|
void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle);
|
||||||
void UninstallExtension(string extensionType, string extensionName);
|
void UninstallExtension(string extensionType, string extensionName);
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/Orchard/Extensions/OrchardFeatureAttribute.cs
Normal file
12
src/Orchard/Extensions/OrchardFeatureAttribute.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Orchard.Extensions {
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class OrchardFeatureAttribute : Attribute {
|
||||||
|
public OrchardFeatureAttribute(string text) {
|
||||||
|
FeatureName = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FeatureName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -181,6 +181,7 @@
|
|||||||
<Compile Include="Extensions\ExtensionFolders.cs" />
|
<Compile Include="Extensions\ExtensionFolders.cs" />
|
||||||
<Compile Include="Extensions\FeatureDescriptor.cs" />
|
<Compile Include="Extensions\FeatureDescriptor.cs" />
|
||||||
<Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" />
|
<Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" />
|
||||||
|
<Compile Include="Extensions\OrchardFeatureAttribute.cs" />
|
||||||
<Compile Include="Extensions\Records\ExtensionRecord.cs" />
|
<Compile Include="Extensions\Records\ExtensionRecord.cs" />
|
||||||
<Compile Include="Extensions\ShellTopology.cs" />
|
<Compile Include="Extensions\ShellTopology.cs" />
|
||||||
<Compile Include="Mvc\AntiForgery\ValidateAntiForgeryTokenOrchardAttribute.cs" />
|
<Compile Include="Mvc\AntiForgery\ValidateAntiForgeryTokenOrchardAttribute.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user