Example #1
0
        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));
        }
Example #2
0
        public async Task<ActionResult> IndexPOST(SetupViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return IndexViewResult(model);
            }

            var setupContext = new SetupContext
            {
                SiteName = model.SiteName,
                DatabaseProvider = model.DatabaseProvider,
                DatabaseConnectionString = model.ConnectionString,
                DatabaseTablePrefix = model.TablePrefix,
                EnabledFeatures = null, // default list,
                AdminUsername = model.AdminUserName,
                AdminEmail = model.AdminEmail,
                AdminPassword = model.Password
            };

            var executionId = await _setupService.SetupAsync(setupContext);

            var urlPrefix = "";
            if (!String.IsNullOrWhiteSpace(_shellSettings.RequestUrlPrefix))
            {
                urlPrefix = _shellSettings.RequestUrlPrefix + "/";
            }

            // Redirect to the welcome page.
            // TODO: Redirect on the home page once we don't rely on Orchard.Demo
            return Redirect("~/" + urlPrefix + "home/index");
        }
        public ActionResult IndexPOST(SetupViewModel model) {
            //HACK: (erikpo) Couldn't get a custom ValidationAttribute to validate two properties
            if (!model.DatabaseOptions && string.IsNullOrEmpty(model.DatabaseConnectionString))
                ModelState.AddModelError("DatabaseConnectionString", "A SQL connection string is required");

            if (!ModelState.IsValid) {
                return IndexViewResult(model);
            }

            try {

                var setupContext = new SetupContext {
                    SiteName = model.SiteName,
                    AdminUsername = model.AdminUsername,
                    AdminPassword = model.AdminPassword,
                    DatabaseProvider = model.DatabaseOptions ? "SQLite" : "SqlServer",
                    DatabaseConnectionString = model.DatabaseConnectionString,
                    DatabaseTablePrefix = model.DatabaseTablePrefix,
                    EnabledFeatures = null // default list
                };

                _setupService.Setup(setupContext);

                // redirect to the welcome page.
                return Redirect("~/");
            }
            catch (Exception exception) {
                _notifier.Error(T("Setup failed:"));
                for (var scan = exception; scan != null; scan = scan.InnerException) {
                    _notifier.Error(scan.Message);
                }
                return IndexViewResult(model);
            }
        }
Example #4
0
        public void Setup() {
            IEnumerable<string> enabledFeatures = null;
            if (!string.IsNullOrEmpty(this.EnabledFeatures)) {
                enabledFeatures = this.EnabledFeatures
                    .Split(',')
                    .Select(s => s.Trim())
                    .Where(s => !string.IsNullOrEmpty(s));
            }

            var setupContext = new SetupContext {
                SiteName = this.SiteName,
                AdminUsername = this.AdminUsername,
                AdminPassword = this.AdminPassword,
                DatabaseProvider = this.DatabaseProvider,
                DatabaseConnectionString = this.DatabaseConnectionString,
                DatabaseTablePrefix = this.DatabaseTablePrefix,
                EnabledFeatures = enabledFeatures
            };

            _setupService.Setup(setupContext);

            Context.Output.WriteLine(T("Site \"{0}\" sucessfully setup to run data provider \"{1}\" (with table prefix \"{2}\").",
                setupContext.SiteName,
                setupContext.DatabaseProvider,
                setupContext.DatabaseTablePrefix));
        }
Example #5
0
        public string SetupInternal(SetupContext context)
        {
            string executionId;

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

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

            // 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);
            shellSettings.DatabaseProvider = context.DatabaseProvider;
            shellSettings.ConnectionString = context.DatabaseConnectionString;
            shellSettings.TablePrefix = context.DatabaseTablePrefix;

            //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 }).ToList()
            };

            // 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.CreateShellContext(shellSettings))
            {
                executionId = CreateTenantData(context, environment);

                using (var store = (IStore)environment.ServiceProvider.GetService(typeof(IStore)))
                {
                    store.InitializeAsync();
                }
            }

            shellSettings.State = TenantState.Running;
            _orchardHost.UpdateShellSettings(shellSettings);
            return executionId;
        }
Example #6
0
 public string Setup(SetupContext context)
 {
     var initialState = _shellSettings.State;
     try {
         return SetupInternal(context);
     }
     catch {
         _shellSettings.State = initialState;
         throw;
     }
 }
Example #7
0
 public async Task<string> SetupAsync(SetupContext context)
 {
     var initialState = _shellSettings.State;
     try
     {
         return await SetupInternalAsync(context);
     }
     catch
     {
         _shellSettings.State = initialState;
         throw;
     }
 }
Example #8
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;
        }
Example #9
0
        public ActionResult IndexPOST(SetupViewModel model)
        {
            if (!ModelState.IsValid) {
                return IndexViewResult(model);
            }

            var setupContext = new SetupContext {
                SiteName = model.SiteName,
                EnabledFeatures = null, // default list
            };

            var executionId = _setupService.Setup(setupContext);

            // redirect to the welcome page.
            return Redirect("~/" + _shellSettings.RequestUrlPrefix + "home/index");
        }
