예제 #1
0
        public void UpdateShellSettings(ShellSettings settings)
        {
            ShellContext context;

            _shellSettingsManager.SaveSettings(settings);
            _runningShellTable.Update(settings);
            _shellContexts.TryRemove(settings.Name, out context);
            context = CreateShellContext(settings);
            ActivateShell(context);
        }
예제 #2
0
        public void SingleSettingsFileShouldComeBackAsExpected()
        {
            ShellSettingsManager.SaveSettings(new ShellSettings {
                Name = "Default", DataProvider = "SQLCe", DataConnectionString = "something else"
            });

            var settings = ShellSettingsManager.LoadSettings().Single();

            Assert.That(settings, Is.Not.Null);
            Assert.That(settings.Name, Is.EqualTo("Default"));
            Assert.That(settings.DataProvider, Is.EqualTo("SQLCe"));
            Assert.That(settings.DataConnectionString, Is.EqualTo("something else"));
        }
예제 #3
0
        public void UpdateShellSettings(ShellSettings settings)
        {
            ShellContext context;

            _shellSettingsManager.SaveSettings(settings);
            _runningShellTable.Remove(settings);
            if (_shellContexts.TryRemove(settings.Name, out context))
            {
                context.Dispose();
            }
            GetOrCreateShellContext(settings);
        }
예제 #4
0
        public string Setup(SetupContext context)
        {
            string executionId = Guid.NewGuid().ToString();

            // The vanilla Orchard distibution has the following features enabled.
            string[] hardcoded =
            {
                // Framework
                "Orchard.Hosting",
                // Core
                "Settings",
                // Test Modules
                "Orchard.Demo", "Orchard.Test1"
            };

            context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty <string>()).Distinct().ToList();

            var shellSettings = new ShellSettings();

            shellSettings.Name = context.SiteName;

            //if (shellSettings.DataProviders.Any()) {
            //    DataProvider provider = new DataProvider();
            //shellSettings.DataProvider = context.DatabaseProvider;
            //shellSettings.DataConnectionString = context.DatabaseConnectionString;
            //shellSettings.DataTablePrefix = context.DatabaseTablePrefix;
            //}

            // TODO: Add Encryption Settings in

            var shellDescriptor = new ShellDescriptor {
                Features = context.EnabledFeatures.Select(name => new ShellFeature {
                    Name = name
                })
            };

            // 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;

            // TODO: Remove and mirror Orchard Setup
            shellSettings.RequestUrlHost   = _httpContextAccessor.HttpContext.Request.Host.Value;
            shellSettings.RequestUrlPrefix = string.Empty;
            //shellSettings.DataProvider = "InMemory";

            _shellSettingsManager.SaveSettings(shellSettings);

            return(executionId);
        }
예제 #5
0
        public async Task <IActionResult> Create(EditTenantViewModel model)
        {
            if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageTenants))
            {
                return(Unauthorized());
            }

            if (!IsDefaultShell())
            {
                return(Unauthorized());
            }

            if (ModelState.IsValid)
            {
                ValidateViewModel(model, true);
            }

            if (ModelState.IsValid)
            {
                // Creates a default shell settings based on the configuration.
                var shellSettings = _shellSettingsManager.CreateDefaultSettings();

                shellSettings.Name             = model.Name;
                shellSettings.RequestUrlHost   = model.RequestUrlHost;
                shellSettings.RequestUrlPrefix = model.RequestUrlPrefix;
                shellSettings.State            = TenantState.Uninitialized;

                shellSettings["ConnectionString"] = model.ConnectionString;
                shellSettings["TablePrefix"]      = model.TablePrefix;
                shellSettings["DatabaseProvider"] = model.DatabaseProvider;
                shellSettings["Secret"]           = Guid.NewGuid().ToString();
                shellSettings["RecipeName"]       = model.RecipeName;

                _shellSettingsManager.SaveSettings(shellSettings);
                var shellContext = await _shellHost.GetOrCreateShellContextAsync(shellSettings);

                return(RedirectToAction(nameof(Index)));
            }

            var recipeCollections = await Task.WhenAll(_recipeHarvesters.Select(x => x.HarvestRecipesAsync()));

            var recipes = recipeCollections.SelectMany(x => x).Where(x => x.IsSetupRecipe).ToArray();

            model.Recipes = recipes;

            // If we got this far, something failed, redisplay form
            return(View(model));
        }
        public async Task <IActionResult> Create(EditTenantViewModel model)
        {
            if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageTenants))
            {
                return(Unauthorized());
            }

            if (!IsDefaultShell())
            {
                return(Unauthorized());
            }

            if (ModelState.IsValid)
            {
                await ValidateViewModel(model, true);
            }

            if (ModelState.IsValid)
            {
                var shellSettings = new ShellSettings
                {
                    Name             = model.Name,
                    RequestUrlPrefix = model.RequestUrlPrefix?.Trim(),
                    RequestUrlHost   = model.RequestUrlHost,
                    ConnectionString = model.ConnectionString,
                    TablePrefix      = model.TablePrefix,
                    DatabaseProvider = model.DatabaseProvider,
                    State            = TenantState.Uninitialized,
                    Secret           = Guid.NewGuid().ToString(),
                    RecipeName       = model.RecipeName
                };

                _shellSettingsManager.SaveSettings(shellSettings);
                var shellContext = await _orchardHost.GetOrCreateShellContextAsync(shellSettings);

                return(RedirectToAction(nameof(Index)));
            }

            var recipeCollections = await Task.WhenAll(_recipeHarvesters.Select(x => x.HarvestRecipesAsync()));

            var recipes = recipeCollections.SelectMany(x => x).Where(x => x.IsSetupRecipe).ToArray();

            model.Recipes = recipes;

            // If we got this far, something failed, redisplay form
            return(View(model));
        }
