public string Setup(SetupContext context) { string executionId; // The vanilla Coevery distibution has the following features enabled. string[] hardcoded = { // Framework "Coevery.Framework", // Core "Settings", // Modules "Coevery.Recipes", "Coevery.Users" }; context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty<string>()).Distinct().ToList(); var shellSettings = new ShellSettings(_shellSettings); if (string.IsNullOrEmpty(shellSettings.DataProvider)) { shellSettings.DataProvider = context.DatabaseProvider; shellSettings.DataConnectionString = context.DatabaseConnectionString; shellSettings.DataTablePrefix = context.DatabaseTablePrefix; } #region Encryption Settings shellSettings.EncryptionAlgorithm = "AES"; // 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(); #endregion var shellDescriptor = new ShellDescriptor { Features = context.EnabledFeatures.Select(name => new ShellFeature { Name = name }) }; var shellBlueprint = _compositionStrategy.Compose(shellSettings, shellDescriptor); var f = shellBlueprint.Dependencies.Where(d => d.Type == typeof(RecipeManager)).ToList(); // initialize database explicitly, and store shell descriptor using (var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint)) { using (var environment = bootstrapLifetimeScope.CreateWorkContextScope()) { // check if the database is already created (in case an exception occured in the second phase) var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>()); try { var tablePrefix = String.IsNullOrEmpty(shellSettings.DataTablePrefix) ? "" : shellSettings.DataTablePrefix + "_"; schemaBuilder.ExecuteSql("SELECT * FROM " + tablePrefix + "ShellDescriptorRecord"); } catch { var reportsCoordinator = environment.Resolve<IReportsCoordinator>(); reportsCoordinator.Register("Data Migration", "Setup", "Coevery installation"); schemaBuilder.CreateTable("DataMigrationRecord", table => table .Column<int>("Id", column => column.PrimaryKey().Identity()) .Column<string>("DataMigrationClass") .Column<int>("Version")); var dataMigrationManager = environment.Resolve<IDataMigrationManager>(); dataMigrationManager.Update("Settings"); foreach (var feature in context.EnabledFeatures) { dataMigrationManager.Update(feature); } environment.Resolve<IShellDescriptorManager>().UpdateShellDescriptor( 0, shellDescriptor.Features, shellDescriptor.Parameters); } } } // in effect "pump messages" see PostMessage circa 1980 while ( _processingEngine.AreTasksPending() ) _processingEngine.ExecuteNextTask(); // 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 = TenantState.Running; using (var environment = _coeveryHost.CreateStandaloneEnvironment(shellSettings)) { try { executionId = CreateTenantData(context, environment); } catch { environment.Resolve<ITransactionManager>().Cancel(); throw; } } _shellSettingsManager.SaveSettings(shellSettings); return executionId; }
private string CreateTenantData(SetupContext context, IWorkContextScope environment) { // set site name and settings var siteService = environment.Resolve<ISiteService>(); var siteSettings = siteService.GetSiteSettings().As<SiteSettingsPart>(); siteSettings.SiteSalt = Guid.NewGuid().ToString("N"); siteSettings.SiteName = context.SiteName; siteSettings.SuperUser = context.AdminUsername; siteSettings.SiteCulture = "en-US"; // add default culture var cultureManager = environment.Resolve<ICultureManager>(); cultureManager.AddCulture("en-US"); var recipeManager = environment.Resolve<IRecipeManager>(); string executionId = recipeManager.Execute(Recipes().FirstOrDefault(r => r.Name.Equals(context.Recipe, StringComparison.OrdinalIgnoreCase))); return executionId; }
private string CreateTenantData(SetupContext context, IWorkContextScope environment) { // 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.SiteSalt = Guid.NewGuid().ToString("N"); siteSettings.SiteName = context.SiteName; siteSettings.SuperUser = context.AdminUsername; siteSettings.SiteCulture = "en-US"; // add default culture var cultureManager = environment.Resolve<ICultureManager>(); cultureManager.AddCulture("en-US"); //var recipeManager = environment.Resolve<IRecipeManager>(); //string executionId = recipeManager.Execute(Recipes().FirstOrDefault(r => r.Name.Equals(context.Recipe, StringComparison.OrdinalIgnoreCase))); // null check: temporary fix for running setup in command line if (HttpContext.Current != null) { authenticationService.SignIn(user, true); } return null; }
public void Setup() { IEnumerable<string> enabledFeatures = null; if (!string.IsNullOrEmpty(EnabledFeatures)) { enabledFeatures = EnabledFeatures .Split(',') .Select(s => s.Trim()) .Where(s => !string.IsNullOrEmpty(s)); } Recipe = String.IsNullOrEmpty(Recipe) ? "Default" : Recipe; var setupContext = new SetupContext { SiteName = SiteName, AdminUsername = AdminUsername, AdminPassword = AdminPassword, DatabaseProvider = DatabaseProvider, DatabaseConnectionString = DatabaseConnectionString, DatabaseTablePrefix = DatabaseTablePrefix, EnabledFeatures = enabledFeatures, Recipe = Recipe, }; _setupService.Setup(setupContext); Context.Output.WriteLine(T("Site \"{0}\" successfully setup to run data provider \"{1}\" (with table prefix \"{2}\") and configured by recipe \"{3}\"", setupContext.SiteName, setupContext.DatabaseProvider, setupContext.DatabaseTablePrefix, setupContext.Recipe)); }
public ActionResult IndexPOST(SetupViewModel model) { // sets the setup request timeout to 10 minutes to give enough time to execute custom recipes. HttpContext.Server.ScriptTimeout = 600; var recipes = OrderRecipes(_setupService.Recipes()); // if no builtin provider, a connection string is mandatory if (model.DatabaseProvider != SetupDatabaseType.Builtin && string.IsNullOrEmpty(model.DatabaseConnectionString)) ModelState.AddModelError("DatabaseConnectionString", T("A connection string is required").Text); if (!String.IsNullOrWhiteSpace(model.ConfirmPassword) && model.AdminPassword != model.ConfirmPassword ) { ModelState.AddModelError("ConfirmPassword", T("Password confirmation must match").Text); } if (model.DatabaseProvider != SetupDatabaseType.Builtin && !String.IsNullOrWhiteSpace(model.DatabaseTablePrefix)) { model.DatabaseTablePrefix = model.DatabaseTablePrefix.Trim(); if(!Char.IsLetter(model.DatabaseTablePrefix[0])) { ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must begin with a letter").Text); } if(model.DatabaseTablePrefix.Any(x => !Char.IsLetterOrDigit(x))) { ModelState.AddModelError("DatabaseTablePrefix", T("The table prefix must contain letters or digits").Text); } } if (!ModelState.IsValid) { model.DatabaseIsPreconfigured = !string.IsNullOrEmpty(_setupService.Prime().DataProvider); return IndexViewResult(model); } try { string providerName = null; switch (model.DatabaseProvider) { case SetupDatabaseType.Builtin: providerName = "SqlCe"; break; case SetupDatabaseType.SqlServer: providerName = "SqlServer"; break; case SetupDatabaseType.MySql: providerName = "MySql"; break; default: throw new ApplicationException("Unknown database type: " + model.DatabaseProvider); } var setupContext = new SetupContext { SiteName = model.SiteName, AdminUsername = model.AdminUsername, AdminPassword = model.AdminPassword, DatabaseProvider = providerName, DatabaseConnectionString = model.DatabaseConnectionString, DatabaseTablePrefix = model.DatabaseTablePrefix, EnabledFeatures = null // default list }; _setupService.Setup(setupContext); // First time installation if finally done. Tell the background views compilation // process to stop, so that it doesn't interfere with the user (asp.net compilation // uses a "single lock" mechanism for compiling views). _viewsBackgroundCompilation.Stop(); // redirect to the welcome page. return Redirect("~/" + _shellSettings.RequestUrlPrefix); } catch (Exception ex) { Logger.Error(ex, "Setup failed"); _notifier.Error(T("Setup failed: {0}", ex.Message)); model.DatabaseIsPreconfigured = !string.IsNullOrEmpty(_setupService.Prime().DataProvider); return IndexViewResult(model); } }
public string Setup(SetupContext context) { string executionId; // The vanilla Coevery distibution has the following features enabled. string[] hardcoded = { // Framework "Coevery.Framework", // Core "Settings", "Common", // Modules "Coevery.Users", "Coevery.Roles" }; context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty <string>()).Distinct().ToList(); var shellSettings = new ShellSettings(_shellSettings); if (string.IsNullOrEmpty(shellSettings.DataProvider)) { shellSettings.DataProvider = context.DatabaseProvider; shellSettings.DataConnectionString = context.DatabaseConnectionString; shellSettings.DataTablePrefix = context.DatabaseTablePrefix; } #region Encryption Settings shellSettings.EncryptionAlgorithm = "AES"; // 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(); #endregion var shellDescriptor = new ShellDescriptor { Features = context.EnabledFeatures.Select(name => new ShellFeature { Name = name }) }; var shellBlueprint = _compositionStrategy.Compose(shellSettings, shellDescriptor); // initialize database explicitly, and store shell descriptor using (var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint)) { using (var environment = bootstrapLifetimeScope.CreateWorkContextScope()) { // check if the database is already created (in case an exception occured in the second phase) var schemaBuilder = new SchemaBuilder(environment.Resolve <IDataMigrationInterpreter>()); try { var tablePrefix = String.IsNullOrEmpty(shellSettings.DataTablePrefix) ? "" : shellSettings.DataTablePrefix + "_"; schemaBuilder.ExecuteSql("SELECT * FROM " + tablePrefix + "ShellDescriptorRecord"); } catch { var reportsCoordinator = environment.Resolve <IReportsCoordinator>(); reportsCoordinator.Register("Data Migration", "Setup", "Coevery installation"); schemaBuilder.CreateTable("DataMigrationRecord", table => table .Column <int>("Id", column => column.PrimaryKey().Identity()) .Column <string>("DataMigrationClass") .Column <int>("Version")); var dataMigrationManager = environment.Resolve <IDataMigrationManager>(); dataMigrationManager.Update("Settings"); foreach (var feature in context.EnabledFeatures) { dataMigrationManager.Update(feature); } environment.Resolve <IShellDescriptorManager>().UpdateShellDescriptor( 0, shellDescriptor.Features, shellDescriptor.Parameters); } } } // in effect "pump messages" see PostMessage circa 1980 while (_processingEngine.AreTasksPending()) { _processingEngine.ExecuteNextTask(); } // 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 = TenantState.Running; using (var environment = _coeveryHost.CreateStandaloneEnvironment(shellSettings)) { try { executionId = CreateTenantData(context, environment); } catch { environment.Resolve <ITransactionManager>().Cancel(); throw; } } _shellSettingsManager.SaveSettings(shellSettings); return(executionId); }