Example #10
0
        public async Task<ActionResult> IndexPOST(SetupViewModel model)
        {
            model.DatabaseProviders = GetDatabaseProviders();
            model.Recipes = await _setupService.GetSetupRecipesAsync();

            var selectedProvider = model.DatabaseProviders.FirstOrDefault(x => x.Value == model.DatabaseProvider);

            if (selectedProvider != null && selectedProvider.HasConnectionString && String.IsNullOrWhiteSpace(model.ConnectionString))
            {
                ModelState.AddModelError("ConnectionString", T["The connection string is mandatory for this provider"]);
            }

            if (String.IsNullOrEmpty(model.Password))
            {
                ModelState.AddModelError(nameof(model.Password), T["The password is required"]);
            }

            if (model.Password != model.PasswordConfirmation)
            {
                ModelState.AddModelError(nameof(model.PasswordConfirmation), T["The password confirmation doesn't match the password."]);
            }

            RecipeDescriptor selectedRecipe = null;

            if (String.IsNullOrEmpty(model.RecipeName) || (selectedRecipe = model.Recipes.FirstOrDefault(x => x.Name == model.RecipeName)) == null)
            {
                ModelState.AddModelError(nameof(model.RecipeName), T["Invalid recipe."]);
            }

            if (!ModelState.IsValid)
            {
                return View(model);
            }

            var setupContext = new SetupContext
            {
                SiteName = model.SiteName,
                DatabaseProvider = model.DatabaseProvider,
                DatabaseConnectionString = model.ConnectionString,
                DatabaseTablePrefix = model.TablePrefix,
                EnabledFeatures = null, // default list,
                AdminUsername = model.AdminUserName,
                AdminEmail = model.AdminEmail,
                AdminPassword = model.Password,
                Errors = new Dictionary<string, string>(),
                Recipe = selectedRecipe
            };

            var executionId = await _setupService.SetupAsync(setupContext);

            // Check if a component in the Setup failed
            if (setupContext.Errors.Any())
            {
                foreach (var error in setupContext.Errors)
                {
                    ModelState.AddModelError(error.Key, error.Value);
                }

                return View(model);
            }

            var urlPrefix = "";
            if (!String.IsNullOrWhiteSpace(_shellSettings.RequestUrlPrefix))
            {
                urlPrefix = _shellSettings.RequestUrlPrefix + "/";
            }

            return Redirect("~/" + urlPrefix);
        }
        public ActionResult IndexPOST(SetupViewModel model) {
            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", "قربون، رشته اتصال لازمه ها!");

            if (!String.IsNullOrWhiteSpace(model.ConfirmPassword) && model.AdminPassword != model.ConfirmPassword ) {
                ModelState.AddModelError("ConfirmPassword", "قربونت برم، رمزهای عبوری که وارد کردی مثل هم نیستن.");
            }

            if (model.DatabaseProvider != SetupDatabaseType.Builtin && !String.IsNullOrWhiteSpace(model.DatabaseTablePrefix)) {
                model.DatabaseTablePrefix = model.DatabaseTablePrefix.Trim();
                if(!Char.IsLetter(model.DatabaseTablePrefix[0])) {
                    ModelState.AddModelError("DatabaseTablePrefix", "شرمنده، ولی پیشوندهای جدول ها باید حتما با حرف شروع بشه");
                }

                if(model.DatabaseTablePrefix.Any(x => !Char.IsLetterOrDigit(x))) {
                    ModelState.AddModelError("DatabaseTablePrefix", "قربونت برم، پیشوندهای جدول ها فقط میتونه حرف یا عدد باشه، چیز دیگه نمیشه");
                }
            }
            if (model.Recipe == null) {
                if (!(recipes.Select(r => r.Name).Contains(DefaultRecipe))) {
                    ModelState.AddModelError("Recipe", "دستور پخت ها رو توی ماژول Setup پیدا نکردم. ببینم، ارچاردفا رو دستکاری کردی؟");
                }
                else {
                    model.Recipe = DefaultRecipe;
                }
            }
            if (!ModelState.IsValid) {
                model.Recipes = recipes;
                foreach (var recipe in recipes.Where(recipe => recipe.Name == model.Recipe)) {
                    model.RecipeDescription = recipe.Description;
                }
                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
                    Recipe = model.Recipe
                };

                string executionId = _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(new LocalizedString(string.Format("اوخیش، راه اندازی به خطا خورد: {0}", ex.Message)));

                model.Recipes = recipes;
                foreach (var recipe in recipes.Where(recipe => recipe.Name == model.Recipe)) {
                    model.RecipeDescription = recipe.Description;
                }
                model.DatabaseIsPreconfigured = !string.IsNullOrEmpty(_setupService.Prime().DataProvider);

                return IndexViewResult(model);
            }
        }