예제 #7
0
        public async Task <IActionResult> Create(EditTenantViewModel model)
        {
            if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageTenants))
            {
                return(Unauthorized());
            }

            if (!IsDefaultShell())
            {
                return(Unauthorized());
            }

            if (ModelState.IsValid)
            {
                ValidateViewModel(model, true);
            }

            if (ModelState.IsValid)
            {
                var shellSettings = new ShellSettings
                {
                    Name             = model.Name,
                    RequestUrlPrefix = model.RequestUrlPrefix,
                    RequestUrlHost   = model.RequestUrlHost,
                    ConnectionString = model.ConnectionString,
                    TablePrefix      = model.TablePrefix,
                    DatabaseProvider = model.DatabaseProvider,
                    State            = TenantState.Uninitialized
                };

                _shellSettingsManager.SaveSettings(shellSettings);
                var shellContext = _orchardHost.GetOrCreateShellContext(shellSettings);

                return(RedirectToAction(nameof(Index)));
            }

            // If we got this far, something failed, redisplay form
            return(View(model));
        }
        public async Task <IActionResult> IndexPost(RegisterUserViewModel viewModel)
        {
            if (ModelState.IsValid)
            {
                var shellSettings = new ShellSettings
                {
                    Name             = viewModel.Handle,
                    RequestUrlPrefix = viewModel.Handle,
                    RequestUrlHost   = "",
                    // This should be a setting in the SaaS module.
                    ConnectionString = "",
                    TablePrefix      = "",
                    DatabaseProvider = "Sqlite",
                    State            = TenantState.Uninitialized,
                    Secret           = Guid.NewGuid().ToString(),
                    RecipeName       = "Blog"
                };

                _shellSettingsManager.SaveSettings(shellSettings);

                var confirmationLink = Url.Action(nameof(HomeController.Confirm), "Home", new { email = viewModel.Email, handle = viewModel.Handle, siteName = viewModel.SiteName }, Request.Scheme);

                var message = new MailMessage
                {
                    From       = new MailAddress("*****@*****.**", "Orchard SaaS"),
                    IsBodyHtml = true,
                    Body       = $"Click <a href=\"{HttpUtility.HtmlEncode(confirmationLink)}\">this link</a>"
                };

                message.To.Add(viewModel.Email);

                await _smtpService.SendAsync(message);

                return(RedirectToAction(nameof(Success)));
            }

            return(View(nameof(Index), viewModel));
        }
