2010-04-28 18:21:32 -07:00
|
|
|
|
using System;
|
2011-02-12 14:57:11 -08:00
|
|
|
|
using System.Collections.Generic;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
using System.Linq;
|
2010-12-03 16:14:17 -08:00
|
|
|
|
using System.Security.Cryptography;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
using System.Web;
|
|
|
|
|
using Orchard.ContentManagement;
|
2010-07-19 13:27:16 -07:00
|
|
|
|
using Orchard.Core.Settings.Descriptor.Records;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
using Orchard.Core.Settings.Models;
|
|
|
|
|
using Orchard.Data;
|
2011-06-09 15:36:03 -07:00
|
|
|
|
using Orchard.Data.Migration;
|
2010-06-29 16:17:08 -07:00
|
|
|
|
using Orchard.Data.Migration.Interpreters;
|
|
|
|
|
using Orchard.Data.Migration.Schema;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
using Orchard.Environment;
|
|
|
|
|
using Orchard.Environment.Configuration;
|
2010-06-11 17:28:46 -07:00
|
|
|
|
using Orchard.Environment.Descriptor;
|
|
|
|
|
using Orchard.Environment.Descriptor.Models;
|
2011-06-09 15:36:03 -07:00
|
|
|
|
using Orchard.Environment.ShellBuilders;
|
|
|
|
|
using Orchard.Environment.State;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
using Orchard.Localization;
|
2010-06-01 17:09:26 -07:00
|
|
|
|
using Orchard.Localization.Services;
|
2011-02-12 14:57:11 -08:00
|
|
|
|
using Orchard.Recipes.Models;
|
|
|
|
|
using Orchard.Recipes.Services;
|
2010-07-09 17:56:58 -07:00
|
|
|
|
using Orchard.Reports.Services;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
using Orchard.Security;
|
|
|
|
|
using Orchard.Settings;
|
2010-12-03 16:14:17 -08:00
|
|
|
|
using Orchard.Utility.Extensions;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
|
|
|
|
|
namespace Orchard.Setup.Services {
|
|
|
|
|
public class SetupService : ISetupService {
|
|
|
|
|
private readonly ShellSettings _shellSettings;
|
|
|
|
|
private readonly IOrchardHost _orchardHost;
|
|
|
|
|
private readonly IShellSettingsManager _shellSettingsManager;
|
|
|
|
|
private readonly IShellContainerFactory _shellContainerFactory;
|
|
|
|
|
private readonly ICompositionStrategy _compositionStrategy;
|
2010-06-25 17:06:02 -07:00
|
|
|
|
private readonly IProcessingEngine _processingEngine;
|
2011-02-12 14:57:11 -08:00
|
|
|
|
private readonly IRecipeHarvester _recipeHarvester;
|
|
|
|
|
private readonly IEnumerable<Recipe> _recipes;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
|
|
|
|
|
public SetupService(
|
|
|
|
|
ShellSettings shellSettings,
|
|
|
|
|
IOrchardHost orchardHost,
|
|
|
|
|
IShellSettingsManager shellSettingsManager,
|
|
|
|
|
IShellContainerFactory shellContainerFactory,
|
2010-06-25 17:06:02 -07:00
|
|
|
|
ICompositionStrategy compositionStrategy,
|
2011-02-12 14:57:11 -08:00
|
|
|
|
IProcessingEngine processingEngine,
|
|
|
|
|
IRecipeHarvester recipeHarvester) {
|
2010-04-28 18:21:32 -07:00
|
|
|
|
_shellSettings = shellSettings;
|
|
|
|
|
_orchardHost = orchardHost;
|
|
|
|
|
_shellSettingsManager = shellSettingsManager;
|
|
|
|
|
_shellContainerFactory = shellContainerFactory;
|
|
|
|
|
_compositionStrategy = compositionStrategy;
|
2010-06-25 17:06:02 -07:00
|
|
|
|
_processingEngine = processingEngine;
|
2011-02-12 14:57:11 -08:00
|
|
|
|
_recipeHarvester = recipeHarvester;
|
|
|
|
|
_recipes = _recipeHarvester.HarvestRecipes("Orchard.Setup");
|
2010-04-28 18:21:32 -07:00
|
|
|
|
T = NullLocalizer.Instance;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-02 13:54:50 -07:00
|
|
|
|
public Localizer T { get; set; }
|
2010-04-28 18:21:32 -07:00
|
|
|
|
|
2010-05-10 16:01:04 -07:00
|
|
|
|
public ShellSettings Prime() {
|
|
|
|
|
return _shellSettings;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-12 14:57:11 -08:00
|
|
|
|
public IEnumerable<Recipe> Recipes() {
|
|
|
|
|
return _recipes;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-17 16:47:36 -08:00
|
|
|
|
public string Setup(SetupContext context) {
|
2012-01-24 12:48:15 -08:00
|
|
|
|
string executionId;
|
2011-12-28 15:10:00 -08:00
|
|
|
|
|
2010-05-13 19:07:53 -07:00
|
|
|
|
// The vanilla Orchard distibution has the following features enabled.
|
2011-12-28 15:10:00 -08:00
|
|
|
|
string[] hardcoded = {
|
2010-11-18 16:01:09 -08:00
|
|
|
|
// Framework
|
2010-05-13 19:07:53 -07:00
|
|
|
|
"Orchard.Framework",
|
2010-11-18 16:01:09 -08:00
|
|
|
|
// Core
|
2011-12-29 15:43:13 +00:00
|
|
|
|
"Common", "Containers", "Contents", "Dashboard", "Feeds", "Navigation", "Reports", "Scheduling", "Settings", "Shapes", "Title",
|
2011-02-19 13:59:59 -08:00
|
|
|
|
// Modules
|
2013-03-13 12:08:00 -07:00
|
|
|
|
"Orchard.Pages", "Orchard.ContentPicker", "Orchard.Themes", "Orchard.Users", "Orchard.Roles", "Orchard.Modules",
|
2012-01-24 12:48:15 -08:00
|
|
|
|
"PackagingServices", "Orchard.Packaging", "Gallery", "Orchard.Recipes"
|
2010-08-31 11:50:07 -07:00
|
|
|
|
};
|
2010-05-13 19:07:53 -07:00
|
|
|
|
|
2012-01-24 12:48:15 -08:00
|
|
|
|
context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty<string>()).Distinct().ToList();
|
2010-05-13 19:07:53 -07:00
|
|
|
|
|
2010-05-10 16:01:04 -07:00
|
|
|
|
var shellSettings = new ShellSettings(_shellSettings);
|
2010-06-04 13:37:34 -07:00
|
|
|
|
|
2010-05-10 16:01:04 -07:00
|
|
|
|
if (string.IsNullOrEmpty(shellSettings.DataProvider)) {
|
|
|
|
|
shellSettings.DataProvider = context.DatabaseProvider;
|
|
|
|
|
shellSettings.DataConnectionString = context.DatabaseConnectionString;
|
|
|
|
|
shellSettings.DataTablePrefix = context.DatabaseTablePrefix;
|
2010-05-13 19:07:53 -07:00
|
|
|
|
}
|
2010-04-28 18:21:32 -07:00
|
|
|
|
|
2010-12-03 16:14:17 -08:00
|
|
|
|
#region Encryption Settings
|
|
|
|
|
|
|
|
|
|
shellSettings.EncryptionAlgorithm = "AES";
|
2011-01-12 18:58:02 -08:00
|
|
|
|
// randomly generated key
|
|
|
|
|
shellSettings.EncryptionKey = SymmetricAlgorithm.Create(shellSettings.EncryptionAlgorithm).Key.ToHexString();
|
|
|
|
|
|
|
|
|
|
shellSettings.HashAlgorithm = "HMACSHA256";
|
|
|
|
|
// randomly generated key
|
|
|
|
|
shellSettings.HashKey = HMAC.Create(shellSettings.HashAlgorithm).Key.ToHexString();
|
|
|
|
|
|
2010-12-03 16:14:17 -08:00
|
|
|
|
#endregion
|
|
|
|
|
|
2010-04-28 18:21:32 -07:00
|
|
|
|
var shellDescriptor = new ShellDescriptor {
|
2010-05-28 13:03:57 -07:00
|
|
|
|
Features = context.EnabledFeatures.Select(name => new ShellFeature { Name = name })
|
2010-04-28 18:21:32 -07:00
|
|
|
|
};
|
|
|
|
|
|
2010-07-19 17:46:35 -07:00
|
|
|
|
var shellBlueprint = _compositionStrategy.Compose(shellSettings, shellDescriptor);
|
2010-04-28 18:21:32 -07:00
|
|
|
|
|
|
|
|
|
// initialize database explicitly, and store shell descriptor
|
2012-06-25 14:42:15 -07:00
|
|
|
|
using (var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint)) {
|
2010-09-02 16:34:17 -07:00
|
|
|
|
|
2012-06-25 14:42:15 -07:00
|
|
|
|
using (var environment = bootstrapLifetimeScope.CreateWorkContextScope()) {
|
2010-07-19 13:27:16 -07:00
|
|
|
|
|
2011-09-08 14:57:08 -07:00
|
|
|
|
// check if the database is already created (in case an exception occured in the second phase)
|
2012-06-25 14:42:15 -07:00
|
|
|
|
var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>());
|
|
|
|
|
try {
|
2012-09-19 12:45:48 -07:00
|
|
|
|
var tablePrefix = String.IsNullOrEmpty(shellSettings.DataTablePrefix) ? "" : shellSettings.DataTablePrefix + "_";
|
2012-06-25 14:42:15 -07:00
|
|
|
|
schemaBuilder.ExecuteSql("SELECT * FROM " + tablePrefix + "Settings_ShellDescriptorRecord");
|
2011-09-08 14:57:08 -07:00
|
|
|
|
}
|
2012-06-25 14:42:15 -07:00
|
|
|
|
catch {
|
2011-09-08 14:57:08 -07:00
|
|
|
|
var reportsCoordinator = environment.Resolve<IReportsCoordinator>();
|
|
|
|
|
|
|
|
|
|
reportsCoordinator.Register("Data Migration", "Setup", "Orchard installation");
|
|
|
|
|
|
|
|
|
|
schemaBuilder.CreateTable("Orchard_Framework_DataMigrationRecord",
|
|
|
|
|
table => table
|
|
|
|
|
.Column<int>("Id", column => column.PrimaryKey().Identity())
|
|
|
|
|
.Column<string>("DataMigrationClass")
|
|
|
|
|
.Column<int>("Version"));
|
|
|
|
|
|
|
|
|
|
var dataMigrationManager = environment.Resolve<IDataMigrationManager>();
|
|
|
|
|
dataMigrationManager.Update("Settings");
|
|
|
|
|
|
2012-06-25 14:42:15 -07:00
|
|
|
|
foreach (var feature in context.EnabledFeatures) {
|
2011-09-08 14:57:08 -07:00
|
|
|
|
dataMigrationManager.Update(feature);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
environment.Resolve<IShellDescriptorManager>().UpdateShellDescriptor(
|
|
|
|
|
0,
|
|
|
|
|
shellDescriptor.Features,
|
|
|
|
|
shellDescriptor.Parameters);
|
2010-07-19 13:27:16 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-28 18:21:32 -07:00
|
|
|
|
}
|
|
|
|
|
|
2011-09-24 20:47:53 -07:00
|
|
|
|
|
|
|
|
|
|
2010-06-25 17:06:02 -07:00
|
|
|
|
// in effect "pump messages" see PostMessage circa 1980
|
|
|
|
|
while ( _processingEngine.AreTasksPending() )
|
|
|
|
|
_processingEngine.ExecuteNextTask();
|
|
|
|
|
|
2010-04-28 18:21:32 -07:00
|
|
|
|
// 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 {
|
2011-02-17 16:47:36 -08:00
|
|
|
|
executionId = CreateTenantData(context, environment);
|
2010-04-28 18:21:32 -07:00
|
|
|
|
}
|
|
|
|
|
catch {
|
|
|
|
|
environment.Resolve<ITransactionManager>().Cancel();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-30 14:18:04 -07:00
|
|
|
|
_shellSettingsManager.SaveSettings(shellSettings);
|
2011-09-24 20:47:53 -07:00
|
|
|
|
|
2011-02-17 16:47:36 -08:00
|
|
|
|
return executionId;
|
2010-04-28 18:21:32 -07:00
|
|
|
|
}
|
2010-10-15 15:18:53 -07:00
|
|
|
|
|
2011-02-17 16:47:36 -08:00
|
|
|
|
private string CreateTenantData(SetupContext context, IWorkContextScope environment) {
|
2010-10-15 15:18:53 -07:00
|
|
|
|
// create superuser
|
|
|
|
|
var membershipService = environment.Resolve<IMembershipService>();
|
|
|
|
|
var user =
|
|
|
|
|
membershipService.CreateUser(new CreateUserParams(context.AdminUsername, context.AdminPassword,
|
|
|
|
|
String.Empty, String.Empty, String.Empty,
|
|
|
|
|
true));
|
|
|
|
|
|
|
|
|
|
// set superuser as current user for request (it will be set as the owner of all content items)
|
|
|
|
|
var authenticationService = environment.Resolve<IAuthenticationService>();
|
|
|
|
|
authenticationService.SetAuthenticatedUserForRequest(user);
|
|
|
|
|
|
|
|
|
|
// set site name and settings
|
|
|
|
|
var siteService = environment.Resolve<ISiteService>();
|
|
|
|
|
var siteSettings = siteService.GetSiteSettings().As<SiteSettingsPart>();
|
|
|
|
|
siteSettings.Record.SiteSalt = Guid.NewGuid().ToString("N");
|
|
|
|
|
siteSettings.Record.SiteName = context.SiteName;
|
|
|
|
|
siteSettings.Record.SuperUser = context.AdminUsername;
|
|
|
|
|
siteSettings.Record.SiteCulture = "en-US";
|
|
|
|
|
|
|
|
|
|
// add default culture
|
|
|
|
|
var cultureManager = environment.Resolve<ICultureManager>();
|
|
|
|
|
cultureManager.AddCulture("en-US");
|
|
|
|
|
|
2011-02-17 11:21:46 -08:00
|
|
|
|
var recipeManager = environment.Resolve<IRecipeManager>();
|
2012-01-24 12:48:15 -08:00
|
|
|
|
string executionId = recipeManager.Execute(Recipes().FirstOrDefault(r => r.Name.Equals(context.Recipe, StringComparison.OrdinalIgnoreCase)));
|
2010-10-15 15:18:53 -07:00
|
|
|
|
|
2011-06-09 15:36:03 -07:00
|
|
|
|
// null check: temporary fix for running setup in command line
|
2010-10-15 15:18:53 -07:00
|
|
|
|
if (HttpContext.Current != null) {
|
|
|
|
|
authenticationService.SignIn(user, true);
|
|
|
|
|
}
|
2011-02-17 16:47:36 -08:00
|
|
|
|
|
|
|
|
|
return executionId;
|
2010-10-15 15:18:53 -07:00
|
|
|
|
}
|
2010-04-28 18:21:32 -07:00
|
|
|
|
}
|
|
|
|
|
}
|