Example #12
0
        public string SetupInternal(SetupContext context)
        {
            string executionId;

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

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

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

            shellSettings.DatabaseProvider = context.DatabaseProvider;
            shellSettings.ConnectionString = context.DatabaseConnectionString;
            shellSettings.TablePrefix      = context.DatabaseTablePrefix;

            //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
                }).ToList()
            };

            // 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.CreateShellContext(shellSettings))
            {
                executionId = CreateTenantData(context, environment);

                using (var store = (IStore)environment.ServiceProvider.GetService(typeof(IStore)))
                {
                    store.InitializeAsync();
                }
            }

            shellSettings.State = TenantState.Running;
            _orchardHost.UpdateShellSettings(shellSettings);
            return(executionId);
        }
Example #13
0
        private string Setup(XDocument recipeDocument)
        {
            // Prepare Setup.
            var setupContext = new SetupContext {
                Recipe = _recipeParser.ParseRecipe(recipeDocument),
                AdminPassword = SuperUserPassword,
                AdminUsername = _orchardServices.WorkContext.CurrentSite.SuperUser,
                DatabaseConnectionString = _shellSettings.DataConnectionString,
                DatabaseProvider = _shellSettings.DataProvider,
                DatabaseTablePrefix = _shellSettings.DataTablePrefix,
                SiteName = _orchardServices.WorkContext.CurrentSite.SiteName,
                EnabledFeatures = Enumerable.Empty<string>()
            };

            // Delete the tenant tables.
            DropTenantDatabaseTables();

            // Execute Setup.
            var executionId = _setupService.Setup(setupContext);

            return executionId;
        }
Example #14
0
        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.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");

            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 executionId;
        }
Example #15
0
 private string CreateTenantData(SetupContext context, ShellContext shellContext)
 {
     // Must mark state as Running - otherwise standalone enviro is created "for setup"
     return(Guid.NewGuid().ToString());
 }
Example #16
0
        public async Task<string> SetupInternalAsync(SetupContext context)
        {
            string executionId;

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Running setup for tenant '{0}'.", _shellSettings.Name);
            }

            // Features to enable for Setup
            string[] hardcoded =
            {
                "Orchard.Hosting" // shortcut for built-in features
            };

            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.DatabaseProvider))
            {
                shellSettings.DatabaseProvider = context.DatabaseProvider;
                shellSettings.ConnectionString = context.DatabaseConnectionString;
                shellSettings.TablePrefix = context.DatabaseTablePrefix;
            }

            // Creating a standalone environment based on a "minimum shell descriptor".
            // 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
            // It is used to initialize the database before the recipe is run.

            using (var shellContext = _orchardHost.CreateShellContext(shellSettings))
            {
                using (var scope = shellContext.CreateServiceScope())
                {
                    executionId = CreateTenantData(context, shellContext);

                    var store = scope.ServiceProvider.GetRequiredService<IStore>();
                    await store.InitializeAsync();

                    // Create the "minimum shell descriptor"
                    await scope
                        .ServiceProvider
                        .GetService<IShellDescriptorManager>()
                        .UpdateShellDescriptorAsync(
                            0,
                            shellContext.Blueprint.Descriptor.Features,
                            shellContext.Blueprint.Descriptor.Parameters);

                   // Apply all migrations for the newly initialized tenant
                    var dataMigrationManager = scope.ServiceProvider.GetService<IDataMigrationManager>();
                    await dataMigrationManager.UpdateAllFeaturesAsync();

                    var deferredTaskEngine = scope.ServiceProvider.GetService<IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }

                    // Invoke modules to react to the setup event
                    var eventBus = scope.ServiceProvider.GetService<IEventBus>();
                    await eventBus.NotifyAsync<ISetupEventHandler>(x => x.Setup(
                        context.SiteName,
                        context.AdminUsername,
                        context.AdminEmail,
                        context.AdminPassword,
                        context.DatabaseProvider,
                        context.DatabaseConnectionString,
                        context.DatabaseTablePrefix)
                    );

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }
                }
            }

            shellSettings.State = TenantState.Running;
            _orchardHost.UpdateShellSettings(shellSettings);
            return executionId;
        }