예제 #9
0
        public string Setup(SetupContext context)
        {
            string executionId;

            Logger.Information("Running setup for tenant '{0}'.", _shellSettings.Name);

            // The vanilla Orchard distibution has the following features enabled.
            string[] hardcoded =
            {
                // Framework
                "Orchard.Framework",
                // Core
                "Common",           "Containers",             "Contents",       "Dashboard",     "Feeds",         "Navigation",      "Scheduling", "Settings", "Shapes", "Title",
                // Modules
                "Orchard.Pages",    "Orchard.ContentPicker",  "Orchard.Themes", "Orchard.Users", "Orchard.Roles", "Orchard.Modules",
                "PackagingServices","Orchard.Packaging",      "Gallery",        "Orchard.Recipes"
            };

            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;
            }

            shellSettings.EncryptionAlgorithm = "AES";
            shellSettings.EncryptionKey       = SymmetricAlgorithm.Create(shellSettings.EncryptionAlgorithm).Key.ToHexString();
            shellSettings.HashAlgorithm       = "HMACSHA256";
            shellSettings.HashKey             = HMAC.Create(shellSettings.HashAlgorithm).Key.ToHexString();

            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()) {
                    // Workaround to avoid a Transaction issue with PostgreSQL.
                    environment.Resolve <ITransactionManager>().RequireNew();

                    var schemaBuilder = new SchemaBuilder(environment.Resolve <IDataMigrationInterpreter>());

                    schemaBuilder.CreateTable("Orchard_Framework_DataMigrationRecord", table => table
                                              .Column <int>("Id", column => column.PrimaryKey().Identity())
                                              .Column <string>("DataMigrationClass")
                                              .Column <int>("Version"));

                    schemaBuilder.AlterTable("Orchard_Framework_DataMigrationRecord",
                                             table => table.AddUniqueConstraint("UC_DMR_DataMigrationClass_Version", "DataMigrationClass", "Version"));

                    var dataMigrationManager = environment.Resolve <IDataMigrationManager>();
                    dataMigrationManager.Update("Settings");

                    foreach (var feature in context.EnabledFeatures)
                    {
                        dataMigrationManager.Update(feature);
                    }

                    var descriptorManager = environment.Resolve <IShellDescriptorManager>();
                    descriptorManager.UpdateShellDescriptor(0, shellDescriptor.Features, shellDescriptor.Parameters);
                }
            }

            // In effect "pump messages" see PostMessage circa 1980.
            while (_processingEngine.AreTasksPending())
            {
                _processingEngine.ExecuteNextTask();
            }

            // Create a standalone environment.
            // Must mark state as Running - otherwise standalone environment is created "for setup".
            shellSettings.State = TenantState.Running;
            using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
                try {
                    executionId = CreateTenantData(context, environment);
                }
                catch {
                    environment.Resolve <ITransactionManager>().Cancel();
                    throw;
                }
            }

            _shellSettingsManager.SaveSettings(shellSettings);

            return(executionId);
        }
예제 #10
0
        public async Task <IActionResult> IndexPost(RegisterUserViewModel model)
        {
            if (!model.AcceptTerms)
            {
                ModelState.AddModelError(nameof(RegisterUserViewModel.AcceptTerms), S["Please, accept the terms and conditions."]);
            }

            if (!string.IsNullOrEmpty(model.Handle) && !Regex.IsMatch(model.Handle, @"^\w+$"))
            {
                ModelState.AddModelError(nameof(RegisterUserViewModel.Handle), S["Invalid tenant name. Must contain characters only and no spaces."]);
            }

            if (ModelState.IsValid)
            {
                if (_shellHost.TryGetSettings(model.Handle, out var shellSettings))
                {
                    ModelState.AddModelError(nameof(RegisterUserViewModel.Handle), S["This site name already exists."]);
                }
                else
                {
                    shellSettings = new ShellSettings
                    {
                        Name             = model.Handle,
                        RequestUrlPrefix = model.Handle.ToLower(),
                        RequestUrlHost   = null,
                        State            = TenantState.Uninitialized
                    };
                    shellSettings["RecipeName"]       = model.RecipeName;
                    shellSettings["DatabaseProvider"] = "Sqlite";

                    _shellSettingsManager.SaveSettings(shellSettings);
                    var shellContext = await _shellHost.GetOrCreateShellContextAsync(shellSettings);

                    var recipes = await _setupService.GetSetupRecipesAsync();

                    var recipe = recipes.FirstOrDefault(x => x.Name == model.RecipeName);

                    if (recipe == null)
                    {
                        ModelState.AddModelError(nameof(RegisterUserViewModel.RecipeName), S["Invalid recipe name."]);
                    }

                    var adminName     = defaultAdminName;
                    var adminPassword = GenerateRandomPassword();
                    var siteName      = model.SiteName;
                    var siteUrl       = GetTenantUrl(shellSettings);

                    var dataProtector     = _dataProtectionProvider.CreateProtector(dataProtectionPurpose).ToTimeLimitedDataProtector();
                    var encryptedPassword = dataProtector.Protect(adminPassword, _clock.UtcNow.Add(new TimeSpan(24, 0, 0)));
                    var confirmationLink  = Url.Action(nameof(Confirm), "Home", new { email = model.Email, handle = model.Handle, siteName = model.SiteName, ep = encryptedPassword }, Request.Scheme);

                    var message = new MailMessage();
                    if (emailToBcc)
                    {
                        message.Bcc.Add(new MailAddress(_smtpSettingsOptions.Value.DefaultSender));
                    }
                    message.To.Add(model.Email);
                    message.IsBodyHtml = true;
                    message.Subject    = emailSubject;
                    message.Body       = S[$"Hello,<br><br>Your demo site '{siteName}' has been created.<br><br>1) Setup your site by opening <a href=\"{confirmationLink}\">this link</a>.<br><br>2) Log into the <a href=\"{siteUrl}/admin\">admin</a> with these credentials:<br>Username: {adminName}<br>Password: {adminPassword}"];

                    await _smtpService.SendAsync(message);

                    return(RedirectToAction(nameof(Success)));
                }
            }

            return(View(nameof(Index), model));
        }
