--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-04-23 17:32:38 -07:00
19 changed files with 254 additions and 24 deletions

View File

@@ -53,5 +53,16 @@ namespace Orchard.Specs.Bindings {
});
}
[When(@"I cycle the app domain")]
public void WhenICycleTheAppDomain() {
var webApp = Binding<WebAppHosting>();
webApp.Host.Execute(() => {
Trace.WriteLine("This call to Host.Reinitialize should not be needed, eventually");
MvcApplication.Host.Reinitialize_Obsolete();
});
}
}
}

View File

@@ -119,6 +119,14 @@ namespace Orchard.Specs.Bindings {
}
[When(@"I go to ""(.*)"" on host (.*)")]
public void WhenIGoToPathOnHost(string urlPath, string host) {
Host.HostName = host;
_details = Host.SendRequest(urlPath);
_doc = new HtmlDocument();
_doc.Load(new StringReader(_details.ResponseText));
}
[When(@"I go to ""(.*)""")]
public void WhenIGoTo(string urlPath) {
_details = Host.SendRequest(urlPath);

View File

@@ -12,6 +12,7 @@ namespace Orchard.Specs.Hosting {
ResponseHeaders = new Dictionary<string, string>();
}
public string HostName { get; set; }
public string UrlPath { get; set; }
public string Page { get; set; }
public string Query { get; set; }

View File

@@ -16,6 +16,7 @@ namespace Orchard.Specs.Hosting {
var physicalPath = Bleroy.FluentPath.Path.Get(webHost.PhysicalDirectory);
var details = new RequestDetails {
HostName = webHost.HostName,
UrlPath = urlPath,
Page = physicalPath
.Combine(urlPath.TrimStart('/', '\\'))
@@ -89,6 +90,9 @@ namespace Orchard.Specs.Hosting {
if (_details.RequestHeaders.TryGetValue("Cookie", out value))
return value;
}
else if (index==HeaderHost) {
return _details.HostName;
}
return base.GetKnownRequestHeader(index);
}

View File

@@ -11,6 +11,7 @@ namespace Orchard.Specs.Hosting {
private Path _tempSite;
private Path _orchardWebPath;
public void Initialize(string templateName, string virtualDirectory) {
var baseDir = Path.Get(AppDomain.CurrentDomain.BaseDirectory);
@@ -29,6 +30,7 @@ namespace Orchard.Specs.Hosting {
.ShallowCopy("*.dll", _tempSite.Combine("bin"))
.ShallowCopy("*.pdb", _tempSite.Combine("bin"));
HostName = "localhost";
PhysicalDirectory = _tempSite;
VirtualDirectory = virtualDirectory;
@@ -44,6 +46,7 @@ namespace Orchard.Specs.Hosting {
sourceModule.Combine("Views").DeepCopy(targetModule.Combine("Views"));
}
public string HostName { get; set; }
public string PhysicalDirectory { get; private set; }
public string VirtualDirectory { get; private set; }

View File

@@ -41,3 +41,36 @@ Scenario: A new tenant is created with uninitialized state
And I am redirected
Then I should see "<td>Uninitialized</td>"
And the status should be 200 OK
Scenario: A new tenant goes to the setup screen
Given I have installed Orchard
And I have installed "Orchard.MultiTenancy"
When I go to "Admin/MultiTenancy/Add"
And I fill in
| name | value |
| Name | Scott |
| RequestUrlHost | scott.example.org |
And I hit "Save"
And I go to "/Setup" on host scott.example.org
Then I should see "Welcome to Orchard"
And I should see "Finish Setup"
And the status should be 200 OK
Scenario: A new tenant runs the setup
Given I have installed Orchard
And I have installed "Orchard.MultiTenancy"
When I go to "Admin/MultiTenancy/Add"
And I fill in
| name | value |
| Name | Scott |
| RequestUrlHost | scott.example.org |
And I hit "Save"
And I go to "/Setup" on host scott.example.org
And I fill in
| name | value |
| SiteName | Scott Site |
| AdminPassword | 6655321 |
And I hit "Finish Setup"
And I go to "/Default.aspx"
Then I should see "<h1>Scott Site</h1>"
And I should see "Welcome, <strong>admin</strong>!"

View File

@@ -2,7 +2,7 @@
// <auto-generated>
// This code was generated by SpecFlow (http://www.specflow.org/).
// SpecFlow Version:1.2.0.0
// Runtime Version:2.0.50727.3603
// Runtime Version:2.0.50727.4927
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -158,6 +158,98 @@ this.ScenarioSetup(scenarioInfo);
testRunner.Then("I should see \"<td>Uninitialized</td>\"");
#line 43
testRunner.And("the status should be 200 OK");
#line hidden
testRunner.CollectScenarioErrors();
}
[NUnit.Framework.TestAttribute()]
[NUnit.Framework.DescriptionAttribute("A new tenant goes to the setup screen")]
public virtual void ANewTenantGoesToTheSetupScreen()
{
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("A new tenant goes to the setup screen", ((string[])(null)));
#line 45
this.ScenarioSetup(scenarioInfo);
#line 46
testRunner.Given("I have installed Orchard");
#line 47
testRunner.And("I have installed \"Orchard.MultiTenancy\"");
#line 48
testRunner.When("I go to \"Admin/MultiTenancy/Add\"");
#line hidden
TechTalk.SpecFlow.Table table3 = new TechTalk.SpecFlow.Table(new string[] {
"name",
"value"});
table3.AddRow(new string[] {
"Name",
"Scott"});
table3.AddRow(new string[] {
"RequestUrlHost",
"scott.example.org"});
#line 49
testRunner.And("I fill in", ((string)(null)), table3);
#line 53
testRunner.And("I hit \"Save\"");
#line 54
testRunner.And("I go to \"/Setup\" on host scott.example.org");
#line 55
testRunner.Then("I should see \"Welcome to Orchard\"");
#line 56
testRunner.And("I should see \"Finish Setup\"");
#line 57
testRunner.And("the status should be 200 OK");
#line hidden
testRunner.CollectScenarioErrors();
}
[NUnit.Framework.TestAttribute()]
[NUnit.Framework.DescriptionAttribute("A new tenant runs the setup")]
public virtual void ANewTenantRunsTheSetup()
{
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("A new tenant runs the setup", ((string[])(null)));
#line 59
this.ScenarioSetup(scenarioInfo);
#line 60
testRunner.Given("I have installed Orchard");
#line 61
testRunner.And("I have installed \"Orchard.MultiTenancy\"");
#line 62
testRunner.When("I go to \"Admin/MultiTenancy/Add\"");
#line hidden
TechTalk.SpecFlow.Table table4 = new TechTalk.SpecFlow.Table(new string[] {
"name",
"value"});
table4.AddRow(new string[] {
"Name",
"Scott"});
table4.AddRow(new string[] {
"RequestUrlHost",
"scott.example.org"});
#line 63
testRunner.And("I fill in", ((string)(null)), table4);
#line 67
testRunner.And("I hit \"Save\"");
#line 68
testRunner.And("I go to \"/Setup\" on host scott.example.org");
#line hidden
TechTalk.SpecFlow.Table table5 = new TechTalk.SpecFlow.Table(new string[] {
"name",
"value"});
table5.AddRow(new string[] {
"SiteName",
"Scott Site"});
table5.AddRow(new string[] {
"AdminPassword",
"6655321"});
#line 69
testRunner.And("I fill in", ((string)(null)), table5);
#line 73
testRunner.And("I hit \"Finish Setup\"");
#line 74
testRunner.And("I go to \"/Default.aspx\"");
#line 75
testRunner.Then("I should see \"<h1>Scott Site</h1>\"");
#line 76
testRunner.And("I should see \"Welcome, <strong>admin</strong>!\"");
#line hidden
testRunner.CollectScenarioErrors();
}

View File

@@ -162,5 +162,51 @@ namespace Orchard.Tests.Environment {
Assert.That(table.Match(new StubHttpContext("~/bar/foo", "wiki.example.com")), Is.Null);
}
[Test]
public void HostNameMatchesRightmostIfRequestIsLonger() {
var table = (IRunningShellTable) new RunningShellTable();
var settings = new ShellSettings {Name = "Default"};
var settingsA = new ShellSettings {Name = "Alpha", RequestUrlHost = "example.com"};
table.Add(settings);
table.Add(settingsA);
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "www.example.com")), Is.SameAs(settingsA));
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "wiki.example.com")), Is.SameAs(settingsA));
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "example.com")), Is.SameAs(settingsA));
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "localhost")), Is.SameAs(settings));
}
[Test]
public void LongestMatchingHostHasPriority() {
var table = (IRunningShellTable) new RunningShellTable();
var settings = new ShellSettings {Name = "Default"};
var settingsA = new ShellSettings {Name = "Alpha", RequestUrlHost = "www.example.com"};
var settingsB = new ShellSettings {Name = "Beta", RequestUrlHost = "example.com"};
var settingsG = new ShellSettings {Name = "Gamma", RequestUrlHost = "wiki.example.com"};
table.Add(settings);
table.Add(settingsA);
table.Add(settingsB);
table.Add(settingsG);
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "www.example.com")), Is.SameAs(settingsA));
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "wiki.example.com")), Is.SameAs(settingsG));
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "username.example.com")), Is.SameAs(settingsB));
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "localhost")), Is.SameAs(settings));
}
[Test]
public void ShellNameUsedToDistinctThingsAsTheyAreAdded() {
var table = (IRunningShellTable)new RunningShellTable();
var settings = new ShellSettings { Name = "Default" };
var settingsA = new ShellSettings { Name = "Alpha", RequestUrlHost = "removed.example.com" };
var settingsB = new ShellSettings { Name = "Alpha", RequestUrlHost = "added.example.com" };
table.Add(settings);
table.Add(settingsA);
table.Add(settingsB);
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "removed.example.com")), Is.SameAs(settings));
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "added.example.com")), Is.SameAs(settingsB));
Assert.That(table.Match(new StubHttpContext("~/foo/bar", "localhost")), Is.SameAs(settings));
}
}
}