Example #17
0
        public async Task<string> SetupInternalAsync(SetupContext context)
        {
            string executionId;

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Running setup for tenant '{0}'.", _shellSettings.Name);
            }

            // Features to enable for Setup
            string[] hardcoded =
            {
                "Orchard.Hosting", // shortcut for built-in features
                "Orchard.Modules",
                "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.DatabaseProvider))
            {
                shellSettings.DatabaseProvider = context.DatabaseProvider;
                shellSettings.ConnectionString = context.DatabaseConnectionString;
                shellSettings.TablePrefix = context.DatabaseTablePrefix;
            }

            // Creating a standalone environment based on a "minimum shell descriptor".
            // 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
            // It is used to initialize the database before the recipe is run.

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

            using (var shellContext = _shellContextFactory.CreateDescribedContext(shellSettings, shellDescriptor))
            {
                using (var scope = shellContext.CreateServiceScope())
                {
                    var store = scope.ServiceProvider.GetRequiredService<IStore>();

                    try
                    {
                        await store.InitializeAsync();
                    }
                    catch
                    {
                        // Tables already exist or database was not found

                        // The issue is that the user creation needs the tables to be present,
                        // if the user information is not valid, the next POST will try to recreate the
                        // tables. The tables should be rollbacked if one of the steps is invalid,
                        // unless the recipe is executing?
                    }

                    // Create the "minimum shell descriptor"
                    await scope
                        .ServiceProvider
                        .GetService<IShellDescriptorManager>()
                        .UpdateShellDescriptorAsync(0,
                            shellContext.Blueprint.Descriptor.Features,
                            shellContext.Blueprint.Descriptor.Parameters);

                    // Apply all migrations for the newly initialized tenant
                    var dataMigrationManager = scope.ServiceProvider.GetService<IDataMigrationManager>();
                    await dataMigrationManager.UpdateAllFeaturesAsync();

                    var deferredTaskEngine = scope.ServiceProvider.GetService<IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }
                }

                _orchardHost.UpdateShellSettings(shellSettings);

                executionId = Guid.NewGuid().ToString("n");

                // Create a new scope for the recipe thread to prevent race issues with other scoped
                // services from the request.
                using (var scope = shellContext.CreateServiceScope())
                {
                    var recipeExecutor = scope.ServiceProvider.GetService<IRecipeExecutor>();

                    // Right now we run the recipe in the same thread, later use polling from the setup screen
                    // to query the current execution.
                    //await Task.Run(async () =>
                    //{
                    await recipeExecutor.ExecuteAsync(executionId, context.Recipe);
                    //});

                }
            }

            // Reloading the shell context as the recipe  has probably updated its features
            using (var shellContext = _orchardHost.CreateShellContext(shellSettings))
            {
                using (var scope = shellContext.CreateServiceScope())
                {
                    // Apply all migrations for the newly initialized tenant
                    var dataMigrationManager = scope.ServiceProvider.GetService<IDataMigrationManager>();
                    await dataMigrationManager.UpdateAllFeaturesAsync();

                    bool hasErrors = false;

                    Action<string, string> reportError = (key, message) => {
                        hasErrors = true;
                        context.Errors[key] = message;
                    };

                    // Invoke modules to react to the setup event
                    var eventBus = scope.ServiceProvider.GetService<IEventBus>();
                    await eventBus.NotifyAsync<ISetupEventHandler>(x => x.Setup(
                        context.SiteName,
                        context.AdminUsername,
                        context.AdminEmail,
                        context.AdminPassword,
                        context.DatabaseProvider,
                        context.DatabaseConnectionString,
                        context.DatabaseTablePrefix,
                        reportError
                    ));

                    if (hasErrors)
                    {
                        // TODO: check why the tables creation is not reverted
                        var session = scope.ServiceProvider.GetService<YesSql.Core.Services.ISession>();
                        session.Cancel();

                        return executionId;
                    }

                    var deferredTaskEngine = scope.ServiceProvider.GetService<IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }
                }

                // Update the shell state
                shellSettings.State = TenantState.Running;
                _orchardHost.UpdateShellSettings(shellSettings);
            }


            return executionId;
        }
        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.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 shellDescriptorRepository = environment.Resolve <IRepository <ShellDescriptorRecord> >();
                    try
                    {
                        shellDescriptorRepository.Get(x => true);
                    }
                    catch
                    {
                        var schemaBuilder      = new SchemaBuilder(environment.Resolve <IDataMigrationInterpreter>());
                        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 = new TenantState("Running");
            using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
                try {
                    executionId = CreateTenantData(context, environment);
                }
                catch {
                    environment.Resolve <ITransactionManager>().Cancel();
                    throw;
                }
            }

            _shellSettingsManager.SaveSettings(shellSettings);

            return(executionId);
        }