예제 #11
0
 public void UpdateShellSettings(ShellSettings settings)
 {
     _shellSettingsManager.SaveSettings(settings);
     ReloadShellContext(settings);
 }
예제 #12
0
        public async Task <IActionResult> Create(CreateApiViewModel model)
        {
            if (!IsDefaultShell())
            {
                return(Unauthorized());
            }

            if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageTenants))
            {
                return(Unauthorized());
            }

            if (!string.IsNullOrEmpty(model.Name) && !Regex.IsMatch(model.Name, @"^\w+$"))
            {
                ModelState.AddModelError(nameof(CreateApiViewModel.Name), S["Invalid tenant name. Must contain characters only and no spaces."]);
            }

            // Creates a default shell settings based on the configuration.
            var shellSettings = _shellSettingsManager.CreateDefaultSettings();

            shellSettings.Name             = model.Name;
            shellSettings.RequestUrlHost   = model.RequestUrlHost;
            shellSettings.RequestUrlPrefix = model.RequestUrlPrefix;
            shellSettings.State            = TenantState.Uninitialized;

            shellSettings["ConnectionString"] = model.ConnectionString;
            shellSettings["TablePrefix"]      = model.TablePrefix;
            shellSettings["DatabaseProvider"] = model.DatabaseProvider;
            shellSettings["Secret"]           = Guid.NewGuid().ToString();
            shellSettings["RecipeName"]       = model.RecipeName;

            if (!IsDefaultShell() && string.IsNullOrWhiteSpace(shellSettings.RequestUrlHost) && string.IsNullOrWhiteSpace(shellSettings.RequestUrlPrefix))
            {
                ModelState.AddModelError(nameof(CreateApiViewModel.RequestUrlPrefix), S["Host and url prefix can not be empty at the same time."]);
            }

            if (!string.IsNullOrWhiteSpace(shellSettings.RequestUrlPrefix))
            {
                if (shellSettings.RequestUrlPrefix.Contains('/'))
                {
                    ModelState.AddModelError(nameof(CreateApiViewModel.RequestUrlPrefix), S["The url prefix can not contain more than one segment."]);
                }
            }

            if (ModelState.IsValid)
            {
                if (_shellHost.TryGetSettings(model.Name, out var settings))
                {
                    // Site already exists, return 200 for indempotency purpose

                    var token = CreateSetupToken(settings);

                    return(StatusCode(201, GetTenantUrl(settings, token)));
                }
                else
                {
                    _shellSettingsManager.SaveSettings(shellSettings);
                    var shellContext = await _shellHost.GetOrCreateShellContextAsync(shellSettings);

                    var token = CreateSetupToken(shellSettings);

                    return(Ok(GetTenantUrl(shellSettings, token)));
                }
            }

            return(BadRequest(ModelState));
        }
예제 #13
0
 public Task UpdateShellSettingsAsync(ShellSettings settings)
 {
     _shellSettingsManager.SaveSettings(settings);
     return(ReloadShellContextAsync(settings));
 }