View File

@@ -75,7 +75,7 @@ namespace Orchard.Tests.Environment.ShellBuilders {
.Returns(_container.BeginLifetimeScope("shell"));
var factory = _container.Resolve<IShellContextFactory>();
var context = factory.CreateSetupContext();
var context = factory.CreateSetupContext(new ShellSettings { Name = "Default" });
Assert.That(context.Descriptor.EnabledFeatures, Has.Some.With.Property("Name").EqualTo("Orchard.Setup"));
}

View File

@@ -1,12 +1,15 @@
using System.Collections.Generic;
using Orchard.Environment;
using Orchard.Environment.Configuration;
namespace Orchard.MultiTenancy.Services {
public class TenantService : ITenantService {
private readonly IShellSettingsManager _shellSettingsManager;
private readonly IOrchardHost _orchardHost;
public TenantService(IShellSettingsManager shellSettingsManager) {
public TenantService(IShellSettingsManager shellSettingsManager, IOrchardHost orchardHost) {
_shellSettingsManager = shellSettingsManager;
_orchardHost = orchardHost;
}
#region Implementation of ITenantService
@@ -17,6 +20,10 @@ namespace Orchard.MultiTenancy.Services {
public void CreateTenant(ShellSettings settings) {
_shellSettingsManager.SaveSettings(settings);
// MultiTenancy: This will not be needed when host listens to event bus
_orchardHost.Reinitialize_Obsolete();
}
#endregion

View File

@@ -23,6 +23,7 @@ using Orchard.UI.Notify;
namespace Orchard.Setup.Controllers {
[ValidateInput(false)]
public class SetupController : Controller {
private readonly ShellSettings _shellSettings;
private readonly INotifier _notifier;
private readonly IOrchardHost _orchardHost;
private readonly IShellSettingsManager _shellSettingsManager;
@@ -31,12 +32,14 @@ namespace Orchard.Setup.Controllers {
private readonly IAppDataFolder _appDataFolder;
public SetupController(
ShellSettings shellSettings,
INotifier notifier,
IOrchardHost orchardHost,
IShellSettingsManager shellSettingsManager,
IShellContainerFactory shellContainerFactory,
ICompositionStrategy compositionStrategy,
IAppDataFolder appDataFolder) {
_shellSettings = shellSettings;
_notifier = notifier;
_orchardHost = orchardHost;
_shellSettingsManager = shellSettingsManager;
@@ -75,10 +78,10 @@ namespace Orchard.Setup.Controllers {
}
try {
var shellSettings = new ShellSettings {
Name = "Default",
var shellSettings = new ShellSettings(_shellSettings) {
DataProvider = model.DatabaseOptions ? "SQLite" : "SqlServer",
DataConnectionString = model.DatabaseConnectionString
DataConnectionString = model.DatabaseConnectionString,
DataTablePrefix = model.DatabaseTablePrefix,
};
// The vanilla Orchard distibution has the following modules enabled.
@@ -99,10 +102,10 @@ namespace Orchard.Setup.Controllers {
var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellToplogy);
using (var environment = new StandaloneEnvironment(bootstrapLifetimeScope)) {
environment.Resolve<ISessionFactoryHolder>().CreateDatabase();
environment.Resolve<IShellDescriptorManager>().UpdateShellDescriptor(
0,
shellDescriptor.EnabledFeatures,
0,
shellDescriptor.EnabledFeatures,
shellDescriptor.Parameters);
}
@@ -110,6 +113,9 @@ namespace Orchard.Setup.Controllers {
// creating a standalone environment.
// in theory this environment can be used to resolve any normal components by interface, and those
// components will exist entirely in isolation - no crossover between the safemode container currently in effect
// must mark state as Running - otherwise standalone enviro is created "for setup"
shellSettings.State = new TenantState("Running");
using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
try {
// create superuser
@@ -165,9 +171,9 @@ namespace Orchard.Setup.Controllers {
}
}
shellSettings.State = new TenantState("Running");
_shellSettingsManager.SaveSettings(shellSettings);
// MultiTenancy: This will not be needed when host listens to event bus
_orchardHost.Reinitialize_Obsolete();
// redirect to the welcome page.

View File

@@ -1,3 +1,4 @@
using System;
using System.ComponentModel.DataAnnotations;
using Orchard.Setup.Annotations;
using Orchard.Mvc.ViewModels;
@@ -17,5 +18,7 @@ namespace Orchard.Setup.ViewModels {
public bool DatabaseOptions { get; set; }
[SqlDatabaseConnectionString]
public string DatabaseConnectionString { get; set; }
public string DatabaseTablePrefix { get; set; }
}
}

View File

@@ -35,6 +35,10 @@ using (Html.BeginFormAntiForgeryPost()) { %>
<%=Html.EditorFor(svm => svm.DatabaseConnectionString)%>
<span class="hint"><%=_Encoded("Example:") %><br /><%=_Encoded("Data Source=sqlServerName;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password") %></span>
</span>
<span data-controllerid="sql">
<label for="DatabaseTablePrefix"><%=_Encoded("Database Table Prefix") %></label>
<%=Html.EditorFor(svm => svm.DatabaseTablePrefix)%>
</span>
</div>
</fieldset>
<fieldset>

View File

@@ -5,6 +5,20 @@
/// from the App_Data settings.txt files.
/// </summary>
public class ShellSettings {
public ShellSettings() {
State = new TenantState("Invalid");
}
public ShellSettings(ShellSettings settings) {
Name = settings.Name;
DataProvider = settings.DataProvider;
DataConnectionString = settings.DataConnectionString;
DataTablePrefix = settings.DataTablePrefix;
RequestUrlHost = settings.RequestUrlHost;
RequestUrlPrefix = settings.RequestUrlPrefix;
State = settings.State;
}
public string Name { get; set; }
public string DataProvider { get; set; }

View File

@@ -96,11 +96,16 @@ namespace Orchard.Environment {
}
ShellContext CreateSetupContext() {
Logger.Debug("Creating shell context for setup");
return _shellContextFactory.CreateSetupContext();
Logger.Debug("Creating shell context for root setup");
return _shellContextFactory.CreateSetupContext(new ShellSettings { Name = "Default" });
}
ShellContext CreateShellContext(ShellSettings settings) {
if (settings.State.CurrentState == TenantState.State.Uninitialized) {
Logger.Debug("Creating shell context for tenant {0} setup", settings.Name);
return _shellContextFactory.CreateSetupContext(settings);
}
Logger.Debug("Creating shell context for tenant {0}", settings.Name);
return _shellContextFactory.CreateShellContext(settings);
}

View File

@@ -8,7 +8,6 @@ using Orchard.Environment.Configuration;
namespace Orchard.Environment {
public interface IRunningShellTable {
void Add(ShellSettings settings);
IEnumerable<ShellSettings> List();
ShellSettings Match(HttpContextBase httpContext);
}
@@ -50,10 +49,6 @@ namespace Orchard.Environment {
}
}
public IEnumerable<ShellSettings> List() {
return _shells;
}
public ShellSettings Match(HttpContextBase httpContext) {
var host = httpContext.Request.ServerVariables.Get("HTTP_HOST") ?? "";

View File

@@ -20,7 +20,7 @@ namespace Orchard.Environment.ShellBuilders {
/// Builds a shell context for an uninitialized Orchard instance. Needed
/// to display setup user interface.
/// </summary>
ShellContext CreateSetupContext();
ShellContext CreateSetupContext(ShellSettings settings);
}
public class ShellContextFactory : IShellContextFactory {
@@ -87,11 +87,9 @@ namespace Orchard.Environment.ShellBuilders {
};
}
public ShellContext CreateSetupContext() {
public ShellContext CreateSetupContext(ShellSettings settings) {
Logger.Warning("No shell settings available. Creating shell context for setup");
var settings = new ShellSettings { Name = "Default" };
var descriptor = new ShellDescriptor {
SerialNumber = -1,
EnabledFeatures = new[] { new ShellFeature { Name = "Orchard.Setup" } },

View File

@@ -10,8 +10,9 @@ namespace Orchard.Mvc.ModelBinders {
}
public void Publish(IEnumerable<ModelBinderDescriptor> binders) {
// MultiTenancy: should hook default model binder instead and rely on shell-specific binders (instead adding to type dictionary)
foreach (var descriptor in binders) {
_binders.Add(descriptor.Type, descriptor.ModelBinder);
_binders[descriptor.Type] = descriptor.ModelBinder;
}
}
}

View File

@@ -8,8 +8,7 @@ namespace Orchard.Mvc.Routes {
public class DefaultRouteProvider : IRouteProvider {
public IEnumerable<RouteDescriptor> GetRoutes() {
return new[] {
new RouteDescriptor {
Name = "Default",
new RouteDescriptor {
Priority = -20,
Route = new Route(
"{controller}/{action}/{id}",