Example #19
0
        public async Task <string> SetupInternalAsync(SetupContext context)
        {
            string executionId;

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Running setup for tenant '{0}'.", _shellSettings.Name);
            }

            // Features to enable for Setup
            string[] hardcoded =
            {
                "Orchard.Commons",
                "Orchard.Modules",
                "Orchard.Recipes",
                "Orchard.Scripting"
            };

            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.DatabaseProvider))
            {
                shellSettings.DatabaseProvider = context.DatabaseProvider;
                shellSettings.ConnectionString = context.DatabaseConnectionString;
                shellSettings.TablePrefix      = context.DatabaseTablePrefix;
            }

            // Creating a standalone environment based on a "minimum shell descriptor".
            // 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
            // It is used to initialize the database before the recipe is run.

            var shellDescriptor = new ShellDescriptor
            {
                Features = context.EnabledFeatures.Select(id => new ShellFeature {
                    Id = id
                }).ToList()
            };

            using (var shellContext = await _shellContextFactory.CreateDescribedContextAsync(shellSettings, shellDescriptor))
            {
                using (var scope = shellContext.CreateServiceScope())
                {
                    var store = scope.ServiceProvider.GetRequiredService <IStore>();

                    try
                    {
                        await store.InitializeAsync();
                    }
                    catch (Exception e)
                    {
                        // Tables already exist or database was not found

                        // The issue is that the user creation needs the tables to be present,
                        // if the user information is not valid, the next POST will try to recreate the
                        // tables. The tables should be rolled back if one of the steps is invalid,
                        // unless the recipe is executing?

                        _logger.LogError("An error occurred while initializing the datastore.", e);
                        context.Errors.Add("DatabaseProvider", T["An error occurred while initializing the datastore: {0}", e.Message]);
                        return(null);
                    }

                    // Create the "minimum shell descriptor"
                    await scope
                    .ServiceProvider
                    .GetService <IShellDescriptorManager>()
                    .UpdateShellDescriptorAsync(0,
                                                shellContext.Blueprint.Descriptor.Features,
                                                shellContext.Blueprint.Descriptor.Parameters);

                    var deferredTaskEngine = scope.ServiceProvider.GetService <IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }
                }

                executionId = Guid.NewGuid().ToString("n");

                // Create a new scope for the recipe thread to prevent race issues with other scoped
                // services from the request.
                using (var scope = shellContext.CreateServiceScope())
                {
                    var recipeExecutor = scope.ServiceProvider.GetService <IRecipeExecutor>();

                    // Right now we run the recipe in the same thread, later use polling from the setup screen
                    // to query the current execution.
                    //await Task.Run(async () =>
                    //{
                    await recipeExecutor.ExecuteAsync(executionId, context.Recipe, new
                    {
                        SiteName                 = context.SiteName,
                        AdminUsername            = context.AdminUsername,
                        AdminEmail               = context.AdminEmail,
                        AdminPassword            = context.AdminPassword,
                        DatabaseProvider         = context.DatabaseProvider,
                        DatabaseConnectionString = context.DatabaseConnectionString,
                        DatabaseTablePrefix      = context.DatabaseTablePrefix
                    });

                    //});
                }
            }

            // Reloading the shell context as the recipe  has probably updated its features
            using (var shellContext = await _orchardHost.CreateShellContextAsync(shellSettings))
            {
                using (var scope = shellContext.CreateServiceScope())
                {
                    bool hasErrors = false;

                    Action <string, string> reportError = (key, message) => {
                        hasErrors           = true;
                        context.Errors[key] = message;
                    };

                    // Invoke modules to react to the setup event
                    var eventBus = scope.ServiceProvider.GetService <IEventBus>();
                    await eventBus.NotifyAsync <ISetupEventHandler>(x => x.Setup(
                                                                        context.SiteName,
                                                                        context.AdminUsername,
                                                                        context.AdminEmail,
                                                                        context.AdminPassword,
                                                                        context.DatabaseProvider,
                                                                        context.DatabaseConnectionString,
                                                                        context.DatabaseTablePrefix,
                                                                        reportError
                                                                        ));

                    if (hasErrors)
                    {
                        return(executionId);
                    }

                    var deferredTaskEngine = scope.ServiceProvider.GetService <IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }
                }
            }

            // Update the shell state
            shellSettings.State = TenantState.Running;
            _orchardHost.UpdateShellSettings(shellSettings);

            return(executionId);
        }
Example #20
0
        public async Task <string> SetupInternalAsync(SetupContext context)
        {
            string executionId;

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Running setup for tenant '{0}'.", _shellSettings.Name);
            }

            // Features to enable for Setup
            string[] hardcoded =
            {
                "Orchard.Hosting",
                "Orchard.Settings",
            };

            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.DatabaseProvider))
            {
                shellSettings.DatabaseProvider = context.DatabaseProvider;
                shellSettings.ConnectionString = context.DatabaseConnectionString;
                shellSettings.TablePrefix      = context.DatabaseTablePrefix;
            }

            // TODO: Add Encryption Settings in

            // Creating a standalone environment based on a "minimum shell descriptor".
            // 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
            // It is used to initialize the database before the recipe is run.

            using (var environment = _orchardHost.CreateShellContext(shellSettings))
            {
                using (var scope = environment.CreateServiceScope())
                {
                    executionId = CreateTenantData(context, environment);

                    var store = scope.ServiceProvider.GetRequiredService <IStore>();
                    await store.InitializeAsync();

                    // Create the "minimum shell descriptor"
                    await scope
                    .ServiceProvider
                    .GetService <IShellDescriptorManager>()
                    .UpdateShellDescriptorAsync(
                        0,
                        environment.Blueprint.Descriptor.Features,
                        environment.Blueprint.Descriptor.Parameters);
                }

                using (var scope = environment.CreateServiceScope())
                {
                    // Apply all migrations for the newly initialized tenant
                    var dataMigrationManager = scope.ServiceProvider.GetService <IDataMigrationManager>();
                    await dataMigrationManager.UpdateAllFeaturesAsync();

                    // Invoke modules to react to the setup event
                    var eventBus = scope.ServiceProvider.GetService <IEventBus>();
                    await eventBus.NotifyAsync <ISetupEventHandler>(x => x.Setup(
                                                                        context.SiteName,
                                                                        context.AdminUsername,
                                                                        context.AdminEmail,
                                                                        context.AdminPassword,
                                                                        context.DatabaseProvider,
                                                                        context.DatabaseConnectionString,
                                                                        context.DatabaseTablePrefix)
                                                                    );
                }
            }

            shellSettings.State = TenantState.Running;
            _runningShellRouterTable.Remove(shellSettings.Name);
            _orchardHost.UpdateShellSettings(shellSettings);
            return(executionId);
        }