예제 #14
0
        public string Setup(SetupContext context)
        {
            string executionId;

            // The vanilla Orchard distibution has the following features enabled.
            string[] hardcoded =
            {
                // Framework
                "Orchard.Framework",
                // Core
                "Common",           "Containers",             "Contents",       "Dashboard",     "Feeds",         "Navigation",      "Reports", "Scheduling", "Settings", "Shapes", "Title",
                // Modules
                "Orchard.Pages",    "Orchard.ContentPicker",  "Orchard.Themes", "Orchard.Users", "Orchard.Roles", "Orchard.Modules",
                "PackagingServices","Orchard.Packaging",      "Gallery",        "Orchard.Recipes"
            };

            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 + "Settings_ShellDescriptorRecord");
                    }
                    catch {
                        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");

                        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 = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
                try {
                    executionId = CreateTenantData(context, environment);
                }
                catch {
                    environment.Resolve <ITransactionManager>().Cancel();
                    throw;
                }
            }

            _shellSettingsManager.SaveSettings(shellSettings);

            return(executionId);
        }
예제 #15
0
 public IPlatoHost UpdateShell(IShellSettings settings)
 {
     _shellSettingsManager.SaveSettings(settings);
     return(this);
 }
예제 #16
0
 public override void Execute(RecipeExecutionContext context)
 {
     _shellSettings.State = TenantState.Running;
     _shellSettingsManager.SaveSettings(_shellSettings);
 }
 public void CreateTenant(ShellSettings settings)
 {
     _shellSettingsManager.SaveSettings(settings);
 }
예제 #18
0
        private string SetupInternal(SetupContext context)
        {
            string executionId;

            Logger.Information("Running setup for tenant '{0}'.", _shellSettings.Name);

            // The vanilla Orchard distibution has the following features enabled.
            string[] hardcoded =
            {
                // Framework
                "Orchard.Framework",
                // Core
                "Common",           "Containers",             "Contents",       "Dashboard",     "Feeds",         "Navigation",      "Scheduling", "Settings", "Shapes", "Title",
                // Modules
                "Orchard.Pages",    "Orchard.ContentPicker",  "Orchard.Themes", "Orchard.Users", "Orchard.Roles", "Orchard.Modules",
                "PackagingServices","Orchard.Packaging",      "Gallery",        "Orchard.Recipes"
            };

            context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty <string>()).Distinct().ToList();

            // Set shell state to "Initializing" so that subsequent HTTP requests are responded to with "Service Unavailable" while Orchard is setting up.
            _shellSettings.State = TenantState.Initializing;

            var shellSettings = new ShellSettings(_shellSettings);

            if (String.IsNullOrEmpty(shellSettings.DataProvider))
            {
                shellSettings.DataProvider         = context.DatabaseProvider;
                shellSettings.DataConnectionString = context.DatabaseConnectionString;
                shellSettings.DataTablePrefix      = context.DatabaseTablePrefix;
            }

            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();

            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>());
                    var installationPresent = true;
                    try {
                        var tablePrefix = String.IsNullOrEmpty(shellSettings.DataTablePrefix) ? "" : shellSettings.DataTablePrefix + "_";
                        schemaBuilder.ExecuteSql("SELECT * FROM " + tablePrefix + "Settings_ShellDescriptorRecord");
                    }
                    catch {
                        installationPresent = false;
                    }

                    if (installationPresent)
                    {
                        throw new OrchardException(T("A previous Orchard installation was detected in this database with this table prefix."));
                    }

                    // Workaround to avoid some Transaction issue for PostgreSQL.
                    environment.Resolve <ITransactionManager>().RequireNew();

                    schemaBuilder.CreateTable("Orchard_Framework_DataMigrationRecord", table => table
                                              .Column <int>("Id", column => column.PrimaryKey().Identity())
                                              .Column <string>("DataMigrationClass")
                                              .Column <int>("Version"));

                    schemaBuilder.AlterTable("Orchard_Framework_DataMigrationRecord",
                                             table => table.AddUniqueConstraint("UC_DMR_DataMigrationClass_Version", "DataMigrationClass", "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.
            using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
                try {
                    executionId = CreateTenantData(context, environment);
                }
                catch {
                    environment.Resolve <ITransactionManager>().Cancel();
                    throw;
                }
            }

            _shellSettingsManager.SaveSettings(shellSettings);
            return(executionId);
        }
예제 #19
0
 public void UpdateShellSettings(IShellSettings settings)
 {
     _shellSettingsManager.SaveSettings(settings);
     RecycleShellContext(settings);
 }