Example #21
0
        public string SetupInternal(SetupContext context)
        {
            string executionId;

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Running setup for tenant '{0}'.", _shellSettings.Name);
            }

            // Features to enable for Setup
            string[] hardcoded = {
                // Framework
                "Orchard.Hosting",
                // Core
                "Settings"
                };

            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.DatabaseProvider))
            {
                shellSettings.DatabaseProvider = context.DatabaseProvider;
                shellSettings.ConnectionString = context.DatabaseConnectionString;
                shellSettings.TablePrefix = context.DatabaseTablePrefix;
            }

            // TODO: Add Encryption Settings in

            // Creating a standalone environment based on a "minimum shell descriptor".
            // 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
            // It is used to initialize the database before the recipe is run.

            using (var environment = _orchardHost.CreateShellContext(shellSettings))
            {
                using (var scope = environment.CreateServiceScope())
                {
                    executionId = CreateTenantData(context, environment);

                    var store = scope.ServiceProvider.GetRequiredService<IStore>();
                    store.InitializeAsync();

                    // Create the "minimum shell descriptor"
                    scope
                        .ServiceProvider
                        .GetService<IShellDescriptorManager>()
                        .UpdateShellDescriptorAsync(
                            0,
                            environment.Blueprint.Descriptor.Features,
                            environment.Blueprint.Descriptor.Parameters).Wait();
                }
            }

            shellSettings.State = TenantState.Running;
            _runningShellRouterTable.Remove(shellSettings.Name);
            _orchardHost.UpdateShellSettings(shellSettings);
            return executionId;
        }
Example #22
0
        public void Setup(SetupContext context)
        {
            // The vanilla Orchard distibution has the following features enabled.
            if (context.EnabledFeatures == null || context.EnabledFeatures.Count() == 0) {
                string[] hardcoded = {
                    "Orchard.Framework",
                    "Common",
                    "Dashboard",
                    "Feeds",
                    "HomePage",
                    "Navigation",
                    "Scheduling",
                    "Settings",
                    "XmlRpc",
                    "Orchard.Users",
                    "Orchard.Roles",
                    "TinyMce",
                    "Orchard.Modules",
                    "Orchard.Themes",
                    "Orchard.Pages",
                    "Orchard.Blogs",
                    "Orchard.Comments",
                    "Orchard.Tags",
                    "Orchard.Media",
                    "Futures.Widgets"};

                context.EnabledFeatures = hardcoded;
            }

            var shellSettings = new ShellSettings(_shellSettings);

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

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

            var shellToplogy = _compositionStrategy.Compose(shellSettings, shellDescriptor);

            // initialize database explicitly, and store shell descriptor
            var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellToplogy);
            using (var environment = new StandaloneEnvironment(bootstrapLifetimeScope)) {
                environment.Resolve<ISessionFactoryHolder>().CreateDatabase();

                environment.Resolve<IShellDescriptorManager>().UpdateShellDescriptor(
                    0,
                    shellDescriptor.EnabledFeatures,
                    shellDescriptor.Parameters);
            }

            // 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
                    var membershipService = environment.Resolve<IMembershipService>();
                    var user =
                        membershipService.CreateUser(new CreateUserParams(context.AdminUsername, context.AdminPassword,
                                                                          String.Empty, String.Empty, String.Empty,
                                                                          true));

                    // set site name and settings
                    var siteService = environment.Resolve<ISiteService>();
                    var siteSettings = siteService.GetSiteSettings().As<SiteSettings>();
                    siteSettings.Record.SiteSalt = Guid.NewGuid().ToString("N");
                    siteSettings.Record.SiteName = context.SiteName;
                    siteSettings.Record.SuperUser = context.AdminUsername;
                    siteSettings.Record.PageTitleSeparator = " - ";

                    // set site theme
                    var themeService = environment.Resolve<IThemeService>();
                    themeService.SetSiteTheme("Classic");

                    var contentManager = environment.Resolve<IContentManager>();

                    // simulate installation-time module activation events
                    var hackInstallationGenerator = environment.Resolve<IHackInstallationGenerator>();
                    hackInstallationGenerator.GenerateInstallEvents();

                    // create home page as a CMS page
                    var page = contentManager.Create("page", VersionOptions.Draft);
                    page.As<BodyAspect>().Text = "<p>Welcome to Orchard!</p><p>Congratulations, you've successfully set-up your Orchard site.</p><p>This is the home page of your new site. We've taken the liberty to write here about a few things you could look at next in order to get familiar with the application. Once you feel confident you don't need this anymore, just click <a href=\"Admin/Pages/Edit/3\">Edit</a> to go into edit mode and replace this with whatever you want on your home page to make it your own.</p><p>One thing you could do (but you don't have to) is go into <a href=\"Admin/Settings\">Manage Settings</a> (follow the <a href=\"Admin\">Admin</a> link and then look for it under \"Settings\" in the menu on the left) and check that everything is configured the way you want.</p><p>You probably want to make the site your own. One of the ways you can do that is by clicking <a href=\"Admin/Themes\">Manage Themes</a> in the admin menu. A theme is a packaged look and feel that affects the whole site.</p><p>Next, you can start playing with the content types that we installed. For example, go ahead and click <a href=\"Admin/Pages/Create\">Add New Page</a> in the admin menu and create an \"about\" page. Then, add it to the navigation menu by going to <a href=\"Admin/Navigation\">Manage Menu</a>. You can also click <a href=\"Admin/Blogs/Create\">Add New Blog</a> and start posting by clicking \"Add New Post\".</p><p>Finally, Orchard has been designed to be extended. It comes with a few built-in modules such as pages and blogs or themes. You can install new themes by going to <a href=\"Admin/Themes\">Manage Themes</a> and clicking <a href=\"Admin/Themes/Install\">Install a new Theme</a>. Like for themes, modules are created by other users of Orchard just like you so if you feel up to it, please <a href=\"http://www.orchardproject.net/\">consider participating</a>.</p><p>--The Orchard Crew</p>";
                    page.As<RoutableAspect>().Slug = "home";
                    page.As<RoutableAspect>().Title = T("Home").ToString();
                    page.As<CommonAspect>().Owner = user;
                    if (page.Has<HasComments>()) {
                        page.As<HasComments>().CommentsShown = false;
                    }
                    contentManager.Publish(page);
                    siteSettings.Record.HomePage = "PageHomePageProvider;" + page.Id;

                    // add a menu item for the shiny new home page
                    var menuItem = contentManager.Create("menuitem");
                    menuItem.As<MenuPart>().MenuPosition = "1";
                    menuItem.As<MenuPart>().MenuText = T("Home").ToString();
                    menuItem.As<MenuPart>().OnMainMenu = true;
                    menuItem.As<MenuItem>().Url = "";

                    //Temporary fix for running setup on command line
                    if (HttpContext.Current != null) {
                        var authenticationService = environment.Resolve<IAuthenticationService>();
                        authenticationService.SignIn(user, true);
                    }

                    //Add ContentType mappings
                    var contentTypeService = environment.Resolve<IContentTypeService>();

                    //Add ContentTypePartNames to MetaData
                    contentTypeService.AddContentTypePartNameToMetaData("HasComments");
                    contentTypeService.AddContentTypePartNameToMetaData("HasTags");

                    //Add mappings from ContentTypes to ContentParts to MetaData
                    contentTypeService.MapContentTypeToContentPart("blogpost","HasComments");
                    contentTypeService.MapContentTypeToContentPart("page", "HasComments");
                    contentTypeService.MapContentTypeToContentPart("sandboxpage", "HasComments");
                    contentTypeService.MapContentTypeToContentPart("blogpost", "HasTags");
                    contentTypeService.MapContentTypeToContentPart("page", "HasTags");
                    contentTypeService.MapContentTypeToContentPart("sandboxpage", "HasTags");

                }
                catch {
                    environment.Resolve<ITransactionManager>().Cancel();
                    throw;
                }
            }

            _shellSettingsManager.SaveSettings(shellSettings);
        }
Example #23
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;
        }
Example #24
0
        private string CreateTenantData(SetupContext context, IWorkContextScope environment)
        {
            // Create site owner.
            var membershipService = environment.Resolve<IMembershipService>();
            var user = membershipService.CreateUser(
                new CreateUserParams(context.AdminUsername, context.AdminPassword,
                String.Empty, String.Empty, String.Empty, true));

            // Set site owner 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>();
            var recipe = context.Recipe;
            var executionId = recipeManager.Execute(recipe);

            // Once the recipe has finished executing, we need to update the shell state to "Running", so add a recipe step that does exactly that.
            var recipeStepQueue = environment.Resolve<IRecipeStepQueue>();
            var recipeStepResultRecordRepository = environment.Resolve<IRepository<RecipeStepResultRecord>>();
            var activateShellStep = new RecipeStep(Guid.NewGuid().ToString("N"), recipe.Name, "ActivateShell", new XElement("ActivateShell"));
            recipeStepQueue.Enqueue(executionId, activateShellStep);
            recipeStepResultRecordRepository.Create(new RecipeStepResultRecord {
                ExecutionId = executionId,
                RecipeName = recipe.Name,
                StepId = activateShellStep.Id,
                StepName = activateShellStep.Name
            });

            // Null check: temporary fix for running setup in command line.
            if (HttpContext.Current != null) {
                authenticationService.SignIn(user, true);
            }

            return executionId;
        }
Example #25
0
        private string CreateTenantData(SetupContext context, ShellContext shellContext)
        {
            // must mark state as Running - otherwise standalone enviro is created "for setup"

            return Guid.NewGuid().ToString();
        }
        public ActionResult IndexPOST(SetupViewModel model) {
            var recipes = OrderRecipes(_setupService.Recipes());

            //TODO: Couldn't get a custom ValidationAttribute to validate two properties
            if (!model.DatabaseOptions && string.IsNullOrEmpty(model.DatabaseConnectionString))
                ModelState.AddModelError("DatabaseConnectionString", T("A SQL 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.DatabaseOptions && !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.Recipe == null) {
                if (!(recipes.Select(r => r.Name).Contains(DefaultRecipe))) {
                    ModelState.AddModelError("Recipe", T("No recipes were found in the Setup module").Text);
                }
                else {
                    model.Recipe = DefaultRecipe;
                }
            }
            if (!ModelState.IsValid) {
                model.Recipes = recipes;
                foreach (var recipe in recipes.Where(recipe => recipe.Name == model.Recipe)) {
                    model.RecipeDescription = recipe.Description;
                }
                model.DatabaseIsPreconfigured = !string.IsNullOrEmpty(_setupService.Prime().DataProvider);
                
                return IndexViewResult(model);
            }

            try {
                var setupContext = new SetupContext {
                    SiteName = model.SiteName,
                    AdminUsername = model.AdminUsername,
                    AdminPassword = model.AdminPassword,
                    DatabaseProvider = model.DatabaseOptions ? "SqlCe" : "SqlServer",
                    DatabaseConnectionString = model.DatabaseConnectionString,
                    DatabaseTablePrefix = model.DatabaseTablePrefix,
                    EnabledFeatures = null, // default list
                    Recipe = model.Recipe
                };

                string executionId = _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("~/");
            } catch (Exception exception) {
                this.Error(exception, T("Setup failed:"), Logger, _notifier);

                model.Recipes = recipes;
                foreach (var recipe in recipes.Where(recipe => recipe.Name == model.Recipe)) {
                    model.RecipeDescription = recipe.Description;
                }
                model.DatabaseIsPreconfigured = !string.IsNullOrEmpty(_setupService.Prime().DataProvider);

                return IndexViewResult(model);
            }
        }
Example #27
0
        public ActionResult IndexPOST(SetupViewModel model) {
            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 (model.Recipe == null) {
                if (!(recipes.Select(r => r.Name).Contains(DefaultRecipe))) {
                    ModelState.AddModelError("Recipe", T("No recipes were found in the Setup module").Text);
                }
                else {
                    model.Recipe = DefaultRecipe;
                }
            }
            if (!ModelState.IsValid) {
                model.Recipes = recipes;
                foreach (var recipe in recipes.Where(recipe => recipe.Name == model.Recipe)) {
                    model.RecipeDescription = recipe.Description;
                }
                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
                    Recipe = model.Recipe
                };

                string executionId = _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.Recipes = recipes;
                foreach (var recipe in recipes.Where(recipe => recipe.Name == model.Recipe)) {
                    model.RecipeDescription = recipe.Description;
                }
                model.DatabaseIsPreconfigured = !string.IsNullOrEmpty(_setupService.Prime().DataProvider);

                return IndexViewResult(model);
            }
        }
Example #28
0
        private void CreateTenantData(SetupContext context, IWorkContextScope environment)
        {
            // create superuser
            var membershipService = environment.Resolve<IMembershipService>();
            var user =
                membershipService.CreateUser(new CreateUserParams(context.AdminUsername, context.AdminPassword,
                                                                  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 = (SiteSettings)siteService.GetSiteSettings();
            siteSettings.SiteSalt = Guid.NewGuid().ToString("N");
            siteSettings.SiteName = context.SiteName;
            siteSettings.SuperUser = context.AdminUsername;

            var settingService = environment.Resolve<ISettingService>();
            settingService.SaveSetting(siteSettings);

            // null check: temporary fix for running setup in command line
            if (HttpContext.Current != null)
            {
                authenticationService.SignIn(user, true);
            }
        }
Example #29
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.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 = new TenantState("Running");
            using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
                try {
                    executionId = CreateTenantData(context, environment);
                }
                catch {
                    environment.Resolve<ITransactionManager>().Cancel();
                    throw;
                }
            }

            _shellSettingsManager.SaveSettings(shellSettings);

            return executionId;
        }
Example #30
0
        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 recipe = _setupService.Recipes().GetRecipeByName(Recipe);

            var setupContext = new SetupContext {
                SiteName = SiteName,
                AdminUsername = AdminUsername,
                AdminPassword = AdminPassword,
                DatabaseProvider = DatabaseProvider,
                DatabaseConnectionString = DatabaseConnectionString,
                DatabaseTablePrefix = DatabaseTablePrefix,
                EnabledFeatures = enabledFeatures,
                Recipe = recipe,
            };

            var executionId = _setupService.Setup(setupContext);

            Context.Output.WriteLine(T("Setup of site '{0}' was started with recipe execution ID {1}. Use the 'recipes result' command to check the result of the execution.", setupContext.SiteName, executionId));
        }